Makefile 笔记
Makefile 笔记
make 就是一个按指定 shell 命令做构建的工具:你声明要构建哪个文件、它依赖哪些源文件、源文件变了怎么重建,剩下的依赖判断 make 自己来。核心思想是"按时间戳增量构建"——只重建真正过期的部分。
规则
一条规则长这样:
target ... : prerequisites ...
command
...
- target(目标):必需,make 要构建的对象。可以是目标文件(
.o)、可执行文件,也可以是一个标签。 - prerequisites(前置条件):生成 target 所需的文件,空格分隔。
- command(命令):make 要执行的 shell 命令,必须以 Tab 缩进。
前置条件和命令至少得有一个。判断逻辑:只要有一个前置文件不存在,或它的修改时间比 target 新,target 就要重建。
命令前面是 Tab,不是空格——这是 Makefile 最经典的坑,用空格会报
missing separator。
目标(target)
target 可以是文件,也可以是只当标签用的"伪目标"。
伪目标
clean 这种只用来执行命令、不产出同名文件的目标,有个隐患:如果目录里恰好有个文件叫 clean,make 看到它存在就认为不用重建,rm 命令不会执行。
clean:
rm *.o # 删除对象文件
声明成 .PHONY 就能避免——make 不再检查同名文件,每次都执行:
.PHONY: clean
clean:
rm *.o temp
像 .PHONY 这样的内置特殊目标还有不少,见 GNU make 手册。
前置条件(prerequisites)
result.txt: source.txt
cp source.txt result.txt
构建 result.txt 依赖 source.txt。如果 source.txt 不存在,得再写一条规则生成它:
source.txt:
echo "this is the source" > source.txt
source.txt 没有前置条件,意味着只要它不存在,每次 make source.txt 都会重新生成。
连着跑两次 make result.txt:第一次先建 source.txt 再建 result.txt;第二次 make 发现 source.txt 没变(时间戳早于 result.txt),什么都不做。这就是增量构建。
一个伪目标可以把多个文件捆一起生成:
source: file1 file2 file3
make source 一次生成 file1、file2、file3,比分三次 make file1/2/3 省事。
执行
把内容存成 Makefile 或 makefile,在该目录直接敲 make:
make # 不指定目标时,默认执行第一个目标
make clean # 指定执行 clean 目标
完整实例
edit : main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
cc -o edit main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
main.o : main.c defs.h
cc -c main.c
kbd.o : kbd.c defs.h command.h
cc -c kbd.c
command.o : command.c defs.h command.h
cc -c command.c
display.o : display.c defs.h buffer.h
cc -c display.c
insert.o : insert.c defs.h buffer.h
cc -c insert.c
search.o : search.c defs.h buffer.h
cc -c search.c
files.o : files.c defs.h buffer.h command.h
cc -c files.c
utils.o : utils.c defs.h
cc -c utils.c
clean :
rm edit main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
行尾的反斜杠 \ 是续行符,便于把长命令拆成多行。这个例子里:
- 可执行文件
edit依赖一堆.o,每个.o又依赖各自的.c和.h。 - 任何一个
.c或.h改了,只会重编对应的.o,再重链edit,不会全量重编。 - 依赖关系本质上就是在说明"目标是由哪些文件生成的、哪些文件更新了要触发重建"。