【问题标题】:How to set pipefail in a Makefile如何在 Makefile 中设置 pipefail
【发布时间】:2016-02-28 18:36:15
【问题描述】:

考虑这个 Makfile:

all: 
    test 1 -eq 2 | cat
    echo 'done'

它将被正确执行。

我听说过set -o pipefail,我可以这样使用:

all: 
    set -o pipefail;     \
    test 1 -eq 2 | cat;  \
    echo 'done'

除了它不起作用之外,这种写作非常痛苦。

另一种解决方案是使用临时文件。我想避免它。

我还可以使用什么其他解决方案?

【问题讨论】:

  • 第二个 sn-p 怎么不起作用?它应该可以正常工作(cat 显然在那里毫无意义)。还是您的意思是它不会阻止done 被回显?它没有这样做,因为没有任何东西告诉 shell 停止执行。这里只有一行而不是多行,因此 make 不能因 test 失败而终止(即使它传播到 | cat 之后)。删除 ; ` between cat` 和 echo,它会如你所愿。
  • 我的GNU Make 4.1没有任何错误
  • 使用您的示例代码,您不应该得到任何错误。 test 失败只是被忽略了。什么都看不到。您期望 make 看到它并使配方失败,但这仅发生在 entire 命令的返回码(通常是单行,但在您的情况下是串联的三行)。
  • 在我的用例中,我使用的是自制的 cksum 脚本,我通过管道将其输入dd -of=$@ -seek=$$(( $$(stat -c %s $@) - 4 ))。如果 cksum 失败,dd 也应该失败,我不应该执行其余的命令。
  • 或者使用两行 set -o pipefail; \ cksum ... | dd ... || exit 1echo done 而不将它们合并在一起。

标签: error-handling makefile pipe


【解决方案1】:

您可以强制 pipefail 作为 make 的 SHELL 调用的一部分 来自equivalent of pipefail in GNU make?

SHELL=/bin/bash -o pipefail

【讨论】:

  • 谢谢。这应该是这里公认的答案。对于Makefile 中的所有 shell 调用,简短、简洁并通常解决它。
【解决方案2】:

对于比单个命令更复杂的事情,我通常更喜欢使用脚本。这样你就可以完全控制解释器(通过shebang line),你可以把更复杂的命令放在一起,而不是试图把它硬塞进一行。例如:

Makefile:

all:
    ./my.sh

my.sh:

#!/usr/bin/env bash
set -o errexit -o pipefail
test 1 -eq 2 | cat
echo 'done'

也就是说,Makefile 命令块的退出代码(如您所拥有的那个)是 last 命令的退出代码,因为您使用 ; 分隔命令。 可以使用&& 只执行直到出现错误(相当于errexit),像这样:

set -o pipefail && test 1 -eq 2 | cat && echo 'done'

【讨论】:

  • 这可能是一个解决方案,但是您将拥有数十个与您的 Makefile 相关的脚本。那么,我想知道你是如何组织它的。
  • 像任何其他复杂的项目一样,您需要使复杂性易于管理。很多脚本各自做一件事通常比单个巨大的 makefile 更易于管理。
  • 你知道我可以从中获得灵感的优秀 GitHub 项目吗?
  • 我有一些makefile includes 用于其他各种项目,但我只是尽量保持简单。并确保尽可能使用真正的语言而不是 shell。代码可能会更长,但您会在可维护性和可测试性方面省去很多麻烦。
  • 这是我的问题。今天,我重写了一个用 Perl 编写的脚本,该脚本通过在每个文件的末尾添加校验和来分割文件,以便嵌入到目标中的 shell 脚本。我尝试了 Python,但它太慢了(比 Perl 慢大约 5-10 倍,有时比纯 shell 脚本慢。
猜你喜欢
  • 1970-01-01
  • 2016-03-07
  • 2019-06-01
  • 2016-06-27
  • 2015-11-26
  • 1970-01-01
  • 2020-12-23
  • 2019-03-23
  • 2012-06-07
相关资源
最近更新 更多