CMake将静态库链接至可执行文件时出现符号缺失问题求解
你当前的配置不生效的核心原因是:静态库(.a文件)的构建过程仅为编译后的目标文件归档操作,不会执行链接步骤,因此你在target_link_libraries中添加的-Wl,--whole-archive等链接器参数,在静态库构建阶段完全不会被执行,自然无法将Boost依赖的符号打包到你的静态库中。该参数仅在构建动态库(.so/.dll)或可执行文件时才会生效。
你遇到的符号缺失报错,本质是下游可执行文件链接你的静态库时,没有额外链接你依赖的Boost组件导致的。
根据你的交付场景可以选择以下任意一种方案:
方案1:依赖自动传递(最简单,无需修改打包逻辑)
如果你的静态库使用者也是通过CMake引入依赖,只需要删除你当前配置中的链接器参数,直接用PUBLIC属性关联Boost依赖即可:
target_link_libraries(myStaticLib PUBLIC Boost::system Boost::thread Boost::coroutine )
CMake会自动将PUBLIC属性的依赖传递给下游目标,当下游可执行文件执行target_link_libraries(myApp PRIVATE myStaticLib)时,会自动把上述3个Boost库加入链接列表,不会出现符号缺失问题。
方案2:合并所有依赖符号到单个静态库(适合单文件交付)
如果你需要给下游提供单个独立的静态库文件,不需要下游额外安装Boost依赖,可以通过自定义命令把Boost静态库的目标文件和你自己的静态库目标文件合并为一个新的静态库:
Linux环境示例:
# 创建临时目录用于解压目标文件 file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/merge_temp) add_custom_command(TARGET myStaticLib POST_BUILD # 解压所有依赖静态库的目标文件 COMMAND ar -x $<TARGET_FILE:Boost::system> COMMAND ar -x $<TARGET_FILE:Boost::thread> COMMAND ar -x $<TARGET_FILE:Boost::coroutine> COMMAND ar -x $<TARGET_FILE:myStaticLib> # 打包所有目标文件为新的静态库 COMMAND ar -rc ${CMAKE_BINARY_DIR}/myStaticLib_all.a *.o COMMAND ranlib ${CMAKE_BINARY_DIR}/myStaticLib_all.a WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/merge_temp )
最终生成的myStaticLib_all.a已经包含所有依赖的符号,下游直接链接该文件即可。
注:Mac环境可替换为
libtool命令合并,Windows环境可使用lib命令完成合并操作。
方案3:改为构建动态库
如果可以接受交付动态库,只需要将你的库类型改为SHARED,你原来的链接器参数就会正常生效,所有Boost的符号会被打包到动态库中,下游直接链接动态库即可:
add_library(mySharedLib SHARED ${YOUR_LIB_SOURCES}) target_link_libraries(mySharedLib PUBLIC -Wl,--whole-archive Boost::system Boost::thread Boost::coroutine -Wl,--no-whole-archive )
内容的提问来源于stack exchange,提问作者Zohar81

