首页 > 代码库 > 静态模式

静态模式

静态模式规则是这样一个规则:规则存在多个目标,并且不同的目标可以根据目标文件的名字来自动构造出依赖文件。静态模式规则比多目标规则更通用,它不需要多个目标具有相同的依赖。但是静态模式规则中的依赖文件必须是相类似的而不是完全相同的。

首先,我们来看一下静态模式规则的基本语法:

 

 TARGETS ...: TARGET-PATTERN: PREREQ-PATTERNS ...

COMMANDS

...

 

“TAGETS”列出了此规则的一系列目标文件。像普通规则的目标一样可以包含通配符。关于通配符的使用可参考 3.4 文件名使用通配符 一节

“TAGET-PATTERN”和“PREREQ-PATTERNS”说明了如何为每一个目标文件生成依赖文件。从目标模式(TAGET-PATTERN)的目标名字中抽取一部分字符串(称为“茎”)。使用“茎”替代依赖模式(PREREQ-PATTERNS)中的相应部分来产生对应目标的依赖文件。下边详细说明这一替代的过程。

首先在目标模式和依赖模式中,一般需要包含模式字符“%”。在目标模式(TAGET-PATTERN)中“%”可以匹配目标文件的任何部分,模式字符“%”匹配的部分就是“茎”。目标文件和目标模式的其余部分必须精确的匹配。看一个例子:目标“foo.o”符合模式“%.o”,其“茎”为“foo”。而目标“foo.c”和“foo.out”就不符合此目标模式。

每一个目标的依赖文件是使用此目标的“茎”代替依赖模式(PREREQ-PATTERNS)中的模式字符“%”而得到。例如:上边的例子中依赖模式(PREREQ-PATTERNS)为“%.c”,那么使用“茎”“foo”替代依赖模式中的“%”得到的依赖文件就是“foo.c”。需要明确的一点是:在模式规则的依赖列表中使用不包含模式字符“%”也是合法的。代表这个文件是所有目标的依赖文件。

在模式规则中字符‘%’可以用前面加反斜杠“\”方法引用。引用“%”的反斜杠也可以由更多的反斜杠引用。引用“%”、“\”的反斜杠在和文件名比较或由“茎”代替它之前会从模式中被删除。反斜杠不会因为引用“%”而混乱。如,模式“the\%weird\\%pattern\\”是“the%weird\”+“%”+“pattern\\”构成。最后的两个反斜杠由于没有任何转义引用“%”所以保持不变。

我们来看一个例子,它根据相应的.c文件来编译生成“foo.o”和“bar.o”文件:

objects = foo.o bar.o

 

all: $(objects)

 

$(objects): %.o: %.c

         $(CC) -c $(CFLAGS) $< -o $@

 

例子中,规则描述了所有的.o文件的依赖文件为对应的.c文件,对于目标“foo.o”,取其茎“foo”替代对应的依赖模式“%.c”中的模式字符“%”之后可得到目标的依赖文件“foo.c”。这就是目标“foo.o”的依赖关系“foo.o: foo.c”,规则的命令行描述了如何完成由“foo.c”编译生成目标“foo.o”。命令行中“$<”和“$@”是自动化变量,“$<”表示规则中的第一个依赖文件,“$@”表示规则中的目标文件(可参考 3.14 自动产生依赖 一节)。以上的规则就是描述了以下两个具体的规则:

 

foo.o : foo.c

      $(CC) -c $(CFLAGS) foo.c -o foo.o

bar.o : bar.c

      $(CC) -c $(CFLAGS) bar.c -o bar.o

 

在使用静态模式规则时,指定的目标必须和目标模式相匹配,否则在执行make时将会得到一个错误提示。如果存在一个文件列表,其中一部分符合某一种模式而另外一部分符合另外一种模式,这种情况下我们可以使用“filter”函数(可参考 第七章 make的内嵌函数)来对这个文件列表进行分类,在分类之后对确定的某一类使用模式规则。例如:

 

files = foo.elc bar.o lose.o

$(filter %.o,$(files)): %.o: %.c

       $(CC) -c $(CFLAGS) $< -o $@

 

$(filter %.elc,$(files)): %.elc: %.el

       emacs -f batch-byte-compile $<

 

其中;$(filter %.o,$(files))的结果为“bar.o lose.o”。“filter”函数过滤不符合“%.o”模式的文件名而至返回所有符合此模式的文件列表。第一条静态模式规则描述了这些目标文件是通过编译对应的.c源文件来重建的。同样第二条规则也是使用这种方式。

我们通过另外一个例子来看一下自动环变量“$*”在静态模式规则中的使用方法:

 

bigoutput littleoutput : %output : text.g

       generate text.g -$* > $@

 

当执行此规则的命令时,自动环变量“$*”被展开为“茎”。在这里就是“big”和“little”。

静态模式规则在一个较大的工程中非常有用的。它可以对一个工程中的同类文件的重建规则进行一次定义,而实现对整个工程中此类文件指定相同的重建规则。比如,可以用来描述整个工程中所有的.o文件的依赖规则和编译命令。通常的做法是将生成同一类目标的模式定义在一个make.rules的文件中。在工程各个模块的Makefile中包含此文件。

4.12.2 静态模式和隐含规则

在Makefile中,静态模式规则和被定义为隐含规则的模式规则都是我们经常使用的两种方式。两者相同的地方都是用目标模式和依赖模式来构建目标的规则中的文件依赖关系,两者不同的地方是make在执行时使用它们的时机。

隐含规则可被用在任何和它相匹配的目标上,在Makefile中没有为这个目标指定具体的规则、存在规则但规则没有命令行或者这个目标的依赖文件可被搜寻到。当存在多个隐含规则和目标模式相匹配时,只执行其中的一个规则。具体执行哪一个规则取决于定义规则的顺序。

相反的,静态模式规则只能用在规则中明确指出的那些文件的重建过程中。不能用在除此之外的任何文件的重建过程中,并且它对指定的每一个目标来说是唯一的。如果一个目标存在于两个规则,并且每一个规则中都定以了命令,make执行时就会提示错误。

静态模式规则相比隐含模式规则由以下两个优点:

2       不能根据文件名通过词法分析进行分类的文件,我们可以明确列出这些文件,并使用静态模式规则来重建其隐含规则。

2       对于无法确定工作目录内容,而且不能确定是否此目录下的无关文件会使用错误的隐含规则而导致make失败的情况。当存在多个适合此文件的隐含规则时,使用哪一个隐含规则取决于其规则的定义顺序。这种情况下我们使用静态模式规则就可以避免这些不确定因素,因为静态模式中,指定的目标文件有特定的规则来描述其依赖关系和重建命令。