2、第一个Makefile:编写最简单的单文件编译规则、使用make命令执行、理解执行流程
好,咱们直接动手。别怕,第一个Makefile简单到让你怀疑人生。
我记得我刚开始学Makefile的时候,看了半天文档,什么变量、函数、自动推导……头都大了。后来我发现,其实核心就一句话:Makefile就是告诉make,怎么从源文件生成目标文件。
说白了,它就是个“菜谱”。你告诉它原料(源文件)和步骤(编译命令),它帮你做菜(生成可执行文件)。
2.1 先准备一个C源文件
咱们先写个最简单的C程序,就叫 hello.c:
#include <stdio.h>
int main() {
printf("Hello, Makefile!\n");
return 0;
}
这个不用多解释了吧?就是打印一句话。保存好,放在一个空目录里。
2.2 编写第一个Makefile
在同一个目录下,新建一个文件,名字就叫 Makefile(注意大小写,M大写)。
打开它,写入以下内容:
hello: hello.c
gcc -o hello hello.c
嗯,就两行。是不是比你想象中简单?
我来解释一下这两行在说什么:
- 第一行:
hello: hello.c—— 这叫“依赖关系”。冒号左边是目标(我要生成的文件),右边是依赖(生成它需要的原料)。意思是:hello依赖于hello.c。 - 第二行:
gcc -o hello hello.c—— 这叫“命令”。注意,前面必须有一个Tab缩进,不能是空格。这是Makefile最坑的地方,我当年就被这个坑过——明明写对了,就是报错,结果发现是空格不是Tab。
我曾经花了一个小时排查一个Makefile报错,最后发现是编辑器把Tab自动转换成了空格。建议你用vim或者VS Code,确保缩进是真正的Tab字符。
2.3 执行make命令
好,现在打开终端,进入这个目录,直接输入:
make
你会看到类似这样的输出:
gcc -o hello hello.c
然后目录下就多了一个 hello 可执行文件。运行它:
./hello
输出:
Hello, Makefile!
成了!第一个Makefile就这么跑起来了。
2.4 理解执行流程
为什么会这样?make到底做了什么?我画个图帮你理解:
流程其实很简单:
- make读取Makefile,找到第一个目标(这里是
hello)。 - 检查依赖文件:看看
hello.c存不存在。如果不存在,报错退出。 - 检查目标文件:如果
hello已经存在,并且比hello.c更新,make会说“无事可做”,直接退出。否则,执行命令。 - 执行命令:运行
gcc -o hello hello.c,生成hello。
💡 核心思想
make只做一件事:当依赖比目标新时,重新生成目标。这就是增量编译的基础——只编译修改过的文件,没改的就不动。
2.5 再试一次
现在你再执行一次 make:
make
你会看到:
make: 'hello' is up to date.
看到了吧?make发现 hello 已经是最新的了,就不做任何操作。这就是make的智能之处——避免不必要的重复编译。
你试试修改一下 hello.c,比如把打印的字符串改一改,再执行 make:
gcc -o hello hello.c
它又编译了。因为 hello.c 比 hello 新,make检测到了变化。
📌 个人小技巧
我习惯在写Makefile时,先手动执行一次编译命令,确认能编译通过,再写到Makefile里。这样能避免“Makefile写错了,但不知道是命令本身有问题还是Makefile语法有问题”的尴尬。
2.6 关于目标名称
你可能注意到了,我写的目标是 hello,而不是 hello.exe 或 hello.out。在Linux/macOS下,可执行文件没有后缀名,所以直接叫 hello 就行。
如果你在Windows下用MinGW或Cygwin,可以写成 hello.exe: hello.c,但原理完全一样。
另外,目标名可以和源文件同名(不带后缀),这是最常见的做法。你也可以起别的名字,比如:
myapp: hello.c
gcc -o myapp hello.c
这样生成的可执行文件就叫 myapp。但说实话,我建议保持目标名和源文件同名,这样一眼就能看出对应关系。
2.7 总结一下
第一个Makefile,你只需要记住三件事:
- 格式:目标: 依赖 + Tab + 命令
- 执行:直接输入
make,它会找第一个目标 - 流程:检查依赖 → 判断是否需要重新编译 → 执行命令
就这么简单。别被Makefile吓到,它本质上就是个自动化脚本,只不过加了一点“智能判断”功能。
下一节,我们会把这个单文件规则扩展一下,看看多文件项目怎么处理。但今天,你先把这个最简单的Makefile跑通,感受一下make的魔力。
✅ 本章核心要点
| 概念 | 说明 |
|---|---|
| 目标 (target) | 要生成的文件,如 hello |
| 依赖 (prerequisites) | 生成目标需要的源文件,如 hello.c |
| 命令 (recipe) | 如何生成目标,必须以Tab开头 |
| 增量编译 | 只有依赖更新时才重新编译 |
好了,去试试吧。写一个你自己的Makefile,编译一个C程序。相信我,当你看到 make 一行命令就搞定编译时,那种感觉——嗯,挺爽的。