在makefile中,%和*有什么区别?

12

GNU make手册在解释这方面不太出色,我找不到相关说明或无法从其他地方推断出信息。

我知道%是一种通配符,但在targetsdependenciescommands的上下文中,%*有什么区别?我可以在哪里使用它,它是否在每个地方都有相同的意义?

target: dependencies ...
    commands
2个回答

13

通配符字符*用于在当前目录中生成匹配的文件列表。模式替换字符%是一个占位符,用于表示此时可能存在或不存在的文件。

为了进一步说明手册中已经发现的通配符陷阱示例,

objects = *.o

如果没有'.o'文件,正确的表达方式应该是这样的:

objects := $(patsubst %.c,%.o,$(wildcard *.c))

make 在此上下文中不会执行通配符扩展,但是当你将字面值 *.o 传递给shell时,如果存在匹配项,则会发生扩展(如果有匹配项),因此这可能会稍微难以调试。在一个规则的目标中,make 将会执行通配符扩展,因此你可以这样说

foo: *.o
并且使它按照你的意图正常工作(前提是在评估此依赖项时,所需文件已经存在)。
相比之下,您可以使用带有模式占位符的规则,该占位符将填充为与任何匹配名称相对应的内容,因为make尝试查找可用于生成所需依赖项的配方。 还有一些内置规则,例如
%.o: %.c
        $(CC) $(CCFLAGS) $^ -o $@

(这里是近似的描述) 假设有一个文件匹配 %.c,对应的文件 %.o 可以通过以下方式生成。这里的 % 是一个占位符,可以被替换为任何内容;因此,如果应用于现有的文件 foo.c,它会说明如何生成 foo.o

您可以重新表述为* 匹配所有匹配的文件,而% 则匹配任何匹配的文件。


6
%*在Makefile的语法中都是普通字符,只是简单地传递给shell进行处理。
其中,%在模式替换中表示文件名称"stem",例如$(patsubst %.o,%.c,$(OBJS))。模式%.o应用于$(OBJS)中的每个元素,%捕获匹配部分。然后在替换模式%.c中,使用捕获的部分替换%,并将替换列表作为patsubst的返回值。 *$(wildcard ...)操作符的参数中非常有用,类似于shell中的*通配符来匹配文件系统中的某些路径。
patsubst的左侧,%表示匹配,类似于*,因为它匹配一些字符。但是,%带有一些限制,例如只能出现一次!例如,虽然我们可以扩展通配符*/*.c,但是像$(patsubst %/%.o,%/foo/%.c,...)这样的双重"stem pattern substitution"是不允许的。这个限制在未来的GNU Make版本中可能会被解除,但目前我所知道的是它仍然有效。
另外,%*之间有一个微妙的区别,即%匹配非空字符序列。通配符模式fo*o.c匹配foo.c,替换模式fo%o.c不匹配foo.c,因为这样%就为空了,而这是不允许的。

你好,你知道如何匹配双茎吗?能否帮我解决这个问题?https://dev59.com/87bna4cB1Zd3GeqPjexN - Y00
1
@Z-Y00 你不能这样做;GNU Make 匹配只有一个主干。你的问题可能是 https://dev59.com/sJrga4cB1Zd3GeqPjDBg 的重复。 - Kaz

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