使用sentinel文件失败的Gnumake原子规则

时间:2014-07-11 19:46:30

标签: makefile gnu atomic sentinel

我一直在努力使用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的工作方式相同吗? 我真的卡住了。

谢谢, - 汤姆

1 个答案:

答案 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输出来创建,但是我已经想要一段时间了,所以请道歉我有点不对劲。)