Makefile静态模式规则匹配问题

时间:2015-04-03 23:24:03

标签: makefile gnu gnu-make

我认为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文件中有几乎相同的其他静态模式规则正在运行。

所以我显然知道如何在需要时“解决”这个问题,但我想了解为什么第二个(以及第二个代码块中已注释掉的部分)没有按照我的期望去做

提前感谢任何帮助/见解。

1 个答案:

答案 0 :(得分:2)

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

foo bar : bin/% : %

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

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

bin/foo bar : bin/% : %

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

要使其发挥作用,您必须在每个目标前加bin/,而不仅仅是第一个目标,因此使用patsubst(或addprefix也会起作用。)