Makefile 防止在过期时重新生成仅限订单的先决条件

Makefile 防止在过期时重新生成仅限订单的先决条件,makefile,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

一位同事刚刚遇到了这个问题,我想问一下,对于以下问题是否有什么好的解决方案:我有一个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

如果我触摸
c
,它会重建
b
,但不会重建
a
。如果仅由订单先决条件调用,是否有方法不重建
b
?(在现实生活中,
b
是一个具有数百个依赖项的文件,当调用
make a
时,这些依赖项可能不存在。我不能仅将
b
的先决条件设置为顺序,因为这样会破坏
make b

行为完全正确。您指示
make
忽略
a
b
之间的紧密依赖关系,只依赖
b
的存在。而
a
c
共享一个日期依赖关系

这就是
a:b
a:b
之间的区别


如果有人想调查这个案件(或其他
make
magic:):

尝试以下操作,您将看到
make
非常热衷,并告诉您它为
b
target做了什么:

% 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'.
并比较结果:

% 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'.
%touch b
%LANG=C make-rd | awk'/^考虑/,/^$/{print}
正在考虑目标文件“a”。
正在考虑目标文件“b”。
正在考虑目标文件“c”。
已完成目标文件“c”的先决条件。
无需重新制作目标“c”。
已完成目标文件“b”的先决条件。
先决条件“c”早于目标“b”。
无需重新制作目标“b”。
正在修剪文件“b”。
已完成目标文件“a”的先决条件。
先决条件“b”仅为目标“a”的订单。

先决条件“b”比目标“a”新 撇开评论不谈,您的问题陈述是非常通用的,它远远没有描述实际的用例。这使得它非常简短,易于阅读和理解。另一方面,理解、解决或解决特定问题更不确定

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

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缺少大_库时构建大_库,但不管它何时过时”,这表面上与“仅顺序依赖”的定义相匹配,甚至

不幸的是,如果有人在
biglib\u多个源\u和\u头中更改任何内容
make nimble\u exe
重建
big\u库
,但不是
nimble\u exe
!这表明“仅顺序依赖项”根本不是为该用例设计的。因此,我建议改为:

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

好问题。据我所知没有。我不认为只有顺序的关系通常可以理解为具有这些语义,但是具有这些语义的先决条件肯定是一件有用的事情。好的,谢谢。考虑到缺少响应,我认为这是不可能的(如果b不存在,我可以在配方中添加一行显式调用
make b
,但这对我来说似乎有点黑客味)
b
如何在没有先决条件的情况下以make不理解的方式存在(类似于它如何处理缺少的中间产物)?或者问题不是因为它们不存在,而是因为它们可能已经改变了,但实际上你并不关心为此重做b?(您可以使用通配符执行Doe-b-exist测试,并仅在不存在的情况下将order only prereq添加到
a
b
是第三方软件
b
是为目标体系结构配置和构建的,并且该体系结构被附加到其名称之后。Target
a
将其打包,但要过很久才能运行。问题是我们想要构建多个版本的b——每个架构一个版本,然后将它们打包成一个包(因此b.mips、b.arm等等)。如果生成
b.arm
后接
b.mips
,则
b.arm
的依赖项将过时
a
依赖于正在生成的
b.mips
b.arm
,但不应基于时间戳重新生成它们。@例如,重新生成了
b
所依赖的一些对象文件(不同的编译器开关,可能是一些不同的汇编程序部件),使它们比
b
更年轻。这很可能是因为违反了外部软件的构建过程始终只生成平台匿名输出文件的规定。我理解为什么会发生这种情况,但我想知道是否有办法解决这一问题——也就是说,在构建a时,如果b还不存在,只重新生成b。我最后添加了一行:
[-eb]|$(MAKE)b
作为配方的第一行。@John,正确的行为就是你所期望的“在构建a时,只有在b还不存在时才重新生成b”。如果不是这样的话,那就是Makefile(您的文件)或
make
工具的问题。请检查表格。我得到了我测试过的所有gnu make版本(3.81,加上几个交叉编译版本)的描述行为。如果我做了
触摸a;触摸b;触摸c;创建一个
然后它将始终重建
b
,因为
c
b
新。。。(虽然它不重建
a
)。很抱歉,交叉编译计算机正在运行3.82,并且演示了相同的行为
nimble_exe: nimble_srcs
    test -e big_lib || $(MAKE) big_lib
    touch $@