我一直在努力使用John Graham-Cumming关于GNU Make"" Atomic Rules in GNU Make" 在http://www.cmcrossroads.com/article/atomic-rules-gnu-make?page=0%2C0
但是,我有时必须使用单独的规则指定两个文件之间的依赖关系 看似简单的食谱:
a : b
这对我来说总是如预期的那样,但是在指定依赖时它会失败 两个原子规则之间。这是一个包含3个测试用例的简单Makefile:
atomic = $(eval $1: $(firstword $1).sentinel ; @:) \
$(firstword $1).sentinel : $2 ; touch $$@ \
$(foreach _, $1, $(if $(wildcard $_), , $(shell rm -f $(firstword $1).sentinel)))
d1 d2 d3:
touch $@
## Test case 1 using sentinel and dependency (u1 u2 : t1 t2) specified in call to atomic
$(call atomic, t1 t2, d1)
touch t1 t2
$(call atomic, u1 u2, t1 t2)
touch u1 u2
## Test case 2 using sentinel and dependency (w1 w2 : v1 v2) specified as another rule does not work
$(call atomic, v1 v2, d2)
touch v1 v2
$(call atomic, w1 w2, )
touch w1 w2
w1 w2 : v1 v2
## Test case 3 showing that specifying a dependency (y1 : x1) with another rule does work
x1 : d3
touch x1
y1 :
touch y1
y1 : x1
##
clean :
rm -f {d,t,u,v,w,x,y}{1,2,3}{,.sentinel} test{1,2,3}
test1 : u1
touch test1
test2 : w1
touch test2
test3 : y1
touch test3
第一个测试用例做正确的事情并按预期顺序构建所有内容
> make test1
touch d1
touch t1.sentinel
touch t1 t2
touch u1.sentinel
touch u1 u2
touch test1
第二个测试用例通过以错误的顺序构建事物来惨败原子规则
> make test2
touch w1.sentinel
touch w1 w2
touch d2
touch v1.sentinel
touch v1 v2
touch test2
第三个简单的测试用例证明使用单独的规则来指定依赖项确实有效
> make test3
touch d3
touch x1
touch y1
touch test3
任何人都可以解释为什么会这样吗? 更好的是,任何人都可以提出解决方案,以便test2与test1的工作方式相同吗? 我真的卡住了。
谢谢, - 汤姆
答案 0 :(得分:0)
您在错误的目标上手动添加了依赖项。
回想原子构造正在做什么。它将原始目标集合折叠为单个标记目标,并将其用作排序点。
您正在将先决条件添加到各个原始目标(原始解决方法首先设计为允许/修复的确切事项)。
您需要将先决条件添加到sentinel文件:w1.sentinel : v1 v2
(或者更好的是,使用原始帖子中的哨兵功能并使用$(call sentinel,w1 w2): v1 v2
。
顺便说一下,在make函数调用中添加,周围的空格要小心。它可能对事物产生非常具有破坏性和奇怪的影响。
atomic.mk:
atomic = $(eval $1: $(firstword $1).sentinel ; @:) \
$(firstword $1).sentinel : $2 ; touch $$@ \
$(foreach _,$1,$(if $(wildcard $_),,$(shell rm -f $(firstword $1).sentinel)))
d1 d2 d3 d4:
>-------touch $@
## Test case 1 using sentinel and dependency (u1 u2 : t1 t2) specified in call to atomic
$(call atomic, t1 t2, d1)
>-------touch t1 t2
$(call atomic, u1 u2, t1 t2)
>-------touch u1 u2
## Test case 2 using sentinel and dependency (w1 w2 : v1 v2) specified as another rule does not work
$(call atomic, v1 v2, d2)
>-------touch v1 v2
$(call atomic, w1 w2, )
>-------touch w1 w2
w1 w2 : v1 v2
## Test case 4 using manual dependencies added to sentinel explicitly.
$(call atomic, z1 z2, d4)
>-------touch z1 z2
$(call atomic, a1 a2, )
>-------touch a1 a2
a1.sentinel : z1 z2
##
clean :
>-------rm -f {d,t,u,v,w,x,y,z,a}{1,2,3,4}{,.sentinel} test{1,2,3,4}
test1 : u1
>-------touch test1
test2 : w1
>-------touch test2
test4: a1
>-------touch test4
make -f ../atomic.mk -drR test1
的输出:
Reading makefiles...
Reading makefile `../atomic.mk'...
Updating makefiles....
....
Updating goal targets....
Considering target file `test1'.
File `test1' does not exist.
Considering target file `u1'.
File `u1' does not exist.
Considering target file `u1.sentinel'.
File `u1.sentinel' does not exist.
Considering target file `t1'.
File `t1' does not exist.
Considering target file `t1.sentinel'.
File `t1.sentinel' does not exist.
Considering target file `d1'.
File `d1' does not exist.
Finished prerequisites of target file `d1'.
Must remake target `d1'.
touch d1
....
Successfully remade target file `d1'.
Finished prerequisites of target file `t1.sentinel'.
Must remake target `t1.sentinel'.
touch t1.sentinel
....
touch t1 t2
....
Successfully remade target file `t1.sentinel'.
Finished prerequisites of target file `t1'.
Must remake target `t1'.
Successfully remade target file `t1'.
Considering target file `t2'.
Pruning file `t1.sentinel'.
Finished prerequisites of target file `t2'.
Prerequisite `t1.sentinel' is older than target `t2'.
No need to remake target `t2'.
Finished prerequisites of target file `u1.sentinel'.
Must remake target `u1.sentinel'.
touch u1.sentinel
....
touch u1 u2
....
Successfully remade target file `u1.sentinel'.
Finished prerequisites of target file `u1'.
Must remake target `u1'.
Successfully remade target file `u1'.
Finished prerequisites of target file `test1'.
Must remake target `test1'.
touch test1
....
Successfully remade target file `test1'.
make -f ../atomic.mk -drR test2
的输出:
Reading makefiles...
Reading makefile `../atomic.mk'...
Updating makefiles....
....
Updating goal targets....
Considering target file `test2'.
File `test2' does not exist.
Considering target file `w1'.
File `w1' does not exist.
Considering target file `w1.sentinel'.
File `w1.sentinel' does not exist.
Finished prerequisites of target file `w1.sentinel'.
Must remake target `w1.sentinel'.
touch w1.sentinel
....
touch w1 w2
....
Successfully remade target file `w1.sentinel'.
Considering target file `v1'.
File `v1' does not exist.
Considering target file `v1.sentinel'.
File `v1.sentinel' does not exist.
Considering target file `d2'.
File `d2' does not exist.
Finished prerequisites of target file `d2'.
Must remake target `d2'.
touch d2
....
Successfully remade target file `d2'.
Finished prerequisites of target file `v1.sentinel'.
Must remake target `v1.sentinel'.
touch v1.sentinel
....
touch v1 v2
....
Successfully remade target file `v1.sentinel'.
Finished prerequisites of target file `v1'.
Must remake target `v1'.
Successfully remade target file `v1'.
Considering target file `v2'.
Pruning file `v1.sentinel'.
Finished prerequisites of target file `v2'.
Prerequisite `v1.sentinel' is older than target `v2'.
No need to remake target `v2'.
Finished prerequisites of target file `w1'.
Must remake target `w1'.
Successfully remade target file `w1'.
Finished prerequisites of target file `test2'.
Must remake target `test2'.
touch test2
....
Successfully remade target file `test2'.
make -f ../atomic.mk -drR test4
的输出:
Reading makefiles...
Reading makefile `../atomic.mk'...
Updating makefiles....
....
Updating goal targets....
Considering target file `test4'.
File `test4' does not exist.
Considering target file `a1'.
File `a1' does not exist.
Considering target file `a1.sentinel'.
File `a1.sentinel' does not exist.
Considering target file `z1'.
File `z1' does not exist.
Considering target file `z1.sentinel'.
File `z1.sentinel' does not exist.
Considering target file `d4'.
File `d4' does not exist.
Finished prerequisites of target file `d4'.
Must remake target `d4'.
touch d4
....
Successfully remade target file `d4'.
Finished prerequisites of target file `z1.sentinel'.
Must remake target `z1.sentinel'.
touch z1.sentinel
....
touch z1 z2
....
Successfully remade target file `z1.sentinel'.
Finished prerequisites of target file `z1'.
Must remake target `z1'.
Successfully remade target file `z1'.
Considering target file `z2'.
Pruning file `z1.sentinel'.
Finished prerequisites of target file `z2'.
Prerequisite `z1.sentinel' is older than target `z2'.
No need to remake target `z2'.
Finished prerequisites of target file `a1.sentinel'.
Must remake target `a1.sentinel'.
touch a1.sentinel
....
touch a1 a2
....
Successfully remade target file `a1.sentinel'.
Finished prerequisites of target file `a1'.
Must remake target `a1'.
Successfully remade target file `a1'.
Finished prerequisites of target file `test4'.
Must remake target `test4'.
touch test4
....
Successfully remade target file `test4'.
请参阅this graph以查看相关的必备树(由于我不知道有任何好的工具可以通过make输出来创建,但是我已经想要一段时间了,所以请道歉我有点不对劲。)