Makefile 与 CMake 关系指南
Makefile 与 CMake 关系指南
一句话理解核心关系
CMake 生成 Makefile,Makefile 指导编译
核心概念对比
特性 | Makefile | CMake |
---|---|---|
角色 | 构建执行者 | 构建生成器 |
文件 | Makefile 或 makefile | CMakeLists.txt |
编写内容 | 具体编译命令 | 项目描述 |
跨平台性 | 弱(需手动适配不同系统) | 强(自动生成平台相关文件) |
使用方式 | 直接运行 make | 先运行 cmake 再运行 make |
学习难度 | 中等(需懂编译过程) | 较低(声明式配置) |
适用规模 | 小型项目 | 中大型项目 |
工作流程对比
Makefile 直接构建
1. 编写 Makefile
2. 运行 make
3. 生成可执行文件
CMake + Makefile 构建
1. 编写 CMakeLists.txt
2. 运行 cmake(生成 Makefile)
3. 运行 make(读取 Makefile)
4. 生成可执行文件
如何选择?
推荐使用 Makefile 当:
- 项目只运行在 Linux/macOS
- 项目文件少于 10 个
- 需要快速编写构建脚本
- 示例:
# 最小Makefile示例 hello:gcc hello.c -o hello
推荐使用 CMake 当:
- 需要支持 Windows/Linux/macOS
- 项目包含多个子目录
- 需要依赖第三方库
- 示例:
# 最小CMake示例 cmake_minimum_required(VERSION 3.10) project(Hello) add_executable(hello hello.c)
典型使用场景
Makefile 最佳场景
# 简单C程序构建
CC = gcc
TARGET = app
SRC = main.c utils.c$(TARGET): $(SRC)$(CC) $^ -o $@
CMake 最佳场景
# 跨平台项目配置
cmake_minimum_required(VERSION 3.10)
project(MyApp)# 添加子目录
add_subdirectory(src)
add_subdirectory(libs)# 包含头文件
include_directories(include)# 添加可执行文件
add_executable(app main.cpp)# 链接库
target_link_libraries(app PRIVATE mylib)
实际项目中的协作
现代项目常用组合方式:
项目目录/
├── CMakeLists.txt # CMake配置文件
├── src/ # 源代码
├── include/ # 头文件
└── build/ # 构建目录(自动生成)├── Makefile # CMake生成的└── app # 生成的可执行文件
构建命令序列:
# 创建构建目录
mkdir build
cd build# 生成Makefile
cmake ..# 编译程序
make# 运行程序
./app
关键差异总结
方面 | Makefile | CMake |
---|---|---|
依赖管理 | 手动指定头文件依赖 | 自动扫描文件依赖 |
编译器切换 | 需修改Makefile | 单命令切换:cmake -DCMAKE_CXX_COMPILER=clang++ |
IDE支持 | 有限 | 完美支持VS/Xcode/CLion等 |
安装规则 | 需手动编写install目标 | 内置install命令 |
测试支持 | 需自行集成 | 内置CTest框架 |
新项目选择建议
- 学习目的 → 从 Makefile 开始
- 跨平台需求 → 直接使用 CMake
- 开源项目 → 优先选择 CMake
- 嵌入式开发 → CMake(简化交叉编译)
- 快速原型 → Makefile
📌 黄金法则:当不确定时,选择 CMake。它虽然需要额外学习,但长期收益更高,特别是当项目规模增长或需要跨平台时。
总结
- Makefile 是厨师:直接烹饪菜肴(编译程序)
- CMake 是食谱作者:编写通用菜谱(生成Makefile)
- 现代C/C++项目:
- 小型/学习 → 只用 Makefile
- 正式/跨平台 → CMake + Makefile组合
两者协同工作,构成高效的构建系统。初学者建议从Makefile入手理解编译过程,再学习CMake提高效率。