附录2-make和cmake
1 Make 工具:为什么工程师不直接敲 gcc
想象一下:你的项目有 50 个 .c 文件,每次编译都要敲:
gcc file1.c file2.c file3.c ... file50.c –o my_program.exe
光文件名就能敲到你怀疑人生。而且你改了其中某一个文件,还得重新敲一遍整条命令。
于是有人发明了 Make。Make 是一个自动化工具,它读一个叫 Makefile 的配置文件,知道哪些文件需要编译、按什么顺序编译、改了一个文件之后哪些需要重新编译。
1.1 第一个 Makefile
先让ai助手帮你装make,给他说:国内网络安装make工具,并添加到环境变量。
等装好之后,将1-2的多文件程序复制到一个新文件夹里(我复制在了2-3make里),新建名字为 Makefile 的文件(大小写不能错)。内容如下:
# 用哪个编译器
CC = gcc
# 最终要生成的可执行文件
TARGET = adddemo.exe
# 参与编译的 .c 文件对应的 .o 文件
OBJS = main.o add.o
# 第一条规则是默认目标:把 main.o 和 add.o 链接成 adddemo.exe
$(TARGET): $(OBJS)
$(CC) $(OBJS) -o $(TARGET)
# main.o 依赖 main.c 和 add.h,add.h 变了 main.o 要重新编译
main.o: main.c add.h
$(CC) -c main.c
# add.o 依赖 add.c 和 add.h
add.o: add.c add.h
$(CC) -c add.c
# 清理编译产物:make clean
clean:
del $(OBJS) $(TARGET)
Makefile 里"规则下面的命令"必须以 Tab 开头,不能是空格。写成空格会报 missing separator 错误。这是 Makefile 著名的坑。
现在回到终端,cd 2-3make进入对应文件夹,敲一句:
make
Make 会告诉你它在干什么:
gcc –c main.c
gcc –c add.c
gcc main.o add.o –o adddemo.exe

1.2 Make 怎么知道哪些要重新编译?
Makefile 里的每一段都是一个"规则",格式是:
目标: 依赖
命令
意思是:如果"依赖"比"目标"新(说明依赖刚被改过),就重新执行"命令"。
假设你有 10 个文件,第一次 make 全部编译。然后你只改了 file2.c:
第一次 make:10个文件全部编译(因为 .o 还不存在)
↓ 你改了 file2.c,重新 make
第二次 make:只有 file2.c 重新编译(file2.o 比 file2.c 旧),
然后重新链接。其他9个文件纹丝不动。
改哪个编译哪个——这就是 Make 帮工程师省下的海量敲键盘和等待时间。文件越多,收益越大。
1.3 清理产物
编译会生成一堆 .o 和 .exe,想一键清空:
make clean

Make 你不用学太细。你只需要知道有这么个东西,它是帮工程师省敲键盘次数的工具。工程里大家不直接写 Makefile,而是用 CMake 来生成 Makefile。如果你想详细了解Makefile的语法,请看:简介 – Makefile教程 – 廖雪峰的官方网站,我之前学Makefile时看的就是这个,写的非常好。
2 CMake:工程级的编译管理
2.1 为什么需要 CMake
你写的程序以后可能不止在你自己电脑上跑。也许你会发给你室友,他用的是 Mac;也许你要把代码传到公司的服务器上,服务器跑的是 Linux。
但有个操蛋的问题是,Makefile不是跨平台的。Windows 上的 Makefile,Mac 和 Linux 不认识。
CMake 解决的就是这个问题,他能跨平台生成Makefile。你写一个 CMakeLists.txt,告诉 CMake"我要编译哪些文件、生成什么名字的程序"。然后 CMake 会根据你当前的操作系统(Windows/Mac/Linux),自动生成对应格式的 Makefile。
2.2 第一个 CMakeLists.txt
ok,先让ai助手帮你装cmake,给他说:国内网络安装cmake工具,并添加到环境变量。
等装好之后,将1-2的多文件程序复制到一个新文件夹里(我复制在了2-4cmake里),新建一个文件,名字必须是 CMakeLists.txt(注意大小写,一个字不能错)。打开它,写入以下内容:
# CMake 要求的最低版本
cmake_minimum_required(VERSION 3.10)
# 项目名
project(adddemo)
# 用哪些源文件生成什么名字的程序
add_executable(adddemo main.c add.c)
就三行,没有一句编译命令。项目要哪几个源文件,一目了然。
2.3 用 CMake 编译
终端输入cd 2-4cmake,进入文件夹,输入:
mkdir build
cd build
cmake –G "MinGW Makefiles" ..
make
这几步在做什么:


运行一下:
.\\adddemo.exe
8

为什么要在 build 文件夹里编译?因为 CMake 会生成一大堆中间文件(CMakeCache.txt、各种 .o 等),如果直接放在源码文件夹里,你的项目目录会变得一团乱。
放到 build 里,想清理就整个文件夹删掉,源码干干净净。这个 build 文件夹以后还会被加到 .gitignore 里(第 5 节会讲 git)。
以后你接触真实项目,看到的流程基本都是这一套:cmake .. 生成构建配置,make(或 ninja)编译,最后在 build 文件夹里找到可执行文件。学会这一套,你就能自己编译任何开源 C 项目了。
3 练习题
题目:把之前所有的项目用 CMake 管理起来——写一个 CMakeLists.txt,生成make,然后在 build 文件夹里 cmake .. && make 编译运行。




