模式规则
模式规则类似于普通规则。只是在模式规则中,目标名中需要包含有模式字符“%”(一个),包含有模式字符“%”的目标被用来匹配一个文件名,“%”可以匹配任何非空字符串。规则的依赖文件中同样可以使用“%”,依赖文件中模式字符“%”的取值情况由目标中的“%”来决定。例如:对于模式规则“%.o : %.c”,它表示的含义是:所有的.o文件依赖于对应的.c文件。我们可以使用模式规则来定义隐含规则。
要注意的是:模式字符“%”的匹配和替换发生在规则中所有变量和函数引用展开之后,变量和函数的展开一般发生在make读取Makefile时(变量和函数的展开可参考第五 章 使用变量 和 第七章 make的函数),而模式规则中的“%”的匹配和替换则发生在make执行时。
模式规则介绍
在模式规则中,目标文件是一个带有模式字符“%”的文件,使用模式来匹配目标文件。文件名中的模式字符“%”可以匹配任何非空字符串,除模式字符以外的部分要求一致。例如:“%.c”匹配所有以“.c”结尾的文件(匹配的文件名长度最少为3个字母),“s%.c”匹配所有第一个字母为“s”,而且必须以“.c”结尾的文件,文件名长度最小为5个字符(模式字符“%”至少匹配一个字符)。在目标文件名中“%”匹配的部分称为“茎”(前面已经提到过,参考4.12 静态模式一节)。使用模式规则时,目标文件匹配之后得到“茎”,依赖根据“茎”产生对应的依赖文件,这个依赖文件必须是存在的或者可被创建的。
因此,一个模式规则的格式为:
%.o : %.c ; COMMAND...
这个模式规则指定了如何由文件“N.c”来创建文件“N.o”,文件“N.c”应该是已存在的或者可被创建的。
模式规则中依赖文件也可以不包含模式字符“%”。当依赖文件名中不包含模式字符“%”时,其含义是所有符合目标模式的目标文件都依赖于一个指定的文件(例如:%.o : debug.h,表示所有的.o文件都依赖于头文件“debug.h”)。这样的模式规则在很多场合是非常有用的。
同样一个模式规则可以存在多个目标。多目标的模式规则和普通多目标规则有些不同,普通多目标规则的处理是将每一个目标作为一个独立的规则来处理,所以多个目标就就对应多个独立的规则(这些规则各自有自己的命令行,各个规则的命令行可能相同)。但对于多目标模式规则来说,所有规则的目标共同拥有依赖文件和规则的命令行,当文件符合多个目标模式中的任何一个时,规则定义的命令就有可能将会执行;因为多个目标共同拥有规则的命令行,因此一次命令执行之后,规则不会再去检查是否需要重建符合其它模式的目标。看一个例子:
#sample Makefile
Objects = foo.o bar.o
CFLAGS := -Wall
%x : CFLAGS += -g
%.o : CFLAGS += -O2
%.o %.x : %.c
$(CC) $(CFLAGS) $< -o $@
当在命令行中执行“make foo.o foo.x”时,会看到只有一个文件“foo.o”被创建了,同时make会提示“foo.x”文件是最新的(其实“foo.x”并没有被创建)。此过程表明了多目标的模式规则在make处理时是被作为一个整体来处理的。这是多目标模式规则和多目标的普通规则的区别之处。大家不妨将上边的例子改为普通多目标规则试试看将会得到什么样的结果。
最后需要说明的是:
1. 模式规则在Makefile中的顺序需要注意,当一个目标文件同时符合多个目标模式时,make将会把第一个目标匹配的模式规则作为重建它的规则。
2. Makefile中明确指定的模式规则会覆盖隐含模式规则。就是说如果在Makefile中出现了一个对目标文件合适可用的模式规则,那么make就不会再为这个目标文件寻找其它隐含规则,而直接使用在Makefile中出现的这个规则。在使用时,明确规则永远优先于隐含规则。
3. 另外,依赖文件存在或者被提及的规则,优先于那些需要使用隐含规则来创建其依赖文件的规则。
模式规则示例
本小节来看一些使用模式规则的例子,这些模式规则在GNU make中已经被预定义。首先看编译.c文件到.o文件的隐含模式规则:
%.o : %.c
$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@
此规则描述了一个.o文件如何由对应的.c文件创建。规则的命令行中使用了自动化变量“$<”和“$@”,其中自动化变量“$<”代表规则的依赖,“$@”代表规则的目标。此规则在执行时,命令行中的自动化变量将根据实际的目标和依赖文件取对应值。关于自动化变量可参考10.5.3 自动化变量一节
make中第二个内嵌模式规则是:
% :: RCS/%,v
$(CO) $(COFLAGS) $<
这个规则的含义是:任何一个文件“X”都可以由目录“RCS”下的相应文件“x.v”来生成。规则的目标为“%”,它匹配任何文件名,因此只要存在相对应的依赖文件(N.v),目标(N)都可被创建。双冒号表示该规则是最终规则,意味着规则的依赖文件不是中间过程文件。参考10.6 万用规则一节
另外,一个具有多目标的隐含规则是:
%.tab.c %.tab.h: %.y
bison -d $<
它是一个多目标模式规则,关于多目标的特征可参考 10.5.1 模式规则介绍一小节最后一个例子。