makefile的使用隐含规则


重新创建目标文件的一些标准方法是经常使用的。例如,一个传统的创建OBJ文件的方法是使用C编译器,如cc,编译C语言
源程序。
隐含规则能够告诉make怎样使用传统的技术完成任务,这样,当您使用它们时,您就不必详细指定它们。例如,有一条编译C
语言源程序的隐含规则,文件名决定运行哪些隐含规则;另如,编译C语言程序一般是使用‘.c’文件,产生‘.o’文件。因
此, make据此和文件名的后缀就可以决定使用编译C语言源程序的隐含规则。一系列的隐含规则可按顺序应用;例如,make
可以从一个‘.y’文件,借助‘.c’文件,重建一个‘.o’文件,参阅隐含规则链。内建隐含规则的命令需要使用变量,通过
改变这些变量的值,您就可以改变隐含规则的工作方式。例如,变量CFLAGS控制隐含规则用于编译C程序传递给C编译器的
标志,参阅隐含规则使用的变量。通过编写格式规则,您可以创建您自己的隐含规则。参阅定义和重新定义格式规则。
后缀规则是对定义隐含规则最有限制性。格式规则一般比较通用和清楚,但是后缀规则却要保持兼容性。参阅过时的后缀规
则。
10.1 使用隐含规则
允许make对一个目标文件寻找传统的更新方法,您所有做的是避免指定任何命令。可以编写没有命令行的规则或根本不编写
任何规则。这样,make将根据存在的源文件的类型或要生成的文件类型决定使用何种隐含规则。
例如,假设makefile文件是下面的格式:
foo : foo.o bar.o
cc -o foo foo.o bar.o $(CFLAGS) $(LDFLAGS)
因为您提及了文件‘foo.o’,但是您没有给出它的规则,make将自动寻找一条隐含规则,该规则能够告诉make怎样更新该文
http://lsec.cc.ac.cn/~peace/articles/gnumaketranslated.html(第 48/79 页)2006-8-18 18:49:01
GNU Make 使用手册(中译版)
件。无论文件‘foo.o’存在与否,make都会这样执行。
如果能够找到一条隐含规则,则它就能够对命令和一个或多个依赖(源文件)提供支持。如果您要指定附加的依赖,例如头
文件,但隐含规则不能支持,您需要为目标‘foo.o’写一条不带命令行的规则。
每一条隐含规则都有目标格式和依赖格式;也许多条隐含规则有相同的目标格式。例如,有数不清的规则产生‘.o’文件:使
用C编译器编译‘.C’文件;使用Pascal编译器编译‘.p’文件;等等。实际应用的规则是那些依赖存在或可以创建的规则。所
以,如果您有一个‘.C’文件,make将运行C编译器;如果您有一个‘.p’文件,make将运行Pascal编译器;等等。
当然,您编写一个makefile文件时,您知道您要make使用哪一条隐含规则,以及您知道make将选择哪一条规则,因为您知道那
个依赖文件是假设存在的。预定义的隐含规则列表的详细内容参阅隐含规则目录。
首先,我们说一条隐含规则可以应用,该规则的依赖必须‘存在或可以创建’。一个文件‘可以创建’是说该文件在makefile
中作为目标或依赖被提及,或者该文件可以经过一条隐含规则的递归调用后能够创建。如果一条隐含规则的依赖是另一条隐
含规则的结果,我们说产生了‘链’。参阅隐含规则链。
总体上说,make为每一个目标搜寻隐含规则,为没有命令行的双冒号规则搜寻隐含规则。仅作为依赖被提及的文件,将被认
为是一个目标,如果该目标的规则没有指定任何内容, make将为它搜寻隐含规则。对于详细的搜寻过程参阅隐含规则的搜寻
算法。
注意,任何具体的依赖都不影响对隐含规则的搜寻。例如,认为这是一条具体的规则:
foo.o: foo.p
文件foo.p不是首要条件,这意味着make按照隐含规则可以从一个Pascal源程序(‘.p’文件)创建OBJ文件,也就是说一个‘.
o’文件可根据‘.p’文件进行更新。但文件foo.p并不是绝对必要的;例如,如果文件foo.c也存在,按照隐含规则则是从文件
foo.c重建foo.o,这是因为C编译规则在预定义的隐含规则列表中比Pascal规则靠前,参阅隐含规则目录。
如果您不希望使用隐含规则创建一个没有命令行的目标,您可以通过添加分号为该目标指定空命令。参阅使用空命令。
10.2隐含规则目录
这里列举了预定义的隐含规则的目录,这些隐含规则是经常应用的,当然如果您在makefile文件中重载或删除后,这些隐含规
则将会失去作用,详细内容参阅删除隐含规则。选项‘-r’或‘--no-builtin-rules’将删除所有预定义的隐含规则。
并不是所有的隐含规则都是预定义的,在make中很多预定义的隐含规则是后缀规则的扩展,因此,那些预定义的隐含规则和
后缀规则的列表相关(特殊目标.SUFFIXES的依赖列表)。缺省的后缀列表为:.out, .a, .ln, .o, .c, .cc, .C, .p, .f, .F, .r, .y, .l, .
s, .S, .mod, .sym, .def, .h, .info, .dvi, .tex, .texinfo, .texi, .txinfo, .w, .ch, .web, .sh, .elc, .el。所有下面描述的隐含规则,如果
它们的依赖中有一个出现在这个后缀列表中,则是后缀规则。如果您更改这个后缀列表,则只有那些由一个或两个出现在您
指定的列表中的后缀命名的预定义后缀规则起作用;那些后缀没有出现在列表中的规则被禁止。对于详细的关于后缀规则的
描述参阅过时的后缀规则。
Compiling C programs(编译C程序)
‘n.o' 自动由‘n.c' 使用命令 ‘$(CC) -c $(CPPFLAGS) $(CFLAGS)'生成 。
Compiling C++ programs (编译C++程序)
‘n.o'自动由‘n.cc' 或‘n.C'使用命令‘$(CXX) -c $(CPPFLAGS) $(CXXFLAGS)’生成。 我们鼓励您对C++源文件使用
后缀‘.cc' 代替后缀‘.C’。
Compiling Pascal programs (编译Pascal程序)
‘n.o'自动由‘n.p'使用命令‘$(PC) -c $(PFLAGS)'生成。
Compiling Fortran and Ratfor programs (编译Fortran 和 Ratfor程序)
‘n.o'自动由‘n.r', ‘n.F'或‘n.f' 运行Fortran编译器生成。使用的精确命令如下:
`.f'
`$(FC) -c $(FFLAGS)'.
`.F'
`$(FC) -c $(FFLAGS) $(CPPFLAGS)'.
`.r'
`$(FC) -c $(FFLAGS) $(RFLAGS)'.
Preprocessing Fortran and Ratfor programs (预处理Fortran 和 Ratfor程序)
‘n.f' 自动从 ‘n.r'或‘n.F'得到。该规则仅仅是与处理器把一个Ratfor 程序或能够预处理的 Fortran 程序转变为标准的
Fortran 程序。使用的精确命令如下:
`.F'
`$(FC) -F $(CPPFLAGS) $(FFLAGS)'.
`.r'
`$(FC) -F $(FFLAGS) $(RFLAGS)'.
Compiling Modula-2 programs(编译Modula-2程序)
‘n.sym'自动由‘n.def'使用命令‘$(M2C) $(M2FLAGS) $(DEFFLAGS)'生成。 ‘n.o' 从‘n.mod'生成;命令为:‘$(M2C)
http://lsec.cc.ac.cn/~peace/articles/gnumaketranslated.html(第 49/79 页)2006-8-18 18:49:01
GNU Make 使用手册(中译版)
$(M2FLAGS) $(MODFLAGS)'。
Assembling and preprocessing assembler programs (汇编以及预处理汇编程序)
‘n.o'自‘n.S'运行C编译器,cpp,生成。命令为:‘$(CPP) $(CPPFLAGS)'。
Linking a single object file (连接一个简单的OBJ文件)
‘n' 自动由‘n.o' 运行C编译器中的连接程序 linker (通常称为 ld)生成。命令为: ‘$(CC) $(LDFLAGS) n.o
$(LOADLIBES) $(LDLIBS)'。该规则对仅有一个源程序的简单程序或对同时含有多个OBJ文件(可能来自于不同的源文
件)的程序都能正常工作。如果同时含有多个OBJ文件,则其中必有一个OBJ文件的名字和可执行文件名匹配。例如:
x: y.o z.o
当‘x.c', ‘y.c' 和‘z.c' 都存在时则执行:
cc -c x.c -o x.o
cc -c y.c -o y.o
cc -c z.c -o z.o
cc x.o y.o z.o -o x
rm -f x.o
rm -f y.o
rm -f z.o
对于更复杂的情况,例如没有一个OBJ文件的名字和可执行文件名匹配,您必须为连接写一条具体的命令。每一种能自动生
成‘.o’的文件,可以在没有‘-c’选项的情况下使用编译器(‘$(CC)',‘$(FC)'或‘$(PC)'; C编译器‘$(CC)'也适用于汇编
程序)自动连接。当然也可以使用OBJ文件作为中间文件,但编译、连接一步完成速度将快很多。
Yacc for C programs (由Yacc生成C程序)
‘n.c'自动由‘n.y'使用命令‘$(YACC) $(YFLAGS)'运行 Yacc生成。
Lex for C programs (由Lex生成C程序)
‘n.c'自动由‘n.l' 运行 Lex生成。命令为:‘$(LEX) $(LFLAGS)'。
Lex for Ratfor programs (由Lex生成Rator程序)
‘n.r'自动由‘n.l' 运行 Lex生成。命令为:‘$(LEX) $(LFLAGS)'。 对于所有的Lex文件,无论它们产生C代码或Ratfor 代
码,都使用相同的后缀‘.l’进行转换,在特定场合下,使用make自动确定您使用哪种语言是不可能的。如果make使
用‘.l’文件重建一个OBJ文件,它必须猜想使用哪种编译器。它很可能猜想使用的是 C 编译器, 因为C 编译器更加普
遍。如果您使用 Ratfor语言, 请确保在makefile文件中提及了‘n.r',使make知道您的选择。否则,如果您专用Ratfor语
言,不使用任何C 文件, 请在隐含规则后缀列表中将‘.c’剔除:
.SUFFIXES:
.SUFFIXES: .o .r .f .l ...
Making Lint Libraries from C, Yacc, or Lex programs(由C, Yacc, 或 Lex程序创建Lint库)
‘n.ln' 可以从‘n.c' 运行lint产生。命令为:‘ $(LINT) $(LINTFLAGS) $(CPPFLAGS) –i’。用于C程序的命令和用
于‘n.y'或‘n.l'程序相同。
TeX and Web(TeX 和 Web)
‘n.dvi'可以从‘n.tex' 使用命令‘$(TEX)'得到。‘n.tex'可以从‘n.web'使用命令‘$(WEAVE)'得到;或者从‘n.
w' (和‘n.ch',如果‘n.ch'存在或可以建造) 使用命令‘$(CWEAVE)'。‘n.p' 可以从‘n.web'使用命令‘$(TANGLE)'产
生。‘n.c' 可以从‘n.w' (和‘n.ch',如果‘n.ch'存在或可以建造) 使用命令‘$(CTANGLE)'得到。
Texinfo and Info(Texinfo和Info)
‘n.dvi'可以从‘n.texinfo',‘n.texi', 或‘n.txinfo', 使用命令‘$(TEXI2DVI) $(TEXI2DVI_FLAGS)'得到。‘n.info'可以从‘n.
texinfo',‘n.texi', 或‘n.txinfo', 使用命令‘$(MAKEINFO) $(MAKEINFO_FLAGS)'创建。
RCS
文件‘n'必要时可以从名为‘n,v'或‘RCS/n,v'的RCS文件中提取。具体命令是:‘$(CO) $(COFLAGS)'。文件‘n'如果
已经存在,即使RCS文件比它新,它不能从RCS文件中提取。用于RCS的规则是最终的规则,参阅万用规则,所以RCS
不能够从任何源文件产生,它们必须存在。
SCCS
文件‘n'必要时可以从名为‘s.n'或‘SCCS/s.n'的SCCS文件中提取。具体命令是:‘$(GET) $(GFLAGS)'。用于SCCS的
规则是最终的规则,参阅万用规则,所以SCCS不能够从任何源文件产生,它们必须存在。SCCS的优点是,文件 ‘n'
可以从文件 ‘n.sh'拷贝并生成可执行文件(任何人都可以)。这用于shell的脚本,该脚本在SCCS内部检查。因为RCS 允
许保持文件的可执行性,所以您没有必要将该特点用于RCS文件。我们推荐您避免使用SCCS,RCS不但使用广泛,而
且是免费的软件。选择自由软件代替相当的(或低劣的)收费软件,是您对自由软件的支持。
通常情况下,您要仅仅改变上表中的变量,需要参阅下面的文档。
隐含规则的命令实际使用诸如COMPILE.c, LINK.p, 和 PREPROCESS.S等等变量,它们的值包含以上列出的命令。Make按照惯例
进行处理,如,编译‘.x’源文件的规则使用变量‘COMPILE.x’;从‘.x’源文件生成可执行文件使用变量‘LINK.x’;预
处理‘.x’源文件使用变量‘PREPROCESS.x’。
任何产生OBJ文件的规则都使用变量‘OUTPUT_OPTION’;make依据编译时间选项定义该变量的值是‘-o $@’或空值。当
源文件分布在不同的目录中,您应该使用‘-O’选项保证输出到正确的文件中;使用变量VPATH时同样(参阅为依赖搜寻目
http://lsec.cc.ac.cn/~peace/articles/gnumaketranslated.html(第 50/79 页)2006-8-18 18:49:01
GNU Make 使用手册(中译版)
录)。一些系统的编译器不接受针对OBJ文件的‘-o’开关;如果您在这样的系统上运行,并使用了变量VPATH,一些文件
的编译输出可能会放到错误的地方。解决办法是将变量OUTPUT_OPTION值设为:‘; mv $*.o $@’
10.3隐含规则使用的变量
内建隐含规则的命令对预定义变量的使用是开放的;您可以在makefile文件中改变变量的值,也可以使用make的运行参数或在
环境中改变,如此,在不对这些规则本身重新定义的情况下,就可以改变这些规则的工作方式。您还可以使用选项‘-
R’或‘--no-builtin-variables’删除所有隐含规则使用的变量。
例如,编译C程序的命令实际是‘$(CC) -c $(CFLAGS) $(CPPFLAGS)’,变量缺省的值是‘cc’或空值,该命令实际是‘cc –
c’。如重新定义变量‘CC’的值为‘ncc’,则所有隐含规则将使用‘ncc’作为编译C语言源程序的编译器。通过重新定义
变量‘CFLAGS’的值为‘-g’,则您可将‘-g’选项传递给每个编译器。所有的隐含规则编译C程序时都使用‘$CC’获得编
译器的名称,并且都在传递给编译器的参数中都包含‘$(CFLAGS)’。
隐含规则使用的变量可分为两类:一类是程序名变量(象cc),另一类是包含程序运行参数的变量(象CFLAGS)。(‘程序
名’可能也包含一些命令参数,但是它必须以一个实际可以执行的程序名开始。) 如果一个变量值中包含多个参数,它们之间
用空格隔开。
这里是内建规则中程序名变量列表:
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'.
MAKEINFO
将Texinfo 源文件转换为信息文件的程序;缺省为:‘makeinfo'.
TEX
从TeX源产生TeX DVI文件的程序;缺省为:‘tex'.
TEXI2DVI
从Texinfo源产生TeX DVI 文件的程序;缺省为:‘texi2dvi'.
WEAVE
将Web翻译成TeX的程序;缺省为:‘weave'.
CWEAVE
将CWeb翻译成TeX的程序;缺省为:‘cweave'.
TANGLE
将Web翻译成 Pascal的程序;缺省为:‘tangle'.
CTANGLE
将Web翻译成C的程序;缺省为:‘ctangle'.
RM
http://lsec.cc.ac.cn/~peace/articles/gnumaketranslated.html(第 51/79 页)2006-8-18 18:49:01
GNU Make 使用手册(中译版)
删除文件的命令;缺省为:‘rm -f'.
这里是值为上述程序附加参数的变量列表。在没有注明的情况下,所有变量的值为空值。
ARFLAGS
用于档案管理程序的标志,缺省为:‘rv'.
ASFLAGS
用于汇编编译器的额外标志 (当具体调用‘.s'或‘.S'文件时)。
CFLAGS
用于C编译器的额外标志。
CXXFLAGS
用于C++编译器的额外标志。
COFLAGS
用于RCS co程序的额外标志。
CPPFLAGS
用于C预处理以及使用它的程序的额外标志 (C和 Fortran 编译器)。
FFLAGS
用于Fortran编译器的额外标志。
GFLAGS
用于SCCS get程序的额外标志。
LDFLAGS
用于调用linker(‘ld’)的编译器的额外标志。
LFLAGS
用于Lex的额外标志。
PFLAGS
用于Pascal编译器的额外标志。
RFLAGS
用于处理Ratfor程序的Fortran编译器的额外标志。
YFLAGS
用于Yacc的额外标志。Yacc。
10.4 隐含规则链
有时生成一个文件需要使用多个隐含规则组成的序列。例如,从文件‘n.y’生成文件‘n.o’,首先运行隐含规则Yacc,其次
运行规则cc。这样的隐含规则序列称为隐含规则链。
如果文件‘n.c’存在或在makefile文件中提及,则不需要任何特定搜寻:make首先发现通过C编译器编译‘n.c’可生成该OBJ
文件,随后,考虑生成‘n.c’时,则使用运行Yacc的规则。这样可最终更新‘n.c’和‘n.o’。
即使在文件‘n.c’不存在或在makefile文件中没有提及的情况下,make也能想象出在文件‘n.y’和‘n.o’缺少连接!这种情
况下,‘n.c’称为中间文件。一旦make决定使用中间文件,它将把中间文件输入数据库,好像中间文件在makefile文件中提及
一样;按照隐含规则的描述创建中间文件。
中间文件和其它文件一样使用自己的规则重建,但是中间文件和其它文件相比有两种不同的处理方式。
第一个不同的处理方式是如果中间文件不存在make的行为不同:平常的文件b如果不存在,make认为一个目标依靠文件b,它
总是创建文件b,然后根据文件b更新目标;但是文件b若是中间文件,make很可能不管它而进行别的工作,即不创建文件b,
也不更新最终目标。只有在文件b的依赖比最终目标‘新’时或有其它原因时,才更新最终目标。
第二个不同点是make在更新目标创建文件b后,如果文件b不再需要,make将把它删除。所以一个中间文件在make运行之前和
make运行之后都不存在。Make向您报告删除时打印一条‘rm –f’命令,表明有文件被删除。
通常情况下,任何在makefile文件中提及的目标和依赖都不是中间文件。但是,您可以特别指定一些文件为中间文件,其方法
为:将要指定为中间文件的文件作为特殊目标 .INTERMEDIATE的依赖。这种方法即使对采用别的方法具体提及的文件也能生
效。
您通过将文件标志为secondary文件可以阻止自动删除中间文件。这时,您将您需要保留的中间文件指定为特殊目标 .
SECONDARY的依赖即可。对于secondary文件,make不会因为它不存在而去创建它,也不会自动删除它。secondary文件必须
也是中间文件。
您可以列举一个隐含规则的目标格式(例如%.o)作为特殊目标 .PRECIOUS的依赖,这样您就可以保留那些由隐含规则创建的
文件名匹配该格式的中间文件。参阅中断和关闭make。
一个隐含规则链至少包含两个隐含规则。例如,从‘RCS/foo.y,v’创建文件‘foo’需要运行RCS、Yacc和cc,文件foo.y和foo.c
是中间文件,在运行结束后将被删掉。
没有一条隐含规则可以在隐含规则链中出现两次以上(含两次)。这意味着,make不会简单的认为从文件‘foo.o.o’创建文
http://lsec.cc.ac.cn/~peace/articles/gnumaketranslated.html(第 52/79 页)2006-8-18 18:49:01
GNU Make 使用手册(中译版)
件foo不是运行linker两次。这还可以强制make在搜寻一个隐含规则链时阻止无限循环。
一些特殊的隐含规则可优化隐含规则链控制的特定情况。例如,从文件foo.c创建文件foo可以被拥有编译和连接的规则链控
制,它使用foo.o作为中间文件。但是对于这种情况存在一条特别的规则,使用简单的命令cc可以同时编译和连接。因为优化
规则在规则表中的前面,所以优化规则和一步一步的规则链相比,优先使用优化规则。
10.5定义与重新定义格式规则
您可以通过编写格式规则定义隐含规则。该规则看起来和普通规则类似,不同之处在于格式规则的目标中包含字符‘%’(只
有一个)。目标是匹配文件名的格式;字符‘%’可以匹配任何非空的字符串,而其它字符仅仅和它们自己相匹配。依赖
用‘%’表示它们的名字和目标名关联。
格式‘%.o : %.c’是说将任何‘stem.c’文件编译为‘stem.o’文件。
在格式规则中使用的‘%’扩展是在所有变量和函数扩展以后进行的,它们是在makefile文件读入时完成的。参阅使用变量和
转换文本函数。
10.5.1格式规则简介
格式规则是在目标中包含字符‘%’(只有一个)的规则,其它方面看起来和普通规则相同。目标是可以匹配文件名的格式,
字符‘%’可以匹配任何非空的字符串,而其它字符仅仅和它们自己相匹配。
例如‘%.c’匹配任何以‘.c’结尾的文件名;‘s.%.c’匹配以‘s.’开始并且以‘.c’结尾的文件名,该文件名至少包含5个
字符(因为‘%’至少匹配一个字符)。匹配‘%’的子字符串称为stem(径)。依赖中使用‘%’表示它们的名字中含有和目
标名相同的stem。要使用格式规则,文件名必须匹配目标的格式,而且符合依赖格式的文件必须存在或可以创建。下面规则:
%.o : %.c ; command...
表明要创建文件‘n.o’,使用‘n.c’作为它的依赖,而且文件‘n.c’ 必须存在或可以创建。
在格式规则中,依赖有时不含有‘%’。这表明采用该格式规则创建的所有文件都是采用相同的依赖。这种固定依赖的格式规
则在有些场合十分有用。
格式规则的依赖不必都包含字符‘%’,这样的规则是一个有力的常规通配符,它为任何匹配该目标格式规则的文件提供创建
方法。参阅定义最新类型的缺省规则。
格式规则可以有多个目标,不象正常的规则,这种规则不能扮演具有相同依赖和命令的多条不同规则。如果一格式规则具有
多个目标,make知道规则的命令对于所有目标来说都是可靠的,这些命令只有在创建所目标时才执行。当为匹配一目标搜寻
格式规则时,规则的目标格式和规则要匹配的目标不同是十分罕见的,所以make仅仅担心目前对文件给出命令和依赖是否有
问题。注意该文件的命令一旦执行,所有目标的时间戳都会更新。
格式规则在makefile文件中的次序很重要,因为这也是考虑它们的次序。对于多个都能使用的规则,使用最先出现的规则。您
亲自编写的规则比内建的规则优先。注意依赖存在或被提及的规则优先于依赖需要经过隐含规则链生成的规则。
10.5.2格式规则的例子
这里有一些实际在make中预定义的格式规则例子,第一个,编译‘.c’文件生成‘.o’文件的规则:
%.o : %.c
$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@
定义了一条编译‘x.c’文件生成‘x.o’文件的规则,命令使用自动变量 ‘$@’和‘$<’ 替换任何情况使用该规则的目标文件
和源文件。参阅自动变量。
第二个内建的例子:
% :: RCS/%,v
$(CO) $(COFLAGS) $<
定义了在子目录‘RCS’中根据相应文件‘x.v’生成文件‘x’的规则。因为目标是‘%’,只要相对应的依赖文件存在,该
规则可以应用于任何文件。双冒号表示该规则是最终规则,它意味着不能是中间文件。参阅万用规则。
下面的格式规则有两个目标:
%.tab.c %.tab.h: %.y
bison -d $<
这告诉make执行命令‘bison -d x.y’将创建‘x.tab.c’和‘x.tab.h’。如果文件foo依靠文件‘parse.tab.o’和‘scan.o’,而文
件‘scan.o’又依靠文件‘parse.tab.h’,当‘parse.y’发生变化,命令‘bison -d parse.y’执行一次。‘parse.tab.o’和‘scan.
o’的依赖也随之更新。(假设文件‘parse.tab.o’由文件‘parse.tab.c’编译生成,文件‘scan.o’由文件‘scan.c’生成,当连
接‘parse.tab.o’、‘scan.o’和其它依赖生成文件foo时,上述规则能够很好执行。)
http://lsec.cc.ac.cn/~peace/articles/gnumaketranslated.html(第 53/79 页)2006-8-18 18:49:01
GNU Make 使用手册(中译版)
10.5.3自动变量
假设您编写一个编译‘.c’文件生成‘.o’文件的规则:您怎样编写命令‘CC’,使它能够操作正确的文件名?您当然不能将
文件名直接写进命令中,因为每次使用隐含规则操作的文件名都不一样。
您应该使用make的另一个特点,自动变量。这些变量在规则每次执行时都基于目标和依赖产生新值。例如您可以使用变
‘$@’代替目标文件名,变量‘$<’代替依赖文件名。
下面是自动变量列表:
$@
规则的目标文件名。如果目标是一个档案成员,则变量 ‘$@’ 档案文件的文件名。对于有多个目标的格式规则(参阅
格式规则简介),变量 ‘$@’是那个导致规则命令运行的目标文件名。
$%
当目标是档案成员时,该变量是目标成员名,参阅使用make更新档案文件。例如,如果目标是‘foo.a(bar.o)',则‘$
%'的值是‘bar.o', ‘$@'的值是‘foo.a'。如果目标不是档案成员,则‘$%'是空值。
$<
第一个依赖的文件名。如果目标更新命令来源于隐含规则,该变量的值是隐含规则添加的第一个依赖。参阅使用隐含
规则。
$?
所有比目标‘新’的依赖名,名字之间用空格隔开。对于为档案成员的依赖,只能使用已命名的成员。参阅使用make
更新档案文件。
$^
所有依赖的名字,名字之间用空格隔开。对于为档案成员的依赖,只能使用已命名的成员。参阅使用make更新档案文
件。对同一个目标来说,一个文件只能作为一个依赖,不管该文件的文件名在依赖列表中出现多少次。所以,如果在
依赖列表中,同一个文件名出现多次,变量‘$^’的值仍然仅包含该文件名一次。
$+
该变量象‘$^',但是,超过一次列出的依赖将按照它们在makefile文件中出现的次序复制。这主要的用途是对于在按
照特定顺序重复库文件名很有意义的地方使用连接命令。
$*
和隐含规则匹配的stem(径),参阅格式匹配。如果一个目标为‘dir/a.foo.b',目标格式规则为:‘a.%.b' ,则stem为‘dir/
foo'。在构建相关文件名时stem 十分有用。在静态格式规则中,stem是匹配目标格式中字符‘%’的文件名中那一部
分。在一个没有stem具体规则中;变量‘$*' 不能以该方法设置。如果目标名以一种推荐的后缀结尾(参阅过时的后缀
规则),变量‘$*'设置为目标去掉该后缀后的部分。例如,如果目标名是‘foo.c',则变量‘$*' 设置为‘foo', 因为‘.
c' 是一个后缀。GNU make 处理这样奇怪的事情是为了和其它版本的make兼容。在隐含规则和静态格式规则以外,您
应该尽量避免使用变量‘$*'。在具体规则中如果目标名不以推荐的后缀结尾,则变量‘$*’在该规则中设置为空值。
当您希望仅仅操作那些改变的依赖,变量‘$?' 即使在具体的规则中也很有用。例如,假设名为‘lib’的档案文件包含几个
OBJ文件的拷贝,则下面的规则仅将发生变化的OBJ文件拷贝到档案文件:
lib: foo.o bar.o lose.o win.o
ar r lib $?
在上面列举的变量中,有四个变量的值是单个文件名。三个变量的值是文件名列表。这七个变量都有仅仅存放文件的路径名
或仅仅存放目录下文件名的变体。变量的变体名是由变量名追加字母‘D’或‘F’构成。这些变体在GNU make中处于半废状
态,原因是使用函数T dir和notdir 能够得到相同的结果。参阅文件名函数。注意,‘F'变体省略所有在dir函数中总是输出的结
尾斜杠这里是这些变体的列表:
`$(@D)'
目标文件名中的路径部分,结尾斜杠已经移走。如果变量 `$@'的值是`dir/foo.o',变体 `$(@D)'的值是`dir'。 如果变量`
$@'的值不包含斜杠,则变体的值是`.'。
`$(@F)'
目标文件名中的真正文件名部分。如果变量 `$@'的值是`dir/foo.o',变体 `$(@F)'的值是` foo.o '。`$(@F)' 等同于 `$(notdir
$@)'
`$(*D)'
`$(*F)'
stem(径)中的路径名和文件名;在这个例子中它们的值分别为:`dir' 和 `foo' 。
http://lsec.cc.ac.cn/~peace/articles/gnumaketranslated.html(第 54/79 页)2006-8-18 18:49:02
GNU Make 使用手册(中译版)
`$(%D)'
`$(%F)'
档案成员名中的路径名和文件名;这仅对采用‘archive(member)’形式的档案成员目标有意义,并且当成员包含路径
名时才有用。参阅档案成员目标。
`$(<D)'
`$(<F)'
第一个依赖名中的路径名和文件名。
`$(^D)'
`$(^F)'
所有依赖名中的路径名和文件名列表。
`$(?D)'
`$(?F)'
所有比目标‘新’的依赖名中的路径名和文件名列表。
注意,在我们讨论自动变量时,我们使用了特殊格式的惯例;我们写"the value of‘$<'", 而不是"the variable <" ;和我们写普通
变量,例如变量 objects 和 CFLAGS一样。我们认为这种惯例在这种情况下看起来更加自然。这并没有其它意义,变量‘$<'的
变量名为 < 和变量‘$(CFLAGS)' 实际变量名为CFLAGS一样。您也可以使用‘$(<)'代替‘$<'。
10.5.4格式匹配
目标格式是由前缀、后缀和它们之间的通配符%组成,它们中的任一个或两个都可以是空值。格式匹配一个文件名只有该文件
名是以前缀开始,后缀结束,而且两者不重叠的条件下,才算匹配。前缀、后缀之间的文本成为径(stem)。当格式‘%.
o’匹配文件名‘test.o’时,径(stem)是‘test’。格式规则中的依赖将径(stem)替换字符%,从而得出文件名。对于上例
中,如果一个依赖为‘%.c’,则可扩展为‘test.c’。
当目标格式中不包含斜杠(实际并不是这样),则文件名中的路径名首先被去除,然后,将其和格式中的前缀和后缀相比
较。在比较之后,以斜杠结尾的路径名,将会加在根据格式规则的依赖规则产生的依赖前面。只有在寻找隐含规则时路径名
才被忽略,在应用时路径名绝不能忽略。例如,‘e%t’和文件名‘src/eat’匹配,stem(径)是‘src/a’。当依赖转化为文件名
时,stem中的路径名将加在前面,stem(径)的其余部分替换‘%’。使用stem(径) ‘src/a’和依赖格式规则‘c%r’匹配得到
文件名‘src/car’。
10.5.5万用规则
一个格式规则的目标仅仅包含‘%’,它可以匹配任何文件名,我们称这些规则为万用规则。它们非常有用,但是make使用
它们的耗时也很多,因为make必须为作为目标和作为依赖列出的每一个文件都考虑这样的规则。
假设makefile文件提及了文件foo.c。为了创建该目标,make将考虑是通过连接一个OBJ文件‘foo.c.o’创建,或是通过使用一步
的C编译连接程序从文件foo.c.c创建,或是编译连接Pascal程序foo.c.p创建,以及其它的可能性等。
我们知道make考虑的这些可能性是很可笑的,因为foo.c就是一个C语言源程序,不是一个可执行程序。如果make考虑这些可
能性,它将因为这些文件诸如foo.c.o和foo.c.p等都不存在最终拒绝它们。但是这些可能性太多,所以导致make的运行速度极
慢。
为了加快速度,我们为make考虑匹配万用规则的方式设置了限制。有两种不同类型的可以应用的限制,在您每次定义一个万
用规则时,您必须为您定义的规则在这两种类型中选择一种。
一种选择是标志该万用规则是最终规则,即在定义时使用双冒号定义。一个规则为最终规则时,只有在它的依赖存在时才能
应用,即使依赖可以由隐含规则创建也不行。换句话说,在最终规则中没有进一步的链。
例如,从RCS和SCCS文件中抽取原文件的内建的隐含规则是最终规则,则如果文件‘foo.c,v' 不存在,make绝不会试图从一个
中间文件‘foo.c,v.o’或‘RCS/SCCS/s.foo.c,v’在创建它。 RCS 和 SCCS 文件一般都是最终源文件,它不能从其它任何文件重新
创建,所以,make可以记录时间戳,但不寻找重建它们的方式。
如果您不将万用规则标志为最终规则,那么它就是非最终规则。一个非最终万用规则不能用于指定特殊类型数据的文件。如
果存在其它规则(非万用规则)的目标匹配一文件名,则该文件名就是指定特殊类型数据的文件名。
例如,文件名‘foo.c' 和格式规则 `%.c : %.y' (该规则运行Yacc)。无论该规则是否实际使用(如果碰巧存在文件‘foo.y’,该规
则将运行),和目标匹配的事实就能足够阻止任何非最终万用规则在文件foo.c上使用。这样,make 考虑就不试图从文件‘foo.
c.o',‘foo.c.c', ‘foo.c.p'等创建可执行的‘foo.c'。
内建的特殊伪格式规则是用来认定一些特定的文件名,处理这些文件名的文件时不能使用非最终万用规则。这些伪格式规则
没有依赖和命令,它们用于其它目的时被忽略。例如,内建的隐含规则:
%.p :
存在可以保证Pascal源程序如‘foo.p' 匹配特定的目标格式,从而阻止浪费时间寻找‘foo.p.o' 或‘foo.p.c'。
http://lsec.cc.ac.cn/~peace/articles/gnumaketranslated.html(第 55/79 页)2006-8-18 18:49:02
GNU Make 使用手册(中译版)
在后缀规则中,为后缀列表中的每一个有效后缀都创建了伪格式规则,如‘%.p' 。参阅过时的后缀规则。
10.5.6删除隐含规则
通过定义新的具有相同目标和依赖但不同命令的规则,您可以重载内建的隐含规则(或重载您自己定义的规则)。一旦定义
新的规则,内建的规则就被代替。 新规则在隐含规则次序表中的位置由您编写规则的地方决定。
通过定义新的具有相同目标和依赖但不含命令的规则,您可以删除内建的隐含规则。例如,下面的定义规则将删除运行汇编
编译器的隐含规则:
%.o : %.s
10.6 定义最新类型的缺省规则
您通过编写不含依赖的最终万用格式规则,您可以定义最新类型的缺省规则。参阅万用规则。这和其它规则基本一样,特别
之处在于它可以匹配任何目标。因此,这样的规则的命令可用于所有没有自己的命令的目标和依赖,以及用于那些没有其它
隐含规则可以应用的目标和依赖。
例如,在测试makefile时,您可能不关心源文件是否含有真实数据,仅仅关心它们是否存在。那么,您可以这样做:
%::
touch $@
这导致所有必需的源文件(作为依赖)都自动创建。
您可以为没有规则的目标以及那些没有具体指定命令的目标定义命令。要完成上述任务,您需要为特殊目标.DEFAULT 编写规
则。这样的规则可以在所有具体规则中用于没有作为目标出现以及不能使用隐含规则的依赖。自然,如果您不编写定义则没
有特殊目标.DEFAULT 的规则。
如果您使用特殊目标.DEFAULT 而不带任何规则和命令:
.DEFAULT:
则以前为目标.DEFAULT定义的命令被清除。如此make的行为和您从来没有定义目标.DEFAULT一样。
如果您不需要一个目标从万用规则和目标.DEFAULT 中得到命令,也不想为该目标执行任何命令,您可以在定义时使用空命
令。参阅使用空命令。
您可以使用最新类型规则重载另外一个makefile文件的一部分内容。参阅重载其它makefile文件。
10.7 过时的后缀规则
后缀规则是定义隐含规则的过时方法。后缀规则因为格式规则更为普遍和简洁而被废弃。它们在GNU make中得到支持是为了
和早期的makefile文件兼容。它们分为单后缀和双后缀规则。
双后缀规则被一对后缀定义:目标后缀和源文件后缀。它可以匹配任何文件名以目标后缀结尾的文件。相应的隐含依赖通过
在文件名中将目标后缀替换为源文件后缀得到。一个目标和源文件后缀分别为‘.o’和‘.c’双后缀规则相当于格式规则`%.
o : %.c'。
单后缀规则被单后缀定义,该后缀是源文件的后缀。它匹配任何文件名,其相应的依赖名是将文件名添加源文件后缀得到。
源文件后缀为‘.c’的单后缀规则相当于格式规则‘% : %.c’。
通过比较规则目标和定义的已知后缀列表识别后追规则。当make见到一个目标后缀是已知后缀的规则时,该规则被认为是一
个单后缀规则。当make见到一个目标后缀包含两个已知后缀的规则时,该规则被认为是一个双后缀规则。
例如,‘.o’和‘.c’都是缺省列表中的已知后缀。所以,如果您定义一个规则,其目标是‘.c.o’,则make认为是一个双后
缀规则,源文件后缀是‘.c’,目标后缀是‘.o’。这里有一个采用过时的方法定义编译C语言程序的规则:
.c.o:
http://lsec.cc.ac.cn/~peace/articles/gnumaketranslated.html(第 56/79 页)2006-8-18 18:49:02
GNU Make 使用手册(中译版)
$(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<
后缀规则不能有任何属于它们自己的依赖。如果它们有依赖,它们将不是作为后缀规则使用,而是以令人啼笑皆非的方式处
理正常的文件。例如,规则:
.c.o: foo.h
$(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<
告诉从依赖foo.h生成文件名为‘.c.o’的文件,并不是象格式规则:
%.o: %.c foo.h
$(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<
告诉从‘.c'文件生成 ‘.o' 文件‘.c'的方法:创建所有‘.o' 文件使用该格式规则,而且同时使用依赖文件‘foo.h'。
没有命令的后缀规则也没有意义。它们并不没有命令的格式规则那样移去以前的规则(参阅删除隐含规则)。他们仅仅简单
的在数据库中加入后缀或双后缀作为一个目标。
已知的后缀是特殊目标‘.SUFFIXES’简单的依赖名。通过为特殊目标‘.SUFFIXES’编写规则加入更多的依赖,您可以添加
您自己的已知后缀。例如:
.SUFFIXES: .hack .win
把‘.hack' 和‘.win'添加到了后缀列表中。
如果您希望排除缺省的已知后缀而不是仅仅的添加后缀,那么您可以为特殊目标‘.SUFFIXES’编写没有依赖的规则。通过这
种方式,可以完全排除特殊目标‘.SUFFIXES’存在的依赖。接着您可以编写另外一个规则添加您要添加的后缀。例如,
.SUFFIXES: # 删除缺省后缀
.SUFFIXES: .c .o .h # 定义自己的后缀列表
标志‘-r'或‘--no-builtin-rules'也能把缺省的后缀列表清空。
变量SUFFIXES在make读入任何makefile文件之前定义缺省的后缀列表。您可以使用特殊目标‘.SUFFIXES’改变后缀列表,但
这不能改变变量SUFFIXES的值。
10.8隐含规则搜寻算法
这里是make为一个目标‘t’搜寻隐含规则的过程。这个过程用于任何没有命令的双冒号规则,用于任何不含命令的普通规则
的目标,以及用于任何不是其它规则目标的依赖。这个过程也能用于来自隐含规则的依赖递归调用该过程搜寻规则链。
在本算法中不提及任何后缀规则,因为后缀规则在makefile文件读入时转化为了格式规则。
对于个是‘archive(member)’的档案成员目标,下述算法重复两次,第一次使用整个目标名‘t’,如果第一次运行没有发现
规则,则第二次使用‘(member)’作为目标‘t’。
1、 在‘t’中分离出路径部分,称为‘d’,剩下部分称为‘n’。例如如果‘t’是‘src/foo.o’,那
么‘d’是‘src/’;‘n’是‘foo.o’。
2、 建立所有目标名匹配‘t’和‘n’的格式规则列表。如果目标格式中含有斜杠,则匹配‘t’,否则,匹
配‘n’。
3、 如果列表中有一个规则不是万用规则,则从列表中删除所有非最终万用规则。
4、 将没有命令的规则也从列表中移走。
5、 对每个列表中的格式规则:
1、 寻找stem‘s’,也就是和目标格式中%匹配的‘t’或‘n’部分。
2、 使用stem‘s’计算依赖名。如果目标格式不包含斜杠,则将‘d’添加在每个依赖的前面。
3、 测试所有的依赖是否存在或能够创建。(如果任何文件在makefile中作为目标或依赖被提及,则我们说它应该
存在。)如果所有依赖存在或能够创建,或没有依赖,则可使用该规则。
6、 如果到现在还没有发现能使用的规则,进一步试。对每一个列表中的规则:
http://lsec.cc.ac.cn/~peace/articles/gnumaketranslated.html(第 57/79 页)2006-8-18 18:49:02
GNU Make 使用手册(中译版)
1、 如果规则是最终规则,则忽略它,继续下一条规则。
2、 象上述一样计算依赖名。
3、 测试所有的依赖是否存在或能够创建。
4、 对于不存在的依赖,按照该算法递归调用查找是否能够采用隐含规则创建。
5、 如果所有依赖存在或能使用隐含规则创建,则应用该规则。
7、 如果没有隐含规则,则如有用于目标‘.DEFAULT’规则,则应用该规则。在这种情况下,将目标‘.
DEFAULT’的命令给与‘t’。
一旦找到可以应用的规则,对每一个匹配的目标格式(无论是‘t’或‘n’)使用stem‘s’替换%,将得到的文件名储存起来
直到执行命令更新目标文件‘t’。在这些命令执行以后,把每一个储存的文件名放入数据库,并且标志已经更新,其时间戳
和目标文件‘t’一样。
如果格式规则的命令为创建‘t’执行,自动变量将设置为相应的目标和依赖(参阅自动变量)。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值