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 .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 .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 the echo command in case that it is the first command in a line is echo 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.

Tags:

Shell

Gnu

Make