GNU Make中,%.c和*.c有什么区别?

6

%.c*.c在makefile中有什么区别?例如,我们可能会看到:

vpath %.c    $(BASE_DIR)platform/$(TARGET)

并且

Files += $(wildcard *.c) 

两者都包含特定目录中以 .c 结尾的所有文件。但是当我们使用 %.c*.c 时有什么区别呢?换句话说,为什么我不能使用

vpath *.c    $(BASE_DIR)platform/$(TARGET)

替代

vpath %.c    $(BASE_DIR)platform/$(TARGET)

?

Thank you.


可能是makefile中百分号符号的作用是什么?的重复问题。 - Alexander
不同的Make函数使用不同的通配符符号。vpath指令使用wildcard函数使用*。除此之外,没有更多的内容,除了这不是Make通配符的最大缺点。 - Beta
更明确地说,$(wildcard ...) 函数使用 shell globbing(就像运行 ls *.c 一样)。Make 自身仅使用简单的模式匹配(使用 %)。 - MadScientist
2个回答

6

在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.bx.c制作x.a,但不能从y.bz1.c制作,即使x.bx.b还不存在,只要它们也可以被制作(尽管此示例未显示出来)。如果不能,则GNU Make会(令人困惑地)表现为规则不存在,如示例所示。


1
在GNU Make中,%*都是通配符函数。它们之间的区别在于%可以用作文本替换函数的一部分,而*则不能。如果你想要制作最快的makefile,应该优先使用*通配符函数,而不是%替换函数,因为不需要使用任何资源来存储匹配项的名称并将其替换为后续函数调用。如果你不太关心将你的make系统优化到极限,那么你不需要太担心选择哪一个。

我并不确定为什么这个答案被编辑了又撤销了编辑。似乎reinierpost只是在扩展我的回答,并且在没有署名的情况下将它发布为他自己的回答。如果这种行为经常发生,他的高分可能主要由空编辑和重复的帖子组成。或者他只是意识到我的回答与他想要达到的水平相比太差了。 - TafT
1
很抱歉,这只是一个错误:我以为我正在创建自己的答案,但我不小心误点击了您的答案编辑按钮,直到我完成我的答案后才发现。我不知道这是怎么发生的。 - reinierpost
顺便说一下,我认为你的回答没有指出主要区别。*匹配文件系统上的文件,而%则不匹配。*只匹配目标,%定义了目标和依赖项名称的公共部分。 - reinierpost

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接