【问题标题】:cmake post-process static library targetcmake 后处理静态库目标
【发布时间】:2021-01-31 03:47:52
【问题描述】:

我正在使用 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)。

【问题讨论】:

    标签: c++ cmake target


    【解决方案1】:

    令人失望的是,这很难。我们设法在 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)
    

    【讨论】:

    • 非常感谢您的努力!
    • 完美!有用!顺便说一句,链接时我得到relocation R_X86_64_32 against '.rodata.str1.8' can not be used when making a PIE object; recompile with '-fPIC'。有没有办法告诉 cmake“每当您与 propertiary 或其任何依赖项链接时使用编译器标志 -no-pie”?
    • 您可以通过使用set_target_properties 将目标属性POSITION_INDEPENDENT_CODE 设置为OFF 来禁用library 的PIC
    猜你喜欢
    • 2018-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多