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)