介绍
想从 Redis 的 Makefile 文件了解 Redis 的构建过程,结果却被作者写的 Makefile ”玩弄“了一番。因为 make 中有些用法和编程逻辑有些差异,另外有些用法连文档没有覆盖,花了好些时间才把构建 Redis 的整个顺序弄清楚。
基础知识
首先如果你完全没有看过 Makefile,这里推荐阮一峰的 make 教程,适合入门。看完这个介绍大概能理解75%的 Redis Makefile 文件。
http://www.ruanyifeng.com/blog/2015/02/make.html
这篇文章主要理解基本语句和每项的意义:
<target> : <prerequisites>
[tab] <commands>
以及.PHONY
这样的伪目标
的意思。
Redis Makefile 中用到的知识补充
下面针对一些相对来说不太常用,但对于理解 Redis Makefile 文件有必要的 make 知识点进行补充。
:= 和 =的区别
上面的介绍入门文章中有解释:
:= 在定义时扩展
= 在执行时扩展,允许递归扩展
虽然每个字都认识,但还是不知道什么意思。
可以看个具体的例子
https://www.cnblogs.com/maruixin/p/3161782.html
但要真正理解这个区别,需要理解 make 读 makefile 文件的两个阶段,这里可以参考手册:
GNU make does its work in two distinct phases. During the first phase it reads all the makefiles, included makefiles, etc. and internalizes all the variables and their values, implicit and explicit rules, and constructs a dependency graph of all the targets and their prerequisites. During the second phase, make uses these internal structures to determine what targets will need to be rebuilt and to invoke the rules necessary to do so.
参考 https://www.gnu.org/software/make/manual/make.html#How-Make-Works
Target 如何被覆盖
先看个例子:
$ cat Makefile
a:
@echo a
b:
@echo b
a: b
@echo another_a
$ make
Makefile:6: warning: overriding commands for target `a'
Makefile:2: warning: ignoring old commands for target `a'
b
another_a
执行 make,echo a
不会执行。但如果去掉@echo another_a
,则会执行echo a
。
$ cat Makefile
a:
@echo a
b:
@echo b
a: b
$ make
b
a
不管哪种情况,实际上都是执行最后的a
这个 target。
include 的执行顺序从最后开始
这可能是最难理解的地方,include 是以一种堆栈的方式进行展开和执行(后进先出)。
➜ tmp cat Makefile
abc:
@echo abc
xyz:
@echo xyz
all:
@echo all
-include abc
-include xyz
➜ tmp make all
xyz
abc
all
可以看到虽然 include 的顺序是abc,然后 xyz,但是执行的顺序是从最后 include 的 xyz 开始。而且 include 的 target 会比在所要执行的 targe(这里是 all)之前。
关于 include 的解释,在官方文档里面是这么说的:
When make processes an include directive, it suspends reading of the containing makefile and reads from each listed file in turn. When that is finished, make resumes reading the makefile in which the directive appears.
参考 https://www.gnu.org/software/make/manual/make.html#Include
然而并没有解释为什么是这种堆栈式先进后出的执行方式,目前没有找到其他理论支持,是通过测试得出的结论。具体可能要深入 make 源码进行探究了。就不在此展开。
其他补充
- .xxx 相当于隐藏文件,不会被默认 make 命令(不加参数情况下)执行
- GNU make 手册(非常详细,仅适合用于查找)
网友评论