必须显式声明static或shared类型,否则依赖build_shared_libs变量会导致跨平台行为不一致;头文件路径需用target_include_directories(public)暴露;链接顺序须从左到右满足符号引用关系。

add_library 必须显式声明 STATIC 或 SHARED
不写类型就依赖 BUILD_SHARED_LIBS 变量,这在跨平台项目里等于埋雷。Linux 默认静态链接倾向强,Windows 开发者常默认期望动态库,靠全局开关根本不可控。
直接写死类型才是唯一可靠做法:
-
add_library(mylib STATIC src/a.cpp)→ 生成libmylib.a(Linux/macOS)或mylib.lib(Windows) -
add_library(mylib SHARED src/a.cpp)→ 生成libmylib.so、mylib.dll或libmylib.dylib - 别用
add_library(mylib src/a.cpp)这种无类型写法,它在不同平台可能产出完全不同的产物
.lib 文件有两种——静态库是归档格式,导入库(import library)只是动态链接的符号表,不能混用。
头文件路径必须用 target_include_directories(PUBLIC) 暴露
静态库和动态库本身都不自带头文件路径,target_link_libraries 不会自动把头文件加进编译命令。你写了 #include "math/utils.h",但编译器找不到,不是库没编译成功,而是路径没传过去。
正确做法是在定义库目标时就声明:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
target_include_directories(mylib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)-
PUBLIC表示:所有链接mylib的目标,都会自动获得这个包含路径 - 绝对不要用
include_directories()全局设置,它污染整个子目录作用域,且无法随目标传递,在多库项目中极易引发头文件冲突
/,Windows 下也支持 /(CMake 内部会自动转换),所以统一用正斜杠即可,不用 \。
多个静态库互相依赖时,target_link_libraries 顺序不能错
链接器从左到右解析符号,如果 libA.a 调用了 libB.a 中的函数,那么 libA 必须写在 libB 左边,否则报 undefined reference。这不是 CMake 的 bug,是所有链接器(GNU ld、LLD、MSVC link.exe)的通用规则。
实操建议:
-
target_link_libraries(myapp PRIVATE libA libB)→ 正确(A 依赖 B) -
target_link_libraries(myapp PRIVATE libB libA)→ 链接失败 - 用
nm -C libB.a | grep some_func(Linux/macOS)或dumpbin /symbols libB.lib(Windows)确认符号确实导出,避免靠猜定顺序 - 动态库之间也有隐式依赖,但 Windows 下需额外处理
__declspec(dllexport),Linux/macOS 一般无需干预
输出名与安装路径要跨平台兼容
CMake 默认给静态库加 lib 前缀(Linux/macOS)、不加(Windows),动态库命名规则也不同。如果不统一控制,下游项目引用时就得写条件判断,徒增复杂度。
推荐做法:
- 用
set_target_properties统一输出名:set_target_properties(mylib_static PROPERTIES OUTPUT_NAME "mylib") - 安装时区分归档(static)和库(shared)目标:
install(TARGETS mylib_static ARCHIVE DESTINATION lib)、install(TARGETS mylib_shared LIBRARY DESTINATION lib RUNTIME DESTINATION bin) - Windows 下
RUNTIME DESTINATION bin是必须的,因为.dll在运行时加载,得放在可执行文件同目录或系统 PATH 中 - Linux/macOS 下
.so/.dylib通常放lib目录,靠LD_LIBRARY_PATH或rpath定位
PUBLIC 头文件路径,调用方也必须通过 target_link_libraries 正确链接该目标——而不是直接传 .a 或 .lib 文件路径,否则头文件路径不会生效。C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










