.ONESHELL is not used Makefile executes each shell commands in a separate shell. What is the benefit of this? Why doesn't makefile uses the same shell?
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
-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 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
makeis 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
.ONESHELLbe used as an implementation extension to achieve the single-shell grouping for a target or group of targets.
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.
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
But even the GNU implementation (seen separately) is not without problems when
.ONESHELLis 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
Multi line shell scripts may be used inside
makeby a backslash newline sequence in the make files.
The performance argument does not apply to modern
makeimplementations since modern implementations try to avoid to call the shell in case that the command line does not contain shell specific meta characters.
smakeimplementation even implements inline support for the
echocommand in case that it is the first command in a line is
echofollowed by only one semicolon and a simple other command. This avoids the need to call the shell for more than 90% of all cases.