Makefile GNU Make中%.c和*.c之间的区别是什么

Makefile GNU Make中%.c和*.c之间的区别是什么,makefile,gnu-make,Makefile,Gnu Make,在makefiles中,%.c和*.c之间有什么区别。例如,我们可能有: vpath %.c $(BASE_DIR)platform/$(TARGET) 及 两者都包括特定目录中以.c结尾的所有文件。但是当我们使用%.c和*.c时?换句话说,为什么我不能使用 vpath *.c $(BASE_DIR)platform/$(TARGET) 而不是 vpath %.c $(BASE_DIR)platform/$(TARGET) ? 谢谢。GNU Make中的%和*都是通配符函

在makefiles中,
%.c
*.c
之间有什么区别。例如,我们可能有:

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

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

vpath *.c    $(BASE_DIR)platform/$(TARGET)
而不是

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


谢谢。

GNU Make中的
%
*
都是通配符函数。它们之间的区别在于,
%
可以用作一个函数的一部分,而
*
不能


如果您试图生成尽可能快的makefile,您应该尝试使用
*
而不是
%
替换函数,因为不应该使用任何资源来存储匹配项的名称并将其替换为后续函数调用。如果你不担心优化你的make系统到极限,你就不必担心你会选择哪一个

GNU Make中的
%
*
都可以被视为通配符,但方式截然不同

*
字符是:它表示全局匹配,即与文件系统中存在的文件的模式匹配。例如,
*.a
扩展到当前目录中名称以
.a
结尾的文件列表,如果不存在此类文件,则扩展到literal
*.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
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
如您所见,
*
是通过将其与文件系统中碰巧存在的文件进行匹配来解释的。例如,
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 '*.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
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
意味着:您可以使用此规则从名称相同的文件中创建名称以
.a
结尾的任何文件,但名称以
.b
.c
结尾的文件除外。因此,我们可以从
x.b
x.c
使用此规则生成
x.a
,但决不能从
y.b
z1.c
生成,即使
x.b
x.b
还不存在,只要它们也可以生成(尽管此示例未显示)。如果没有,GNU Make将(令人困惑地)表现为规则不存在,如您在示例中所见。

不同Make函数的可能重复使用不同的通配符。
vpath
指令使用
%
通配符
函数使用
*
。除了这不是生成通配符的最大缺点之外,它没有更多的功能。更清楚地说,
$(通配符…
函数使用shell globbing(就像运行
ls*.c
)。Make本身只使用简单的模式匹配(使用
%
)。我不太清楚为什么这个答案是经过编辑的,然后是未经编辑的。似乎reinierpost只是用示例扩展了我的答案,然后决定将其作为自己的答案发布,而不进行归因。如果定期这样做,他的高分可能主要来自于无效编辑和重复发布。我很抱歉,这只是一个错误:我以为我在创建自己的答案,但我错误地点击了你答案上的编辑按钮,我只是在完成我的答案后才发现它。我不知道这是怎么发生的。顺便说一句,我认为你的回答没有指出主要的区别<代码>*匹配文件系统上的文件,而
%
不匹配<代码>*仅匹配目标,
%
定义目标和依赖项名称的公共部分。