CMake基础
1. CMake
CMake 是一个跨平台的构建系统生成工具。它不直接编译代码,而是根据开发者编写的 CMakeLists.txt 配置文件,生成对应平台的构建文件(如 Unix 下的 Makefile、Windows 下的 Visual Studio 解决方案、Ninja 构建文件等),再由这些构建文件驱动编译器完成编译。
简单来说,CMake 解决的是"同一个项目如何在不同的平台和编译器上编译"的问题。
1.1 CMakeLists.txt 文件
CMakeLists.txt 是 CMake 的配置文件,所有构建规则都写在它里面。CMake 对它有严格的命名和位置要求:
1. 文件名严格区分大小写,必须精确地命名为 CMakeLists.txt,不能写成 cmakelists.txt、Cmakelists.txt 或其他变体。这是因为 CMake 在搜索配置文件时只会匹配这个准确的文件名。
2. 文件必须放在项目的根目录下(也可以放在子目录中以构建多级项目,但是也属于子项目的根目录)。
3. 每一个包含 CMakeLists.txt 的目录都是一个独立的构建单元,CMake 会从根目录开始逐层处理。
# 这是一个 CMakeLists.txt 文件中的注释,使用 # 开头
1.2 一个基础的 CMakeLists.txt 文件示例
下面是一个最简单的 CMake 配置,它定义一个名为 test 的项目,并将 main.cpp 编译为可执行文件 exename:
cmake_minimum_required(VERSION 3.1.0) # 指定 CMake 最低版本要求
project(test) # 定义项目名称
add_executable(exename main.cpp) # 将 main.cpp 编译为可执行文件 exename
三条命令各自的作用:
| 命令 | 含义 |
|---|---|
cmake_minimum_required(VERSION 版本号) |
声明构建此项目所需的 CMake 最低版本,低于该版本会报错并中止配置 |
project(项目名) |
设置项目名称,同时会隐式创建 <项目名>_SOURCE_DIR 等变量 |
add_executable(可执行文件名 源文件1 源文件2 ...) |
定义一个可执行文件的构建目标,列出参与编译的所有源文件 |
2. CMake 基本命令
CMake 的典型工作流程分为两步:配置阶段和构建阶段。
假设项目结构如下:
D:\test\
├── CMakeLists.txt
└── main.cpp
在终端中执行以下命令:
# 第一步:进入项目目录
cd D:\test
# 第二步:配置——让 CMake 读取 CMakeLists.txt 并生成构建文件到 build 目录
cmake -B build .
# 第三步:构建——调用底层构建工具(如 make、MSBuild)完成编译
cmake --build build
# 第四步:运行生成的可执行文件
build\exename.exe
理解要点:
cmake -B build .是"翻译"阶段——把 CMakeLists.txt 翻译成 Makefile 或 .sln;cmake --build build是"编译"阶段——调用真正的编译器去编译源码。两步分离的设计使得同一个 CMakeLists.txt 可以在不同平台上生成不同的构建文件。
2.1 -B 参数的含义
-B 参数用于指定 构建目录(build directory),即 CMake 生成的构建文件和编译中间产物存放的位置。
cmake -B build .
这里 build 和 . 都是 相对路径:
build:构建目录的相对路径,CMake 会在当前目录下创建build文件夹.:源码目录的相对路径,即CMakeLists.txt所在的目录(当前目录)
也可以使用绝对路径来避免路径歧义:
cmake -B D:\test\build D:\test
使用独立的 build 目录(外部构建 / out-of-source build)的好处是:所有生成的中间文件、构建产物都集中在 build 文件夹中,不会污染源码目录。如果想清理所有构建产物,只需删除 build 文件夹即可。
注意:如果不指定
-B,CMake 会在当前目录直接生成构建文件(内部构建 / in-source build),这会导致源码和构建产物混在一起,不推荐使用。
2.2 -S 参数的含义
-S 参数用于显式指定 源码目录(source directory),即 CMakeLists.txt 所在的根目录。
cmake -S D:\test -B D:\test\build
-S D:\test:告诉 CMake 去D:\test下找CMakeLists.txt-B D:\test\build:告诉 CMake 把构建文件生成到D:\test\build
实际上,cmake -B build . 中的 . 就是一个被省略了 -S 的源码路径参数。以下三种写法是等价的:
cmake -B build . # 省略 -S,用位置参数指定源码路径
cmake -S . -B build # 显式指定 -S
cmake -S D:\test -B D:\test\build # 使用绝对路径
当 CMakeLists.txt 不在当前目录时,-S 就派上了用场——你可以在任意目录执行:
cmake -S D:\test -B D:\test\build
而不需要先 cd 到项目目录。
2.3 -G 参数与工具链的选择
-G 参数用于指定 生成器(Generator),决定 CMake 要生成哪种构建系统文件。
cmake -G "生成器名称" -B build .
常见的生成器:
| 生成器 | 生成的构建文件 | 适用平台 |
|---|---|---|
"MinGW Makefiles" |
Makefile | Windows(MinGW 环境) |
"Visual Studio 17 2022" |
.sln 解决方案文件 | Windows(Visual Studio) |
"Unix Makefiles" |
Makefile | Linux / macOS |
"Ninja" |
build.ninja | 跨平台(需安装 Ninja) |
"Xcode" |
.xcodeproj 项目文件 | macOS |
如果不指定 -G,CMake 会使用平台默认生成器。例如在安装了 Visual Studio 的 Windows 上可能默认使用 MSBuild,而在 Linux 上默认使用 Unix Makefiles。
# 查看当前平台可用的生成器列表
cmake --help
2.4 -D 参数的含义
-D 参数用于在配置阶段向 CMake 传递 变量,格式为 -D 变量名=值。
cmake -D CMAKE_BUILD_TYPE=Release -B build .
常用变量举例:
| 变量 | 含义 | 常用值 |
|---|---|---|
CMAKE_BUILD_TYPE |
构建类型 | Debug、Release、RelWithDebInfo、MinSizeRel |
CMAKE_INSTALL_PREFIX |
安装路径 | 如 /usr/local、D:\libs |
CMAKE_CXX_COMPILER |
指定 C++ 编译器 | 如 g++、clang++ |
BUILD_SHARED_LIBS |
是否构建动态库 | ON / OFF |
-D 也可以用来传递自定义变量,供 CMakeLists.txt 中的 if() 判断使用:
# CMakeLists.txt 中
if(ENABLE_TESTS)
enable_testing()
endif()
# 命令行中开启该选项
cmake -D ENABLE_TESTS=ON -B build .
理解要点:
-D就像是给 CMakeLists.txt 传入的"命令行参数",你可以在外部灵活控制构建行为,而不需要每次都修改 CMakeLists.txt 文件本身。
2.5 –build 参数的作用
--build 参数用于触发实际的 编译过程,它调用底层构建工具来完成编译链接。
cmake --build build
这里的 build 就是之前在 -B 中指定的构建目录。CMake 会自动检测该目录中生成的构建文件类型,并调用相应的构建工具(如 make、MSBuild、ninja)。
同样,build 可以使用相对路径或绝对路径:
# 相对路径
cmake --build build
# 绝对路径
cmake --build D:\test\build
--build 的常用子选项:
| 选项 | 作用 | 示例 |
|---|---|---|
--config |
指定构建配置(多配置生成器如 VS、Xcode) | --config Release |
--target 目标名 |
只构建指定目标而非全部 | --target exename |
-j N / --parallel N |
并行编译,N 为同时编译的任务数 | --parallel 4 |
--clean-first |
构建前先清理旧的产物 | — |
# 以 Release 模式并行编译
cmake --build build --config Release --parallel 8
# 只编译特定目标
cmake --build build --target exename
理解要点:
cmake --build build本质上是一个"代理命令"——你不必关心底层用的是 make 还是 MSBuild 还是 ninja,CMake 会自动帮你调用正确的工具。这让你在不同平台上使用统一的构建命令。


