在makefile中处理管道及其退出状态的最佳方法

joz*_*yqk 13 linux bash makefile

如果命令失败make,例如gcc,它退出...

gcc
gcc: fatal error: no input files
compilation terminated.
make: *** [main.o] Error 4
Run Code Online (Sandbox Code Playgroud)

但是,如果我有一个管道,则会获取管道中最后一个命令的退出状态.举个例子,gcc | cat因为cat成功不会失败.

我知道整个管道的退出代码存储在PIPESTATUS数组中,我可以得到错误代码4 ${PIPESTATUS[0]}.我应该如何构建我的makefile来处理管道命令并在正常情况下退出失败?


在评论中,另一个例子是gcc | grep something.在这里,我假设最理想的行为仍然是,gcc并且只会gcc导致失败,而不是grep如果它没有找到任何东西.

Eta*_*ner 9

你应该能够告诉make使用bash,而不是sh和让bashset -o pipefail设定,因此在管道中的第一次失败退出.

GNU Make3.81(并且可能更早,虽然我不确定)你应该能够做到这一点SHELL = /bin/bash -o pipefail.

GNU Make3.82(及更新版本)中,您应该可以使用SHELL = /bin/bash.SHELLFLAGS = -o pipefail -c(虽然我不知道是否需要添加-c到最后,或者即使指定时make也会为您添加.SHELLFLAGS.

bash手册页:

除非启用了pipefail选项,否则管道的返回状态是最后一个命令的退出状态.如果启用了pipefail,则管道的返回状态是以非零状态退出的最后(最右侧)命令的值,如果所有命令都成功退出,则返回零.如果保留字!在管道之前,该管道的退出状态是如上所述的退出状态的逻辑否定.shell在返回值之前等待管道中的所有命令终止.

  • 如果只需要 make 中的一行,[`set -o pipelinefail ; 海湾合作委员会 | cat`](http://stackoverflow.com/a/19804002/1888983) 是等效的。 (2认同)
  • 我个人认为任何使用 `gcc | 的东西 makefile 规则上下文中的 grep` 已经走错方向了。 (2认同)

Syl*_*oux 6

我会去的pipefail.但是如果你真的不想要(或者如果你只想在第一个进程中失败 - 不管其他管道出现故障):

SHELL=bash

all:
        gcc | cat ; exit "$${PIPESTATUS[0]}"
Run Code Online (Sandbox Code Playgroud)

与@jozxyqk自我回答相比,唯一的优点是您不会丢失退出状态代码.