这篇学Makefile
手写gcc的麻烦
单个C文件的编译很简单:
gcc hello.c -o hello
但手敲有个坑:-o后面跟的是输出文件,要是顺序写反了,gcc不会拦你,而是直接把源文件当成输出覆盖掉:
gcc -o hello.c hello
执行完,hello.c里的源码就没了
文件一多,编译顺序、链接参数、哪些文件要重编,靠脑子记迟早出错。Makefile就是把这些写进一个文件,以后只敲一个make
依赖关系与依赖方法
Makefile里的规则只有两类内容:依赖关系和依赖方法
mycode: mycode.c
gcc -o mycode mycode.c

第一行是依赖关系,表示mycode由mycode.c生成;第二行是依赖方法,也就是生成时执行的命令
命令那一行前面必须是Tab,写成空格会报missing separator,编辑器自动把Tab转空格的话要注意
之后在目录下执行make,它会自动找到Makefile或makefile并完成编译:
make
gcc -o mycode mycode.c
make默认执行第一个目标
make不带参数时,只执行文件里的第一个目标
所以顺序写错会出事:
.PHONY:clean
clean:
rm -f mycode
mycode:mycode.c
gcc -o mycode mycode.c
这时直接执行make,跑的是删除而不是编译:
make
rm -f mycode

这时要编译只能写明make mycode。一般把最终产物放最前面,clean这种放最后
把编译过程拆开
上面是一步完成编译。gcc从.c到可执行文件实际经过四步,Makefile可以把四步都写成规则:
hello: hello.o
gcc hello.o -o hello
hello.o: hello.s
gcc -c hello.s -o hello.o
hello.s: hello.i
gcc -S hello.i -o hello.s
hello.i: hello.c
gcc -E hello.c -o hello.i

这样写好之后,make会从最终目标往回找,缺哪个中间文件就先生成哪个:hello依赖hello.o,hello.o依赖hello.s,一直找到hello.c,再按顺序执行每条命令
clean与伪目标
清理编译产物一般单独写一个目标:
.PHONY:clean
clean:
rm -f mycode
clean没有依赖文件,规则里只有一行命令。.PHONY:clean把它声明为伪目标:伪目标不对应真实文件,声明之后,即使目录下正好有个叫clean的文件,make clean也会照常执行
.PHONY后面写的是目标名,不是依赖文件,很容易写混
普通目标则不同,依赖没变过时make会直接跳过:
make
make: 'mycode' is up to date.
make怎么判断要不要重新编译
依据是文件的修改时间。用stat能看到一个文件的三个时间:
stat mycode
| 字段 | 含义 |
|---|---|
Access |
最近一次被读取的时间 |
Modify |
最近一次内容被修改的时间 |
Change |
最近一次元数据(权限、属主等)被修改的时间 |
make比较的是Modify:目标文件的Modify比依赖文件新,说明产物是最新的,不需要重建

为什么不用另外两个:Access现在默认按relatime策略更新,只有它比mtime或ctime旧、或者距上次更新超过24小时才会刷新(每读一次就写一次盘太费了),所以不准;Change记的是权限、属主这类元数据的变化,跟源码改没改不是一回事
想强制重新编译,可以手动刷新源文件的时间:
touch mycode.c
make
touch把文件时间改成现在,make一看源文件比目标新,就会重新编译
变量与自动变量
规则一多,编译器、选项、目标名到处都是重复的,可以用变量:
CC = gcc
CFLAGS = -Wall -O2
TARGET = mycode
$(TARGET): $(TARGET).c
$(CC) $(CFLAGS) -o $@ $<
.PHONY: clean
clean:
rm -f $(TARGET) *.o

变量用$(名字)引用,要换编译器或者改选项,只改开头一处就行
$@、$<这类是自动变量,执行规则时由make自动填值:
| 写法 | 含义 |
|---|---|
$@ |
当前规则的目标名 |
$< |
第一个依赖文件 |
$^ |
全部依赖文件 |
所以$(CC) $(CFLAGS) -o $@ $<展开就是gcc -Wall -O2 -o mycode mycode.c,换个目标名规则也不用改
来源
本文为个人学习笔记,根据lvy的《【Linux必备工具】自动化构建工具makefile的使用详解》提炼并重新组织,补充了变量与自动变量部分,保留原文链接供进一步阅读
留言
评论区暂未开放;可先通过 RSS 或「关于」页联系。