Makefile基础教程 7

一、实验介绍--Makefile 规则进阶(3)

本次实验将介绍强制目标、多规则目标、多目标规则、静态模式、双冒号规则的使用。

1.1 实验内容

  1. 强制目标的使用
  2. 多规则目标的使用
  3. 多目标规则的使用
  4. 静态模式的使用
  5. 双冒号规则的使用

1.2 实验知识点

  1. 强制目标没有命令或依赖,且其目标是一个不存在的文件名,可以起到强制更新依赖其的目标的作用。
  2. 一个目标文件可以对应到多个规则目标,make 会合并其依赖项,并以最后一次出现的规则命令作为重建命令,其它命令将被忽略。
  3. 同样的依赖文件和重建指令可以对应多条不同的目标,此时可以使用多目标规则来进行定义。
  4. 静态模式的规则存在多个目标,且不同目标可以根据模式,匹配不同的依赖文件。
  5. 双冒号规则可以让同一个目标文件对应多个规则时,每个规则都被独立执行和处理。

1.3 实验环境

Ubuntu系统, GNU gcc工具,GNU make工具

1.4 适合人群

本课程难度为中等,适合已经初步了解 makefile 规则的学员进行学习。

1.5 代码获取

可以通过以下命令获取代码:

$ git clone https://github.com/darmac/make_example.git

二、实验原理

依据 makefile 的基本规则进行正反向实验,学习和理解规则的使用方式。

三、开发准备

进入实验楼课程即可。

四、项目文件结构

.
├── force:强制目标的使用测试
│   ├── aim
│   ├── dep_a
│   ├── makefile
│   └── normal.mk
├── multi:多规则目标和多目标规则的使用测试
│   ├── aim.mk
│   ├── file_1
│   └── makefile
├── readme.md:实验说明文件
├── rule:双冒号规则使用测试
│   ├── err.mk
│   └── makefile
└── static:静态规则使用测试
    └── makefile

五、实验步骤

5.1 强制目标的使用

5.1.1 抓取源代码

使用如下cmd获取 GitHub 源代码并进入相应章节:

cd ~/Code/
git clone https://github.com/darmac/make_example.git
cd make_example/chapter6
5.1.2 普通目标使用测试

为了验证强制目标的功能,我们先使用一个普通目标测试其被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

终端打印:

touch dep_a
date >> aim
make: `aim' is up to date.

可见终极目标 aim 只会重建一次,之后因为依赖文件没有更新,aim 目标 也不会再被重建。

5.1.3 强制目标使用测试

如果希望终极目标每次都能够被重建,一种方法是将其声明为伪目标,另一种方法是使用强制目标。

强制目标是指没有依赖或者命令行的目标,此目标每次被执行时都会被更新到,因此依赖于此目标的目标也会被强制更新。

源代码的force/makefile中有一个强制目标的示例,内容如下:

#this is a makefor for foce aim test

aim:FORCE
        date >> aim

FORCE:

本例中FORCE就是一个强制目标,由于FORCE没有依赖项和命令行,且搜索目录下不存在同名的FORCE文件,

因此FORCE目标每次被执行时都会无条件更新,导致aim也会被强制更新。

直接执行三次make,检查终端打印和aim文件内容:

make;make;make;cat aim

终端打印如下:

date >> aim
date >> aim
date >> aim
Tue Jul 18 12:57:50 CST 2017
Tue Jul 18 12:59:15 CST 2017
Tue Jul 18 12:59:15 CST 2017
Tue Jul 18 12:59:15 CST 2017

可见aim目标被连续重建三次,aim文件中第一个时间是使用normal.mk时加入的,后面三次时间是使用makefile加入的。

实验过程如下图所示:

5.1

5.2 多规则目标的使用

多规则目标是指一个目标可以对应到多个规则,每条规则有不同的依赖。

make 对多规则目标的处理方式是:

1)合并依赖文件列表。

2)不断重写目标的重建规则,由新的规则直接覆盖旧的规则。

源代码目录下有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

终端打印:

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.13.8产生的依赖项摆放顺序不一样,感兴趣的同学可以自己测试。

make 4.1的排列是按照makefile规则的顺序从后到前,从左到右。

make3.81则是最后的依赖项在前,其它依赖项从前往后合并。

实验过程如下图所示:

5.2

5.3 多目标规则的使用

makefile 的规则书写格式允许一个规则对应多个目标,规则的依赖关系和命令对所有目标有效。

我们使用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

终端打印:

touch depen_1
touch depen_2
this is a multi-aim rule for  file_1
touch file_1
this is a multi-aim rule for  file_2
touch file_2
this is a multi-aim rule for  file_3
touch file_3

说明处理符合预期,$@能够识别到当前的执行目标。

另一点需要说明的地方是多目标规则同样能支持终极目标,多目标中的第一个目标就是终极目标。

执行make验证一下:

make -f aim.mk clean;make -f aim.mk

终端打印:

rm -f depen_* file_*
touch depen_1
touch depen_2
this is a multi-aim rule for  file_1
touch file_1

表明file_1就是aim.mk的终极目标。

实验过程如下图所示:

5.3

5.4 静态模式的使用

多目标规则可以利用自动化变量来区分不同目标并做出相应的处理,但所有目标的依赖文件必须相同。

如果某种情况下我们希望多目标规则中,不同目标能对应不同的依赖文件,可以使用静态模式规则来实现。

静态模式规则的基本语法如下:

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_%
        @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

终端打印:

touch depen_1
target:aim_1  depen: depen_1
touch depen_2
target:aim_2  depen: depen_2
touch depen_3
target:aim_3  depen: depen_3

可见它们分别依赖于各自特有的依赖文件。

实验过程如下图所示:

5.4

5.5 双冒号规则的使用

5.5.1 双冒号规则

双冒号规则使用“::”代替普通规则中的“:”。当一个文件作为多个双冒号规则的目标时,这些不用的规则会被独立处理,分别执行,而不是像普通规则一样被新的处理命令覆盖。

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

终端打印:

touch depen_a
aim  :  depen_a  [cmd1]
touch depen_b
touch depen_c
aim  :  depen_b depen_c  [cmd2]
touch depen_d
aim  :  depen_d  [cmd3]
aim  :   [cmd4]

可见四个规则都被执行到,并且每一条规则都是独立执行,依赖项并不想普通多规则目标那样发生合并。

5.5.2 双冒号规则的限制

一个目标可以出现在多个规则中,但这些规则类型必须相同,要么都是普通规则,要么都是双冒号规则。

err.mk 演示了普通规则和双冒号规则混合使用的情况,它将makefile中的第四条双冒号规则修改为普通规则,如下:

aim:
        @echo $@ " : " $^ " [cmd4]"

执行此文件:

make -f err.mk

终端打印:

err.mk:14: *** target file 'aim' has both : and :: entries.  Stop.

可知make不允许不同类型规则混用的情况出现。

实验过程如下图所示:

5.5

六、实验总结

本次实验测试了强制目标、多规则目标、多目标规则、静态模式、双冒号规则的使用方法。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值