强制 GNU-make 使用符号 link 目标的修改时间,而不是源的修改时间

force GNU-make to use modification time of symbolic link target, not modification time of the source

我在 GNU make 3.81 中遇到修改时间问题。

我的 Makefile 使用从远程服务器安装的数据,出于某种我不知道的原因,它已将文件的修改时间设置为遥远的未来(进入下个世纪)。

Makefile 首先在本地目录中创建一个符号link 到远程文件"from the future",然后基于此文件运行s 几个脚本,这些脚本都生成一些输出文件。

现在,当我想在中断后重新运行 "make all" 获取我所有的输出文件时,它不会用它生成的最新输出文件重新启动(假设从脚本编号 3),而是它从头开始重新生成所有内容,因为它注意到第一个文件(我在其中对文件 "from the future" 进行 symlink 编辑的那个文件)较新。

是否有选项告诉 make 获取 symlink 本身的修改时间,而不是 symlink 的目标的修改时间?

例子

这是一个最小的工作示例,它重新生成了问题:

设置文件夹和文件:

mkdir symlinkmake
cd symlinkmake
echo $PWD > futurefile.txt
# set file modification time to the future
touch -t 212111111111 futurefile.txt

Makefile 的内容:

all: symlink.txt first_output.txt second_output.txt

symlink.txt:
    ln -s futurefile.txt symlink.txt

first_output.txt: symlink.txt
    cut -f1 -d"/" symlink.txt > first_output.txt

second_output.txt: first_output.txt
    wc first_output.txt > second_output.txt

现在运行make all并删除第二个输出文件。然后重新运行 make。由于第一个输出文件已经存在,因此只需要生成第二个文件。但由于 futurefile.txt 比任何其他文件都新,因此还将生成第一个输出文件:

make all
rm second_output.txt
make all

在我的机器上,输出如下所示:

$ ls
Makefile        futurefile.txt  symlink.txt
$ make all
make: Warning: File `symlink.txt' has modification time 3.3e+09 s in the future
cut -f1 -d"/" symlink.txt > first_output.txt
wc first_output.txt > second_output.txt
make: warning:  Clock skew detected.  Your build may be incomplete.
$ rm second_output.txt
$ make all
make: Warning: File `symlink.txt' has modification time 3.3e+09 s in the future
cut -f1 -d"/" symlink.txt > first_output.txt
wc first_output.txt > second_output.txt
make: warning:  Clock skew detected.  Your build may be incomplete.

--check-symlink-times make option 但是:

On systems that support symbolic links, this option causes make to consider the timestamps on any symbolic links in addition to the timestamp on the file referenced by those links. When this option is provided, the most recent timestamp among the file and the symbolic links is taken as the modification time for this target file.

这不是你想要的,它只考虑 link 的时间戳。由于您无法解决您的 date/time 问题,我可以想象只有一个 2 解决方案

  1. order-only prerequisites (面向对象):

    .PHONY: all
    
    all: first_output.txt second_output.txt | symlink.txt
    
    symlink.txt:
        ln -s futurefile.txt $@
    
    first_output.txt: | symlink.txt
        cut -f1 -d"/" $| > $@
    
    second_output.txt: first_output.txt
        wc $< > $@
    

    symlink.txt 作为 OOP make 只会考虑它的存在,而不是它的时间戳。换句话说,make 将构建它,并(重新)构建所有依赖它的目标,只有当它丢失时。

    注意:我还在所有可能的地方使用了 automatic variables。它们很方便,不易出错,并且经常允许分解规则。

    缺点:与真正的解决方案相比,这是一个快速而肮脏的 hack。实际上,如果 link 引用的文件发生变化,您的其他目标将 不会 重建:

    $ ls -al
    Sep 14 14:55 Makefile
    Dec  1  2018 futurefile.txt
    $ make
    ln -s futurefile.txt symlink.txt
    cut -f1 -d"/" symlink.txt > first_output.txt
    wc first_output.txt > second_output.txt
    $ ls -al
    Sep 14 14:55 Makefile
    Sep 14 15:05 first_output.txt
    Dec  1  2018 futurefile.txt
    Sep 14 15:05 second_output.txt
    Sep 14 15:05 symlink.txt -> futurefile.txt
    $ make
    make: Warning: File 'symlink.txt' has modification time 6688452 s in the future
    make: Nothing to be done for 'all'.
    make: warning:  Clock skew detected.  Your build may be incomplete.
    $ touch --date=2018-12-02 futurefile.txt
    $ ls -al futurefile.txt
    $ make
    make: Warning: File 'symlink.txt' has modification time 6774852 s in the future
    make: Nothing to be done for 'all'.
    make: warning:  Clock skew detected.  Your build may be incomplete.
    
  2. 为了减轻第一个解决方案的缺点,您在构建目标时将本地主机的 date/time 替换为远程服务器的 date/time。偶然地,touch 命令有一个很好的 --reference 选项,它强制一个文件的时间戳是另一个文件的时间戳:

    .PHONY: all
    
    all: first_output.txt second_output.txt
    
    first_output.txt: futurefile.txt
        cut -f1 -d"/" $< > $@
        touch --reference=$< $@
    
    second_output.txt: first_output.txt
       wc $< > $@
       touch --reference=$< $@
    

    缺点:不是一个符号link,你将有两个文件(first_output.txtsecond_output.txt)与未来的时间:

    $ ls -al
    Sep 14 14:55 Makefile
    Dec  1  2018 futurefile.txt
    $ make
    make: Warning: File 'futurefile.txt' has modification time 6688320 s in the future
    cut -f1 -d"/" futurefile.txt > first_output.txt
    touch --reference=futurefile.txt first_output.txt
    wc first_output.txt > second_output.txt
    touch --reference=first_output.txt second_output.txt
    make: warning:  Clock skew detected.  Your build may be incomplete.
    $ ls -al
    Sep 14 14:55 Makefile
    Dec  1  2018 first_output.txt
    Dec  1  2018 futurefile.txt
    Dec  1  2018 second_output.txt
    $ make
    make: Warning: File 'first_output.txt' has modification time 6688320 s in the future
    make: Nothing to be done for 'all'.
    make: warning:  Clock skew detected.  Your build may be incomplete.
    $ touch --date=2018-12-02 futurefile.txt
    $ ls -al futurefile.txt
    $ make
    make: Warning: File 'first_output.txt' has modification time 6688320 s in the future
    cut -f1 -d"/" futurefile.txt > first_output.txt
    touch --reference=futurefile.txt first_output.txt
    wc first_output.txt > second_output.txt
    touch --reference=first_output.txt second_output.txt
    make: warning:  Clock skew detected.  Your build may be incomplete.