一个仅仅描述依赖关系的述规则可用来给出一个或做多个目标文件的依赖文件。例
如,Makefile 中通常存在一个变量,就像以前我们提到的“objects”,它定义为所有的
需要编译生成的.o文件的列表。当这些.o文件在其源文件所包含的头文件“config.h”
发生变化之后能够自动的被重建,我们可以使用多目标的方式来书写 Makefile:
objects = foo.o bar.o #定义为所有的需要编译生成的.o文件的列表
foo.o : defs.h
bar.o : defs.h test.h
$(objects) : config.h
这样做的好处是:我们可以在源文件增加或者删除了包含的头文件以后不用修改已经存在的Makefile的规则,只需要增加或者删除某一个.o文件依赖的头文件。这种方式很简单也很方便。对于一个大的工程来说,这样做的好处是显而易见的。在一个大的工程中,对于一个单独目录下的.o文件的依赖规则建议使用此方式。规则中头文件的依赖描述规则也可以使用gcc自动产生。可参考 4.14 自动产生依赖 一节
另外,我们也可以通过一个变量来增加目标的依赖文件,使用make的命令行来指定某一个目标的依赖头文件,例如:
extradeps=
$(objects) : $(extradeps) #extradeps是object的依赖文件。
它的意思是:如果我们执行“make extradeps=foo.h”那么“foo.h”将作为所有的.o
文件的依赖文件。当然我们只执行“make”的话,就没有指定任何文件作为.o 文件的
依赖文件。
在多规则的目标中,如果目标的任何一个规则没有定义重建此目标的命令,make
将会寻找一个合适的隐含规则来重建此目标。关于隐含规则可参考 第十章 make的隐
含规则
======================================
4.12 静态模式
静态模式规则是这样一个规则:规则存在多个目标,并且不同的目标可以根据目标
文件的名字来自动构造出依赖文件。静态模式规则比多目标规则更通用,它不需要多个
目标具有相同的依赖。但是静态模式规则中的依赖文件必须是相类似的而不是完全相同
的。
4.12.1 静态模式规则的语法
首先,我们来看一下静态模式规则的基本语法:
TARGETS ...: TARGET-PATTERN: PREREQ-PATTERNS ... 一系列目标文件:目标模式:依赖模式
COMMANDS
...
“TAGETS”列出了此规则的一系列目标文件。像普通规则的目标一样可以包含通
配符。关于通配符的使用可参考 4.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”。命令行中“$<”和“$@”是自动化变量, “$<”表示规则中的第一个依赖文件,“$@”表示规则中的目标文件(可参考 10.5.3 自 动化变量 一小节)。上边的这个规则描述了以下两个具体的规则: 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 中包含 此文件。