Makefile and .ONESHELL
One reason is that a failure in one of the recipe commands would not be detected by GNU make
. Only the final exit status of the shell would be given to make
. One would have to additionally set .SHELLFLAGS
to -e
to get the shell to terminate early upon errors (this is required for multi-command shell invocations even without .ONESHELL
if they need to fail at the first error).
This is all well and good for when SHELL
is a POSIX shell. A Makefile can also set SHELL
to e.g. /usr/bin/perl
or some other command interpreter. It may then be appropriate, or not, to use .ONESHELL
.
Making .ONESHELL
the default behaviour in make
would potentially break older Makefiles.
Even though this is not a question relating to the POSIX standard or the compliance to that standard by GNU make
, the Rationale of the POSIX specification for make
has this to say about the issue at hand:
The default in some advanced versions of
make
is to group all the command lines for a target and execute them using a single shell invocation; the System V method is to pass each line individually to a separate shell. The single-shell method has the advantages in performance and the lack of a requirement for many continued lines. However, converting to this newer method has caused portability problems with many historical makefiles, so the behavior with the POSIX makefile is specified to be the same as that of System V. It is suggested that the special target.ONESHELL
be used as an implementation extension to achieve the single-shell grouping for a target or group of targets.
GNU make
is POSIX compliant in this respect as it implements the System V behaviour and provides a .ONESHELL
target for enabling the alternative behaviour, if wanted. ... which is another reason for GNU make
to keep the current behaviour.
.ONESHELL
is a GNU vendor specific extension that is not portable and not part of the POSIX standard.
The reason why this is not in the POSIX standard is most likely that there is only one implementation so far that supports it.
The reason why this is not the default of the standard is easier to explain:
POSIX tries to standardize existing behavior and POSIX does not like to make existing original UNIX implementations being in conflict with the standard - except when a specific behavior can be seen as a clear design bug.
The original make
implementation from Stuart Feldman in 1977 called each line from the action list in a separate shell using sh -ce cmdline
and this has become the master for all later make
implementations.
But even the GNU implementation (seen separately) is not without problems when .ONESHELL
is in effect. The reason is that GNU make does not set the -e
flag of the shell when invoking commands. This causes a multi line shell script caused by .ONESHELL
not to be terminated when an error occurs.
Beyond that, I see few benefit for .ONESHELL
:
Multi line shell scripts may be used inside
make
by a backslash newline sequence in the make files.The performance argument does not apply to modern
make
implementations since modern implementations try to avoid to call the shell in case that the command line does not contain shell specific meta characters.My
smake
implementation even implements inline support for theecho
command in case that it is the first command in a line isecho
followed by only one semicolon and a simple other command. This avoids the need to call the shell for more than 90% of all cases.