CMake 学习引入:从 GCC 到 Makefile 再到 CMake
- 笔记
- 3小时前
- 9热度
- 0评论
通过三个阶段的演进,理解为什么需要 CMake:GCC 命令行 → Makefile → CMake
示例代码
add.h:
#ifndef ADD_H
#define ADD_H
int add(int a, int b);
#endif
add.c:
#include "add.h"
int add(int a, int b) {
return a + b;
}
main.c:
#include <stdio.h>
#include "add.h"
int main() {
int result = add(10, 20);
printf("sum:%d\n", result);
return 0;
}
第一阶段:GCC 命令行
项目结构:
cmakeS/
├── main.c
├── add.c
└── add.h
编译运行
gcc -o main main.c add.c
运行结果
$ ./main
sum:30
存在的问题
⚠️ 警告
- 每次修改代码都要重新编译所有文件(即使只改了一个文件)
- 文件多了命令会很长,容易出错
- 无法自动管理依赖关系
- 团队协作时每个人的编译命令可能不一致
如果只修改了 add.c,理论上只需要重新编译 add.c,但 GCC 命令会重新编译所有文件,浪费时间。
第二阶段:Makefile
项目结构:
cmakeS/
├── main.c
├── add.c
├── add.h
└── Makefile # 新增
Makefile 内容
Makefile:
# 目标:依赖
# <tab>命令
# 最终目标:生成可执行文件 main
main: main.o add.o
gcc main.o add.o -o main
# 编译 main.c 生成 main.o
main.o: main.c
gcc -c main.c -o main.o
# 编译 add.c 生成 add.o
add.o: add.c
gcc -c add.c -o add.o
# 清理编译产物
clean:
rm -rf *.o main
# 测试运行
test:
./main
⚠️ 重要:Makefile 语法规则
目标: 依赖文件 <TAB>命令
- 目标:要生成的文件(如
main.o) - 依赖:生成目标需要的文件(如
main.c) - 命令:如何生成目标(必须用 TAB 缩进,不能用空格)
编译过程
$ make
gcc -c main.c -o main.o
gcc -c add.c -o add.o
gcc main.o add.o -o main
$ make test
./main
sum:30
增量编译演示
# 第一次编译:编译所有文件
$ make
gcc -c main.c -o main.o
gcc -c add.c -o add.o
gcc main.o add.o -o main
# 修改 add.c 后再次编译:只重新编译 add.c
$ make
gcc -c add.c -o add.o # 只编译 add.c
gcc main.o add.o -o main # 重新链接
# 如果没有修改任何文件
$ make
make: 'main' is up to date. # 不做任何事
Makefile 的优势
✅ 改进
- 增量编译:只重新编译修改过的文件
- 依赖管理:自动检测文件变化
- 命令统一:团队成员使用相同的编译命令
- 自动化:一个
make命令完成所有操作
仍然存在的问题
⚠️ 警告
- 手动维护依赖:每个
.c文件都要手写规则 - 不跨平台:Linux 用 Makefile,Windows 用 Visual Studio 项目文件
- 难以扩展:文件多了 Makefile 会变得很复杂
- 重复劳动:每个项目都要写类似的 Makefile
如果项目有 100 个 .c 文件,你需要写 100 条类似的规则,非常繁琐。
第三阶段:CMake
项目结构:
cmakeS/
├── main.c
├── add.c
├── add.h
├── CMakeLists.txt # 新增
└── build/ # 构建目录
CMakeLists.txt 内容
CMakeLists.txt:
# 指定 CMake 最低版本
cmake_minimum_required(VERSION 3.10)
# 项目名称和语言
project(study_cmake C)
# 创建可执行文件
add_executable(main main.c add.c)
⚠️ 重要:CMake 规定语言标识符必须大写:
- C 语言 →
C - C++ 语言 →
CXX - Fortran 语言 →
Fortran
编译流程
# 1. 创建构建目录
mkdir build && cd build
# 2. 生成 Makefile
cmake ..
# 3. 编译(两种方式都可以)
make # 方式1:直接用 make
cmake --build . # 方式2:用 cmake 命令(推荐,跨平台)
# 4. 运行
./main
输出示例
$ cmake ..
-- Configuring done (1.2s)
-- Generating done (0.0s)
-- Build files have been written to: /root/cmakeS/build
$ make
[ 33%] Building C object CMakeFiles/main.dir/main.c.o
[ 66%] Building C object CMakeFiles/main.dir/add.c.o
[100%] Linking C executable main
[100%] Built target main
$ ./main
sum:30
CMake 的优势
✅ 改进
- 自动生成构建文件:CMake 自动生成 Makefile(或其他构建系统)
- 跨平台:同一个 CMakeLists.txt 在 Linux/Windows/macOS 都能用
- 简洁:3 行代码替代几十行 Makefile
- 自动依赖:CMake 自动处理头文件依赖
- 易于扩展:添加新文件只需修改一行
- 现代化:支持库管理、第三方依赖、测试等高级功能
三个阶段对比
| 特性 | GCC 命令行 | Makefile | CMake |
|---|---|---|---|
| 编译命令 | 手动输入完整命令 | make |
cmake .. && make |
| 增量编译 | 不支持 | 支持 | 支持 |
| 依赖管理 | 手动 | 半自动 | 全自动 |
| 跨平台 | 不支持 | 不支持 | 支持 |
| 代码量 | 一行命令 | 10+ 行 | 3 行 |
| 维护成本 | 高 | 中 | 低 |
| 适用场景 | 单文件测试 | 小型项目 | 任何规模项目 |
为什么需要 CMake
跨平台编译
项目需要在 Linux、Windows、macOS 上编译。
传统方式: Linux 写 Makefile,Windows 创建 VS 项目,macOS 写 Xcode 项目
CMake 方式: 只写一个 CMakeLists.txt,自动生成对应平台的构建文件
复杂项目管理
项目有 100 个源文件。
Makefile 方式: 需要手写 100 条规则
CMake 方式:
add_executable(main file1.c file2.c ... file100.c)
第三方库集成
项目需要使用 OpenCV 等第三方库。
Makefile 方式:
CFLAGS = -I/usr/include/opencv4
LDFLAGS = -L/usr/lib -lopencv_core ...
CMake 方式:
find_package(OpenCV REQUIRED)
target_link_libraries(main ${OpenCV_LIBS})
CMake 工作流程

