静态模式

静态模式可以更加容易地定义多目标的规则,可以让我们的规则变得更加的有弹性和灵活。我们还是先来看一下语法:

  1. <targets ...> : <target-pattern> : <prereq-patterns ...>
  2. <commands>
  3. ...

targets定义了一系列的目标文件,可以有通配符。是目标的一个集合。

target-parrtern是指明了targets的模式,也就是的目标集模式。

prereq-parrterns是目标的依赖模式,它对target-parrtern形成的模式再进行一次依赖目标的定义。

这样描述这三个东西,可能还是没有说清楚,还是举个例子来说明一下吧。如果我们的<target-parrtern>定义成 %.o ,意思是我们的<target>;集合中都是以 .o 结尾的,而如果我们的<prereq-parrterns>定义成 %.c ,意思是对<target-parrtern>所形成的目标集进行二次定义,其计算方法是,取<target-parrtern>模式中的 % (也就是去掉了 .o 这个结尾),并为其加上 .c 这个结尾,形成的新集合。

所以,我们的“目标模式”或是“依赖模式”中都应该有 % 这个字符,如果你的文件名中有 % 那么你可以使用反斜杠 \ 进行转义,来标明真实的 % 字符。

看一个例子:

  1. objects = foo.o bar.o
  2.  
  3. all: $(objects)
  4.  
  5. $(objects): %.o: %.c
  6. $(CC) -c $(CFLAGS) $< -o $@

上面的例子中,指明了我们的目标从$object中获取, %.o 表明要所有以 .o 结尾的目标,也就是 foo.o bar.o ,也就是变量 $object 集合的模式,而依赖模式 %.c 则取模式%.o% ,也就是 foo bar ,并为其加下 .c 的后缀,于是,我们的依赖目标就是 foo.c bar.c 。而命令中的 $<$@ 则是自动化变量, $< 表示第一个依赖文件,$@ 表示目标集(也就是“foo.o bar.o”)。于是,上面的规则展开后等价于下面的规则:

  1. foo.o : foo.c
  2. $(CC) -c $(CFLAGS) foo.c -o foo.o
  3. bar.o : bar.c
  4. $(CC) -c $(CFLAGS) bar.c -o bar.o

试想,如果我们的 %.o 有几百个,那么我们只要用这种很简单的“静态模式规则”就可以写完一堆规则,实在是太有效率了。“静态模式规则”的用法很灵活,如果用得好,那会是一个很强大的功能。再看一个例子:

  1. files = foo.elc bar.o lose.o
  2.  
  3. $(filter %.o,$(files)): %.o: %.c
  4. $(CC) -c $(CFLAGS) $< -o $@
  5. $(filter %.elc,$(files)): %.elc: %.el
  6. emacs -f batch-byte-compile $<

$(filter %.o,$(files))表示调用Makefile的filter函数,过滤“$files”集,只要其中模式为“%.o”的内容。其它的内容,我就不用多说了吧。这个例子展示了Makefile中更大的弹性。