makefile - GNU Make 目标在 "up to date"之前构建了两次;为什么不在第一遍之后呢?

标签 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 操作不被跳过?

更多信息

我在 Antergos 上使用 GNU Make 4.2.1,并在 VirtualBox 中使用 ext4 文件系统。

最佳答案

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

根据 prerequisite types 的文档:

Consider an example where your targets are to be placed in a separate directory, and that directory might not exist before make is run. In this situation, you want the directory to be created before any targets are placed into it but, because the timestamps on directories change whenever a file is added, removed, or renamed, we certainly don’t want to rebuild all the targets whenever the directory’s timestamp changes. One way to manage this is with order-only prerequisites: make the directory an order-only prerequisite on all the targets.

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

build:
    mkdir -p $@

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

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

关于makefile - GNU Make 目标在 "up to date"之前构建了两次;为什么不在第一遍之后呢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51575707/

相关文章:

c++ - CMakeLists.txt结构

c++ - 如何使用 __attribute__((visibility ("default")))?

makefile - .deps/*.Po : No such file or directory compiler error

makefile - GNU 制作 : Multiple targets in a single rule

linux - 如何编写一个 makefile 以更改另一组 makefile 中的路径

compiler-errors - 由于无法识别的选项,无法在 MingW 上制作

java - Makefile 找不到其他类(Java、Linux、Ubuntu)

c++ - 更新旧版 C makefile 以包含 C++ 源文件

c - 尝试安装 valgrind 但卡在 make valgrind,怎么办?

makefile - 将目标名称传递给 makefile 中的依赖项