我缺少对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。
答案 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 $@ $<