七、使用隐式规则(Using Implicit Rules)

使用隐式规则

某些生成target文件的方法可能很常用,比如使用C编译器将.c的源文件编译成.o的目标文件。make将这些常用的方法整合成了隐式规则,以便在需要的时候自动应用(需要的时候,指的是需要生成某个target文件,但是又没有显式地指定该怎么去生成)。对于那些常用方法就可以生成的target文件,我们没有必要为其显式定义一条规则或者手写recipes,make可以自动寻找合适的隐式规则去生成。但是有一个前提就是make能够找到可以构造出这个target文件的prerequisites文件,也就是说我们需要提供能生成target的prerequisites文件。

对于某些类型的target,可能对应有很多的隐式规则都可以生成,比如对于.o的目标文件,可以使用C编译器从.c源文件生成,可以使用Pascal编译器从.p源文件生成,还可以使用汇编器从.s的源文件生成。make会按照隐式规则定义的先后顺序依次去查找这些隐式规则使用的prerequisites文件,如果找到了,则应用这条隐式规则,生成target。

比如说我让make生成一个name.o文件,但是我并没有为name.o写一条规则,告诉make该怎么去生成name.o,该使用什么prerequisites。假设当前目录下同时存在name.c和name.p,则make会使用C编译器从name.c生成name.o;假设当前目录下只有name.p,则make会使用Pascal编译器从name.p生成name.o。

所以,make使用哪条隐式规则,取决于它能找到什么样的prerequisites文件。并且,在规则里面显式指定了prerequisites列表也不影响隐式规则的查找匹配。比如说,有如下的一条规则:

foo.o: foo.p

我们显式指定了prerequisites文件列表为foo.p,并不意味着make就会直接应用Pascal生成.o的隐式规则。因为这条规则没有显式指明recipes,所以make还是会尝试查找合适的隐式规则。如果它能找到foo.c,则使用C编译器生成foo.o。当然,通常来说,make只能找到一个合适的prerequisites,因为prerequisites文件是我们提供的。既然我们手动写了foo.p,那肯定表示我们提供的是foo.p,不会同时提供一个foo.c或foo.s。

make会尝试为所有没有指定规则或recipes的target文件寻找合适的隐式规则,如果不想为某个target进行隐式规则查找,可以为其写一个空的recipe,这个在前面的文章也有讲过。

隐式规则里面的recpies会使用一些预定义的变量,比如C编译器经常使用的CC,CFLAGS,LDFLAGS等等。我们可以在运行make的时候手动传入这些变量,或者直接在shell里面将它们设置为环境变量,这样我们就可以通过改变这些预定义变量的值来控制目标的构建过程。

隐式规则的级联

隐式规则可以级联,一个目标可以通过多条隐式规则的调用而生成。比如name.o可以通过C编译器编译name.c得到,而name.c可以Yacc编译name.y得到。当我们指定构建目标name.o,但是提供的却是name.y时,make会先调用隐式规则从name.y生成name.c,然后再调用隐式规则从name.c生成name.o。这里name.c是隐式规则级联调用过程中生成的中间文件(intermediate file),构建过程中需要生成的中间文件以及生成中间文件对应的隐式规则也会被记录到make的数据库里面,就像其它的目标文件一样。

一般来说,构建过程中生成的中间文件在构建结束后会被删除,make会通过打印rm命令告知我们它删除了某个不再使用的中间文件。

我们可以将某个文件指定为特殊目标.INTERMEDIATE的prerequisite来显式表明它是个中间文件。如果一个文件是target文件,或者被显式指定为某个target的prerequisite,则它不能是中间文件。如果我们希望生成的文件不被删除,可以将它指定为某个target的prerequisite。这样,这个文件将不是中间文件,它将被隐式规则构造,并且不会被删除,只是这个方法会让make在匹配模板规则的时候做额外的工作。

有一个更好的方法可以保留生成的中间文件,将文件作为特殊目标.NOTINTERMEDIATE的prerequisite,可以强制让make将文件当作非中间文件处理。甚至可以在makefile里面定义没有prerequisites列表的目标.NOTINTERMEDIATE,这样,make将不使用中间文件,构建过程中的所有文件将被保留。

定义模板规则

模板规则前面已经用过了,通过定义我们自己的模板规则,可以让make按照我们想要的方式来构建某些类型的target文件。比如,有如下的模板规则:

%.o : %.c ; recipe...

对于一个没有提供显式规则的target文件name.o,make将首先尝试使用该模板规则,通过name.c来构建出name.o。

自动变量

隐式规则的recipes里面使用的都是自动变量,这是为了提高隐式规则的通用性。

结语

到此为止,make的学习就差不多结束了,熟悉这几篇文章的内容已经足够让我们写出漂亮而简洁的makefile。我深入学习make是为了学习linux内核,linux内核和uboot里面有很多makefile,如果连makefile都看不懂,就无法去梳理linux内核和uboot的构建过程。将学习到的东西梳理成文档也是为了加深记忆,时间久了可以翻出来看,快速回顾。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值