makefile:隐式规则:相同的目标不同的先决条件

Posted

技术标签:

【中文标题】makefile:隐式规则:相同的目标不同的先决条件【英文标题】:makefile: implicit rules: same target different prerequisites 【发布时间】:2012-10-13 15:03:02 【问题描述】:

我有以下生成文件:

all: DIR/0/a.txt DIR/1/b.txt DIR/2/c.txt DIR/3/abc.txt

DIR/%/abc.txt: DIR/%/def.xtx # rule #1
    mkdir -p $(@D)
    touch $@

DIR/%.txt: # rule #2
    mkdir -p $(@D)
    touch $@

DIR/%.xtx:
    touch $@

我想在生成DIR/%/abc.txt 时生成DIR/%/def.xtx;否则只生成DIR/%.txt

但是,在 GNU Make 3.81 中使用上面的 makefile,只会生成 DIR/3/abc.txt 而不会生成 DIR/%/def.xtx

按照GNU make用户手册中的“隐式规则搜索算法”我们得到:

(1) 将 t 拆分为目录部分,称为 d,其余部分称为 n。例如,如果 t 是“src/foo.o”,则 d 是“src/”,n 是“foo.o”。

对于DIR/3/abc.txtd = DIR/3n = abc.txt

(2) 列出所有模式规则,其中一个目标与 t 或 n 匹配。如果目标模式包含斜杠,则匹配 t;否则,反对n。

规则 #1 和 #2 匹配。

(3) 如果该列表中的任何规则不是任意匹配规则,则从列表中删除所有非终结符任意匹配规则。

不确定:没有从列表中删除任何规则。

(4) 从列表中删除所有没有配方的规则。

没有删除任何规则。

(5) 对于列表中的每个模式规则:

(5.a) 找到词干s,即目标模式中与'%'匹配的t或n的非空部分。

对于规则 #1,s = 3。 对于规则 #2,s = 3/abc

(5.b) 通过将 s 替换为“%”来计算先决条件名称;如果目标模式不包含斜杠,则将 d 附加到每个先决条件名称的前面。

对于规则 #1,它变为:DIR/3/abc.txt: DIR/3/def.xtx 规则 #2 没有先决条件。

(5.c) 测试所有先决条件是否存在或应该存在。 (如果在 makefile 中将文件名作为目标或明确的先决条件提及,那么我们说它应该存在。)

不确定:DIR/3/def.xtx 被规则 DIR/%.xtx: 提及。

经过这么长时间的解释,我的看法是我在 (5.c) 中可能是错误的。

【问题讨论】:

我可能错了,但我认为% 永远不会匹配带有/ 的东西。因此,假设以上是您的全部Makefile,您没有任何匹配DIR/3/def.txt 的规则,make 应该抱怨“不知道如何构建 DIR/3/def.txt”或类似的东西。 它 [%] 确实与 / 匹配;否则DIR/0/a.txtDIR/1/b.txtDIR/2/c 不会被触及;但他们确实如此。 学到了一些新东西......它似乎确实有效。那么,也许DIR/3/def.xtx 没有被创建,因为第三条规则缺少mkdir 部分?由于它是DIR/3/abc.txt 的先决条件,因此需要在目录存在之前先构建它,因此规则 1 中的 mkdir 在尝试运行规则 3 之前不会发生。 是的,这是一个错误,但是 make 不会查看配方来查找它必须执行的配方。如果它起作用,触摸至少会抱怨该目录不存在。 【参考方案1】:

来自the manual,

先决条件实际存在或总是被提及的规则 优先于具有先决条件的规则 链接其他隐式规则。

您的规则 #1 需要链接,您的规则 #2 没有先决条件,因此 Make 在尝试构建 DIR/3/abc.txt 时会选择 #2 而不是 #1。

编辑:

如果您可以忍受目录列表:

DIRS := DIR/0 DIR/1 DIR/2 DIR/3

那么您可以使用static pattern rule:

all: DIR/0/a.txt DIR/1/b.txt DIR/2/c.txt DIR/3/abc.txt

ABC_TXT := $(addsuffix /abc.txt, $(DIRS))

$(ABC_TXT): DIR/%/abc.txt : DIR/%/def.xtx

DIR/%.txt:
    mkdir -p $(@D)
    touch $@

DIR/%.xtx:
    touch $@

(它也避免了 .txt 规则的重复!)

【讨论】:

这回答了为什么选择规则 #2 而不是规则 #1 的问题,但是,我该如何规避这种行为?! 我们可以在配方中明确地设置先决条件(即make DIR/$*/def.xtx),但这会非常低效。还有其他方法吗?! 非常感谢!那会……至少现在是这样。 :) 我们解决方案的唯一问题是需要指定目录列表。为了避免我做了以下事情:将所有的先决条件分配给一个变量(即ALL);然后不是$(ABC_TXT): ...,而是$filter DIR/%/abc.txt, $(ALL): DIR/%/abc.txt: DIR/%/def.xtx。这里的诀窍是使用静态模式规则。非常感谢。

以上是关于makefile:隐式规则:相同的目标不同的先决条件的主要内容,如果未能解决你的问题,请参考以下文章

Makefile学习13——理解make的解析行为

第15课 - make的隐式规则(上)

makefile失败 - 隐式规则编译一个目标文件但不编译其余文件

特定于目标的变量作为 Makefile 中的先决条件

Makefile 中的隐式规则

Makefile 隐式规则不起作用