将--whole archive链接器选项与CMake和具有其他库依赖项的库一起使用

Using --whole-archive linker option with CMake and libraries with other library dependencies

本文关键字:依赖 其他 一起 链接 archive --whole 选项 CMake      更新时间:2023-10-16

我有一个项目,它曾经是一组巨大的源文件,所有这些文件都经过编译,然后链接为一个可执行文件。作为使项目更加模块化的第一步,我将构建分解为几个较小的块,并使它们成为静态库。有一个层次结构,所以Exe1将链接到静态库Lib2ALib2BLib2A将取决于静态Lib3Alib3Blib3C等。此处的数字显示了它们在层次结构中的层。

问题是,链接时需要使用--whole-archive,否则找不到底层库中的一些符号。

当我为Exe1的链接添加以下内容时:

target_link_libraries(Exe1 -Wl,--whole-archive Lib2A Lib2B -Wl,--no-whole-archive)

我最终得到了一个实际的链接阶段命令,如:

g++ -o Exe1 -Wl,--whole-archive libLib2A.a libLib2B.a -Wl,--no-whole-archive libLib3A.a libLib3B.a libLib3C.a

不可避免的是,一些第3层静态库中的符号会丢失,我也会出现丢失符号的错误。

我预计,由于Lib2A具有作为依赖项的Lib3*库,它们也将位于链接器命令的--whole-archive部分的"内部",但它们显示在外部。

我尝试过许多不同的组合(例如,将--whole-archive的东西放在较低的层(,但没有发现一种使用CMake的方法。我做错了什么?

感谢

对于3.12和更新版本的CMake,我将使用对象库。

我为早期版本找到的解决方法是创建一个中间静态库,该库使用一些属性魔术将所有链接依赖项放置在--whole归档部分中。对我来说,顶级静态库被称为"源"。它本身实际上什么都不包含,但与其他一些静态库有链接依赖关系。我创建了"源组合"如下:

add_library(source-combined STATIC "")
set_target_properties(source-combined PROPERTIES LINKER_LANGUAGE CXX)
target_link_libraries(source-combined PUBLIC
-Wl,--whole-archive
$<TARGET_PROPERTY:source,INTERFACE_LINK_LIBRARIES>
-Wl,--no-whole-archive
)

现在,当我通过链接到这个souce组合库来创建一个可执行文件或共享库时,我会得到--whole archive和--no whole archifile作为整个静态库集的书尾,这些静态库是"source"的链接依赖项。我花了很长时间才偶然发现这项技术,所以我分享它

如果您需要使用链接器选项--whole-archive,那么您可以定义地使用对象库:

# Lib2A/CMakeLists.txt
add_library(Lib2A OBJECT ${Lib2A_SRC})
# Lib2B/CMakeLists.txt
add_library(Lib2B OBJECT ${Lib2B_SRC})

它是可移植的,不需要使用链接器选项--whole-archive

以下对我有效。考虑两个库:

  • my_platform
  • my_clib

我们想要my_clib的整个存档,以及指向它的my_platform链接。

add_library(my_platform INTERFACE) # this could also be a regular library
add_library(my_clib STATIC)
target_sources(my_clib
PRIVATE 
gcc_newlib_nano.c 
gcc_newlib_nano_cpp.cc 
)
# Link my_clib and any other libs
target_link_libraries(my_platform
INTERFACE
my_clib
)
# Ensure the whole archive is linked
target_link_options(my_platform
INTERFACE
-Wl,--whole-archive ${CMAKE_CURRENT_BINARY_DIR}/libmy_clib.a -Wl,--no-whole-archive
)

CMake 3.24添加了一种使用LINK_LIBRARY:WHOLE_ARCHIVE生成器表达式来实现这一点的官方方法:

add_library(lib1 STATIC ...)
add_library(lib2 ...)
target_link_libraries(lib2 PRIVATE "$<LINK_LIBRARY:WHOLE_ARCHIVE,lib1>")

也就是说,使用对象库通常是一个更容易的解决方案。这样,您链接的库中已编译的对象文件列表只需在最终的链接器命令中按原样使用,而不是首先创建静态库文件。

作为上述答案的替代方案,我需要快速而肮脏地了解添加整个归档目标标志(或将代码库转换为对象库…(是否是正确的解决方案。通过遵循默认链接命令的CMake源代码,我将项目的命令修改为:

set(CMAKE_CXX_LINK_EXECUTABLE "<CMAKE_CXX_COMPILER>  <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> -Wl,--start-group -Wl,--whole-archive <LINK_LIBRARIES> -Wl,--no-whole-archive -Wl,--end-group")

真是太棒了!虽然不是最好的解决方案,但它至少会很快得到一些结果。