GNU Makefile 中的进程替换

GNU Makefile 中的进程替换

在 bash 提示符下,可以使用伪文件执行 diff:

diff <(echo test) <(echo test)

将其按原样添加到 Makefile 中失败:

all:
        diff <(echo test) <(echo test)

错误(提示:/bin/sh 指向该系统上的/bin/bash):

/bin/sh: -c: line 0: syntax error near unexpected token `('
/bin/sh: -c: line 0: `diff <(echo test) <(echo test)'

这是什么意思?有没有办法在不使用临时文件的情况下仍然比较两个输出?

答案1

/bin/sh可能bash在您的系统上,但当作为 调用时shbash将以 POSIX 模式运行(就好像POSIXLY_CORRECT已定义,或者以 启动--posix)。

在此模式下,不存在进程替换。

解决方案:

  1. 使用显式临时文件:

    all:
        command1 >tmpfile
        command2 | diff tmpfile -
        rm -f tmpfile
    
  2. 使用bash -c内联脚本:

    all:
        bash -c 'diff <(command1) <(command2)'
    
  3. 将 Makefile 变量定义SHELL为(或系统上的/bin/bash任何路径):bash

    SHELL=/bin/bash
    

如果您想要便携性,请选择第一个解决方案。如果您可以接受对 的依赖bash,请选择第二个。如果您另外不需要关心非 GNUmake实现,请使用第三种。


关于设置SHELL: POSIX 标准规定 Makefile 中的可执行文件应该system()由 .c 库函数调用make。该函数不保证使用SHELL环境变量(事实上,标准不鼓励这样做)。该标准还详细说明设置 Makefile 变量SHELL不应影响环境变量 SHELL。然而,在我所知道的大多数实现中make,Makefile 变量SHELL将用于执行命令。

中的建议make该实用程序的基本原理是使用bash -c

历史MAKESHELL特征以及其他make实现提供的相关特征被省略。在某些实现中,它用于让用户覆盖用于运行make命令的 shell。这很令人困惑;对于便携式make,shell 应由 makefile 编写者选择。此外,makefile 编写者不能要求使用备用 shell 并仍然认为 makefile 是可移植的。虽然可以标准化指定备用 shell 的机制,但现有的实现并不同意这种机制,并且 makefile 编写者已经可以通过在目标规则中指定 shell 名称来调用备用 shell;例如:

python -c "foo"

相关内容