1.0 Makefile 基础
在 Linux 下,通过 make 命令即可实现通过 Makefile 文件定义的规则自动化执行任意命令(包括编译)。
即通过一个命令一个文件即可实现预定义好的任意操作。
1.1 规则
Makefile 由若干条规则(Rule)构成,每条规则指出一个目标文件(Target),若干依赖文件(Prerequisites),以及生成目标文件的命令。
例如,如果需要生成文件 m.txt 其由 a.txt 和 b.txt 合并而来,则有如下规则:
# 目标文件:依赖文件 1 依赖文件 2
m.txt: a.txt b.txt
cat a.txt b.txt > m.txt第一行定义了一条规则,第二行通过tab规定了一条命令,使用 cat 合并两个文件,其中 # 开头的为注释 make命令会忽略。
在 makefile 中命令必须使用 tab 定义,空格定义的无效。由于 make 执行时默认执行第一条规则,所以仿照上述的方法可以写出第二个规则:
x.txt: m.txt c.txt
cat m.txt c.txt > x.txt
m.txt: a.txt b.txt
cat a.txt b.txt > m.txt此时在系统内某一文件夹创建 a.txt、b.txt、c.txt,输入一些内容执行 make:

make 默认执行第一条规则,在创建 x.txt 的时候发现 m.txt 不存在,因此先执行规则 m.txt 创建 m.txt 文件,再执行规则 x.txt 。
综上可见,Makefile 定义了一系列的规则,在每个规则满足目标的前提下执行命令,就能创建出一个目标文件。
在编写 Makefile 的时候把默认执行的规则放在第一条,其它的规则顺序无关紧要,因为 make 在执行的时候会自行判断依赖。
此外 make 会打印出每一条执行的命令,便于观察执行顺序。
在上述 make 命令执行完毕后再次执行 make 后,输出如下:
$ make
make: “x.txt”已是最新。make 检测到 x.txt 为最新的版本,无需再次执行,因为 x.txt 的创建时间晚于它依赖文件的最后修改时间。
可见,make 使用文件的创建和修改时间来判断是否该更新一个目标文件。
如果修改任意依赖文件后,再次执行 make 命令即可触发 x.txt 的更新。
假设修改了 c.txt 文件,则执行 make 命令后会触发 x.txt 的更新,并不会触发 m.txt 的更新,因为 m.txt 的依赖文件并没有变化,所以,make 会根据 Makefile 执行必要的规则,并非无脑执行所有规则。
在编译大型程序时,完全编译一次往往需要几十分钟甚至数小时,若每次对文件修改后都要执行完全编译则太过于浪费时间,Makefile 的存在即可大幅节省编译时间。
当然,对于 Makefile 是否能高效的完成增量更新,取决于规则书写的是否正确,make 本身并不会检查规则逻辑是否正确。
1.2 伪目标
在上述的例子中,m.txt 和 x.txt 是自动生成的文件,所以可以安全地删除。
但是如果我们希望自动删除,则可以编写一个 clean 规则来删除它们:
clean:
rm -f m.txt
rm -f x.txtclear 命令,与上面所用的命令不同,其没有依赖文件,因此需要执行 clean 命令时必须在命令行使用命令 make clean
值得注意的是,如果在执行 clean 的时候,目录下并没有 clean 文件,每次执行 make clean 命令时都会执行 Makefile 中这个规则的命令。
所以,如果目录下有一个名为 clean 的文件,则此时 Makefile 中的 clean 规则就不会执行了!
如果目录下既需要 clean 文件,还想正常使用 Makefile 文件的 clean 规则,则可以添加一个标识:
.PHONY: clean
clean:
rm -f m.txt
rm -f x.txt此时的 clean 就不会被视为一个文件,而是伪目标(Phony Target)
在大型项目中约定俗成下将:clean、install 这些视为伪目标名称,方便用户快速执行对应的任务。
一般不会有人在目录下创建名为 clean 的文件,除非有人蓄意搞破坏。1.3 执行多条命令
1.4 控制打印
1.5 控制错误
1.6 小结
编写 Makefile 就是编写一系列的规则,用来告诉 make 该如何执行这些规则,从而生成我们最终需要的文件。
评论区(暂无评论)