一、常用 CMake 内置全局变量总表(工程实践版)
1️⃣ 项目与目录相关(最常用)
| 变量名 | 含义 | 典型使用场景 |
|---|---|---|
PROJECT_NAME | 项目名 | 打印日志、命名 target |
PROJECT_SOURCE_DIR | 顶层源码目录 | 引用源码路径 |
PROJECT_BINARY_DIR | 顶层构建目录 | 生成文件路径 |
CMAKE_SOURCE_DIR | 最顶层 CMakeLists 所在目录 | 多子项目判断 |
CMAKE_BINARY_DIR | 最顶层 build 目录 | 全局输出路径 |
CMAKE_CURRENT_SOURCE_DIR | 当前 CMakeLists 目录 | 子目录相对路径 |
CMAKE_CURRENT_BINARY_DIR | 当前子目录 build 目录 | 生成中间文件 |
📌使用频率:极高
📌所有 CMake 项目必用
2️⃣ 编译器与语言相关
| 变量名 | 含义 | 使用场景 |
|---|---|---|
CMAKE_C_COMPILER | C 编译器路径 | 判断 gcc / clang |
CMAKE_CXX_COMPILER | C++ 编译器路径 | 同上 |
CMAKE_C_COMPILER_ID | 编译器类型 | GNU / Clang / MSVC |
CMAKE_CXX_COMPILER_ID | C++ 编译器类型 | 条件分支 |
CMAKE_CXX_COMPILER_VERSION | 编译器版本 | 特性判断 |
CMAKE_CXX_STANDARD | C++ 标准 | 推荐方式 |
CMAKE_CXX_FLAGS | 全局 C++ 编译参数 | 老项目常见 |
示例:
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") add_compile_options(-Wall) endif()3️⃣ 构建类型相关(Debug / Release)
| 变量名 | 含义 | 使用场景 |
|---|---|---|
CMAKE_BUILD_TYPE | 构建类型 | 单配置生成器 |
CMAKE_CXX_FLAGS_DEBUG | Debug 编译参数 | 调试 |
CMAKE_CXX_FLAGS_RELEASE | Release 编译参数 | 性能 |
CMAKE_CONFIGURATION_TYPES | 多配置类型 | VS / Xcode |
⚠️ 注意:
Makefile / Ninja:用
CMAKE_BUILD_TYPEVisual Studio:忽略
CMAKE_BUILD_TYPE
4️⃣ 平台 / 系统 / 架构相关(跨平台必用)
| 变量名 | 含义 | 使用场景 |
|---|---|---|
CMAKE_SYSTEM_NAME | 操作系统 | Linux / Windows |
CMAKE_SYSTEM_PROCESSOR | 架构 | x86_64 / aarch64 |
UNIX | 是否类 Unix | 条件判断 |
WIN32 | 是否 Windows | 条件判断 |
APPLE | 是否 Apple 平台 | macOS/iOS |
CMAKE_SIZEOF_VOID_P | 指针大小 | 32/64 位判断 |
示例:
if (CMAKE_SIZEOF_VOID_P EQUAL 8) message(STATUS "64-bit build") endif()5️⃣ 输出、安装、路径相关(部署必用)
| 变量名 | 含义 | 使用场景 |
|---|---|---|
CMAKE_INSTALL_PREFIX | 安装前缀 | make install |
CMAKE_RUNTIME_OUTPUT_DIRECTORY | exe 输出路径 | bin 统一 |
CMAKE_LIBRARY_OUTPUT_DIRECTORY | so 输出路径 | lib 统一 |
CMAKE_ARCHIVE_OUTPUT_DIRECTORY | a 输出路径 | lib 统一 |
CMAKE_PREFIX_PATH | 查找依赖前缀 | find_package |
CMAKE_MODULE_PATH | 自定义 Find*.cmake | 第三方库 |
6️⃣ Generator / 构建系统相关
| 变量名 | 含义 | 使用场景 |
|---|---|---|
CMAKE_GENERATOR | 生成器类型 | Ninja / Make |
CMAKE_MAKE_PROGRAM | make 程序路径 | 自动化 |
CMAKE_TOOLCHAIN_FILE | 工具链文件 | 交叉编译 |
7️⃣ CMake 自身行为控制(高级)
| 变量名 | 含义 | 使用场景 |
|---|---|---|
CMAKE_VERBOSE_MAKEFILE | 显示详细命令 | 调试 |
CMAKE_EXPORT_COMPILE_COMMANDS | 生成 compile_commands.json | clangd |
CMAKE_POLICY_DEFAULT_CMPxxxx | 策略控制 | 老项目兼容 |
二、CMake常见命令
一、项目与基本配置类(Project / Configure)
| 命令 | 作用 | 典型使用场景 |
|---|---|---|
cmake_minimum_required() | 指定最低 CMake 版本 | 每个项目必须 |
project() | 定义项目名、版本、语言 | 项目入口 |
set() | 设置变量 | 设置选项、路径 |
option() | 定义 ON/OFF 开关 | 是否开启测试、功能 |
message() | 打印信息 | 调试 CMake |
include() | 引入模块 | 引入 GNUInstallDirs |
if() / elseif() / else() | 条件判断 | 平台/编译器分支 |
foreach() | 循环 | 批量处理目标 |
cmake_policy() | 设置策略 | 新旧行为兼容 |
二、目标(Target)定义类(核心)
| 命令 | 作用 | 使用说明 |
|---|---|---|
add_library() | 定义库 | 静态 / 动态 / 接口库 |
add_executable() | 定义可执行文件 | 主程序 |
add_custom_target() | 自定义目标 | 生成文件、脚本 |
add_custom_command() | 自定义命令 | 代码生成 |
add_dependencies() | 目标依赖 | 控制构建顺序 |
add_library(ALIAS) | 别名 target | 导出库必备 |
三、Target 属性设置(现代 CMake 核心)
| 命令 | 作用 | 推荐级别 |
|---|---|---|
target_link_libraries() | 链接库 | ⭐⭐⭐⭐⭐ |
target_include_directories() | 头文件路径 | ⭐⭐⭐⭐⭐ |
target_compile_definitions() | 宏定义 | ⭐⭐⭐⭐⭐ |
target_compile_options() | 编译参数 | ⭐⭐⭐⭐ |
target_compile_features() | 语言特性 | ⭐⭐⭐⭐⭐ |
set_target_properties() | 设置属性 | ⭐⭐⭐ |
get_target_property() | 查询属性 | ⭐⭐ |
四、源码与文件处理
| 命令 | 作用 | 使用说明 |
|---|---|---|
target_sources() | 添加源文件 | 动态拆分源码 |
file() | 文件操作 | 读/写/拷贝 |
configure_file() | 配置头文件 | 生成 config.h |
aux_source_directory() | 收集源码 | ❌ 不推荐 |
source_group() | IDE 分组 | VS/CLion |
五、第三方库与依赖管理
| 命令 | 作用 | 场景 |
|---|---|---|
find_package() | 查找已安装库 | 系统/包管理器 |
FetchContent_Declare() | 声明依赖 | 拉取源码 |
FetchContent_MakeAvailable() | 引入依赖 | 现代方式 |
find_library() | 查找库文件 | 不推荐 |
find_path() | 查找头文件 | 不推荐 |
pkg_check_modules() | pkg-config | Linux 库 |
六、构建控制与生成器
| 命令 | 作用 | 说明 |
|---|---|---|
add_subdirectory() | 添加子目录 | 模块化项目 |
enable_language() | 启用语言 | Fortran / CUDA |
set_property() | 设置属性 | 高级用法 |
get_property() | 获取属性 | 调试 |
七、安装(install / export / package)
| 命令 | 作用 | 场景 |
|---|---|---|
install() | 安装目标 | make install |
export() | 导出 targets | build-tree 使用 |
install(EXPORT) | 安装 targets | package |
configure_package_config_file() | 生成 Config.cmake | find_package |
write_basic_package_version_file() | 生成版本文件 | 版本管理 |
include(GNUInstallDirs) | 标准目录 | /usr/lib |
八、测试(CTest)
| 命令 | 作用 | 使用说明 |
|---|---|---|
enable_testing() | 启用测试 | 顶层 |
add_test() | 注册测试 | 单元测试 |
ctest | 运行测试 | CI |
九、编译器 / 平台判断(常用变量 + 命令)
| 命令 / 变量 | 作用 |
|---|---|
CMAKE_CXX_COMPILER_ID | 编译器类型 |
CMAKE_SYSTEM_NAME | 系统名 |
CMAKE_BUILD_TYPE | 构建类型 |
CMAKE_SIZEOF_VOID_P | 32/64 位 |
WIN32 / UNIX / APPLE | 平台宏 |
十、调试 & 排错(非常实用)
| 命令 | 作用 |
|---|---|
message(STATUS ...) | 打印状态 |
cmake -LA | 查看 cache |
cmake --trace | 跟踪执行 |
cmake --trace-expand | 展开变量 |
make VERBOSE=1 | 查看真实命令 |
十一、反模式(应避免)
| 命令 | 问题 |
|---|---|
CMAKE_CXX_FLAGS | 全局污染 |
include_directories() | 不可控 |
link_libraries() | 隐式依赖 |
aux_source_directory() | 不稳定 |
十二、“必会命令清单”
如果只记10 个:
project add_library add_executable target_link_libraries target_include_directories target_compile_features add_subdirectory find_package install configure_package_config_file三、CMakeLists与CMakeCache
(1)、CMakeLists.txt
👉 定义:CMakeLists.txt是 CMake 的“源代码文件”,是由项目维护者编写。描述内容包括:项目结构、如何编译,使用的编译器/标准,依赖哪些库,生成哪些目标(exe / so / a)。
👉 本质:构建规则说明书
👉 特点:必须存在(否则无法使用 CMake);可以有多个(每个子目录一个);会被反复解析;不保存状态(每次配置都从头执行)
👉 举例:
project(MyApp LANGUAGES C CXX) add_executable(myapp main.cpp) target_compile_features(myapp PRIVATE cxx_std_17) target_link_libraries(myapp PRIVATE pthread)(2)、CMakeCache.txt
👉 定义:CMakeCache.txt是 CMake 的“配置结果缓存文件”。是由CMake 自动生成,位于build 目录。其内容是记录:已选择的编译器、构建类型、路径、用户/脚本设置的 cache 变量
👉 本质:一次配置的“结果快照”
👉 特点:不是手写出来的;只在第一次 cmake 配置或 cache 改变时更新;决定“这次 build 实际用什么配置”
👉 举例:
CMAKE_CXX_COMPILER:FILEPATH=/usr/bin/g++ CMAKE_BUILD_TYPE:STRING=Release CMAKE_INSTALL_PREFIX:PATH=/usr/local(3)、两者的关系
CMakeLists.txt 负责“怎么算”,
CMakeCache.txt 负责“算完后的结果记住”。
CMakeLists.txt = 程序代码
CMakeCache.txt = 程序运行后的变量存储
CMakeLists.txt ↓(解析) cmake 配置 ↓(计算变量) CMakeCache.txt(写入) ↓ 生成 Makefile / Ninja / VS 工程(4)、CACHE 变量机制
1️⃣ 普通变量(不进 cache)
set(FOO 123)只在当前配置过程中存在
下次 cmake 就没了
2️⃣ Cache 变量(写入 CMakeCache.txt)
set(FOO 123 CACHE STRING "demo variable")写入
CMakeCache.txt下次 cmake 直接读取
用户可通过
-D修改
3️⃣FORCE的影响
set(CMAKE_CXX_FLAGS "... " CACHE STRING "" FORCE)强制覆盖 cache
用户无法修改
常见于老项目(技术债)
(5)、生命周期对比
| 项目 | CMakeLists.txt | CMakeCache.txt |
|---|---|---|
| 谁创建 | 人写 | CMake 自动生成 |
| 是否可版本管理 | ✔️ 是 | ❌ 否 |
| 是否可删除 | ❌ | ✔️(安全) |
| 是否参与逻辑 | ✔️ | ❌ |
| 是否保存状态 | ❌ | ✔️ |
| 修改是否推荐 | ✔️ | ❌ |
(6)、最常见误区
❌ 误区 1:改了 CMakeLists.txt,但结果没变
原因:值已在CMakeCache.txt中存在;被 cache 覆盖
解决:rm -rf build && cmake ..
❌ 误区 2:改 cache 当改源码
直接编辑CMakeCache.txt:
短期“好像有用”
下次 cmake 可能被覆盖
不可维护
❌ 误区 3:不知道编译器“被锁死”了
一旦第一次配置选择了编译器:CMAKE_CXX_COMPILER=/usr/bin/g++
后续:CC=clang CXX=clang++ cmake ..
👉无效,除非清 cache
(7)、工程实践总结
CMakeLists.txt 是规则,必须可读、可维护
CMakeCache.txt 是状态,可删不可改
遇到“CMake 怎么都不生效”:删 build 目录
不要在 CMakeLists.txt 里滥用:set(... CACHE ... FORCE)
CMakeLists.txt 决定“应该怎么构建”,
CMakeCache.txt 记录“这次到底怎么构建了”。
四、CMakeLists实例
一、示例项目目录结构
my_project/ ├── CMakeLists.txt # 顶层 ├── cmake/ │ └── toolchain-clang.cmake # 可选 ├── src/ │ ├── main.cpp │ ├── math/ │ │ ├── add.cpp │ │ └── add.h │ └── CMakeLists.txt ├── include/ │ └── my_project/ │ └── config.h ├── tests/ │ ├── test_add.cpp │ └── CMakeLists.txt └── README.md二、顶层CMakeLists.txt(核心文件)
cmake_minimum_required(VERSION 3.16) # 1️⃣ 项目定义 project( MyProject VERSION 1.0.0 LANGUAGES C CXX ) # 2️⃣ C++ 标准(全局约束,不是 flags) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) # 3️⃣ 常用构建选项 option(ENABLE_TESTS "Build tests" ON) option(ENABLE_WARNINGS "Enable compiler warnings" ON) # 4️⃣ 编译器相关设置(只放“安全判断”) if (ENABLE_WARNINGS) if (MSVC) add_compile_options(/W4) else() add_compile_options(-Wall -Wextra -Wpedantic) endif() endif() # 5️⃣ 添加子目录 add_subdirectory(src) if (ENABLE_TESTS) enable_testing() add_subdirectory(tests) endif()三、src/CMakeLists.txt(业务代码)
# 1️⃣ 创建库(推荐:先库后程序) add_library(my_math math/add.cpp ) # 2️⃣ 头文件路径(PUBLIC 会传递) target_include_directories(my_math PUBLIC ${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/src ) # 3️⃣ 编译特性(比 set(CMAKE_CXX_STANDARD) 更精细) target_compile_features(my_math PUBLIC cxx_std_17) # 4️⃣ 可执行程序 add_executable(my_app main.cpp ) # 5️⃣ 链接库 target_link_libraries(my_app PRIVATE my_math )四、tests/CMakeLists.txt(单元测试)
add_executable(test_add test_add.cpp ) target_link_libraries(test_add PRIVATE my_math ) add_test( NAME test_add COMMAND test_add )五、示例源码(最小可跑)
src/main.cpp
#include <iostream> #include "math/add.h" int main() { std::cout << add(2, 3) << std::endl; return 0; }src/math/add.h
#pragma once int add(int a, int b);src/math/add.cpp
#include "math/add.h" int add(int a, int b) { return a + b; }六、构建方式
mkdir build cd build cmake .. \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_CXX_COMPILER=clang++ cmake --build . ctest七、这个示例里“正确做了什么”
✅ 1️⃣ 没有使用CMAKE_CXX_FLAGS
# ❌ 没有 set(CMAKE_CXX_FLAGS "...") # ✅ 使用 target_compile_options() target_compile_features()✅ 2️⃣ 库 / 可执行分离
业务逻辑 →
add_library程序入口 →
add_executable
这是大型项目必备结构
✅ 3️⃣ include 目录是 target 级别
target_include_directories(my_math PUBLIC ...)不会污染全局
✅ 4️⃣ 测试是可选的
option(ENABLE_TESTS ON)适合 CI / Release 裁剪
八、一个“反例”
❌ 不推荐的 CMakeLists:
set(CMAKE_CXX_FLAGS "-std=c++11 -O2") include_directories(include) link_libraries(mylib)原因:全局污染;不可维护;多 target 会炸