如何让 CMake 动态地 link 一个与系统库合并的静态库?

How do I get CMake to dynamically link a merged static library with system libraries?

我必须使用这个可怕的 CMake 代码将我的一个应用程序库与 NVIDIA CUDA 静态库合并:

GET_TARGET_PROPERTY(OUTPUT_LIB ${LIBNAME} LOCATION)
add_custom_command (TARGET ${LIBNAME}
                    POST_BUILD
                    COMMAND mv ${OUTPUT_LIB} ${OUTPUT_LIB}.old
                    COMMAND echo "create ${OUTPUT_LIB}" > combineLibs.mri
                    COMMAND echo "addlib ${OUTPUT_LIB}.old" >> combineLibs.mri
                    COMMAND echo "addlib ${CUDA_LOCATION}"  >> combineLibs.mri
                    COMMAND echo "save"  >> combineLibs.mri
                    COMMAND echo "end" >> combineLibs.mri
                    COMMAND ar -M <combineLibs.mri
                    COMMAND rm ${OUTPUT_LIB}.old
                    COMMENT "Building merged library for ${LIBNAME} at ${OUTPUT_LIB}, including ${CUDA_LOCATION}"
)
target_link_libraries(${LIBNAME} -pthread -c)

这成功生成了一个包含所有符号的合并静态库。然而,NVIDIA CUDA 静态库以未解析符号的形式带来了对 libpthread 和 libc 的依赖。现在合并后的库也有那些未解析的符号,target_link_libraries 行似乎并没有像我认为的那样做,因为这些符号在 link 时没有被解析。如何让合并的静态库动态地 link 针对 libpthread 和 libc?

the target_link_libraries 行确实不是你想的那样。

target_link_libraries(target,options)可以达到想要的效果 仅当 target 是 linker 制作的东西。如果没有 linkage 发生在 生成 target 则此指令将无效。

您的目标是一个静态库。静态库——不像程序,也不像 dynamic/shared 库 - 不是由 linker 制作的。作为你的 custom_command 事实上说明,静态库是由 GNU 通用归档程序生成的, ar。它只不过是恰好是目标文件的文件存档, 但就 ar 而言,它们也可能是您的内容 文档、图片和音乐文件夹。由于没有 linkage 参与其中 生成静态库,什么都不能用静态库link编辑。

ar 存档可以用作 linker input 在 linkage 的东西 由 linker 制作的 - 程序或共享库。在那种情况下 linker 将查看存档以查看是否包含它需要的任何目标文件 继续 link 年龄。如果找到任何内容,它将从存档中提取它们 和 link 他们 进入程序。 linkage 将与 if 完全相同 您已经在 linker 命令行中列出了所需的目标文件,而不是 完全提到了存档。

但是如果 linker 从存档中提取的任何目标文件带来 与他们未定义的参考,然后让他们解决你必须 link 一些 在link时代定义这些引用的一个或多个图书馆 您希望 linker 制作 的程序或共享库 - 就像您一样 必须解决您在任何其他目标文件中的未定义引用 输入 linkage.

所以,

How do I get the merged static library to dynamically link against libpthread and libc?

你不能。这没有意义。目标文件的任何库依赖性 在静态库中只能在 link 程序或共享库 的年龄得到满足 通过 linking 这些目标文件获得了这些依赖关系。

最后,-c 不是 GCC linkage 选项,会产生请求的效果 linklibc 岁。它根本不是 linkage 选项。这是一个选项 指示 GCC 前端 not 调用 linker。它被传递给 GCC 以 请求没有 linkage 的编译,以及将其包含在 CMake target_link_libraries 指令将停止任何 linkage 的 目标发生。

如果要明确请求linklibc的年龄,请使用-lc,如下 linker 使用协议,-lname 请求 link年龄 libname

也许您从假设中推断出 -c 要求 linklibc 的年龄 -pthread 请求 link 年龄 libpthread。事实上,-lpthread 会 请求 linklibpthread 的年龄。选项 -pthread 是一个更抽象的 GCC 选项,对于编译和 linkage,这意味着 做正确的事情,对于这个平台,link 与 Posix 线程 library - 这可能需要将 -lpthead 传递给 linker,也可能不需要。

因此 -pthread 可以作为 target_link_libraries 的参数 具有请求 Posix 线程 linkage 的效果,但请参阅 cmake and libpthread 的答案 对于 CMake 的正确方法。