【问题标题】:Getting make to delete additional files on error获取 make 以删除错误的其他文件
【发布时间】:2009-03-12 19:11:20
【问题描述】:

我们最近正在讨论我们在基于 make 的构建过程中处理依赖项的 .d 文件的方式。已提出的问题是,有时 .d 文件会在构建中断时损坏。

我们使用 .DELETE_ON_ERROR 目标来确保如果构建被中断或失败,它正在生成的目标文件被删除。但是,我们也使用 GCC 在编译时生成 .d 文件,这些文件也需要删除。似乎没有一种直接的方式来告诉 make 这件事。

所以问题是,有没有办法让我们在出错的情况下同时删除我们的对象和依赖文件?有什么方法可以设置规则,让它知道 .d 和 .o 文件是同时生成的,如果出现错误需要删除?

或者,我们可以采取其他措施来解决损坏的 .d 文件的问题吗?沿着这些思路的一个建议是生成具有临时名称的 .d 文件,并且每个文件都有一个单独的后编译步骤,将其复制到正确的名称。

【问题讨论】:

    标签: build-process makefile


    【解决方案1】:

    一般来说,GNU make 不支持具有多个输出的目标。但是,该规则有一个例外:模式规则。如果您可以构建您的makefile,使其使用模式规则生成目标文件,您可能能够实现您的目标。例如:

    .DELETE_ON_ERROR:
    
    all: foo.o
    
    %.o %.d: %.c
        @touch $*.d
        @touch $*.o
        @exit 1
    

    您会看到,当在规则中检测到“错误”时,使用此 makefile 会删除 .d 和 .o 文件。这种方法的优点是它通过描述如何生成 .d 文件以及生成它的规则来更准确地表达依赖关系图。

    或者,在这种情况下,一个常见的范例正如您所建议的那样:让 GCC 将 .d 文件生成为一个临时文件名,并且仅在 GCC 命令成功完成后将其移动到位。通常这是通过 shell 的技巧来完成的:

    all: foo.o
    
    %.o: %.c
        gcc -o $@ -MMD -MF $(basename $@).d.tmp -c $< \
            && mv $(basename $@).d.tmp $(basename $@).d
    

    这里的“神奇”技巧是使用 GCC 标志 -MMD,它生成依赖文件作为编译的副作用,以及 -MF,它允许您指定依赖文件的输出名称;以及使用shell cmd1 &amp;&amp; cmd2 语法,这会导致shell 仅在cmd1 成功退出时才执行cmd2

    【讨论】:

    • makefile 顶部的.DELETE_ON_ERROR: 让我摆脱了所有的临时文件。谢谢!
    • 我建议将 mv 作为模式规则“%.o: %.c”的配方中的第二行。我没有看到使用 shell '&&' 将其放在第一行的行为或好处有任何变化。
    • @RichardPerrin 如果使用 -i(忽略错误)选项调用 gmake,您的提案将产生不正确的行为。在这种情况下,无论gcc 是否有错误,您的版本都会运行mv 命令,而我的原始版本不会。
    【解决方案2】:

    我没有得到 Eric 的示例正常工作。当您传入 -MM 开关时,GCC(4.4 版)不会编译任何内容,因此看起来您不能一次编译和编写 .d。这是我所做的:

    %.o: %.c
        @rm -f $@ $(patsubst %.o,%.d,$@)
        gcc -c $< -o $@
        @$(CXX) -MM -MG > $(patsubst %.o,%.d,$@)
    

    首先删除现有的 .d 文件,生成新文件的第三行仅在第二个命令(实际编译步骤)成功时执行(Eric 的 && 技巧不是必需的,make 会自动执行此操作) . 出于某种我不明白的原因,如果编译失败,不会自动删除现有的 .o 文件,但是通过将 $@ 添加到第一个 rm 很容易解决。

    【讨论】:

    • 正确,如果只指定-MM,gcc 将不会真正编译文件。您还必须使用-MF,如我原来的答案中所述。
    • @Eric 我也添加了 -MF 开关,但是预处理器似乎没有向 gcc 的编译器部分发送任何输出,所以我最终得到了一个零字节的目标文件......跨度>
    • 抱歉,我弄错了:你想要的是-MMD,而不是-MM。我也更正了原来的答案。
    猜你喜欢
    • 2020-02-04
    • 1970-01-01
    • 2013-10-31
    • 2011-03-20
    • 1970-01-01
    • 2018-05-06
    • 2017-03-08
    • 1970-01-01
    • 2023-03-07
    相关资源
    最近更新 更多