在这个 makefile 中,为什么目标 "bunzip2/data2.tar" 的先决条件总是被重新制作?

In this makefile, why is the prerequisite for the target "bunzip2/data2.tar" always being remade?

尽管先决条件是最新的,但我有一个总是重新运行规则的生成文件:

data.tar.bz2: data.tar
    bzip2 --keep data.tar

# The following rule always runs the rule for its prerequisite
# even if it is up-to-date. Note that it doesn't matter whether
# the bunzip2 directory exists or not. I suppose is has something
# to do with the dir/file naming of the rule but I haven't been
# able to decipher why.
bunzip2/data2.tar: data.tar.bz2
    mkdir bunzip2 && cd bunzip2 && bzip2 -ckd ../data.tar.bz2 > data2.tar && cd ..

.PHONY: clean
clean:
    rm -f data.tar.bz2
    rm -Rf bunzip2

任何想法表示赞赏。

示例中缺少某些内容 - 但分析过程是相同的,无论如何:您可以使用 make 的调试功能来查看它使用的规则,例如,

make -d

我想我明白这是怎么回事了。

使用@Thomas Dickey 建议尝试 make -d,它说文件 data.tar.bz2data.tar 本身更新。这看起来很愚蠢,因为前者是从后者创建的。但是使用 ls --full-time 显示 bzip2 存档似乎使用了源文件的时间戳,但它也在第二位之后 截断了它 。在我的例子中,时间戳 2015-03-12 09:32:02.452091888 被截断为 2015-03-12 09:32:02.000000000 这使得它看起来比源更新。 (截断我的意思是 2015-03-12 13:10:29.681793152 转到 2015-03-12 13:10:29.000000000... 即使在那种情况下它也不会四舍五入)似乎 bzip 需要提高时间戳的准确性。

似乎 lunzip 也截断了时间戳,unxz 保留了原始时间戳,而 gzip 使用当前时间。换句话说,在使用压缩实用程序时要小心你的 makefile,因为它们处理事情的方式不同。

在文件上设置时间戳的标准 POSIX 系统调用不支持亚秒级精度。为了让这些工具在文件上设置特定时间(他们试图这样做,以便压缩文件具有与原始文件相同的时间戳)并保持原始准确性,他们需要使用不同的系统调用;显然他们不这样做。

要解决此问题,您可以像这样更改规则:

data.tar.bz2: data.tar
        bzip2 --keep data.tar && touch $@

以便将目标的时间戳设置为"now"。

ETA 设置文件修改时间的传统系统调用是utime() which accepts timestamps only in increments of one second. Newer versions of the POSIX spec introduced utimensat(),它允许纳秒时间戳设置。还有 utimes() 允许微秒级精度,但长期以来一直被认为是 "legacy"。

如果当前最新版本 bzip2 中存在此行为,我认为这是一个值得向他们报告错误的错误。