为什么patsubst在使用$$ *的二次扩展时会停止工作?

时间:2014-08-31 06:44:15

标签: makefile gnu-make

以下是GNU Make manual section on Secondary Expansion(略微简化)的示例:

foo_SRCS := bar.c baz.c

.SECONDEXPANSION:
# $$@ expands to the target ("foo" in this case)
foo: $$(patsubst %.c,%.o,$$($$@_SRCS))

这很有效;它构建bar.obaz.o

cc    -c -o bar.o bar.c
cc    -c -o baz.o baz.c

但如果我稍微调整一下这个例子,patsubst就会停止工作:

all: foo.a

foo_SRCS := bar.c baz.c

.SECONDEXPANSION:
# $$* expands to the stem of the match ("foo" in this case).
%.a: $$(patsubst %.c,%.o,$$($$*_SRCS))
        ar rcs $@ $^

它不再构建bar.obaz.o,而是直接使用*.c文件作为先决条件!

ar rcs foo.a bar.c baz.c

请注意,$$($$*_SRCS)部分显然正常工作,因为它找到了foo_SRCS并将其作为先决条件。但由于某种原因,patsubst部分已成为无操作!它不是将%.c替换为%.o,而是直接使用foo_SRCS

这里发生了什么?我怎样才能让我的榜样起作用?

编辑:我有一个理论认为%内的patsubst字符是使用词干匹配(foo)提前评估的,所以patsubst本身看起来像这样:

$(patsubst foo.c,foo.o,bar.c baz.c)

为了测试这个理论,我在foo.c添加了一个名为foo_SRCS的文件:

all: foo.a

foo_SRCS := foo.c bar.c baz.c

.SECONDEXPANSION:
# $$* expands to the stem of the match ("foo" in this case).
%.a: $$(patsubst %.c,%.o,$$($$*_SRCS))
        ar rcs $@ $^

这导致了更奇怪的事情:

make: *** No rule to make target `foo.a', needed by `all'.  Stop.

2 个答案:

答案 0 :(得分:4)

make正在读取百分比字符作为与词干中的通配符的匹配,并且正在被词干匹配替换。如果您查看示例的make -p输出,您会看到解析后的目标行如下所示:

%.a: $(patsubst %.c,%.o,$($*_SRCS))

就制作而言,这只是一组非常奇怪的图案目标(或类似的东西)。

如果你以类似于逃避$进行评估的方式转义make解析中的百分比字符,你可以得到你想要的工作:

pc := %
$$(patsubst $$(pc).c,$$(pc).o,$$($$*_SRCS))

有关添加的信息substitution references(即$(foo_SRCS:.c=.o))可用于此类转换,而不是对patsubst的较长调用。但是,在这种情况下,虽然它在这种情况下可以使用:(通过c := :)进行类似的转义,但它似乎并不是目标的唯一先决条件( Makefile:23: *** commands commence before first target. Stop.错误,我不太了解)至少使用GNU Make 3.81。

答案 1 :(得分:4)

您混合了三个功能不佳的功能:secondary expansionpattern rulespatsubst。我将尝试详细解释在评估代码时所做的工作(AFAIUI)。

让我们从你的第一个Makefile开始:

foo_SRCS := bar.c baz.c

.SECONDEXPANSION:
%.a: $$(patsubst %.c,%.o,$$($$*_SRCS))
        ar rcs $@ $^

阅读阶段。所有美元符号都已转义,因此此处不会进行任何评估。 Make在其数据库中输入以下规则:

%.a: $(patsubst %.c,%.o,$($*_SRCS))

模式替换。就make而言,这只是另一种模式规则,目标为%.a,两个先决条件由空格分隔:$(patsubst和{{1 }}

%.c,%.o,$($*_SRCS))与目标模式匹配,因此每个先决条件中的第一个 foo.a将被%替换。规则变为:

foo

目标更新阶段。当您请求二次扩展时,将在目标更新阶段再次评估该模式:

foo.a: $(patsubst foo.c,%.o,$($*_SRCS))

因此最终执行命令

    foo.a: $(patsubst foo.c,%.o,$($*_SRCS))
==> foo.a: $(patsubst foo.c,%.o,bar.c baz.c)
==> foo.a: bar.c baz.c

那么foo.c呢?如果你把foo.c添加到foo_SRCS,那么二级扩展就像这样:

ar rcs foo.a bar.c baz.c

规则失败,因为make不知道如何构建 foo.a: $(patsubst foo.c,%.o,$($*_SRCS)) ==> foo.a: $(patsubst foo.c,%.o,foo.c bar.c baz.c) ==> foo.a: %.o bar.c baz.c

解决方法。您可以使用反斜杠转义%.o字符:

%