将--whole archive链接器选项与CMake和具有其他库依赖项的库一起使用
Using --whole-archive linker option with CMake and libraries with other library dependencies
我有一个项目,它曾经是一组巨大的源文件,所有这些文件都经过编译,然后链接为一个可执行文件。作为使项目更加模块化的第一步,我将构建分解为几个较小的块,并使它们成为静态库。有一个层次结构,所以Exe1
将链接到静态库Lib2A
和Lib2B
。Lib2A
将取决于静态Lib3A
、lib3B
、lib3C
等。此处的数字显示了它们在层次结构中的层。
问题是,链接时需要使用--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")
真是太棒了!虽然不是最好的解决方案,但它至少会很快得到一些结果。
- 将--whole archive链接器选项与CMake和具有其他库依赖项的库一起使用
- 对于BTreeMap和其他依赖于Ord的东西,是否有等效于C++比较器对象?
- 当 lib 已添加到其他依赖项时,如何在 VS 中调试未解析的外部符号错误
- 错误 LNK1104:错误消息中显示的路径未在其他依赖项中定义
- 可视C++ - 从链接器>输入>其他依赖项中排除文件
- 依赖于其他模板参数的模板参数
- 扣除其他类型的依赖类型
- 与具有循环依赖关系的 NS3 模块链接到其他库
- 依赖于其他静态库的静态库
- 共享库依赖于具有硬编码路径的其他库
- SFML 不静态链接到 openal32(静态链接到所有其他依赖项)
- 您可以将链接器/其他依赖项等复制到其他项目吗?
- 如何设置依赖于其他参数的参数默认值
- 如何找出特定 Boost 库需要哪些依赖项(即其他 Boost 库)
- 提供具有其他依赖项的 xcode 框架
- VC++ 2012 链接器和库管理员中的其他依赖项选项
- C++/OOP:对其他类具有隐式依赖关系的类
- C/C++Makefile:如何在with.C文件和其他目录中的对象文件之间建立依赖关系
- 依赖于其他DLL的DLL
- 如何解决结构对其他结构类型的循环依赖,在头文件库中定义(c++)