CMake
CMake
01 简介
CMake 是一个 跨平台的构建系统生成工具,通常被称为 元构建工具(meta-build system),这个说法很贴切。
CMake 允许开发者编写一种 平台无关的 CMakeList.txt 文件来定制整个编译流程,然后再根据目标用户的平台进一步生成所需的本地化 Makefile 和工程文件,如 Unix 的 Makefile 或 Windows 的 Visual Studio 工程。从而做到 Write once, run everywhere。
它自己并不直接负责怎么编译每个 .cpp,而是:
- 你用 CMakeLists.txt 描述:有哪些源码、要生成哪些库/可执行文件、依赖哪些第三方库、编译选项是什么……
- CMake 再根据你的平台与选择的生成器(Generator),生成具体的构建系统文件,比如:
- Linux/macOS:
Makefile、Ninja构建文件 - Windows:Visual Studio
.sln/.vcxproj - MacOS:Xcode 工程等
- Linux/macOS:
CMake 写一次构建描述,然后在不同平台生成对应的构建工程/脚本。Make/Ninja/MSBuild 才是实际执行编译的“构建工具”。
最常见的项目结构:
my_project/
├── CMakeLists.txt
├── include/
│ └── hello.h
└── src/
├── main.cpp
└── hello.cpp
02 最小例子
一个最基本的 CMakeLists.txt:
cmake_minimum_required(VERSION 3.16)
project(MyProject)
set(CMAKE_CXX_STANDARD 17)
add_executable(my_app
src/main.cpp
src/hello.cpp
)
target_include_directories(my_app PRIVATE include)
target_include_directories(my_app PRIVATE include)这条 CMake 命令的作用是:为目标
my_app指定头文件搜索路径(-I),并且该路径仅在my_app内部生效。具体拆解如下:
my_app:目标名称(通常由add_executable或add_library创建)。PRIVATE:可见性范围。表示include目录下的头文件仅供my_app自身编译时使用。如果有其他目标链接了my_app,不会继承该头文件路径。include:头文件所在的目录路径(支持相对路径或绝对路径,此处为当前源码目录下的include文件夹)。可见性对比小结:
PRIVATE:仅自己用(最常用,避免污染其他模块)。INTERFACE:自己不用,只给依赖自己的模块用(常见于 header-only 库)。PUBLIC:自己和依赖自己的模块都要用。
然后在项目根目录执行:
cmake -S . -B build
cmake --build build
这两条命令是现代 CMake 构建项目的标准两步走工作流:第一步配置与生成,第二步执行编译。
cmake -S . -B build(配置与生成阶段)
-S .:指定源码目录(Source directory)为当前目录.(寻找CMakeLists.txt)。-B build:指定构建目录(Build directory)为build文件夹(如果不存在会自动创建)。- 作用:检查编译器环境、解析配置逻辑,并在
build/目录下生成对应平台的构建文件(如Makefile、Ninja 规则或 VS 工程)。cmake --build build(编译构建阶段)
--build build:让 CMake 调用底层构建工具去编译build目录中的工程。- 作用:真正触发源码编译并链接生成可执行文件或库。
核心优势:
- 跨平台统一:无论底层用的是
make、ninja还是 MSBuild,第二条命令写法完全一致。- 源码树外构建(Out-of-source build):所有编译生成的中间文件都在
build/里,清理项目只需删除该文件夹,完全不会污染源码。
--build后面紧跟的参数是构建输出目录的路径(即前面-B生成的文件所在位置)。除了指定目录,
--build后面还可以追加常用的控制参数:
- 指定构建目标:
--target <name>(简写-t)
- 仅编译某个特定的目标,例如:
cmake --build build --target my_app- 开启多核并行编译:
-j <n>或--parallel <n>
- 加快编译速度(如 8 线程):
cmake --build build -j 8- 指定构建配置(多配置生成器如 VS/Xcode):
--config <Debug|Release>
- 决定编译 Release 还是 Debug 版本:
cmake --build build --config Release- 清理构建产物:
--clean-first
- 编译前先清空旧的目标文件。
cmake --build build 内部已经自动帮你调用了底层的 make(或 Ninja / MSBuild),并且完成了全部的编译和链接工作。
编译完成后通常会得到:
build/
└── my_app
后续操作只需要直接运行生成的可执行程序:
-
在根目录直接运行:
./build/my_app # Linux / macOS .\build\Debug\my_app.exe # Windows (若使用 MSBuild) -
或者进入 build 目录运行:
cd build ./my_app
cd build && make是早期的传统写法;现代 CMake 用cmake --build build一条命令就全包了,跨平台且不需要手动切换目录。
CMake 中最常用的几个命令可以先记住:
project(MyProject):定义项目add_executable(app main.cpp):生成可执行程序
如果你要生成库:
add_library(mylib
src/a.cpp
src/b.cpp
)
然后给程序链接这个库:
target_link_libraries(app PRIVATE mylib)
可以理解为:
mylib
↑
│ 链接
app
添加头文件路径:
target_include_directories(app PRIVATE include)
相当于告诉编译器:去 include/ 目录找 .h/.hpp 文件。
如果项目稍微正规一些,一般会这样写:
cmake_minimum_required(VERSION 3.16)
project(MyProject
VERSION 1.0
LANGUAGES CXX
)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_library(core
src/hello.cpp
)
target_include_directories(core
PUBLIC
${PROJECT_SOURCE_DIR}/include
)
add_executable(app
src/main.cpp
)
target_link_libraries(app
PRIVATE core
)
依赖关系就是:
hello.cpp
│
▼
core 库
│
▼
main.cpp + core
│
▼
app
你还会经常看到:
find_package(...)
这是用来寻找第三方库的,例如:
find_package(OpenCV REQUIRED)
target_link_libraries(app PRIVATE ${OpenCV_LIBS})

浙公网安备 33010602011771号