关于模式匹配:makefile中%和*之间的区别是什么

What is the difference between % and * in a makefile

GNU make手册并不擅长解释这部分,我找不到解释或者我无法在其他地方推断出这些信息。

我意识到%是一种通配符,但targetsdependenciescommands的上下文中%*之间的区别是什么? 我在哪里可以使用它,到处都有相同的含义?

1
2
target: dependencies ...
    commands


%*都是Make配方行中的普通字符;它们只是传递给shell。

%表示模式替换中的文件"词干",如$(patsubst %.o,%.c,$(OBJS))。模式%.o应用于$(OBJS)中的每个元素,%捕获匹配部分。然后在替换模式%.c中,将捕获的部分替换为%,并且从patsubst中出现替换列表作为返回值。

*$(wildcard ...)运算符的参数中很有用,它类似于shell * glob在匹配文件系统中某些路径时的操作。

patsubst的左侧,其中%表示匹配,它类似于*,因为它匹配某些字符。但是,%有一些限制,例如它只能出现一次!例如,我们可以扩展通配符*/*.c,当然,我们不能像$(patsubst %/%.o,%/foo/%.c,...)那样使用双干模式替换。这个限制可以在GNU Make的某个未来版本中解除,但据我所知它目前仍然存在。

此外,%*之间存在细微差别,因为%匹配非空字符序列。通配符模式fo*o.c匹配foo.c。替换模式fo%o.cfoo.c不匹配,因为干%将为空,这是不允许的。


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

要扩展您已经发现的手册中的Wildcard陷阱示例,

1
objects = *.o

简单地为变量赋予相当无用的文字值*.o - 一个目标文件,它可能依赖于一个名为字面*.c的文件,当然也不存在。因此,您会收到错误和/或不稳定的行为。

短语的正确方法是类似的

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

make本身在此上下文中不执行通配符扩展,但当然,如果将文字值*.o传递给shell,那就是扩展发生时(如果存在匹配),因此这可能稍微难以调试。 make将在规则的目标中执行通配符扩展,因此您可以这么说

1
foo: *.o

并使其完全按照您的意图工作(假设在评估此依赖关系时保证所需的文件存在)。

相比之下,您可以使用带有模式占位符的规则,当使用make尝试查找可用于生成所需依赖项的配方时,该占位符将填入任何匹配的名称。有内置的规则,如

1
2
%.o: %.c
        $(CC) $(CCFLAGS) $^ -o $@

(这里接近真实的东西)说"给定文件匹配%.c,可以如下生成相应的文件%.o"。这里,%是占位符,可以被任何东西取代;因此,如果它应用于现有文件foo.c,则说明如何生成foo.o

你可以改写它说*匹配每个匹配的文件,而%匹配任何匹配的文件。