Makefile静态模式规则匹配问题

Makefile static pattern rule matching issue

我认为我缺少一些关于 gnu make 的基本知识(如果重要的话,我正在使用 3.81)静态模式规则匹配(显然其他人也在我工作的地方做了,因为这是我发现的正在尝试修复已被注释掉的规则)。我试图将我的例子简化到它的症结所在(希望我没有错过真实例子中的任何重要内容)。

这似乎符合我的预期

JUNK:=foo bar
BINS:=$(patsubst %,bin/%,$(JUNK))

all : $(BINS)
.PHONY : all

# This works
$(BINS) : bin/% : %
        mkdir -p bin && cp $< $@

但是这个(更接近我在真正的 Makefile 中找到的)

JUNK:=foo bar
BINS:=$(patsubst %,bin/%,$(JUNK))

all : $(BINS)
.PHONY : all

# This doesn't work
$(JUNK) : bin/% : %
       mkdir -p bin && cp $< $@

# This doesn't work either
#bin/$(JUNK) : bin/% : %
#       mkdir -p bin && cp $< $@

根据我对这两种情况下应该发生的情况的理解,我预计两个 Makefile 的行为将完全相同;然而,只有第一个的行为符合我的预期(即,将文件正确复制到 bin),第二个给出以下输出

Makefile:12: target `foo' doesn't match the target pattern
Makefile:12: target `bar' doesn't match the target pattern
make: *** No rule to make target `bin/foo', needed by `all'.  Stop.

更令人困惑的是,我正在检查的 make 文件中有几乎相同的其他静态模式规则在起作用。

所以我显然知道如何 "work around" 这个问题,但我想了解为什么第二个(以及第二个代码块中注释掉的部分)不做我想做的事期待他们。

提前感谢任何help/insight。

第一个不起作用,因为在扩展 JUNK 变量后,make 会看到:

foo bar : bin/% : %

静态模式规则的工作方式是第一个模式(目标模式)必须匹配目标列表中的每个单词。这告诉 make 目标名称的哪一部分是词干(与 % 匹配的部分)。如果目标模式不匹配,make 不知道词干是什么。模式 bin/% 与文本 foo 不匹配(文本 foo 中没有 bin/)所以您会看到错误。

第二个不起作用,因为在此示例 (bin/$(JUNK) : bin/% : %) 中扩展 JUNK 变量的结果如下所示:

bin/foo bar : bin/% : %

此处,bin/foo 匹配模式,但 bar 不匹配,因此您会得到与上一个相同的错误。

要使其正常工作,您必须将 bin/ 添加到 每个 目标,而不仅仅是第一个目标,因此使用 patsubst(或者, addprefix 也可以。