GNU Make目标在“最新”之前构建了两次;为什么不通过第一遍?

时间:2018-07-28 22:24:22

标签: makefile gnu-make

我缺少对make如何确定是否必须建立依赖项的一些世俗而又批判性的理解。我把问题归结为一个非常简单的例子。

build:
    mkdir -p $@

.PRECIOUS: build/%.txt
build/%.txt: build
    @echo "$*" > $@

%.zip: %.txt
    zip -jquX $@ $<

我认为make build/foo.zip的首次运行应首先创建“ build”目录,然后编写“ build / foo.txt”,最后一次构建“ build / foo.zip”,而剩下“ build / foo.txt” ”。然后,所有连续运行都应该无关,因为没有依赖关系比依赖它们的目标新。

但是,我得到以下输出:

➜  make build/f.zip
mkdir -p build
zip -jquX build/f.zip build/f.txt

➜  make build/f.zip
zip -jquX build/f.zip build/f.txt

➜  make build/f.zip
make: 'build/f.zip' is up to date.

如何避免这种情况?是什么导致第二个zip操作不被跳过?

更多信息

我在VirtualBox内的ext4文件系统上在Antergos上使用GNU Make 4.2.1。

2 个答案:

答案 0 :(得分:4)

在@ o11c的大力推荐下,我提出了解决方案。原来这是记录的行为。将文件添加到目录时,目录时间会更新。由于没有文件写入该文件夹,因此第二次运行不会发生这种情况。

根据prerequisite types的文档:

  

考虑一个示例,其中将目标放置在单独的目录中,并且在运行make之前该目录可能不存在。在这种情况下,您希望在放置任何目标之前先创建目录,但是由于目录的时间戳会在添加,删除或重命名文件时发生变化,因此我们当然不希望在以下情况下重建所有目标:目录的时间戳更改。解决此问题的一种方法是使用仅订购的先决条件:使目录成为所有目标上的仅订购的先决条件。

这是可行的解决方案。只需添加|

build:
    mkdir -p $@

.PRECIOUS: build/%.txt
build/%.txt: | build
    @echo "$*" > $@

%.zip: %.txt
    zip -jquX $@ $<

答案 1 :(得分:1)

我没有解释,但这是替代方法。由于mkdir -p不会失败,因此可以为mkdir build删除单独的目标。在Linux,Debian buster的GNU Make 4.2.1和ext4上,这对我来说似乎是可靠的:

.PRECIOUS: build/%.txt
build/%.txt:
    mkdir -p build
    @echo "$*" > $@

%.zip: %.txt
    zip -jquX $@ $<