当前位置:首页 > Makefile的规则
Makefile的规则
Makefile中,规则描述了在何种情况下使用什么命令来重建一个特定的文件,此文件被称为规则?目标?(通常规则中的目标只有一个)。规则中出目标之外的罗列的其它文件称为?目标?的依赖,而规则的命令是用来更新或者创建此规则的目标。
除了makefile的?终极目标?所在的规则以外,其它规则的顺序在makefile文件中没有意义。?终极目标?就是当没有使用make 命令行指定具体目标时,make默认的更新的哪一个目标。它是makefile文件中第一个规则的目标。如果在makefile中第一个规则有多个目标的话,那么多个目标中的第一个将会被作为make的?终极目标?。有两种情况的例外:1. 目标名以点号?.?开始的并且其后不存在斜线?/?(?./?被认为是当前目录;?../?被认为是上一级目录);2. 模式规则的目标。当这两种目标所在的规则是Makefile的第一个规则时,它们并不会被作为?终极目标?。
?终极目标?是执行make的唯一目的,其所在的规则作为第一个被执行的规则。而其它的规则是在完成重建?终极目标?的过程中被连带出来的。所以这些目标所在规则在Makefile中的顺序无关紧要。
因此,我们书写的makefile的第一个规则应该就是重建整个程序或者多个程序的依赖关系和执行命令的描述。
4.1 一个例子
我们来看一个规则的例子:
foo.o : foo.c defs.h # module for twiddling the frobs
cc -c -g foo.c
这是一个典型的规则。看到这个例子,大家应该能够说出这个规则的各个部分之间的关系。不过我们还是要把这个例子拿出来讨论。目的是让我们更加明确地理解Makefile的规则。本例第一行中,文件?foo.o?是规则需要重建的文件,而?foo.c?和?defs.h?是重建?foo.o?所要使用的文件。我们把规则所需要重建的文件称为规则的?目标?(foo.o),而把重新目标所需要的文件称为规
则的?依赖?(或者目标的依赖)。规则中的第二行?cc -c -g foo.c?是规则的?命令?。它描述了如何使用规则中的依赖文件重建目标。
而且,上面的规则告诉我们了两件事:
1. 如何确定目标文件是否过期(需要重建目标),过期是指目标文件不存
在或者目标文件?foo.o?在时间戳上比依赖文件中的任何一个(?foo.c?或者?defs.h?)?老?。
2. 如何重建目标文件?foo.o?。这个规则中使用cc编译器。规则的命令中
没有明确的使用到依赖文件?defs.h?。我们假设在源文件?foo.c?中已经包含了此头文件。这也是为什么它作为目标依赖出现的原因。
4.2 规则语法
通常规则的语法格式如下:
TARGETS : PREREQUISITES
COMMAND ... 或者:
TARGETS : PREREQUISITES ; COMMAND
COMMAND ...
规则中?TARGETS?可以是空格分开的多个文件名,也可以是一个标签(例如:执行清空的?clean?)。?TARGETS?的文件名可以使用通配符,格式?A(M)?表示档案文件(Linux下的静态库.a文件)的成员?M?(关于静态库的重建可参考 第十一章 使用make更新静态库文件)。通常规则只有一个目标文件(建议这么做),偶尔会在一个规则中需要多个目标。
书写规则是我们需要注意的几点:
1. 规则的命令部分有两种书写方式:a. 命令可以和目标:依赖描述放在同
一行。命令在依赖文件列表后并使用分号(;)和依赖文件列表分开。
b. 命令在目标:依赖的描述的下一行,作为独立的命令行。当作为独立的命令行时此行必须以[Tab]字符开始。在Makefile中,在第一个规则之后出现的所有以[Tab]字符开始的行都会被当作命令来处理。
2. Makefile中符号?$?有特殊的含义(表示变量或者函数的引用),在规
则中需要使用符号?$?的地方,需要书写两个连续的(?$$?)。 3. 前边已提到过,对于Makefile中一个较长的行,我们可以使用反斜线?\\?
将其书写到几个独立的物理行上。虽然make对Makefile文本行的最大长度是没有限制的,但还是建议这样做。不仅书写方便而且更有利于别人的阅读(这也是一个程序员修养的体现)。
一个规则告诉?make?两件事:1. 目标在什么情况下已经过期; 2. 如果需要重建目标时,如何去重建这个目标。目标是否过期是由那些使用空格分割的规则的依赖文件所决定的。当目标文件不存在或者目标文件的最后修改时间比依赖文件中的任何一个晚时,目标就会被创建或者重建。就是说执行规则命令行的前提条件是以下两者之一:1. 目标文件不存在; 2. 目标文件存在,但是规则的依赖文件中存在一个依赖的最后修改时间比目标的最后修改时间晚。
规则的中心思想是:目标文件的内容是由依赖文件文件决定,依赖文件的任何一处改动,将导致目前已经存在的目标文件的内容过期。规则的命令为重建目标提供了方法。这些命令运行在系统shell之上。
4.3 依赖的类型
在GNU make的规则中可以使用两种不同类型的依赖:1. 以前章节所提到的规则中使用的是常规依赖,这是书写Makefile规则时最常用的一种。2. 另外一种在我们书写Makefile时不会经常使用,它比较特殊、称之为?order-only?依赖。一个规则的常规依赖(通常是多个依赖文件)表明了两件事:首先,它决定了重建此规则目标所要执行规则(确切的说是执行命令)的顺序;表明在更新这个规则的目标(执行此规则的命令行)之前需要按照什么样的顺序、执行那些规则(命令)来重建这些依赖文件(对所有依赖文件的重建,使用明确或者隐含规则。就是说对于这样的规则:A:B C,那么在重建目标A之前,首先需要完成对它的依赖文件B和C的重建。重建B和C的过程就是执行Makefile中以文件B和C为
目标的规则)。其次,它确定了一个依存关系;规则中如果依赖文件的任何一个比目标文件新,则认为规则的目标已经过期而需要重建目标文件。
通常,如果规则中依赖文件中的任何一个被更新,则规则的目标相应地也应该被更新。
有时,需要定义一个这样的规则,在更新目标(目标文件已经存在)时只需要根据依赖文件中的部分来决定目标是否需要被重建,而不是在依赖文件的任何一个被修改后都重建目标。为了实现这一目的,相应的就需要对规则的依赖进行分类,一类是在这些依赖文件被更新后,需要更新规则的目标;另一类是更新这些依赖的,可不需要更新规则的目标。我们把第二类称为:?order-only?依赖。书写规则时,?order-only?依赖使用管道符号?|?开始,作为目标的一个依赖文件。规则依赖列表中管道符号?|?左边的是常规依赖,管道符号右边的就是?order-only?依赖。这样的规则书写格式如下:
TARGETS : NORMAL-PREREQUISITES | ORDER-ONLY-PREREQUISITES
这样的规则中常规依赖文件可以是空;同样也可以对一个目标进行多次追加依赖。需要注意:规则依赖文件列表中如果一个文件同时出现在常规列表和?order-only?列表中,那么此文件被作为常规依赖处理(因为常规依赖所实现的动作是?order-only?依赖所实现的动作的一个超集)。
?order-only?依赖的使用举例: LIBS = libtest.a
foo : foo.c | $(LIBS)
$(CC) $(CFLAGS) $< -o $@ $(LIBS)
make在执行这个规则时,如果目标文件?foo?已经存在。当?foo.c?被修改以后,目标?foo?将会被重建,但是当?libtest.a?被修改以后。将不执行规则的命令来重建目标?foo?。
就是说,规则中依赖文件$(LIBS)只有在目标文件不存在的情况下,才会参与规则的执行。当目标文件存在时此依赖不会参与规则的执行过程。
共分享92篇相关文档