【问题标题】:Make and last modification times of directories on LinuxLinux 上目录的创建和最后修改时间
【发布时间】:2023-03-26 21:57:01
【问题描述】:

考虑以下生成文件:

foo :
    mkdir foo

foo/a.out : foo a.in
    cp a.in foo/a.out

foo/b.out : foo b.in
    cp b.in foo/b.out

以及与它的以下交互,从包含文件 a.inb.in 的目录开始,仅此而已:

$ make foo/a.out
mkdir foo
cp a.in foo/a.out

到目前为止,一切都很好。

$ make foo/b.out
cp b.in foo/b.out

还不错,但现在:

$ make foo/a.out   # a.out should be up to date now!
cp a.in foo/a.out

它会重建 a.out 目标,即使它的先决条件都没有改变。

似乎正在发生的事情是,当创建 foo/b.out 时,目录 foo 的最后修改时间已更新,因此它会将其视为“已更改”。

有没有办法避免这种情况?例如,有没有一种方法可以声明 foo/a.out 依赖于 foo 仅因为 foo 必须存在,并且在 foo 中创建文件不会导致 foo 被认为已过期?

【问题讨论】:

    标签: linux makefile gnu-make


    【解决方案1】:

    As an authority on Make recently pointed out:

    “你绝不能做的一件事是使用目录作为一个简单的先决条件。文件系统用于更新目录修改时间的规则不适用于 make。”

    但我认为这会做你想要的:

    foo :
        mkdir foo
    
    foo/a.out : a.in | foo
        cp a.in foo/a.out
    
    foo/b.out : b.in | foo
        cp b.in foo/b.out
    

    【讨论】:

    • +1 不知道此功能,但请注意它仅在新版本的 GNU Make 中可用。
    • Err... 对于“新”的一些定义,我猜。在 10 多年前的 2002 年 10 月发布的 GNU make 3.80 中添加了仅订购的先决条件。
    【解决方案2】:

    我喜欢@Beta 的回答,但它不可移植。对于一个简单的可移植解决方法,请在创建目录时创建一个哨兵文件,并改为依赖哨兵文件。

    foo/.dir:
            mkdir -p foo
            touch $@
    foo/a.out: a.in foo/.dir
            cp $< $@
    foo/b.out: b.in foo/.dir
            cp $< $@
    

    这可以通过模式规则进一步简化:

    foo/%.out: %.in foo/.dir
            cp $< $@
    

    【讨论】:

      【解决方案3】:

      您可以简单地在其构建规则中无条件地创建目录,而不是使目标依赖于目录:

      foo/a.out: a.in
              mkdir -p foo
              cp a.in foo/a.out
      
      foo/b.out: b.in
              mkdir -p foo
              cp b.in foo/b.out
      

      这避免了使用目录作为先决条件的问题。

      【讨论】:

      • @HighCommander4 是的,尽管在实践中我希望为此使用基于模式的规则,而不是为每个目标使用单独的规则。如果您的 make 版本支持,我会推荐其他答案。另请参阅 Beta 链接到的问题,其中对此问题进行了更多讨论。
      • 考虑稍微修改的场景,.in 文件也在foo 中,并且还有另一个目录bar 类似于foo。假设我的基于模式的规则是 %.out : %.in(省略了操作),然后我有规则 foo/% : foobar/% : bar 没有任何操作来获得目录先决条件。我在%.out : %.in 规则的正文中mkdir 是什么?
      • @HighCommander4 我很难想象这个。如果目录不存在,%.in 文件如何存在?
      • 你说得对,这没有任何意义 :) 让我再试一次,这次是一个真实的例子。假设我有一个规则来制作任何目标文件,形式为%.o : (然后是动作)。我在这里没有提出任何先决条件。然后我有没有foo/cat.o : src/cat.c foobar/dog.o : src/dog.c bar 形式的操作的规则。如果我将mkdir 操作放入这些规则中,它们将运行而不是%.o 规则,而不仅仅是向其添加先决条件。但是如果我尝试将mkdir 放入%.o 规则中,我该怎么做mkdir
      • @HighCommander4,你应该总是 mkdir -p $(@D)$(@D) 自动变量给出了目标的目录 ($@)。使用-p 选项,这样如果目录已经存在,它就不会失败。
      猜你喜欢
      • 1970-01-01
      • 2011-12-09
      • 1970-01-01
      • 2011-11-11
      • 2011-07-02
      • 2012-05-13
      • 1970-01-01
      • 1970-01-01
      • 2016-04-03
      相关资源
      最近更新 更多