这个系列把 CMake 的核心用法整理成了一条由浅入深的完整路径:从把单个源文件编译成可执行文件的第一步开始,经过构建类型与编译器选项的精细控制,进入操作系统与外部库的环境检测,再到函数、宏、模块化的工程化组织,最后以动态库链接和 GDB 调试两个高频实战场景收尾。全系列 22 篇,按发文时间顺序读即是推荐阅读顺序。
CMake 本身不是编译器,而是一个构建系统生成器:它读取 CMakeLists.txt 里的描述,为 Unix Makefile、Ninja、Visual Studio 等底层构建系统生成指令。理解了这一定位,系列里反复出现的「配置(configure)→ 生成(generate)→ 构建(build)」三段式流程就顺理成章了。
第一阶段:构建入门(一~八)
从零开始跑通一个完整项目,掌握日常使用频率最高的一批命令:
- 编译第一个可执行文件:
cmake_minimum_required、project()、add_executable()三板斧,源外构建 - 切换构建生成器:Makefile、Ninja、Visual Studio 之间自由切换
- 构建和链接静态库与动态库:
add_library()的 STATIC/SHARED 之选,编译期与运行期的链接 - 用条件控制编译:
option()与if-else(),让同一份代码构建出不同形态 - 指定编译器:环境变量与缓存变量两条路,GCC/Clang 混用场景
- 切换构建类型:Debug、Release、RelWithDebInfo、MinSizeRel 各自的适用场景
- 设置编译器选项:从
CMAKE_CXX_FLAGS到target_compile_options()的现代写法 - 脚本控制流:
if、foreach、while、函数与宏,CMake 也是门语言
第二阶段:检测环境(九~十一)
CMake 跨平台,但源代码未必可移植——这三篇解决「同一份代码如何适配不同平台与编译器」:
- 检测操作系统:
CMAKE_SYSTEM_NAME判定 Windows/Linux/macOS - 处理与平台相关的源代码:按平台选择源文件与依赖
- 处理与编译器相关的源代码:GCC、Clang、Intel 编译器的差异适配
第三阶段:外部库与测试(十二~十六)
真实项目总要依赖第三方库、总要写测试,这一阶段把两件事都规范化:
- 检测 Python 解释器:
find_package(PythonInterp)与版本约束 - 检测 Python 库:解释器之外还要找到库和头文件
- 检测 Eigen 库:纯头文件库的检测与使用
- 检测 Boost 库:组件化依赖的
find_package(Boost COMPONENTS ...),与本站 Boost.Asio 系列正好配套 - 用 Google Test 做单元测试:从检测 gtest 到
enable_testing()与add_test()
第四阶段:工程化组织(十七~二十)
项目变大之后的可维护性课题——用函数、模块与作用域消灭全局变量:
- 用函数和宏重用代码:
function()与macro()的区别与陷阱 - 将 CMake 源码分成模块:
include()拆分CMakeLists.txt - add_subdirectory 的作用域:父子目录的变量隔离与传递
- 用 target_sources 避免全局变量:把源文件归属到目标,而不是塞进全局列表
第五阶段:实战技巧(二十一~二十二)
两个开发中天天遇到的高频场景:
- 链接动态库并指定路径的多种方法:
link_directories()、find_library()、target_link_directories()全对比 - 让 CMake 支持 GDB 调试:Debug 模式加
-g -ggdb,调试信息从哪来;调试功夫可续读本站 GDB 系列
怎么读这个系列
- 没用过 CMake:按顺序通读第一阶段,八篇读完就能独立维护日常项目;后面按需选读
- 会基本用法:直接跳第三、四阶段(外部库检测与工程化组织),这是中型项目最常见的痛点
- 急着解决具体问题:把系列当手册用——链接报错看第二十一篇,想让 IDE/gdb 有符号看第六、七篇,变量作用域诡异看第十九篇