GNU Make 中的% 和* 都可以被视为通配符,但方式却截然不同。
* 字符是what the GNU Make manual calls a wildcard:它代表一个glob 匹配,一种针对文件系统上存在的文件的模式匹配。例如。 *.a 扩展为当前目录中存在的名称以 .a 结尾的文件列表,如果不存在此类文件,则扩展为文字 *.a。
例如:
sh> rm -f *.a *.b *.c
sh> cat Makefile
all: *.a
*.a : *.b *.c
@echo $+ > $@
sh> make
make: *** No rule to make target '*.b', needed by '*.a'. Stop.
sh> touch x.a
sh> make
make: *** No rule to make target '*.b', needed by 'x.a'. Stop.
sh> touch y.b
sh> make
make: *** No rule to make target '*.c', needed by 'x.a'. Stop.
sh> touch z1.c z2.c
sh> make
sh> cat x.a
y.b z2.c z1.c
如您所见,* 是通过将其与文件系统中恰好存在的文件进行匹配来解释的。例如,make 将*.a 解释为文字文件名*.a,直到我创建名称以.a 结尾的文件,此时它扩展为这些文件的名称; *.b 和 *.c 也一样。
因此,仅当您确实想要指定文件系统上已经存在的一组文件时才使用*。这对于源文件很常见(规则中的先决条件),但在规则的目标中使用它真的很奇怪,就像在这个例子中一样。
% 字符也执行模式匹配,但方式非常不同:当在: 的两侧使用时,它是pattern rule 的一部分,它说明了名称之间的关系目标文件和依赖项的名称。
例如:
sh> rm -f *.a *.b *.c
sh> cat Makefile
all: %.a
%.a : %.b %.c
@echo $+ > $@
sh> make
make: *** No rule to make target '%.a', needed by 'all'. Stop.
sh> touch x.a y.b z1.c z2.c
sh> make
make: *** No rule to make target '%.a', needed by 'all'. Stop.
sh> make x.a
make: Nothing to be done for 'x.a'.
sh> make y.a
make: *** No rule to make target 'y.a'. Stop.
sh> touch y.c
sh> make y.a
sh> cat y.a
y.b y.c
% 字符永远不会与文件系统上的文件匹配,而是表示目标文件名和必备文件名之间的对应关系:%.a: %.b %.c 表示:您可以使用此规则使 any名称以.a 结尾的文件来自名称相同但以.b 和.c 结尾的文件。所以我们可以使用来自x.b 和x.c 的规则来生成x.a,但永远不能来自y.b 或z1.c,即使x.b 和x.b 尚不存在也是如此,只要因为它们也可以制作(尽管这个例子没有显示)。如果不存在,GNU Make 将(令人困惑地)表现得好像规则不存在,正如您在示例中看到的那样。