【问题标题】:add_custom_command: Remove redirected output on failureadd_custom_command:在失败时删除重定向输出
【发布时间】:2023-04-20 21:04:01
【问题描述】:

考虑以下自定义命令(最新的 CMake + ninja):

add_custom_command(
        OUTPUT
            ${OUTPUT}
        COMMAND
            ${Python3_EXECUTABLE} script.py ${INPUT} > ${OUTPUT}
        DEPENDS
            ${INPUT}
        VERBATIM
        COMMAND_EXPAND_LISTS
    )

script.py 运行没有错误时,它工作正常。

但是,当 script.py 因错误而失败时,仍会创建 ${OUTPUT}
因此,当前构建按预期失败,但下一个构建看到 ${OUTPUT}${INPUT} 更新,并且不会尝试再次运行自定义命令。

我希望构建系统在命令失败时自动删除${OUTPUT},以防止这种情况发生,但显然这不会发生。

  • 有没有办法在自定义命令“失败”时执行操作?
    如果有,我可以删除那里的${OUTPUT}
  • 或者,除非命令成功,否则防止创建输出的最简单方法是什么?

我天真地尝试过类似的事情:

${Python3_EXECUTABLE} script.py ${INPUT} > ${OUTPUT} || rm -f ${OUTPUT}

但这不起作用,因为命令结果代码实际上是 rm 结果代码而不是 Python 的结果代码,因此自定义命令不会像在后续构建中那样失败。

【问题讨论】:

    标签: cmake ninja build-system cmake-custom-command


    【解决方案1】:

    您快到了,只需在 rm 之后添加一个命令,该命令将返回错误代码。例如。那样:

    ${Python3_EXECUTABLE} script.py ${INPUT} > ${OUTPUT} || (rm -f ${OUTPUT} && /bin/false)
    

    不应使用 add_custom_command 的此类命令 VERBATIM 选项:使用该选项,CMake 会引用方括号(()),这会阻止 shell 将它们解释为用于分组目的。


    我希望构建系统在命令失败时自动删除 ${OUTPUT}

    请注意,CMake 本身不是构建系统,它只是为构建系统生成代码。

    例如,当 CMake 生成 Makefile 时,它​​ adds .DELETE_ON_ERROR target,因此 make 实用程序实际上会在失败时删除输出文件。

    看起来,Ninja 没有 Make 那样的功能。或者 CMake 在为 Ninja 生成代码时不使用此功能。

    【讨论】:

    • 添加 (rm -f ${OUTPUT} && /bin/false) 不起作用,因为 cmake 无法正确处理 (/bin/sh: 1: (: not found。还试图逃避它\( 或引用它但仍然无法正常工作。
    • 是的,CMake 在转义/引用事物方面“过于聪明”......也许,从 add_custom_command 调用中删除 VERBATIM 应该会有所帮助。
    • 删除 VERBATIM 有帮助。命令行变得很长,有没有办法在||之前换行?尝试转义行结尾 `\` 并尝试将整个命令放在多行字符串中,但均无效。
    • 您可以创建一个辅助脚本(在 bash、python 等中),它的名称类似于 redirect_output_smart.sh ${OUTPUT} ${Python3_EXECUTABLE} script.py ${INPUT}。该脚本将调用包装命令并将其输出重定向到给定文件。如果命令失败,脚本将删除该文件。