5.2.2 Makefile中的依赖关系
依赖关系是Makefile在执行过程中的核心内容。在应用中Makefile不仅可以用于编译,也可用于处理其他的逻辑,本节以一个Makefile为例,说明在执行make工作中处理依赖关系的过程。
Makefile文件如下所示:
all:rule0 file.o rule0:rule1 @echo "+++++++ rule0 +++++++" @echo 'The deps:$^' @echo 'The target:$@' rule1:rule2 @echo "+++++++ rule1 +++++++"
rule2:rule3 @echo "+++++++ rule2 +++++++"
rule3: @echo "+++++++ rule3 +++++++"
file.o: @echo "1234567890" > file.o @echo "File path: $(@D) File name : $(@F)"
.PHONY : clean rule0 rule1 rule2 rule3 clean: @echo "------- clean ------" rm -f file.o |
在这个Makefile的路径下,执行make命令:
执行后显示的结果为:
+++++++ rule3 +++++++ +++++++ rule2 +++++++ +++++++ rule1 +++++++ +++++++ rule0 +++++++ The deps:rule1 The target:rule0 File path: . File name : file.o |
由于make没有指定选项和目标,将默认使用Makefile文件,并执行其中的all目标。在执行的过程中,首先发现all目标依赖于rule0和file.o两个目标,因此需要完成这两个目标的处理。对于rule0目标,依次寻找它的依赖关系,直到找到rule3目标,然后再从rule3目标执行,依次执行rule3,rule2,rule1,rule0。对于file.o目标,将生成file.o文件,它由file.o目标生成,内容为"1234567890",变量@D表示目标的所在目录的路径,@F表示目标的文件名。
在规则rule0:rule1中,使用了变量$^和$@,前者表示依赖的所有文件,后者表示目标的名称。事实上,Makefile的执行顺序不是按照每条规则书写的先后顺序,而是由规则之间的依赖关系确定的。
在Makefile中,将目标clean rule0 rule1 rule2 rule3定义为伪目标(.PHONY),这是由于它们不是需要生成的内容的名称;file.o是实际生成的结果,因此它是真实的目标,而不是伪目标。
在执行过一次make之后,再次执行make命令,得到的结果如下所示:
+++++++ rule3 +++++++ +++++++ rule2 +++++++ +++++++ rule1 +++++++ +++++++ rule0 +++++++ The deps:rule1 The target:rule0
|
从执行结果中可见,这次只执行了rule0及其依赖的目标,没有执行目标file.o。这是由于目标file.o依赖的内容没有变化,所以这条目标不需要被执行,这说明了Makefile条件编译的特性。
执行make clean的结果如下所示:
$ make clean ------- clean ------ rm -f file.o
|
这次执行删除了file.o文件,状态已经退回到make执行之前。因此再次执行make的时候,将和首次执行是一致的。
在make命令的使用中,可以使用-n选项显示执行的序列:
本次执行的结果为:
echo "+++++++ rule3 +++++++" echo "+++++++ rule2 +++++++" echo "+++++++ rule1 +++++++" echo "+++++++ rule0 +++++++" echo 'The deps:rule1' echo 'The target:rule0' echo "1234567890" > file.o echo "File path: . File name : file.o"
|
由此可见,在本次的执行中,只显示了需要执行的命令,而不是真正地执行这些命令。在这个过程中,寻找依赖关系的过程和直接的make过程是一致的,但是只显示要执行命令而不执行命令。
在使用make的过程中,也可以指定一条单独的目标来执行,例如:
$ make rule2 +++++++ rule3 +++++++ +++++++ rule2 +++++++
|
这时,将指定目标rule2来执行,执行的过程发现它依赖于目标rule3,因此先执行rule3的内容,再执行目标rule2的内容。对于其他的目标则不需要执行。