在GNU Make中,%
和*
都可以被视为通配符,但它们的使用方式非常不同。
*
字符是GNU Make手册所称的通配符:它代表了一个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
也是同样的情况。
因此,只有在您真正想指定已经存在于文件系统中的一组文件时才使用
*
。这对于源文件(规则中的先决条件)很常见,但在规则的目标中使用它真的很奇怪,就像这个例子中一样。
字符
%
也执行模式匹配,但方式非常不同:当在
:
的两侧使用时,它是
模式规则的一部分,并且它声明了目标文件的名称与依赖项的名称之间的关系。
例如:
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
表示:您可以使用此规则从文件名除以.b
和.c
的相同文件中制作以.a
结尾的任何文件。因此,我们可以使用此规则从x.b
和x.c
制作x.a
,但不能从y.b
或z1.c
制作,即使x.b
和x.b
还不存在,只要它们也可以被制作(尽管此示例未显示出来)。如果不能,则GNU Make会(令人困惑地)表现为规则不存在,如示例所示。
vpath
指令使用%
,wildcard
函数使用*
。除此之外,没有更多的内容,除了这不是Make通配符的最大缺点。 - Beta$(wildcard ...)
函数使用 shell globbing(就像运行ls *.c
一样)。Make 自身仅使用简单的模式匹配(使用%
)。 - MadScientist