文章目录
- 前言
- 一、CMake的优势
- 二、使用CMake前的准备
-
- [1. CMake 安装](#1. CMake 安装)
- [2. VS Code CMake 插件安装](#2. VS Code CMake 插件安装)
- [三、CMake 工程构建流程 及 相关命令行工具的介绍](#三、CMake 工程构建流程 及 相关命令行工具的介绍)
-
- [1. CMake 工程构建流程图](#1. CMake 工程构建流程图)
- [2. 编写工程代码](#2. 编写工程代码)
- [3. 生成构建系统](#3. 生成构建系统)
- [4. 编译链接](#4. 编译链接)
- [5. 测试](#5. 测试)
- [6. 本机安装](#6. 本机安装)
- [7. 打包](#7. 打包)
- [8. 补充部分命令行工具](#8. 补充部分命令行工具)
-
- [8.1 脚本模式](#8.1 脚本模式)
- [8.2 调用外部命令](#8.2 调用外部命令)
- [8.3 查看帮助](#8.3 查看帮助)
前言
该博客中,cmake命令执行环境为:
编辑环境:VS Code
编译环境:VS Code Remote SSH模式 + Ubuntu 24.04
CMake 官方源代码下载地址:https://cmake.org/download/
CMake 官方英文档地址:https://cmake.org/cmake/help/latest/index.html
一、CMake的优势
(1)传统方式:

(2)CMake方式:

| 传统方式的缺陷 | CMake方式 | 优势 |
|---|---|---|
| 人工编辑Makefile等配置文件 | CMake自动帮我们生成构建配置文件 | 解决跨平台构建难题,一处配置,到处构建 |
| Makefile 等语法复杂 | 语法简单,表达能力强大 | 大幅减少学习成本,提升研发效率 |
| 手动查找包 | 自动查找包 | 包管理规规范化,解决包管理难题 |
| 每个IDE都有自己的构建方式 | 各个IDE都支持使用cmake来构建程序 | IDE对CMake支持度高,⼀处配置,多IDE支持 |
下图展示了:主流C++商业级开发IDE 对CMake的支持情况

结论:
CMake语法简单易上手,功能强大,使用广泛,IDE支持度高,已经是C/C++事实上的构建标准,也是⼀个十分重要的C/C++工程管理工具。
二、使用CMake前的准备
1. CMake 安装
Step 1:使用ubuntu自带apt 安装:
bash
sudo apt install cmake
Step 2:验证安装:
安装完成后,可通过以下命令验证 CMake 是否安装成功以及查看其版本。
bash
cmake --version


.
2. VS Code CMake 插件安装
VS Code CMake 插件有以下2点好处:
- 语法高亮和代码补全:对 CMakeLists.txt 文件提供语法高亮显示,使代码结构更加清晰易读。同时,支持代码补全功能,当你输⼊ CMake 命令或变量时,插件会自动提示可能的选项,减少手动输入的错误和时间。
- 智能分析和错误检查:能够对 CMakeLists.txt ⽂件进行智能分析,检查其中的语法错误和潜在问题,并在编辑器中实时显示错误提示和警告信息,帮助你及时发现和解决问题。
安装步骤如下:
Step 0:打开 VS Code,点击左侧活动栏中的 扩展图标(或按 Ctrl+Shift+X )。

Step 1:在搜索框中输入 CMake ,我们选择安装以下4个插件:
• CMake Tools
• CMake Language Support
• CMake IntelliSence
• CMake

三、CMake 工程构建流程 及 相关命令行工具的介绍
1. CMake 工程构建流程图

构建流程全过程,使用的命令行工具如下:
bash
# 0. 编写工程代码并创建CMakeLists.txt文件
touch CMakeLists.txt
# 1. 创建构建⽬录并进⼊
mkdir build && cd build
# 2. 配置项⽬
cmake ..
# 3. 构建项⽬
make
或者
cmake --build .
# 4. 执⾏测试(如果有)
make test
或者
ctest .
# 5. 安装项⽬
make install
或者
cmake --install .
# 6. ⽣成安装包
make package
或者
cpack
# 7 解压 ⽣成的tar 包
tar xvf TestCMakeTools-0.1.1-Linux.tar.gz
2. 编写工程代码
- Step 0:目录结构
bash
cmake_tools
├── build(目录)
├── CMakeLists.txt
├── main.cpp
└── test.cp

- Step 1.1:编辑 main.cpp
cpp
#include <iostream>
int main()
{
std::cout << "hello world!" << std::endl;
return 0;
}
Step 1.2:编辑 test.cpp
cpp
#include <iostream>
#include <cassert>
int main()
{
assert( 1 + 2 == 3);
std::cout << "test passed!" << std::endl;
return 0;
}
- Step 2:编辑文件 CMakeLists.txt
bash
# 1 设置能运行此cmake 工程的最低cmake版本要求
cmake_minimum_required(VERSION 3.18)
# 2 设置项目名称
project(helloWorld)
# 3 添加构建目标
# g++ main.cpp -o main
add_executable(main main.cpp)
# 生成测试二进制可执行程序
add_executable(testAdd test.cpp)
# 4 开启测试功能 & 集成测试逻辑
include(CTest)
add_test(
NAME Case_Add
COMMAND testAdd
)
# 5 安装二进制可执行程序到本地
include(GNUInstallDirs)
install(TARGETS main)
# 6 开启打包功能 & 打包二进制可执行程序
include(CPack)
# cpack 默认收集install 对应的目标,然后会把收集到的目标 打包在压缩包里
注: 为什么需要设置最低的cmake版本?
CMake 是一个不断迭代的工具(目前最新4.x,历史有3.x),不同版本可能会引入新的语法、命令、模块或行为变更。如果项目中使用了高版本 CMake 才支持的特性(例如特定的函数、生成器表达式、目标属性等),而用户本地安装的cmake版本低于项目要求的版本,就会出现无法解释或者产生不可预知的行为。为了防止以上情况出现:
CMake 给我们提供了 cmake_minimum_required ,这个命令会在配置阶段( cmake 命令执行时)检查当前 CMake 版本:
(1)若当前版本低于最低要求,CMake 会直接终止并报错,明确提示 "需要至少 X.X 版本",避免后续因版本不兼容导致的模糊错误。
(2)若当前安装的版本满足要求,则继续执行后续配置流程。
3. 生成构建系统
通过 cmake 可以看到cmake命令支持的详细参数,常用的参数如下:
bash
cmake [options] <path-to-source>
cmake [options] <path-to-existing-build>
cmake [options] -S <path-to-source> -B <path-to-build>
| 参数 | 含义 |
|---|---|
| -S | 指定源文件根目录,必须包含一个CMakeLists.txt文件 |
| -B | 指定构建目录,构建生成的中间文件和目标文件的生成路径,通常会保存⼀个CMakeCache.txt来存储⼀些变量 |
- 源文件目录 用 -S 选项指定
在 CMake 中,源文件树(Source Tree) 指的是项目源代码的目录结构,CMake 通过 CMakeLists.txt 文件来组织和管理这个结构。通常使用顶层 CMakeLists.txt 来标识。
// 源文件目录的特征:包含源文件 和 CMakeLists.txt文件
// 例如:cmake_tools 就是源文件目录,它包含源文件main.cpp、test.cpp 以及 CMakeLists.txt文件
bash
cmake_tools
├── build(目录)
├── CMakeLists.txt
├── main.cpp
└── test.cpp

- 构建目录 用 -B 选项指定
在 CMake 中,构建树(Build Tree) 是指项目构建过程中生成的临时文件目录,它与源文件树(Source Tree) 相对应。构建树包含编译过程中生成的中间文件(如目标文件、依赖信息)和最终产物(如可执行文件、库文件)。通常使用CMakeCache.txt来标识。
// 用于存放 项目构建过程中生成的文件 (含编译过程中生成的中间文件 和 最终产物)的目录,被称之为构建目录
- 构建时,根据构建中间文件是独立保存还是放在当前源代码目录下, 构建过程分为以下2种:
(1)源内构建:
在包含顶级CMakeLists.txt的源代码目录下进行直接构建
下图中,当前所在目录:源文件目录cmake_tools

bash
cmake 源文件目录
// cmake 查找到指定目录下有CMakeLists.txt文件,通过CMakeLists.txt文件进行构建,将构建过程中生成的临时文件存放到当前目录下

将源文件目录 作为 构建目录,存放 构建过程中生成的临时文件。这一方式是极不推荐的,将源文件目录 和 构建目录混在一起,非常不利于管理!
(2)源外构建
为了维护一个纯净的源文件树,可通过使用一个单独目录来进行源外构建
使用 -S 参数指定源文件目录也就是包含CMakeLists.txt的目录,再使用 -B 参数指定一个构建目录(此处选择空目录 build):
c
cmake -S . -B ./build
// 当前处于 源文件目录cmake_tools中


- 构建生成的CMakeCache.txt文件中,会存储⼀些变量,记录各种信息(如构建目录 和 源文件目录的路径)
cd进入构建目录build,然后执行命令:
c
cmake .
发现竟然 构建成功了,可是cmake不是要指定 包含CMakeLists.txt文件的源文件目录,才能执行构建嘛?
当前目录是构建目录,其下没有CMakeLists.txt文件,为什么构建能成功执行呢?
答:当前目录下确实没有CMakeLists.txt文件,但是当前目录下有CMakeCache.txt文件,该文件记录了源文件目录的路径,通过该路径,能找到源文件目录下的CMakeLists.txt文件,所以构建能成功执行。


4. 编译链接
- 方式1:使用make命令
进入构建目录build,该目录下有 构建过程中生成的Makefile文件:
、

可以直接使用make命令,它会搜索当前目录下的Makefile文件 进行编译链接:

- 方式2:cmake --build 指定构建目录
该命令的效果:相当于 在指定的构建目录下执行make指令


原理解析:
CMakeCache.txt文件中存储了 make命令的软连接路径
当执行 "cmake --build 指定构建目录" 命令时,系统会根据构建目录下的 CMakeCache.txt文件 中记录的软连接路径,在指定的构建目录下执行make命令!


5. 测试
在构建前,就已经在源文件目录的 CMakeLists.txt文件中设置好了测试case的数量(通过 add_test添加,我只设置了一个测试case),并为每一个测试case设置好 测试名 以及 要测试的目标 可执行文件

构建时,会在构建目录下创建一个叫 CTestTestfile.cmake的文件,里面会设置 测试相关的配置信息(根据 CMakeLists.txt文件中的add_test相关信息 进行配置):

在编译链接阶段,生成了可执行文件testAdd(由源文件test.cpp 编译链接生成):
// 源文件test.cpp中代码 没有任何问题,所以生成的可执行文件testAdd在测试时也不会出问题

(1) 先对没有问题的可执行文件testAdd进行测试:
有两种测试方法:
- 在构建文件下,使用 ctest命令 (该命令会查询当前目录下的CTestTestfile.cmake文件,根据文件中的配置信息 进行测试操作)

- 在构建文件下,使用 make test命令

查看一下Makefile下的 test目标,发现调用了 /usr/bin/ctest
所以make test命令 的本质就是 调用ctest命令
修改源文件test.cpp中代码,添加一行执行时会报错的代码:

执行make命令,重新编译链接生成 有问题的可执行文件testAdd:

(2) 对有问题的可执行文件testAdd进行测试:


6. 本机安装
在构建前,就已经在源文件目录的 CMakeLists.txt文件中设置好了 要安装的目标文件 以及 要安装在哪一个路径下:
Linux下,默认安装路径为 /usr/local

构建时,会在构建目录下创建一个叫 cmake_install.cmake 的文件,里面会设置 安装相关的配置信息(根据 CMakeLists.txt文件中的相关信息 进行配置):


安装目标是编译链接阶段生成的 可执行文件main,要将该目标安装到指定路径下。
要达成上述目标,一共有两种方式:
- 方式一:cmake --install 指定构建目录
该命令会搜索构建目录下的 cmake_install.cmake文件,根据该文件的配置信息,就能知道该操作是要将 构建目录下的可执行文件main 安装(拷贝)到 /usr/local/bin 路径下
/usr/local/bin 目录的读写权限都是root,所以需要sudo提高权限到root,才能将 可执行文件main 拷贝到 /usr/local/bin 路径下

安装完成后,会在构建目录下一个叫 install_manifest.txt的文件,该文件被称为资源清单,会记录安装好的文件:
cmake_install.cmake文件中的最后一步:将安装好的文件路径 写入 构建目录下的 install_manifest.txt文件中
(第一次执行安装操作时,会在构建目录下创建install_manifest.txt文件,再进行写入;后续再执行安装操作,直接将安装好的文件路径写入已创建的install_manifest.txt文件)
- 方式二:make install

Makefile文件下,执行install目标 实际也是 根据cmake_install.cmake文件来进行安装操作!
7. 打包
打包操作,需要在构建目录下执行以下命令:
bash
cpack
或者
make package
使用cpack命令时,一般都要加sudo提权,否则可能执行失败

cpack指令具体做了哪些工作:
- 先在构建目录下创建 _CPack_Packages/Linux目录,再查找CPackConfig.cmake文件,设置好临时安装目录:
./_CPack_Packages/Linux/STGZ/helloWorld-0.1.1-Linux/
./_CPack_Packages/Linux/TGZ/helloWorld-0.1.1-Linux/
./_CPack_Packages/Linux/TZ/helloWorld-0.1.1-Linux/

- 执行构建目录下的 cmake_install.cmake文件,将 install对应的目标main 拷贝到 临时安装目录下:
./_CPack_Packages/Linux/STGZ/helloWorld-0.1.1-Linux/bin/main
./_CPack_Packages/Linux/TGZ/helloWorld-0.1.1-Linux/bin/main
./_CPack_Packages/Linux/TZ/helloWorld-0.1.1-Linux/bin/main
树状结构如下:
c
./_CPack_Packages
└── Linux
├── STGZ
│ └── helloWorld-0.1.1-Linux
│ └── bin
│ └── main
│
├── TGZ
│ └── helloWorld-0.1.1-Linux
│ └── bin
│ └── main
│
└── TZ
└── helloWorld-0.1.1-Linux
└── bin
└── main

cpack命令前加sudo的原因:
cpack命令的执行过程中会调用cmake_install.cmake文件,而cmake_install.cmake文件最后会将安装文件的信息 写入install_manifest.txt文件中,但是install_manifest.txt文件的权限是root,所以必须使用root权限!
install_manifest.txt文件的权限为什么会是root?
install_manifest.txt文件是在第一次使用 安装命令时创建的,我们第一次 使用安装指令时用了sudo提权,所以创建的 install_manifest.txt文件也是root权限
- 执行打包

c
./_CPack_Packages
└── Linux
├── STGZ
│ ├── helloWorld-0.1.1-Linux
│ │ └── bin
│ │ └── main
│ └── helloWorld-0.1.1-Linux.sh
├── TGZ
│ ├── helloWorld-0.1.1-Linux
│ │ └── bin
│ │ └── main
│ └── helloWorld-0.1.1-Linux.tar.gz
└── TZ
├── helloWorld-0.1.1-Linux
│ └── bin
│ └── main
└── helloWorld-0.1.1-Linux.tar.Z
- 将压缩包拷贝到构建目录

8. 补充部分命令行工具
8.1 脚本模式
bash
cmake -P <file> = Process script mode.
CMake脚本模式,不会生成构建产物,也不会生成中间过程。 适合处理各种与构建系统无关的自动化任务,通过编写简洁的脚本文件,你可以实现环境检查、文件处理、部署打包等功能。
以下是hello_world 工程里cmake生成用于安装目标的主makefile代码片段,在主makefile里使用 cmake的脚本模式调用了cmake_install.cmake,在这里执行文件的拷贝等操作。

8.2 调用外部命令
bash
cmake -E = CMake command mode.
⼀下是hello_world 工程里主makefile里的 RM命令,其实就是使用命令模式调用了rm -f 外部命令:
bash
# The command to remove a file.
RM = /usr/bin/cmake -E rm -f
8.3 查看帮助
bash
cmake --help






