为什么我得到 "Makefile:1: *** missing separator. Stop." 而 "set -e"?

Why do I get "Makefile:1: *** missing separator. Stop." with "set -e"?

我有一个 单行 Makefile 抛出以下错误:Makefile:1: *** missing separator. Stop。我知道 dozens of duplicate questions 有相同的错误消息,但其中大多数建议与不使用制表符或神秘的特殊字符有关。

$ cat -e -v -t Makefile 
set -e$

$ make
Makefile:1: *** missing separator.  Stop.

据我所知,没有神秘的特殊字符。也许有些字符 cat -e -v -t 没有显示?

以下工作正常,所以我猜这不是我的 make 安装的问题:

$ cat -v -e -t Makefile 
foo:$
^Iecho "Foo"$

$ make
echo "Foo"
Foo

一些相关版本和shell信息。

$ make --version
GNU Make 3.81

$ echo [=14=]
-bash

编辑:查看@AProgrammer 的评论

请注意,无论我在 set -e 下面有什么,它都会抛出相同的错误消息。

$ cat -e -v -t Makefile 
set -e$
$
foo:$
^Iecho "foo"$

$ make
Makefile:1: *** missing separator.  Stop.

编辑 2:

注意添加 #!/bin/bash 会引发相同的错误消息。

$ cat -e -v -t Makefile 
#!/bin/bash$
set -e$
$
foo:$
^Iecho "foo"$

$ make
Makefile:2: *** missing separator.  Stop.

编辑 3:

运行 set -e 在我的 shell 上似乎直接工作(它按预期退出失败的 make 调用)。

$ set -e
$ make
Makefile:2: *** missing separator.  Stop.
Saving session...completed.
Deleting expired sessions...11 completed.

[Process completed]

绝对没有理由 make 能够在规则之外解释任意 shell 命令。

如果你想在出现错误时立即退出规则,有几种方法可以做到,或多或少是可移植的。

首先,规则中的每一行都由 shell 的单独实例执行。这意味着如果您不手动合并它们(使用 \;),如果每行一个命令,您将获得所需的行为。

然后您可以使用 set -e 作为可能需要它的少数规则的一部分。例如;

foo:
        set -e; for i in a b c d; mkdir $$i; done

使用 GNU Make,您可以更改用于调用 shell 的标志,另外传递 -e:

.SHELLFLAGS=-ec

用POSIXmake,可以改成shell。我不知道是否支持传递标志,但 GNU Make 似乎支持:

SHELL=/bin/sh -e

但您始终可以传递一个包装器,根据需要设置标志:

SHELL=/path/to/mywrapper

其中 mywrapper

#!/bin/sh
exec /bin/sh -e "$@"