ChatGPT解决这个技术问题 Extra ChatGPT

如何在 Makefile 目标中使用 Bash 语法?

我经常发现 Bash 语法非常有用,例如 diff <(sort file1) <(sort file2) 中的进程替换。

是否可以在 Makefile 中使用此类 Bash 命令?我在想这样的事情:

file-differences:
    diff <(sort file1) <(sort file2) > $@

在我的 GNU Make 3.80 中,这将给出一个错误,因为它使用 shell 而不是 bash 来执行命令。

这正是我的问题,我花了至少一个小时才找到这个问题!我将错误消息留在这里,以便未来的读者可以找到它:/bin/sh: -c: line 0: syntax error near unexpected token ('`

J
Jens

GNU Make documentation

5.3.2 Choosing the Shell
------------------------

The program used as the shell is taken from the variable `SHELL'.  If
this variable is not set in your makefile, the program `/bin/sh' is
used as the shell.

所以把 SHELL := /bin/bash 放在你的 makefile 的顶部,你应该很高兴。

顺便说一句:您也可以为一个目标执行此操作,至少对于 GNU Make。每个目标都可以有自己的变量赋值,如下所示:

all: a b

a:
    @echo "a is $$0"

b: SHELL:=/bin/bash   # HERE: this is setting the shell for b only
b:
    @echo "b is $$0"

那将打印:

a is /bin/sh
b is /bin/bash

有关更多详细信息,请参阅文档中的“目标特定变量值”。该行可以放在 Makefile 中的任何位置,它不必紧挨在目标之前。


500 赏金正在等待 man 的报价。谈论时间。 :P
@inLoveWithPython 嗯,info,实际上,但是,我想它确实帮助了安迪。我知道我有过这样的日子...
如果有疑问,@derobert 的字面意思是:SHELL=/bin/bash 作为 Makefile 的第一行(或在评论之后)。
如果您使用 /usr/bin/env bash,它将使用 PATH 中的 bash。但是如果它只是 SHELL := bash 呢?
如果您尝试从 makefile 执行 $(info $(SHELL)) 并查看 /bin/bash 可能会发生的一些混淆,还有一个注意事项:它没有任何意义! GNU Make 从环境中继承变量,因此 SHELL 变量来自环境,但是$(origin SHELL)environment(我的猜测)时它不会使用它。
C
Chris Lutz

您可以直接调用 bash,使用 -c 标志:

bash -c "diff <(sort file1) <(sort file2) > $@"

当然,您可能无法重定向到变量 $@,但是当我尝试执行此操作时,我收到 -bash: $@: ambiguous redirect 作为错误消息,因此您可能需要在深入了解之前先调查一下(尽管我正在使用 bash 3.2.something,所以也许你的工作方式不同)。


N
Nicolas Marshall

一种可行的方法是将它放在目标的第一行:

your-target: $(eval SHELL:=/bin/bash)
    @echo "here shell is $$0"

M
Menno Smits

如果可移植性很重要,您可能不想依赖 Makefile 中的特定外壳。并非所有环境都有 bash 可用。


p
paxdiablo

您可以直接在 Makefile 中调用 bash 而不是使用默认 shell:

bash -c "ls -al"

代替:

ls -al

请注意,make 忽略环境变量 SHELL 的值。
B
Bill G

有一种方法可以做到这一点,而无需将您的 SHELL 变量显式设置为指向 bash。如果您有许多 makefile,这会很有用,因为 SHELL 不会被后续的 makefile 继承或取自环境。您还需要确保编译您的代码的任何人都以这种方式配置他们的系统。

如果您运行 sudo dpkg-reconfigure dash 并对提示回答“否”,您的系统将不会使用破折号作为默认 shell。然后它将指向 bash(至少在 Ubuntu 中)。请注意,使用破折号作为系统外壳会更有效。


当以名称 sh 调用时,bash 以兼容模式 (set -o posix) 运行。 OP 尝试使用的功能(进程替换)在此模式下不可用。
I
Ilya Bystrov

这不是问题的直接答案,makeit 是有限的 Makefile 替换为 bash 语法,在某些情况下它可能很有用(我是作者)

规则可以定义为 bash 函数

自动完成功能

基本思想是在脚本末尾有 while 循环:

while [ $# != 0 ]; do
  if [ "$(type -t $1)" == 'function' ]; then
    $1 
  else
    exit 1
  fi 
  shift
done

https://asciinema.org/a/435159

https://asciinema.org/a/Nvx7QOvUyMnZc8MVfKk2xETnj.svg


顺便说一句,您在回答中披露您是链接项目的作者是一条规则。