CMake中使用对象库构建静态与共享库的正确方式及依赖问题
CMake OBJECT库构建静态/共享库的私有依赖问题与解决方案
首先明确:OBJECT库本身没有根本性缺陷,你遇到的私有依赖不当传播问题,源于CMake对OBJECT库依赖的特殊处理逻辑——OBJECT库的私有依赖会被继承到所有引用它的目标中,这和直接构建共享库时私有依赖仅作用于当前目标的逻辑不同。
解决方法(同时避免重复编译)
以下几种方式可以在复用OBJECT库编译结果的前提下,解决依赖传播问题:
直接引用OBJECT库的目标文件列表
不将OBJECT库作为target_link_libraries的依赖项,而是用$<TARGET_OBJECTS:foo-object>直接把对象文件注入到静态/共享库中,然后单独给最终库设置私有依赖:# 定义OBJECT库,仅编译源码生成目标文件 add_library(foo-object OBJECT foo.cpp) target_compile_options(foo-object PRIVATE -fPIC) # 统一设置-fPIC,满足静态库需求 # 构建静态库 add_library(foo-static STATIC $<TARGET_OBJECTS:foo-object>) # 构建共享库,单独设置私有依赖 add_library(foo-shared SHARED $<TARGET_OBJECTS:foo-object>) target_link_libraries(foo-shared PRIVATE uuid)这种方式下,foo-shared的私有依赖
uuid不会被传播到测试程序foo-test。剥离OBJECT库的依赖,移到最终库中
如果之前把依赖加在了OBJECT库上,现在把依赖从OBJECT库移除,只在最终的静态/共享库中按需添加:add_library(foo-object OBJECT foo.cpp) target_compile_options(foo-object PRIVATE -fPIC) # 静态库无需依赖uuid,直接构建 add_library(foo-static STATIC $<TARGET_OBJECTS:foo-object>) # 共享库单独添加私有依赖 add_library(foo-shared SHARED $<TARGET_OBJECTS:foo-object>) target_link_libraries(foo-shared PRIVATE uuid)这样OBJECT库仅负责编译源码,依赖由最终库自行管理,从根源上避免了依赖不当传播。
使用CMake 3.13+的私有链接语法
如果你必须将OBJECT库作为依赖项链接,确保在引用时明确使用PRIVATE关键字,同时调整OBJECT库的依赖范围:add_library(foo-object OBJECT foo.cpp) target_compile_options(foo-object PRIVATE -fPIC) # OBJECT库的依赖设为PRIVATE,但仍需注意:OBJECT库的依赖会被传递到引用它的目标 target_link_libraries(foo-object PRIVATE uuid) add_library(foo-shared SHARED) target_sources(foo-shared PRIVATE $<TARGET_OBJECTS:foo-object>) # 显式限定OBJECT库的依赖仅作用于当前共享库 target_link_libraries(foo-shared PRIVATE foo-object)这种方式能一定程度上限制依赖传播,但不如前两种方式直接。
关于重复编译
OBJECT库的核心作用就是复用编译后的目标文件,只要正确配置,就能实现一次编译源码,同时生成静态库和共享库,不会出现重复编译的问题。你遇到的问题是依赖传播逻辑导致的,而非OBJECT库本身的设计缺陷。
内容的提问来源于stack exchange,提问作者Ton van den Heuvel
相关产品推荐
相关产品推荐

