第一章:CMake入门——CMake是什么、为什么选择CMake、核心思想与工作流程
大家好,我是你们这门课的老师。在开始之前,我想先问一个问题:你写 C/C++ 项目时,最头疼的是什么?
对我来说,不是算法,不是内存泄漏,而是——构建系统。尤其是跨平台项目,Windows 上用 Visual Studio,Linux 上用 Makefile,macOS 上又可能用 Xcode。每次换个环境,都要重新折腾一遍编译脚本,烦不烦?
嗯,CMake 就是来解决这个问题的。
1.1 CMake 是什么?
CMake 的全称是 Cross-platform Make。它本身不是一个编译器,也不是一个构建工具。它更像是一个「构建系统的生成器」。
说白了,你写一份 CMakeLists.txt 文件,CMake 就能根据你当前的平台和工具链,自动生成对应的构建文件——比如 Makefile、Visual Studio 的 .sln 文件、Xcode 的 .xcodeproj 等等。
核心概念:CMake 是「元构建系统」。它不直接编译代码,而是生成供其他构建系统使用的文件。
我记得刚入行时,有个同事把 CMake 和 Make 混为一谈。其实差别很大:Make 是直接执行编译命令的,而 CMake 是先生成 Makefile,再让 Make 去干活。你想想看,这中间多了一层抽象,但正是这层抽象,让跨平台变得可能。
1.2 为什么选择 CMake?
市面上构建工具不少,Autotools、Scons、Bazel、Meson……为什么 CMake 成了事实标准?我个人的经验告诉我,主要有这几个原因:
- 跨平台能力极强:Windows、Linux、macOS、Android、iOS、嵌入式……几乎你能想到的平台,CMake 都支持。
- 生态成熟:几乎所有现代 C++ 库(OpenCV、Boost、Qt、PCL 等)都提供 CMake 支持。你只需要
find_package就能引入。 - 灵活且可扩展:你可以写自己的模块、函数、宏,甚至自定义构建规则。
- IDE 友好:CLion、VS Code、Qt Creator 等主流 IDE 都原生支持 CMake。
个人经验:我曾经接手过一个用 Autotools 维护的老项目,每次加一个新文件都要改好几个 .am 文件,稍不留神就编译不过。换成 CMake 后,一行 aux_source_directory 就搞定了。嗯,那种感觉就像从手动挡换成了自动挡。
1.3 CMake 的核心思想
CMake 的设计哲学其实很简单,就三个关键词:
- 声明式:你告诉 CMake「我要什么」,而不是「怎么做」。比如你说「我要一个可执行文件,源文件是 main.cpp」,CMake 自己会去处理编译、链接的细节。
- 目标导向:CMake 3.x 之后,一切皆「目标」(target)。一个目标可以是一个可执行文件、一个库、一个自定义命令。目标之间可以设置依赖关系、传递编译选项。
- 配置即代码:CMakeLists.txt 本身就是一门脚本语言,支持变量、函数、流程控制。你可以像写程序一样写构建脚本。
避坑指南:我曾经见过有人把 CMakeLists.txt 写成了一锅粥,几百行代码堆在一起,变量满天飞。记住:CMake 是声明式的,不是过程式的。能用 target_link_libraries 解决的问题,就别自己拼链接命令。
1.4 CMake 的工作流程
CMake 的工作流程分为两个阶段:
| 阶段 | 做什么 | 输入 | 输出 |
|---|---|---|---|
| 配置阶段 | 解析 CMakeLists.txt,检测编译器、库、头文件等 | CMakeLists.txt + 源码 | CMakeCache.txt + 构建文件(Makefile/.sln等) |
| 构建阶段 | 调用底层构建系统(make/ninja/msbuild)实际编译 | 构建文件 | 目标产物(.exe/.so/.a等) |
我习惯把配置阶段比作「点菜」——你告诉厨师你要什么菜、什么口味;构建阶段就是「炒菜」——厨师按单子干活。你想想看,如果点菜时没说清楚,炒出来的菜肯定不对味。CMake 也一样,配置阶段没写好,构建阶段就会出各种幺蛾子。
1.5 核心知识体系
下面这张图,是我自己总结的 CMake 知识体系。你可以把它当作整个课程的地图:
这张图把 CMake 的核心思想和工作流程串在了一起。你从中心出发,左边是声明式构建,右边是目标导向,下面是配置和构建两个阶段,最终产出你需要的二进制文件。
1.6 一个最简单的例子
光说不练假把式。我们来看一个最基础的 CMakeLists.txt:
cmake_minimum_required(VERSION 3.10)
project(HelloWorld)
add_executable(hello main.cpp)
就三行。第一行指定 CMake 最低版本,第二行定义项目名称,第三行告诉 CMake:「我要一个叫 hello 的可执行文件,源文件是 main.cpp」。
然后你在终端里执行:
mkdir build && cd build
cmake ..
make
./hello
搞定。是不是很简单?
我建议:刚开始学 CMake,一定要养成「out-of-source build」的习惯——也就是在源码目录外建一个 build 目录来编译。这样源码目录干干净净,想删掉构建产物直接 rm -rf build 就行。我曾经见过有人直接在源码目录里编译,结果一堆 .o 文件和源码混在一起,看着就头疼。
1.7 本章小结
这一章我们聊了 CMake 是什么、为什么选它、它的核心思想是什么,以及它的工作流程。说白了,CMake 就是一个帮你管理 C/C++ 项目构建的工具,尤其擅长跨平台场景。
下一章,我们会深入 CMakeLists.txt 的语法细节,从变量、命令到控制流,一步步带你写出更复杂的构建脚本。
公众号:蓝海资料掘金营,微信deep3321