您的位置:首页 > 其它

makefile 隐含规则

2015-10-08 20:20 218 查看
在我们使用Makefile时,有一些我们会经常使用,而且使用频率非常高的东西,比如,我们编译C/C++的源程序为中间目标文件(Unix下是[.o]文件,Windows下是[.obj]文件)。本章讲述的就是一些在Makefile中的“隐含的”,早先约定了的,不需要我们再写出来的规则。
“隐含规则”也就是一种惯例,make会按照这种“惯例”心照不喧地来运行,那怕我们的Makefile中没有书写这样的规则。例如,把[.c]文件编译成[.o]文件这一规则,你根本就不用写出来,make会自动推导出这种规则,并生成我们需要的[.o]文件。
“隐含规则”会使用一些我们系统变量,我们可以改变这些系统变量的值来定制隐含规则的运行时的参数。如系统变量“CFLAGS”可以控制编译时的编译器参数。
我们还可以通过“模式规则”的方式写下自己的隐含规则。用“后缀规则”来定义隐含规则会有许多的限制。使用“模式规则”会更回得智能和清楚,但“后缀规则”可以用来保证我们Makefile的兼容性。

如果要使用隐含规则生成你需要的目标,你所需要做的就是不要写出这个目标的规则。那么,make会试图去自动推导产生这个目标的规则和命令,如果make可以自动推导生成这个目标的规则和命令,那么这个行为就是隐含规则的自动推导。当然,隐含规则是make事先约定好的一些东西。例如,我们有下面的一个Makefile:
foo : foo.o bar.o

cc –o foo foo.o bar.o $(CFLAGS) $(LDFLAGS)
我们可以注意到,这个Makefile中并没有写下如何生成foo.o和bar.o这两目标的规则和命令。因为make的“隐含规则”功能会自动为我们自动去推导这两个目标的依赖目标和生成命令。
make会在自己的“隐含规则”库中寻找可以用的规则,如果找到,那么就会使用。如果找不到,那么就会报错。在上面的那个例子中,make调用的隐含规则是,把[.o]的目标的依赖文件置成[.c],并使用C的编译命令“cc
–c $(CFLAGS) [.c]”来生成[.o]的目标。也就是说,我们完全没有必要写下下面的两条规则:
foo.o : foo.c

cc –c foo.c $(CFLAGS)

bar.o : bar.c

cc –c bar.c $(CFLAGS)
因为,这已经是“约定”好了的事了,make和我们约定好了用C编译器“cc”生成[.o]文件的规则,这就是隐含规则。
当然,如果我们为[.o]文件书写了自己的规则,那么make就不会自动推导并调用隐含规则,它会按照我们写好的规则忠实地执行。
还有,在make的“隐含规则库”中,每一条隐含规则都在库中有其顺序,越靠前的则是越被经常使用的,所以,这会导致我们有些时候即使我们显示地指定了目标依赖,make也不会管。如下面这条规则(没有命令):
foo.o : foo.p
依赖文件“foo.p”(Pascal程序的源文件)有可能变得没有意义。如果目录下存在了“foo.c”文件,那么我们的隐含规则一样会生效,并会通过“foo.c”调用C的编译器生成foo.o文件。因为,在隐含规则中,Pascal的规则出现在C的规则之后,所以,make找到可以生成foo.o的C的规则就不再寻找下一条规则了。如果你确实不希望任何隐含规则推导,那么,你就不要只写出“依赖规则”,而不写命令。

二、隐含规则一览



、编译C的目标的依赖目标会自动推导为“.c”,并且其生成命令是“$(CC)
–c $(CPPFLAGS) $(CFLAGS)”
2程序的隐含规则。

“.o”、编译Pascal、编译Fortran/Ratfor、预处理Fortran/Ratfor的目标的依赖目标会自动推导为“.r”或“.F”。这个规则只是转换Ratfor或有预处理的Fortran程序到一个标准的Fortran程序。其使用的命令是:

“.F” “$(FC) –F $(CPPFLAGS) $(FFLAGS)”

“.r” “$(FC) –F $(FFLAGS) $(RFLAGS)”
6程序的隐含规则。

“.sym”的目标的依赖目标会自动推导为“.def”,并且其生成命令是:“$(M2C)
$(M2FLAGS) $(DEFFLAGS)”。“” 、汇编和汇编预处理的隐含规则。“.o” 的目标的依赖目标会自动推导为“.s”,默认使用编译品“as”,并且其生成命令是:“$(AS)
$(ASFLAGS)”。
8文件的隐含规则。

“”、Yacc C。(“Yacc”是一个语法分析器,关于其细节请查看相关资料)
10程序时的隐含规则。

“.c”。(关于“Lex”的细节请查看相关资料)
11程序时的隐含规则。

“.r”。

12程序、Yacc文件创建Lint(lint生成的文件)的依赖文件被自动推导为“n.c”,其生成命令是:“$(LINT)
$(LINTFALGS) $(CPPFLAGS) -i”。对于“.y”和“.l”也是同样的规则。

三、隐含规则使用的变量



、关于命令的变量。
AR

函数库打包程序。默认命令是“ar”。

AS

汇编语言编译程序。默认命令是“as”。

CC

C语言编译程序。默认命令是“cc”。

CXX

C++语言编译程序。默认命令是“g++”。

CO

从 RCS文件中扩展文件程序。默认命令是“co”。

CPP

C程序的预处理器(输出是标准输出设备)。默认命令是“$(CC) –E”。

FC

Fortran 和 Ratfor 的编译器和预处理程序。默认命令是“f77”。

GET

从SCCS文件中扩展文件的程序。默认命令是“get”。

LEX

Lex方法分析器程序(针对于C或Ratfor)。默认命令是“lex”。

PC

Pascal语言编译程序。默认命令是“pc”。

YACC

Yacc文法分析器(针对于C程序)。默认命令是“yacc”。

YACCR

Yacc文法分析器(针对于Ratfor程序)。默认命令是“yacc
–r”、关于命令参数的变量

有些时候,一个目标可能被一系列的隐含规则所作用。例如,一个[.o]的文件生成,可能会是先被Yacc的[.y]文件先成[.c],然后再被C的编译器生成。我们把这一系列的隐含规则叫做“隐含规则链”。
在上面的例子中,如果文件[.c]存在,那么就直接调用C的编译器的隐含规则,如果没有[.c]文件,但有一个[.y]文件,那么Yacc的隐含规则会被调用,生成[.c]文件,然后,再调用C编译的隐含规则最终由[.c]生成[.o]文件,达到目标。
我们把这种[.c]的文件(或是目标),叫做中间目标。不管怎么样,make会努力自动推导生成目标的一切方法,不管中间目标有多少,其都会执着地把所有的隐含规则和你书写的规则全部合起来分析,努力达到目标,所以,有些时候,可能会让你觉得奇怪,怎么我的目标会这样生成?怎么我的makefile发疯了?
在默认情况下,对于中间目标,它和一般的目标有两个地方所不同:第一个不同是除非中间的目标不存在,才会引发中间规则。第二个不同的是,只要目标成功产生,那么,产生最终目标过程中,所产生的中间目标文件会被以“rm
-f”: mid )
你也可以阻止make自动删除中间目标,要做到这一点,你可以使用伪目标“.SECONDARY”来强制声明(如:.SECONDARY
: sec),于是优化过的规则就不会生成中间文件。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: