令人失望的是,这很难。我们设法在 Halide 团队中做到了,但这只是因为这是一个企业客户的硬性要求。对于没有这种限制的其他读者,我这样说:这里有龙。使用 CMake 的常用目标和依赖项,让它将所有静态库放在最终产品的链接行上。
对于 OP,我说,试试这个:
首先,在您的vendor 目录中创建一个CMakeLists.txt,内容如下:
# 0. Convenience variable
set(proprietary_lib "${CMAKE_CURRENT_SOURCE_DIR}/proprietary.a")
# 1. Get list of objects inside static lib
execute_process(COMMAND "${CMAKE_AR}" -t "${proprietary_lib}"
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
OUTPUT_VARIABLE proprietary_objects)
string(STRIP "${proprietary_objects}" proprietary_objects)
string(REPLACE "\n" ";" proprietary_objects "${proprietary_objects}")
# 2. Attach configure dependency to the static lib
set_property(DIRECTORY . APPEND PROPERTY
CMAKE_CONFIGURE_DEPENDS proprietary.a)
# 3. Extract the lib at build time
add_custom_command(
OUTPUT ${proprietary_objects}
COMMAND "${CMAKE_AR}" -x "${proprietary_lib}"
DEPENDS "${proprietary_lib}")
# 4. Get absolute paths to the extracted objects
list(TRANSFORM proprietary_objects
PREPEND "${CMAKE_CURRENT_BINARY_DIR}/")
# 5. Attach the objects to a driver target so the
# custom command doesn't race
add_custom_target(proprietary.extract DEPENDS ${proprietary_objects})
# 6. Add a target to encapsulate this
add_library(proprietary OBJECT IMPORTED GLOBAL)
set_target_properties(proprietary PROPERTIES
IMPORTED_OBJECTS "${proprietary_objects}")
# TODO: add usage requirements
# target_include_directories(proprietary INTERFACE ...)
# 7. Force proprietary to run completely after extraction
add_dependencies(proprietary proprietary.extract)
这里有很多,但最终步骤很简单,复杂之处在于解释对 CMake 的依赖关系。此外,需要注意的是它仅适用于 Linux(或至少仅与 GNU-ar 兼容的存档器)。可以为 MSVC 做类似的事情,但对于这个答案来说太过分了。
所以首先我们询问归档程序库中有哪些对象,然后我们将其每行一个对象的输出处理成一个 CMake 列表。这是上面的第 1 步。
第 2 步告诉 CMake,如果 proprietary.a 上的时间戳已更新,则需要重新运行 CMake(从而获得新的对象列表)。
第 3 步创建一个 自定义命令,该命令将在构建时运行归档工具将对象提取到 vendor 构建目录中。
在自定义命令运行后,第 4 步将(相对)对象列表转换为这些对象的绝对路径列表。这是为了 add_custom_target 的利益,它需要绝对路径(或者更确切地说,如果启用了某些策略,则会对相对路径做一些奇怪的事情)。
第 5 步创建一个自定义目标来驱动存档提取。
第 6 步创建一个 导入对象 库来封装提取的库。它必须是全局的,因为默认情况下导入的目标是目录范围的,这是对导入库功能的滥用。您可以在此处添加其他使用要求。
最后,步骤 7 将驱动程序目标的依赖项放在对象库上。
然后可以透明地使用它。这是一个例子:
cmake_minimum_required(VERSION 3.16)
project(example)
add_subdirectory(vendor)
add_library(library library.cpp)
target_link_libraries(library PRIVATE proprietary)