能,Object_library通过预编译共享对象文件减少重复编译,但仅在多目标共用相同源码且正确引用时有效;改头文件仍会触发整个object library重编译。

什么是 OBJECT_LIBRARY,它真能减少重编译吗?
能,但只在特定结构下有效——它把源码编译成中间对象文件(.o 或 .obj),不打包成静态库,也不生成符号表,因此不会触发下游目标的全量重链接。关键在于:它让多个可执行目标或库共享同一组预编译对象,避免重复编译相同源码。
常见错误现象:add_library(myobj OBJECT src/a.cpp src/b.cpp) 写对了,但后续 target_sources(exe1 private $<myobj>)</myobj> 漏掉 PRIVATE 或路径拼错,导致对象没被实际引用,白忙一场。
使用场景:
- 多个测试可执行文件共用同一套工具函数和 fixture 类(比如
test_utils.cpp+mock_network.cpp) - 主程序和插件模块共享核心解析逻辑,但插件需独立加载
- 跨平台项目中,把平台无关逻辑抽为 object library,再按需链接进 windows DLL / linux SO
target_sources() 引用 object library 时为什么总报 “unknown target”?
因为 $<xxx></xxx> 是生成器表达式,只能用在支持该语法的命令里,最典型的是 target_sources() 和 target_link_libraries()(后者仅限 CMake 3.12+ 且仅用于链接时传递依赖,不推荐)。如果写在 add_executable() 的源码列表里,CMake 会直接报错说找不到 target。
立即学习“C++免费学习笔记(深入)”;
正确做法:
- 必须先定义
add_library(myobj OBJECT ...),且名字不能含::或空格 - 引用时严格用
target_sources(myexe PRIVATE $<myobj>)</myobj>,不能写成target_sources(myexe PRIVATE myobj) - 如果 object library 本身依赖其他库(比如用了
fmt::fmt),得用target_link_libraries(myobj PRIVATE fmt::fmt),否则下游链接时报 undefined reference
参数差异:PRIVATE 表示只影响当前目标,不会把 myobj 的头文件路径或编译定义透传给依赖它的其他目标——这点和静态库不同,得手动补 target_include_directories()。
用 OBJECT_LIBRARY 后,修改头文件还会触发重编译吗?
会,而且可能比想象中更频繁。object library 本身不管理头文件依赖,CMake 只根据源文件时间戳决定是否重编译对象;一旦你改了被 myobj 中某个 .cpp 包含的头文件(比如 common.h),整个 myobj 所有对象都会重编译——哪怕只有 1 个 .cpp 实际用到了这个头文件。
性能影响:
- 优势:避免多目标重复编译同一份
.cpp,尤其适合 CI 上并行构建多个测试二进制 - 代价:失去细粒度增量编译能力;若 object library 包含 20 个源文件,改一个头文件就 recompile 20 个对象
- 兼容性:CMake 3.12+ 才完全支持
$<...></...>