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.txt
、d = DIR/3
和n = 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.txt
、DIR/1/b.txt
和DIR/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:隐式规则:相同的目标不同的先决条件的主要内容,如果未能解决你的问题,请参考以下文章