不使用时.ONESHELL
Makefile 在单独的 shell 中执行每个 shell 命令。这样做有什么好处呢?为什么 makefile 不使用相同的 shell?
答案1
不在单个 shell 实例中运行与收据关联的所有命令的原因之一是 无法检测到其中一个命令的失败make
。仅将 shell 的最终退出状态提供给make
.必须另外设置.SHELLFLAGS
以-e
使 shell 在出现错误时尽早终止(这是多命令 shell 调用所必需的,即使.ONESHELL
它们不存在)需要在第一个错误时失败)。
SHELL
对于POSIX shell来说,这一切都很好。 Makefile 还可以设置SHELL
为例如/usr/bin/perl
、/usr/bin/python
或其他一些命令解释器。那么使用 可能合适,也可能不合适.ONESHELL
。
进行.ONESHELL
默认行为make
也可能会破坏旧的 Makefile。
尽管这不是与 POSIX 标准或 GNU 对该标准的遵守情况相关的问题make
,POSIX 规范make
关于当前的问题有这样的说法:
某些高级版本中的默认设置
make
是将目标的所有命令行分组并使用单个 shell 调用来执行它们;System V 方法是将每一行单独传递到一个单独的 shell。单壳方法具有性能上的优势并且不需要许多连续线。然而,转换到这种较新的方法导致了许多历史 makefile 的可移植性问题,因此 POSIX makefile 的行为被指定为与 System V 相同。建议将特殊目标.ONESHELL
用作实现扩展,以实现一个目标或一组目标的单 shell 分组。
GNUmake
在这方面符合 POSIX,因为它实现了 System V 行为和如果需要,提供.ONESHELL
启用替代行为的目标。 ...这是 GNUmake
保持当前行为的另一个原因。
答案2
.ONESHELL
是 GNU 供应商特定的扩展,不可移植,也不属于 POSIX 标准的一部分。
POSIX 标准中没有这一点的原因很可能是迄今为止只有一种实现支持它。
这不是标准默认值的原因更容易解释:
POSIX 试图标准化现有的行为,并且 POSIX 不喜欢使现有的原始 UNIX 实现与标准发生冲突 - 除非特定行为可以被视为明显的设计错误。
Stuart Feldman 在 1977 年的最初make
实现在单独的 shell 中调用操作列表中的每一行sh -ce cmdline
,这已成为所有后来实现的主要实现make
。
.ONESHELL
但即使是 GNU 实现(单独参见)在生效时也并非没有问题。原因是GNU make-e
在调用命令时没有设置shell的标志。这会导致多行 shell 脚本在.ONESHELL
发生错误时无法终止。
除此之外,我认为没有什么好处.ONESHELL
:
make
多行 shell 脚本可以通过 make 文件中的反斜杠换行序列在内部使用。性能参数不适用于现代
make
实现,因为现代实现尝试避免在命令行不包含 shell 特定元字符的情况下调用 shell。我的
smake
实现甚至实现了对该echo
命令的内联支持,以防它是一行中的第一个命令,echo
后面仅跟一个分号和一个简单的其他命令。这避免了 90% 以上的情况下都不需要调用 shell。