如何使用CMake避免链接不必要的静态库?
CMake避免链接不必要静态库的解决方案
针对当前场景的具体解决方法
问题核心在于:lib1对utils只有编译阶段的头文件依赖,不需要将utils的链接依赖传递给下游的main目标,以下是两种可行的落地方法:
方案1:拆分编译依赖与链接依赖
直接提取utils的头文件目录配置给lib1,不通过target_link_libraries关联utils静态库,从根源上切断依赖传递:
# 替换lib1中原来的target_link_libraries(lib1 PRIVATE utils)配置 target_include_directories(lib1 PRIVATE $<TARGET_PROPERTY:utils,INTERFACE_INCLUDE_DIRECTORIES>)
该方案下:
lib1编译时依然可以获取到utils的头文件路径,不影响自身代码编译lib1不会携带对utils的链接依赖,main链接lib1时不会自动引入utils,也不会强制要求编译utils- 如果后续有其他可执行文件需要调用
lib1中依赖utils的函数,只需手动给该可执行文件添加target_link_libraries(other_target PRIVATE lib1 utils)即可
方案2:配置静态库依赖不传递
如果你需要保留lib1对utils的target_link_libraries配置,可以给main目标设置属性,禁止继承静态库的私有静态链接依赖:
# 加在main的CMakeLists.txt中target_link_libraries配置之前或之后均可 set_target_properties(main PROPERTIES LINK_DEPENDS_NO_STATIC TRUE)
CMake 3.16及以上版本支持该属性,开启后链接main时会忽略所有依赖静态库的私有静态链接依赖,不会把utils加入main的链接列表,也不会在构建main时强制编译utils。
通用场景下避免链接冗余静态库的方法
- 严格区分编译依赖和链接依赖:不要为了获取头文件路径就直接链接整个静态库,编译阶段的头文件依赖可以通过
target_include_directories单独配置,也可以用无实现的INTERFACE库封装头文件配置,仅当确实需要依赖对应实现时才通过target_link_libraries关联。 - 合理使用链接可见性配置:
PRIVATE:仅当前目标需要该依赖的编译、链接属性,不需要传递给下游INTERFACE:仅下游目标需要该依赖的属性,当前目标本身不需要PUBLIC:当前目标和下游目标都需要该依赖的属性
对于静态库的私有依赖如果不需要传递给下游,可以手动清空静态库的INTERFACE_LINK_LIBRARIES属性,避免下游自动继承链接依赖。
- 按需启用可选依赖:对于功能模块的可选依赖,通过
option配置开关,仅在开关开启时才将对应依赖加入链接列表,同时通过预编译宏控制对应功能代码的编译。 - 利用链接器优化:开启链接器的垃圾回收功能,MSVC可以加
/OPT:REF选项,GCC/Clang可以加-Wl,--gc-sections选项,会自动移除最终二进制中没有用到的符号,即使链接了冗余静态库也不会增加最终文件体积。
内容的提问来源于stack exchange,提问作者Elad Maimoni
相关产品推荐
相关产品推荐

