第一节:CMake 简介
一、什么是"构建(Build)"
1. 构建的本质
构建 = 将"人类可读的源码"转化为"机器可执行产物"的全过程
至少包含三个核心阶段:
- 编译(Compile)
.c / .cpp → .o / .obj- 由编译器(gcc / clang / cl.exe)完成
- 链接(Link)
- 多个
.o+ 库 → 可执行文件 / 库 - 由链接器(ld / link.exe)完成
- 多个
- 可选阶段
- 代码生成
- 资源处理
- 单元测试
- 安装(install)
- 打包(package)
2. 构建 ≠ 编译命令
手写命令:
bash
g++ main.cpp -o app
只适合:
- 单文件
- 无依赖
- 无跨平台需求
真实工程一定需要构建系统。
二、什么是"构建系统(Build System)"
1. 构建系统的职责
构建系统不是编译器,它负责 "管理"和"调度":
- 解析工程描述文件
- 计算文件依赖关系
- 判断哪些文件需要重新编译
- 并行执行构建任务
- 生成中间文件和最终产物
2. 常见构建系统
| 系统 | 特点 |
|---|---|
| make | 规则简单,依赖时间戳 |
| Ninja | 极速、小巧 |
| MSBuild | Windows / Visual Studio |
| Xcode Build | Apple 平台 |
| CMake | 构建系统生成器 |
⚠️ 关键点:
CMake 本身不是构建系统,而是"构建系统生成器"
三、CMake 到底是什么?
1. CMake 的官方定义(工程语义)
CMake 是一个跨平台的、开源的、现代化的构建系统生成器
核心特征:
- 不负责编译
- 生成平台原生构建文件
- 再由底层构建工具执行
2. CMake 在构建生态中的位置
text
CMakeLists.txt
↓
CMake
↓
Makefile / Ninja / VS Project
↓
make / ninja / msbuild
↓
gcc / clang / cl
👉 CMake 的工作 到"生成构建系统"为止
3. CMake 能解决什么问题?
| 问题 | 传统方式 | CMake |
|---|---|---|
| 跨平台 | 多套脚本 | 一套配置 |
| IDE 切换 | 手工改 | 自动生成 |
| 依赖管理 | 易错 | 目标传播 |
| 构建一致性 | 难保证 | 强约束 |
| 工程规模 | 难维护 | 可扩展 |
四、CMake 的核心设计思想(非常重要)
1. 声明式,而非命令式
你不是在"写怎么编译",而是在声明目标之间的关系。
cmake
add_executable(app main.cpp)
target_link_libraries(app PRIVATE MyLib)
不是告诉它"先干什么后干什么",
而是告诉它:
"app 依赖 MyLib"
2. 目标(Target)是一切的核心
CMake 的现代哲学是:
Everything is a Target
目标可以是:
- 可执行文件
- 静态库
- 动态库
- 接口库(只传播属性)
3. 使用要求(Usage Requirements)
目标不仅有产物,还有"我怎么被用":
- 头文件路径
- 编译宏
- 编译选项
- 链接依赖
并且 可以自动传递给下游目标。
五、CMake 的基本构建流程(用户视角)
1. 三阶段模型(非常关键)
(1)配置阶段(Configure)
bash
cmake -S . -B build
发生的事情:
- 解析所有 CMakeLists.txt
- 创建目标
- 计算依赖
- 生成缓存(CMakeCache.txt)
(2)生成阶段(Generate)
- 根据生成器(Make / Ninja / VS)
- 输出对应的构建文件
(3)构建阶段(Build)
bash
cmake --build build
真正调用:
- make / ninja / msbuild
- 编译 & 链接
六、源内构建 vs 源外构建
1. 源内构建(不推荐)
bash
cmake .
缺点:
- 污染源码目录
- 不可维护
- 不可并行多配置
2. 源外构建(标准做法)
bash
cmake -S . -B build
cmake --build build
优势:
- 源码目录干净
- 支持多 build(Debug / Release)
- 工程级标准实践
七、CMake 的安装(Install)概念
1. 安装 ≠ 构建
构建:
- 产物在 build 目录
安装:
- 拷贝到"系统/发布目录"
2. 默认安装前缀
text
CMAKE_INSTALL_PREFIX = /usr/local
典型结构:
text
/usr/local/bin
/usr/local/lib
/usr/local/include
3. GNUInstallDirs 的意义
- 为不同系统定义标准安装路径
- 保证工程可移植性
- 强烈推荐使用
八、一个最小 CMake 工程的语义拆解
cmake
cmake_minimum_required(VERSION 3.18)
project(helloWorld)
add_executable(main main.cpp)
含义逐行解释:
cmake_minimum_required- 锁定 CMake 行为策略
- 防止不同版本语义变化
project- 定义工程身份
- 初始化语言、变量、版本
add_executable- 注册一个目标
- 不做编译,只是"声明"
九、衍生但必须知道的概念(第一节就要有)
1. 生成器(Generator)
CMake 根据生成器决定输出什么构建文件:
- Unix Makefiles
- Ninja
- Visual Studio
- Xcode
bash
cmake -G Ninja ..
2. 构建类型(Build Type)
常见:
- Debug
- Release
- RelWithDebInfo
- MinSizeRel
bash
cmake -DCMAKE_BUILD_TYPE=Release ..
3. CMakeCache.txt
- 配置阶段生成
- 保存所有缓存变量
- 删除 build 就是"重置一切"
十、第一节你必须真正掌握的"底层认知"
如果你只记住几句话,那就记住这些:
- CMake 不编译代码
- CMake 生成构建系统
- Target 是核心抽象
- 属性是通过 Target 传播的
- 源外构建是工程铁律
- 声明关系,而不是写流程