目录
- [1. cmake_minimum_required 函数](#1. cmake_minimum_required 函数)
- [2. project 函数](#2. project 函数)
- [3. include 函数](#3. include 函数)
- [4. install 函数](#4. install 函数)
- [5. add_executable 函数](#5. add_executable 函数)
- [6. 小结与经典面试题](#6. 小结与经典面试题)
- [6.1 本文小结](#6.1 本文小结)
- [6.2 经典面试题](#6.2 经典面试题)
1. cmake_minimum_required 函数
📚函数作用:指定项目所需要的最低
CMake版本,放在顶级CMakeLists.txt的第一行。
基本形式
bash
cmake_minimum_required(VERSION <min>[...<policy_max>] [FATAL_ERROR])
参数解释
| 参数 | 含义 |
|---|---|
VERSION |
关键字,表示后面跟的是版本号 |
<min> |
版本号,<major>[.<minor>[.<patch>[.<tweak>]]] 形式,指定所需的最低 CMake 版本(如 3.18) |
[...<policy_max>] |
可选,指定策略兼容的最高版本,用于限定策略行为的上限 |
FATAL_ERROR |
可选,若指定,当 CMake 版本不满足时会终止配置并报错(CMake 2.6+ 默认为此行为) |
2. project函数
📚 函数作用:指定项⽬名字,放在顶级
CMakeLists⽂件的第⼆⾏,⼦⽬录中⼀般⽆需调⽤。
基本形式
bash
project(<PROJECT-NAME> [<language-name>...])
project(<PROJECT-NAME>
[VERSION <major>[.<minor>[.<patch>[.<tweak>]]]]
[DESCRIPTION <project-description-string>]
[HOMEPAGE_URL <url-string>]
[LANGUAGES <language-name>...])
关键参数
| 参数 | 含义 |
|---|---|
<PROJECT-NAME> |
项目名称(如 MyProject),用于生成默认变量(如 PROJECT_NAME) |
VERSION(可选) |
项目版本号(如 1.0.0),会自动定义 PROJECT_VERSION 等变量 |
DESCRIPTION(可选) |
项目描述信息(用于生成文档或包配置) |
HOMEPAGE_URL(可选) |
项目主页 URL |
LANGUAGES(可选) |
指定项目支持的语言(如 C、CXX、Fortran、ASM 等) |
project() 执⾏之后,CMake 会⾃动创建以下变量,可在后续命令中使⽤:
| 变量 | 描述 |
|---|---|
PROJECT_NAME |
项⽬名称(如 MyProject) |
CMAKE_PROJECT_NAME |
顶级项⽬名称(与 PROJECT_NAME 相同) |
PROJECT_VERSION |
完整版本号(如 1.2.3) |
PROJECT_VERSION_MAJOR |
主版本号(如 1) |
PROJECT_VERSION_MINOR |
次版本号(如 2) |
PROJECT_VERSION_PATCH |
修订号(如 3) |
PROJECT_SOURCE_DIR |
顶级 CMakeLists.txt 所在⽬录(即源⽂件树根⽬录) |
PROJECT_BINARY_DIR |
构建⽬录(如 build/) |
📌注意:
1 ⼤多数项⽬都只有⼀个名字,复杂项⽬如
c++的boost库,每⼀个⼦功能都设置⼀个project。2 项⽬的顶级
CMakeLists.txt⽂件必须包含对project()命令的直接调⽤。
PROJECT_NAME 变量的使⽤场景:
1 动态库的输出名称
2 cmake配置⽂件的名称
3 命名空间的名称
PROJECT_VERSION 变量的使⽤场景:
1 打印变量
2 ⽣成pkg-config或者.cmake对应的版本配置⽂件
3 动态库/静态库的的版本号
举例如下:
bash
cmake_minimum_required(VERSION 3.18)
project(hello VERSION 1.2.3 LANGUAGES CXX)
add_executable(hello src/main.cpp)
message(STATUS "PROJECT_NAME: ${PROJECT_NAME}")
message(STATUS "PROJECT_VERSION: ${PROJECT_VERSION}")
message(STATUS "PROJECT_SOURCE_DIR: ${PROJECT_SOURCE_DIR}")
message(STATUS "PROJECT_BINARY_DIR: ${PROJECT_BINARY_DIR}")
message(STATUS "CMAKE_CURRENT_LIST_FILE: ${CMAKE_CURRENT_LIST_FILE}")
message(STATUS "CMAKE_CURRENT_LIST_DIR: ${CMAKE_CURRENT_LIST_DIR}")
执行命令cmake ../即可得到如下输出结果
bash
-- PROJECT_NAME: hello
-- PROJECT_VERSION: 1.2.3
-- PROJECT_SOURCE_DIR: /Users/lj/Desktop/CMakeDemo/hello
-- PROJECT_BINARY_DIR: /Users/lj/Desktop/CMakeDemo/hello/build
-- CMAKE_CURRENT_LIST_FILE: /Users/lj/Desktop/CMakeDemo/hello/CMakeLists.txt
-- CMAKE_CURRENT_LIST_DIR: /Users/lj/Desktop/CMakeDemo/hello
3.include函数
📚 函数作用:加载指定的脚本⽂件或者功能模块到当前
CMakeLists上下⽂中并运⾏。
基本形式
bash
include(<file|module> [OPTIONAL] [RESULT_VARIABLE <var>] [NO_POLICY_SCOPE])
<file|module> :表示要运行的文件或者模块名.
CMake进⼊⼦⽬录之后,内置变量的变化情况如下表所示:
| 变量名 | 进⼊⼦⽬录后是否变化? | 说明 |
|---|---|---|
CMAKE_CURRENT_SOURCE_DIR |
❌ 不变化 | 还是⽗⽬录的源代码树的⽬录 |
CMAKE_CURRENT_BINARY_DIR |
❌ 不变化 | 还是⽗⽬录的构建树的⽬录 |
CMAKE_CURRENT_LIST_FILE |
✅ 变化 | 变为⼦⽬录的 CMakeLists.txt ⽂件全路径 |
CMAKE_CURRENT_LIST_DIR |
✅ 变化 | 变为⼦⽬录的 CMakeLists.txt ⽂件⽬录 |
📌 说明:
CMAKE_CURRENT_SOURCE_DIR与CMAKE_CURRENT_BINARY_DIR在add_subdirectory()进入子目录后,会切换为子目录对应的源码目录与构建目录;而CMAKE_CURRENT_LIST_FILE与CMAKE_CURRENT_LIST_DIR始终指向当前正在被解析的CMakeLists.txt文件及其所在目录,因此会随进入子目录而变化。化情况
举例理解:
此处我们创建一个新工程项目然后打印对应的变量辅助理解:
目录结构
bash
test_include
├── CMakeLists.txt
├── build
└── sub
└── sub.cmake
新建⽂件-CMakeLists.txt
bash
# 顶层CMakeLists.txt
cmake_minimum_required(VERSION 3.18)
project(TestInclude)
message(STATUS "CMAKE_CURRENT_SOURCE_DIR: ${CMAKE_CURRENT_SOURCE_DIR}")
message(STATUS "CMAKE_CURRENT_LIST_FILE: ${CMAKE_CURRENT_LIST_FILE}")
message(STATUS "CMAKE_CURRENT_LIST_DIR: ${CMAKE_CURRENT_LIST_DIR}")
include(sub/sub.cmake)
新建⽂件-sub.cmake
bash
message(STATUS "from sub/sub.cmake")
message(STATUS "CMAKE_CURRENT_SOURCE_DIR: ${CMAKE_CURRENT_SOURCE_DIR}")
message(STATUS "CMAKE_CURRENT_LIST_FILE: ${CMAKE_CURRENT_LIST_FILE}")
message(STATUS "CMAKE_CURRENT_LIST_DIR: ${CMAKE_CURRENT_LIST_DIR}")
运⾏cmake
bash
[lijing@localhost build]$ cmake ../
-- from top-level CMakeLists.txt
-- CMAKE_CURRENT_SOURCE_DIR: /home/lijing/testInclude
-- CMAKE_CURRENT_LIST_FILE: /home/lijing/testInclude/CMakeLists.txt
-- CMAKE_CURRENT_LIST_DIR: /home/lijing/testInclude
-- from sub/sub.cmake
-- CMAKE_CURRENT_SOURCE_DIR: /home/lijing/testInclude
-- CMAKE_CURRENT_LIST_FILE: /home/lijing/testInclude/sub/sub.cmake
-- CMAKE_CURRENT_LIST_DIR: /home/lijing/testInclude/sub
-- Configuring done
-- Generating done
📌注意:
观察运行结果发现,只有
CMAKE_CURRENT_LIST_FILE和CMAKE_CURRENT_LIST_DIR才能定位正在执⾏的cmake⽂件路径和所属的目录,不论是include还是add_subdirectory命令。
4.install函数
📚 函数作用:安装(简单理解为cp) 将 ⼆进制,静态库,动态库,头⽂件,配置⽂件 部署到指定⽬录。
bash
install(TARGETS <targets>... [EXPORT <export-name>]
[RUNTIME DESTINATION <dir>]
[LIBRARY DESTINATION <dir>]
[ARCHIVE DESTINATION <dir>]
[INCLUDES DESTINATION <dir>]
[...])
install(FILES <files>... DESTINATION <dir>
[PERMISSIONS <permissions>...]
[CONFIGURATIONS <configs>...]
[COMPONENT <component>]
[...])
install(DIRECTORY <dirs>... DESTINATION <dir>
[FILE_PERMISSIONS <permissions>...]
[DIRECTORY_PERMISSIONS <permissions>...]
[...])
install(EXPORT <export-name> DESTINATION <dir>
[NAMESPACE <namespace>::]
[FILE <filename>]
[...])
关键参数:
| 参数 | 含义 |
|---|---|
TARGETS |
安装使用 add_executable() 和 add_library() 构建的目标文件 |
FILES |
安装文件 |
DIRECTORY |
安装整个目录 |
EXPORT |
安装导出目录,用于发布自己的程序,供别人使用 |
DESTINATION |
指定安装路径,路径可以是绝对路径,也可以是相对路径(相对于 CMAKE_INSTALL_PREFIX) |
🐳
CMAKE_INSTALL_PREFIX的 默认路径为/usr/local,此处特指Linux环境下。

5.add_executable函数
📚 函数作用:指示
cmake从源代码生成一个一个可执行文件.
基本形式
bash
add_executable(生成的可执行文件名字 [WIN32] [MACOSX_BUNDLE]
[EXCLUDE_FROM_ALL]
依赖的源文件)
关键参数
| 参数 | 含义 |
|---|---|
target_name |
可执行文件的名称(不包含扩展名,如 myapp),项目内部唯一 |
<sources> |
源文件列表(如 src/main.cpp) |
📌 注意
默认情况下,生成的二进制可执行文件会放到构建目录树上,即源外构建的
build目录下。当然也可> 以使用属性RUNTIME_OUTPUT_DIRECTORY修改默认的存放位置。
6. 小结与经典面试题
6.1 本文小结
本文围绕 CMake 中最常用的五个命令展开,梳理了它们的作用、基本形式与关键参数:
cmake_minimum_required():声明项目所需的最低 CMake 版本,必须放在顶级CMakeLists.txt的第一行,是配置阶段的"版本守门员"。project():定义项目名称、版本、描述与支持语言,并自动生成PROJECT_NAME、PROJECT_VERSION、PROJECT_SOURCE_DIR等一系列变量,是后续逻辑的基础。include():把外部脚本或模块加载进当前上下文执行,同时要注意CMAKE_CURRENT_SOURCE_DIR、CMAKE_CURRENT_LIST_FILE等内置变量在进入子目录后的变化规律。install():把可执行文件、库、头文件、目录等"拷贝"到安装目录,DESTINATION相对路径以CMAKE_INSTALL_PREFIX(Linux 默认/usr/local)为基准。add_executable():由源文件生成可执行目标,默认输出到构建目录,可通过RUNTIME_OUTPUT_DIRECTORY调整输出位置。
一句话概括:版本声明 → 项目定义 → 脚本复用 → 目标构建 → 安装部署,这五步基本覆盖了一个 CMake 工程的骨架。
6.2 经典面试题
Q1:cmake_minimum_required() 为什么必须写在第一行?它和 cmake_policy() 有什么关系?
答:它必须在任何可能受策略影响的命令之前执行,因为该命令会设置 CMake 的策略版本(Policy Version) 。CMake 的每条策略都有 OLD 和 NEW 两种行为,cmake_minimum_required(VERSION x.y) 会把所有在该版本之前引入的策略自动设为 NEW,从而保证不同 CMake 版本下行为一致。若写在后面,前面的命令可能已按旧策略执行,导致行为不可预期。需要精细控制时,可再用 cmake_policy(SET CMP00xx NEW) 单独设置。
Q2:project() 会自动生成哪些常用变量?PROJECT_SOURCE_DIR 和 CMAKE_SOURCE_DIR 有什么区别?
答:project() 会生成 PROJECT_NAME、PROJECT_VERSION(及 _MAJOR/_MINOR/_PATCH)、PROJECT_SOURCE_DIR、PROJECT_BINARY_DIR、PROJECT_LANGUAGES 等变量。
区别在于作用域:
CMAKE_SOURCE_DIR/CMAKE_BINARY_DIR始终指向顶级工程的源码目录与构建目录,全局唯一;PROJECT_SOURCE_DIR/PROJECT_BINARY_DIR指向最近一次project()调用 所在目录。在子目录中再次调用project()后,它们会变为子项目的目录。
Q3:include() 和 add_subdirectory() 有什么区别?
答:两者都能复用 CMake 脚本,但语义不同:
| 对比项 | include() |
add_subdirectory() |
|---|---|---|
| 处理对象 | 一个 .cmake 脚本或模块 |
一个包含 CMakeLists.txt 的子目录 |
| 作用域 | 在当前作用域内直接执行,变量、目标共享 | 创建新的目录作用域,变量默认不向父级回传 |
| 构建系统 | 不产生新的构建单元 | 会生成子目录对应的构建规则 |
| 典型用途 | 引入函数、宏、工具脚本 | 组织多模块工程 |
另外,include() 后 CMAKE_CURRENT_LIST_FILE / CMAKE_CURRENT_LIST_DIR 会变为被包含脚本的路径,而 CMAKE_CURRENT_SOURCE_DIR 保持不变。
Q4:install() 中 DESTINATION 写相对路径和绝对路径有什么区别?CMAKE_INSTALL_PREFIX 起什么作用?
答:DESTINATION 写相对路径时,最终安装位置为 ${CMAKE_INSTALL_PREFIX}/<相对路径>,这是推荐做法,便于用户通过 -DCMAKE_INSTALL_PREFIX=... 或 cmake --install . --prefix ... 自定义安装位置;写绝对路径则完全忽略 CMAKE_INSTALL_PREFIX,可移植性差,一般只在特殊场景使用。Linux 下 CMAKE_INSTALL_PREFIX 默认为 /usr/local,Windows 下通常为 C:/Program Files/<项目名>。
Q5:add_executable() 生成的可执行文件默认输出到哪里?如何修改?
答:默认输出到当前构建目录(即 CMAKE_CURRENT_BINARY_DIR),也就是源外构建时 build/ 下对应位置。修改方式有两种:
cmake
# 方式一:设置目标属性
set_target_properties(myapp PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
# 方式二:设置全局变量(需在 add_executable 之前)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
add_executable(myapp src/main.cpp)
注意多配置生成器(如 Visual Studio)下还会追加 Debug/、Release/ 子目录,可用 RUNTIME_OUTPUT_DIRECTORY_DEBUG 等按配置单独指定。
Q6:一个标准的最小 CMakeLists.txt 应该包含哪些内容?
答:
cmake
cmake_minimum_required(VERSION 3.18) # 1. 声明最低版本
project(MyApp VERSION 1.0.0 LANGUAGES CXX) # 2. 定义项目
add_executable(myapp src/main.cpp) # 3. 生成可执行目标
install(TARGETS myapp RUNTIME DESTINATION bin) # 4. 安装规则
这四行构成了一个可配置、可构建、可安装的最小工程骨架,其余内容(依赖查找、编译选项、测试等)都在此基础上扩展。