1

我一直在尝试在http://www.cmcrossroads.com/article/atomic-rules-gnu-make?page=0%2C0上使用 John Graham-Cumming 关于“GNU Make 中的原子规则”的优秀文章

但是,有时我必须使用单独的规则来指定两个文件之间的依赖关系,而无需看起来像这样的配方:

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 一样工作吗?我真的被困住了。

谢谢,-汤姆

4

1 回答 1

0

您手动添加了对错误目标的依赖项。

回想一下原子构造在做什么。它将一组原始目标分解为单个哨兵目标,并将其用作排序点。

您正在将先决条件添加到各个原始目标(原子解决方法最初旨在允许/修复的确切内容)。

您需要将先决条件添加到哨兵文件:w1.sentinel : v1 v2

(或者更好的是,使用原始帖子中的哨兵功能并使用$(call sentinel,w1 w2): v1 v2.

,顺便说一句,在 make 函数调用中添加空格时要小心。它会对事物产生非常有害且有些奇怪的影响。

原子.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'.

请参阅此图以查看相关的先决条件树(手动创建,因为我不知道任何好的工具可以从 make 输出中执行此操作,尽管我已经想要一个一段时间了,如果我有什么问题,请道歉)。

于 2014-07-11T20:12:39.170 回答