Makefile Make不应重建深度依赖关系

Makefile Make不应重建深度依赖关系,makefile,Makefile,下面的Makefile示例大致描述了一个构建过程: a: b @echo "Build a, just using b. Don't care about c." touch a b: c @echo "Constructing b from c is cheap..." touch b @echo "Once accomplished, I no longer need c." c: @echo "Constructing c is ver

下面的Makefile示例大致描述了一个构建过程:

a: b
    @echo "Build a, just using b.  Don't care about c."
    touch a

b: c
    @echo "Constructing b from c is cheap..."
    touch b
    @echo "Once accomplished, I no longer need c."

c:
    @echo "Constructing c is very expensive..."
    @echo "Work work work..."
    touch c

clean:
    $(RM) a b c

example: clean
    make a
    $(RM)   c
    make a
关键是:我需要
c
来构建
b
,但一旦我拥有
b
,我就再也不需要
c
。当我做
make example
make
c
b
a
(如预期的那样),删除
c
,然后,在最后一次
调用中,只需重新做
c
(并且不重新做
b
a
,尽管我认为它们现在已经过时了)。但是,由于我的目标是
a
,而
b
没有改变,我不想重拍
c
。算了吧!谁在乎<代码>a
应视为最新的

另一件奇怪的事是当我

make a
rm c
make a
(而不是
makeexample
),在第二次调用中
make
重建一切(而在
makeexample
中,第二次调用只重建
c

如果
make
的目标是
a
,并且
a
的所有直接先决条件都存在并且比它们更新鲜(
a
b
相比并不过时),我如何防止
make
构建
c


编辑:我想我可能想要的是将每个文件视为旧文件(例如使用
--旧文件
),除非该文件不存在。

b
可能是从
c
构建的,但你不想告诉Make
b
取决于
c
——如果
b
仅仅存在,那就足够了。因此,您可以将
b
的配方编写为

b:
    $(MAKE) c
    @echo "Constructing b from c is cheap..."
    touch b
    @echo "Once accomplished, I no longer need c."
或者,如果
c
仅用于制作
b
,您可以将制作
c
的命令折叠到
b
的配方中,而不公开要制作的
c
的存在


也许有更优雅的方式表达这一点,而无需调用sub make。如果
c
有一些先决条件,这些先决条件在更新后会导致重建,我想它们也需要被列为
b
的必备条件。

看起来您希望
使
将文件
c
视为中间文件,一种对您没有任何重要性的文件,除了在生成另一个或多个文件时作为中间结果。本手册第节对此概念进行了解释。由于您的示例不使用任何隐式规则,因此可以手动将文件
c
标记为

此生成文件将
c
显示为中间文件

a: b
        @echo "Build a, just using b.  Dont care about c."
        touch a

b: c
        @echo "Constructing b from c is cheap..."
        touch b
        @echo "Once accomplished, I no longer need c."

c: d
        @echo "Constructing c is very expensive..."
        @echo "Work work work..."
        touch c

.INTERMEDIATE: c
.PRECIOUS: c
我添加了一个基于的文件
d
,尽管本例不需要它

在调用
make
之前,文件
d
必须存在,它是链的起点。调用
make
时,会发生以下情况:

$ touch d
$ make
Constructing c is very expensive...
Work work work...
touch c
Constructing b from c is cheap...
touch b
Once accomplished, I no longer need c.
Build a, just using b.  Dont care about c.
touch a
现在删除
c
不会对构建产生任何影响:

$ rm c
$ make
make: `a' is up to date.
除此之外,基于依赖关系的更新行为“与平常一样”


选项是可选的。它是一个内置程序,指示
make
不删除名为
c
的中间文件。你可以自己看看如果你删除那行会发生什么。

我无法重现你为
做例子
:删除
c
后,重建
c
b
a
。您使用的make版本是什么?GNU make 3.81(OS X)使用
GNU make 4.2.1
似乎与3.81有所不同。当我使用4.2.1时,第二个
make example
中创建一个
,它重建了一切。非常有趣,我不知道3.81和更新版本之间的差异。虽然我没有证据证明你看到了这一点,请注意,有报告称MacOS/Xcode提供的GNU make 3.81版本存在问题,即使是为MacOS编译的GNU make 3.81原始版本中也没有出现这些问题。不幸的是,在我的真实例子中,我有很多东西可能依赖于c,而不仅仅是b。一旦有了这些东西,c就可以被扔了。c也有一些先决条件,如果这些先决条件发生变化,c也会发生变化(这取决于c的变化)。但是如果删除了c,并且您已经得到了依赖于它的东西,那就没问题了。有趣的是,我不知道
.INTERMEDIATE
。你能解释一下
.INTERMEDIATE
.SECONDARY
之间的区别吗?我从来没有使用过
.SECONDARY
,但它看起来与
.INTERMEDIATE
的功能相同,而且它不会丢弃你的中间文件。看来你也可以用它来代替
.INTERMEDIATE
.PRECIOUS
。对我来说,后两者的名称更清楚地表明了它们的意图,但这是一个偏好问题。再仔细想想:必须明确地将文件标记为
.INTERMEDIATE
。由于第10.4节中解释的隐式链接,文件通常是中间的。不过,
.PRECIOUS
指示很常见。这就是我最终明确使用这两种方法的原因,也是我对
.SECONDARY
不太熟悉的原因。当然,如果您首先不想保留
c
,那么只需使用
。中间
就足够了,
make
将自动删除
c
。确定。因此,如果我不想自动删除c,我可以标记它(
.INTERMEDIATE
.PRECIOUS
)或
.SECONDARY
,因为它们是等效的?如果它们是等效的,为什么要有一个
.SECONDARY
目标呢?
.PRECIOUS
的文档确实表明与
.SECONDARY
有重叠。不同之处似乎是当make在shell执行时收到致命信号时所产生的行为,s