cmake post-进程静态库目标
cmake post-process static library target
我正在使用 cmake 来创建我的静态库,其中包含
add_library(library library.cpp)
install(TARGETS library DESTINATION lib)
创建 liblibrary.a
这就是我想要的。但是我想将它与一个库捆绑在一起,让我们说 vendor/proprietary.a
通过做一些自定义的事情
tmp=$(mktemp -d)
cd $tmp
ar -x $<TARGET_FILE:library>
ar -x vendor/proprietary.a
ar -qc $<TARGET_FILE:library> *
rm -rf $tmp
我可以用 cmake 做到这一点而不会忘记目标 library
实际上是一个库(例如通过使用 add_custom_command
/add_custom_target
)。
令人失望的是,这很难。我们设法在 Halide 团队中做到了,但这只是因为这是来自公司客户的硬性要求。对于没有这种限制的其他读者,我这样说:这里有龙。使用 CMake 的常用目标和依赖项,让它将所有静态库放在最终产品的 link 行。
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-only(或至少 GNU-ar-compatible archiver only)。可以为 MSVC 做类似的事情,但对于这个答案来说太多了。
因此,首先我们询问存档器库中有哪些对象,然后我们将其每行一个对象的输出轻松处理到 CMake 列表中。这是上面的第 1 步。
第 2 步告诉 CMake,如果 proprietary.a
上的时间戳被更新,那么它将需要重新 运行 CMake(从而获得新的对象列表)。
第 3 步创建一个 自定义命令 ,它将在构建时 运行 归档工具将对象提取到 vendor
构建目录中。
步骤 4 在自定义命令 运行s 之后将(相对)对象列表转换为这些对象的绝对路径列表。这是为了 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)
我正在使用 cmake 来创建我的静态库,其中包含
add_library(library library.cpp)
install(TARGETS library DESTINATION lib)
创建 liblibrary.a
这就是我想要的。但是我想将它与一个库捆绑在一起,让我们说 vendor/proprietary.a
通过做一些自定义的事情
tmp=$(mktemp -d)
cd $tmp
ar -x $<TARGET_FILE:library>
ar -x vendor/proprietary.a
ar -qc $<TARGET_FILE:library> *
rm -rf $tmp
我可以用 cmake 做到这一点而不会忘记目标 library
实际上是一个库(例如通过使用 add_custom_command
/add_custom_target
)。
令人失望的是,这很难。我们设法在 Halide 团队中做到了,但这只是因为这是来自公司客户的硬性要求。对于没有这种限制的其他读者,我这样说:这里有龙。使用 CMake 的常用目标和依赖项,让它将所有静态库放在最终产品的 link 行。
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-only(或至少 GNU-ar-compatible archiver only)。可以为 MSVC 做类似的事情,但对于这个答案来说太多了。
因此,首先我们询问存档器库中有哪些对象,然后我们将其每行一个对象的输出轻松处理到 CMake 列表中。这是上面的第 1 步。
第 2 步告诉 CMake,如果 proprietary.a
上的时间戳被更新,那么它将需要重新 运行 CMake(从而获得新的对象列表)。
第 3 步创建一个 自定义命令 ,它将在构建时 运行 归档工具将对象提取到 vendor
构建目录中。
步骤 4 在自定义命令 运行s 之后将(相对)对象列表转换为这些对象的绝对路径列表。这是为了 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)