Makefile文件的构成——显式规则
一个完整的Makefile文件由5部分构成:显式规则、隐含规则、使用变量、文件指示和注释。
1、显式规则
显式规则指明了目标文件、依赖文件、生成或更新目标文件所使用的命令。有些规则没有命令,这些规则只是描述了文件间的依赖关系。例如:
foo.o:foo.c defs.h
gcc -c -g foo.c
规则两个作用:
- 目标文件是否过时(不存在或比依赖文件早);
- 重新生成
foo.o
,命令中没有明确指出defs.h
,foo.c
已经包含过头文件,这也是作为依赖文件出现的原因;
一般形式:
目标文件列表 分隔符 依赖文件列表 [; 命令]
[命令]
[命令]
书写规则几个注意点:
(1)规则命令两种写法:命令和“目标文件、依赖文件”放在同一行,使用,
将命令和依赖文件分开;命令放在下一行作为独立命令行,以Tab
键开头,Makefile中所有以Tab
键开头的都作为命令行处理;
(2)Makefile中$
表示使用变量或函数,规则中需要$
的地方,书写两个连续的$$
;
(3)Makefile中较长的行,使用反斜线\
将其书写到独立的物理行上;
2、依赖的类型
makefile文件有两种依赖,一种是前面提到的,依赖文件列表中的任一文件比目标文件新,则需重新生成目标文件;还有一种如下:
foo.o:foo.c | somelib
gcc -o foo foo.c somelib
|
前面的文件是普通依赖文件,如果foo.c
过时,将导致foo重新生成,如果|
后面过时则不会重新生成,第二行命令不会重新生成。
3、命令行属性
一条规则可以有一个或多个命令行,每个命令行以Tab键开头,可以在Tab键后写上+
,-
,@
,如果不写,将使用缺省的命令——命令遇到错误就推出make。+
:本行命令始终被执行,即使运行make命令时使用-n,-q,-t选项(前提目标文件过时,需要执行命令更新);-
:执行本行命令,遇到错误继续执行而不退出make;@
:执行本行命令时不在屏幕上打印命令内容。
例如:
file.o:file.c head1.h head2.h
-mv file.o /tmp
gcc -c file.c
其含义是:如果file.o
过时,先将file.o
备份到tmp目录下,然后再生成新的目标文件;第一次执行时,由于file.o
不存在,mv
会出错,默认情况下,一旦发生错误,make
就会停止运行,在mv
前面加上减号-
,遇到错误,make忽略它继续运行。
4、伪目标
makefile中文件分为两类:实目标文件和伪目标。实目标是真正要生成的,存在在硬盘上;伪目标不要求生成实际文件,为了让make执行的一些辅助命令,如打印一些信息,删除无用的中间文件。
例如:
clean:
-rm -f *.o
含义:删除当前目录下,以.o结尾的文件,遇到错误继续执行;clean没有依赖文件,总是认为它是最新的,因此不会执行第二行的命令,为了执行clean后面的命令,shell提示符下使用命令make clean
。
如果当前目录下有一个名为clean的文件,输入make clean
不会执行下面的命令,需要将clean声明为伪目标。将一个目标声明为伪目标的方法是将它作为特殊目标“.PHONY”的依赖,如下:
.PHONY : clean
clean被声明为伪目标之后,无论目录下是否有名为clean文件,make clean
都会执行rm
命令,而且,当一个目标被声明为伪目标之后,make在执行规则命令时不会试图查找该目标的依赖文件,从而提高make效率,也不要担心目标与文件重名而不能实现我们的目的。
.PHONY : clean
clean:
-rm -f *.o
makefile中伪目标也有可以有自己的依赖。在一个目录下如果需要生成多个可执行程序1,可以在一个makefile文件中实现,因为makefile中第一个目标是最终目标,通常用伪目标all
作为最终目标,它的依赖文件就是那些需要创建的可执行程序。
all : program1 program2 program3
.PHONY : all
program1: program1.c utils.h
gcc -o program1 program1.c
program2: program2.c utils.h
gcc -o program2 program2.c
program3: program3.c utils.h
gcc -o program3 program3.c
all
作为终极目标,make生成依赖文件(program1 program2 program3),也可以单独生成目标文件(make program1
)。
5、特殊目标
- .PHONY:目标“.PHONY”的所有依赖被视为伪目标,前面提到过;
- .IGNORE:目标“.IGNORE”后面的依赖文件,生成这些依赖文件在执行时遇到错误,make将忽略错误继续执行,功能类似与命令行属性“-”,当此命令没有依赖文件时,忽略所有错误;
- .SUFFIXES:该目标的依赖被认为是一个后缀列表,在检查后缀规则时使用;
- .SILENT:该目标依赖的文件,执行生成依赖文件时,make不会打印执行的命令行;如果“.SILENT”后面没有依赖文件,则表示执行makefile中所有命令都不会打印;
.SILENT:module2.o
modeule2.o:module2.c head2,h
gcc -c module2.c
在执行第三行命令时,不会打印命令,它等价于:
modeule2.o:module2.c head2,h
@gcc -c module2.c
- .PRECIOUS:该目标依赖的文件会受到特别对待,如果make被kill终止或遇到意外终止,这些依赖不会被删除,而且这些依赖文件是中间文件,在不需要时也不会被删除;
- .INTERMEDIATE:该目标依赖的文件当做中间文件对待,如果“.INTERMEDIATE”后面没有依赖文件,该规则是没有意义的;
6、含有多个目标的规则
一个规则可以含有多个目标,规则所定义的命令对所有目标都有效。一个具有都目标的规则相当于多个规则。多目标规则意味着所有目标有相同的依赖文件,规则命令中可以使用自动变量,从而可以把几天类似的规则归为一条,例如:
module1.o module2.o module3.o:command.h
7、搜索目录
较大的项目源文件、头文件、库文件放在不同的目录中,make需要到不同的目中去寻找依赖文件。当文件所在目录发生变化后,可以不用更改makefile文件规则,只改变依赖文件的搜索目录。
make可以识别一个特殊变量“VPATH”,通过“VPATH”可以指定依赖文件的搜索目录。当规则的依赖文件不存在时,make会在此变量所指定的目录下去寻找这些依赖文件。
定义变量“VPATH”时,是用空格或者冒号将多个需要搜索的目录分开。make搜索目录的顺序是按照变量“VPATH”定义的目录顺序进行的(当前目录永远是第一搜索目录)。例如对变量定义如下:
VPATH= /usr/src:../headers
定义了两个搜索目录:“/usr/src”和“../headers”。
另一个设置文件搜索目录的方式是使用make的“vpath”(小写)关键字,方法如下:
(1)vpath<pattern><directories>
为符合模式<pattern>
的文件指定搜索目录<directories>
(2)vpath<pattern>
清除符合模式<pattern>
的文件指定搜索目录
(3)vpath
清除所有已被设置好的文件搜索目录
vpath中的<pattern>
需要包含%
字符,%
表示匹配零个或若干字符,例如%.h
表示所有以“.h”结尾的文件。<pattern>
指定了要搜索的文件集,<directories>
指定了文件集的搜索目录。例如:
vpath %.h ../headers
该语句表示在../headers”目录下搜索以“.h”结尾的文件(当前目录没有找到的话)。
可以重复使用vpath
语句,以指定不同的搜索策略。如果连续的vpath语句出现了相同的<pattern>
,make会按照vpath语句先后顺序来执行搜索。
vpath %.c src1
vpath % scr2
vpath %.c src3
表示以“.c”结尾的文件,现在src1目录中寻找,然后是“scr2”,最后是“scr3”。
评论已关闭