防止在过期时重建仅限订单的先决条件

时间:2015-07-07 14:29:33

标签: makefile

一位同事刚刚遇到这个问题,我想我是否会问以下问题是否有任何简洁的解决方案:我有一个GNU makefile:

a: | b
    touch $@
b:c
    touch $@
c:
    touch $@

然后我跑:

~/tmp> make a
touch c
touch b
touch a
~/tmp> make a
make: `a' is up to date.
~/tmp> touch b
~/tmp> make a
make: `a' is up to date.
~/tmp> touch c
~/tmp> make a
touch b

如果我触摸b,它会重建a但不会重建c。有没有一种方法可以重建b,如果它是由仅订单的先决条件调用的? (在现实案例中b是一个包含数百个依赖项的文件,在调用make a时可能不存在。我无法生成b&#39}。先决条件是仅限订单,因为它会破坏make b

2 个答案:

答案 0 :(得分:1)

行为完全正确。您已指示make忽略ab之间的紧密依赖关系,并仅依赖b存在。虽然ac共享日期依赖关系

这是a: ba: | b之间的区别。

如果有人想调查此案例(或其他make 魔法 :)):

尝试以下操作,您会看到make非常热衷并告诉您它对b目标的作用:

% touch b
% LANG=C make -rd | awk '/^Considering/,/^$/ {print}'
Considering target file `a'.
  Considering target file `b'.
    Considering target file `c'.
     Finished prerequisites of target file `c'.
    No need to remake target `c'.
   Finished prerequisites of target file `b'.
   Prerequisite `c' is older than target `b'.
  No need to remake target `b'.
 Finished prerequisites of target file `a'.
 Prerequisite `b' is order-only for target `a'.      <--- "order-only"
No need to remake target `a'.

现在,添加一个紧密的依赖:

% echo "a:b" >> Makefile 

并比较结果:

% touch b
% LANG=C make -rd | awk '/^Considering/,/^$/ {print}'
Considering target file 'a'.
  Considering target file 'b'.
    Considering target file 'c'.
     Finished prerequisites of target file 'c'.
    No need to remake target 'c'.
   Finished prerequisites of target file 'b'.
   Prerequisite 'c' is older than target 'b'.
  No need to remake target 'b'.
  Pruning file 'b'.
 Finished prerequisites of target file 'a'.
 Prerequisite 'b' is order-only for target 'a'.
 Prerequisite 'b' is newer than target 'a'.          <--- additional "date dependency"
Must remake target 'a'.
touch a                                              <--- 'a' is rebuilt
Putting child 0x1b09ec0 (a) PID 5940 on the chain.
Live child 0x1b09ec0 (a) PID 5940 
Reaping winning child 0x1b09ec0 PID 5940 
Removing child 0x1b09ec0 PID 5940 from chain.
Successfully remade target file 'a'.

我使用了make -r(没有隐式规则),因为这个例子没有使用它们而且无聊来阅读。

答案 1 :(得分:0)

除了注释,您的问题陈述是非常通用的,与描述实际用例相距甚远。这使得它非常简短,易于阅读和理解。另一方面,了解和解决您的特定问题或解决该问题的不确定性更高。

我已经看到您的完全相同的通用问题陈述适用于其他用例:

nimble_exe: nimble_srcs | big_lib
    touch $@

big_lib: biglib_many_sources_and_headers
    touch $@
    sleep 1 # simulate a long [no-op] build time

biglib_many_sources_and_headers
    touch $@

此代码的含义是:“在nimble_exe缺少时构建big_lib,但在过期时不在乎”,这与“仅订购的依赖项”甚至used to match ninja's behavior until 2011

不幸的是,如果有人在biglib_many_sources_and_headers中进行了任何更改,make nimble_exe会重建big_lib,但不会 nimble_exe!这表明“仅订购依赖项”根本不是针对该用例设计的。因此,我建议改为:

nimble_exe: nimble_srcs
    test -e big_lib || $(MAKE) big_lib
    touch $@