GNU make
手册在解释这方面不太出色,我找不到相关说明或无法从其他地方推断出信息。
我知道%
是一种通配符,但在targets
、dependencies
和commands
的上下文中,%
和*
有什么区别?我可以在哪里使用它,它是否在每个地方都有相同的意义?
target: dependencies ...
commands
GNU make
手册在解释这方面不太出色,我找不到相关说明或无法从其他地方推断出信息。
我知道%
是一种通配符,但在targets
、dependencies
和commands
的上下文中,%
和*
有什么区别?我可以在哪里使用它,它是否在每个地方都有相同的意义?
target: dependencies ...
commands
通配符字符*
用于在当前目录中生成匹配的文件列表。模式替换字符%
是一个占位符,用于表示此时可能存在或不存在的文件。
为了进一步说明手册中已经发现的通配符陷阱示例,
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
。
您可以重新表述为*
匹配所有匹配的文件,而%
则匹配任何匹配的文件。
%
和*
在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
,因为这样%
就为空了,而这是不允许的。