CMake 工作流程
CMakeLists.txt → cmake .. → Makefile → cmake --build . → 可执行文件
- 编写 CMakeLists.txt:描述项目结构、指定源文件
- 运行 cmake:检测编译器、查找依赖库、生成 Makefile
- 运行 cmake --build:编译代码、生成可执行文件(或直接用
make)
Out-of-Source Build
使用独立的构建目录,保持源代码目录干净。
推荐结构:
cmakeS/
├── CMakeLists.txt
├── main.c
├── add.c
├── add.h
└── build/ # 所有编译产物都在这里
├── Makefile
└── main
操作:
mkdir build && cd build
cmake ..
make
# 清理:删除 build 目录即可
cd .. && rm -rf build
常用命令
GCC
gcc -o main main.c add.c
Makefile
make # 编译
make clean # 清理
CMake
# 标准流程
mkdir build && cd build
cmake ..
cmake --build . # 推荐,跨平台
# 或
make # Linux/macOS 可用
# 一行命令
cmake -B build && cmake --build build
# 清理
rm -rf build
总结
演进路径:
GCC 命令行 → Makefile → CMake
手动编译 → 半自动 → 全自动
CMake 核心价值:
- 跨平台:一次编写,到处编译
- 自动化:自动管理依赖和编译
- 简洁:3 行代码替代几十行 Makefile
基本流程:
mkdir build && cd build
cmake ..
cmake --build . # 或 make
./main
最后更新:2026-05-26