Shell – Makefile and .ONESHELL

gnumakeshell

When .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?

Best Answer

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.

Related Question