Subject: make -j and failure modes
To: None <,>
From: James Chacon <>
List: tech-userlevel
Date: 12/09/2003 15:33:58
As folks have noticed (and PR#18573 documents), make -j doesn't stop correctly
on errors. At least in all cases.

The reason for this comes down to rules like the following:

        (cd ${.CURDIR} && make bar)
        (cd ${.CURDIR} && make bar2)

With non-compat mode (i.e. what -j turns make into) that gets turned into
a shell script and fed via stdin to sh -ev.

i.e. 1 script for all the commands. (which is a nice performance boost from
running a separate shell instance for each one).

Here's the catch. This is basically equiv to:

printf "(exit 1)\n(exit 0)\n" | sh -ev 

(and expecting the first command to fail which would be equiv to a multiline
make rule with the 1st one failing)

On NetBSD (and linux for those cross building) that returns:

(exit 1)
(exit 0)

On Solaris, FreeBSD (4.9) it returns:

(exit 1)

I would expect it to exit on error after the first command exits with non-zero.

According to SUSE3:

-e When this option is on, if a simple command fails for any of the reasons 
   listed in Consequences of Shell Errors or returns an exit status value >0,
   and is not part of the compound list following a while, until, or if 
   keyword, and is not a part of an AND or OR list, and is not a pipeline 
   preceded by the ! reserved word, then the shell shall immediately exit. 

I'm purely guessing here but bash (/bin/sh on my linux box) and our shell
seem to be taking the group command definition to mean -e has no effect.

My take is that's non-obvious behavior and probably /bin/sh should be looked
at and decided if that's correct.

In any case a solution for make -j needs to happen somewhere (and with
hosting on non-NetBSD hosts a reality the most portable method should be
considered of course)


1. Have make scan the command for parens and if it finds them, exec via
   the compat methods.
2. Fix sh to deal with group'd commands and -e. Then provide nbsh as a host
   tool and tell make to use it.
3. Go through all the Makefile's and change (... && ...) into .... && ...

(I'm leaning towards #2 but I need opinions/knowledge on whether sh is
doing the right thing or not.)