本次将介绍强制目标、多规则目标、多目标规则、静态模式、双冒号规则的使用。
知识点
- 强制目标的使用
- 多规则目标的使用
- 多目标规则的使用
- 静态模式的使用
- 双冒号规则的使用
本章实验涉及到的代码文件位于 /home/project/make_example-master/chapter6 目录下,请在 Terminal 中通过 cd 命令切换至该目录后再进行实验学习。
chapter6 文件夹结构如下:
├── force #强制目标的使用测试
│ ├── makefile
│ └── normal.mk
├── multi #多规则目标和多目标规则的使用测试
│ ├── aim.mk
│ └── makefile
├── rule #双冒号规则使用测试
│ ├── err.mk
│ └── makefile
└── static #静态规则使用测试
└── makefile
强制目标的使用
为了验证强制目标的功能,我们先使用一个普通目标测试其被 make 执行的状况。 测试使用到的源代码的 force/normal.mk 内容如下:
#this is a makefor for foce aim test
aim:dep_a
date >> aim
dep_a:
touch dep_a
最终目标 aim 依赖于 dep_a 文件,dep_a 文件会在执行时被 touch 指令更新时间戳。
进入 force 目录并连续执行两次此 makefile 文件:
cd force;make -f normal.mk;make -f normal.mk
Terminal 的输出结果如下图:
可见终极目标 aim 只会重建一次,之后因为依赖文件没有更新,aim 目标也不会再被重建。
如果希望最终目标每次都能够被重建,
- 一种方法是将其声明为
伪目标, - 另一种方法是使用
强制目标。 强制目标是指没有依赖或者命令行的目标,此目标每次被执行时都会被更新到,因此依赖于此目标的目标也会被强制更新。
源代码的 force/makefile 中有一个强制目标的示例,内容如下:
#this is a makefor for foce aim test
aim:FORCE
date >> aim
FORCE:
从内容中可以看出 FORCE 是一个强制目标,同时搜索目录下不存在同名的 FORCE 文件,因此 FORCE 目标每次被执行时都会无条件更新,导致 aim 也会被强制更新。
现在直接执行三次 make,查看 aim 文件内容与 Terminal 的输出结果。
make;make;make;cat aim
Terminal 的输出结果如下图:
从输出结果中可以看出 aim 目标被连续重建三次,aim 文件中第一个时间是使用 normal.mk 时加入的,后面三次时间是使用 makefile 加入的。
多规则目标的使用
多规则目标是指,每条规则有不同的依赖。 make 对多规则目标的处理方式如下:
- 合并依赖文件列表。
- 不断重写目标的重建规则,由新的规则直接覆盖旧的规则。
通过提供的 multi/makefile 文件,可以对多规则目标进行测试,文件内容如下:
#this is a makefile for multi-command test
.PHONY: multi prepare
multi:dep_a dep_b
@echo $^ "[cmd1]"
multi:dep_c dep_d
@echo $^ "[cmd2]"
multi:prepare
@echo $^ "[cmd3]"
multi:
@echo $^ "[cmd4]"
prepare:
@touch dep_a dep_b dep_c dep_d
从文件内容上可以看到 multi 目标对应了四条规则,依赖文件,执行的指令都不一样。先观察 make 会怎样处理这个文件,切换目录并执行 make 命令:
cd ../multi;make
Terminal 的输出结果如下:
makefile:9: warning: overriding commands for target `multi'
makefile:6: warning: ignoring old commands for target `multi'
makefile:12: warning: overriding commands for target `multi'
makefile:9: warning: ignoring old commands for target `multi'
makefile:15: warning: overriding commands for target `multi'
makefile:12: warning: ignoring old commands for target `multi'
prepare dep_a dep_b dep_c dep_d [cmd4]
可以看见
multi规则指令一直在被重写,并忽略之前的指令。最后使用
cmd4来重建multi目标,其它指令都没有得到执行。最后依赖文件列表值得思考。
注意:使用 make 4.1 和 3.8 产生的依赖项摆放顺序不一样,感兴趣的同学可以自己测试。 make 4.1 的排列是按照 makefile 规则的顺序从后到前,从左到右。而 make3.81 则是最后的依赖项在前,其它依赖项从前往后合并。
多目标规则的使用
我们使用 aim.mk 来测试多目标规则,aim.mk 内容如下:
#this is a makefile for multi-aim test
.PHONY:clean
file_1 file_2 file_3:depen_1 depen_2
@echo "this is a multi-aim rule for " $@
touch file_1 file_2 file_3
depen_1:
touch depen_1
depen_2:
touch depen_2
clean:
$(RM) depen_* file_*
从内容上可以看到 file_1、file_2、file_3 共用一条规则,并共同依赖于 depen_1、depen_2 两个文件。规则中可以使用自动化变量$@ 来区分具体执行哪一条规则。
现在分别执行三条规则并观察输出结果。
cd ../multi/
make -f aim.mk file_1;make -f aim.mk file_2;make -f aim.mk file_3
Terminal 的输出结果如下图:
说明处理符合预期,$@ 能够识别到当前的执行目标。另一点需要说明的地方是多目标规则同样能支持最终目标,而。执行 make 验证一下:
make -f aim.mk clean;make -f aim.mk
Terminal 的输出结果如下图:
,这里是file_1 file_2 file_3:depen_1 depen_2 file1
静态模式的使用
多目标规则可以利用自动化变量来区分不同目标并做出相应的处理,但所有目标的依赖文件必须相同。如果某种情况下我们希望多目标规则中,不同目标能对应不同的依赖文件,可以使用静态模式规则来实现。
静态模式规则的基本语法如下:
TARGETS...:TARGET-PATTERN:PREREQ-PATTERNS...
COMMANDS
...
TARGETS 表示目标文件列表,RARGET-PATTERN 为目标模式,它提取出与 TARGETS 中相匹配的部分作为「茎」,替换 PREREQ-PATTERNS 中相应的部分来产生依赖文件。这样不同的目标就可以通过模式匹配来依赖不同的文件。
chapter6/static/ 目录下的 makefile 文件用于验证静态模式规则,文件内容如下:
#this is a makefile for static mode
.PHONY:clean aim_1 aim_2 aim_3
aim_1 aim_2 aim_3:aim_%:depen_% # 这行将aim_%(1,2,3)的依赖对象产生为depen_%这个变量
@echo "target:"$@ " depen:" $^
depen_%:
touch $@
clean:
$(RM) aim_* depen*
aim_1、aim_2 和 aim_3 是规则目标,根据静态模式的语法可以看出他们分别依赖于depen_1、depen_2 和 depen_3 文件。这三个依赖文件也使用了模式匹配规则,通过 touch 命令生成或更新自己。分别执行三个目标,命令如下:
cd ../static/
make aim_1;make aim_2;make aim_3
Terminal 的输出结果如下图:
可见它们分别依赖于各自特有的依赖文件。
双冒号规则的使用
双冒号规则使用“::”代替普通规则中的“:”。当一个文件作为多个双冒号规则的目标时,这些不用的规则会被独立处理,分别执行,而不是像普通规则一样被新的处理命令覆盖。
chapter6/rule/ 目录下的 makefile 文件可以用来测试双冒号规则,内容如下:
#this is a test makefile
.PHONY:clean
aim::depen_a
@echo $@ " : " $^ " [cmd1]"
aim::depen_b depen_c
@echo $@ " : " $^ " [cmd2]"
aim::depen_d
@echo $@ " : " $^ " [cmd3]"
aim::
@echo $@ " : " $^ " [cmd4]"
depen_%:
touch $@
clean:
$(RM) depen_*
从文件内容上来看 aim 是多个双冒号规则的目标,这些规则的依赖和命令都不一样。现在来测试 aim 的重建过程,执行 make 命令:
cd ../rule/
make
Terminal 的输出结果如下图:
可见四个规则都被执行到,并且每一条规则都是独立执行,依赖项并不像普通多规则目标那样发生合并。
一个目标可以出现在多个规则中,但这些要么都是普通规则,要么都是双冒号规则。
err.mk 演示了普通规则和双冒号规则混合使用的情况,它将 makefile 中的第四条双冒号规则修改为普通规则,内容如下:
#this is a test makefile
.PHONY:clean
aim::depen_a
@echo $@ " : " $^ " [cmd1]"
aim::depen_b depen_c
@echo $@ " : " $^ " [cmd2]"
aim::depen_d
@echo $@ " : " $^ " [cmd3]"
#这块改成普通模式:
aim:
@echo $@ " : " $^ " [cmd4]"
depen_%:
touch $@
clean:
$(RM) depen_*
执行下面的命令并观察输出结果。
make -f err.mk
Terminal 的输出结果如下图:
从结果上可以知道,make 确实是不允许不同类型的规则混合使用.
本章节测试了强制目标、多规则目标、多目标规则、静态模式、双冒号规则的使用方法。