Subject: Re: make -j and failure modes
To: None <jmc@netbsd.org>
From: Ben Harris <bjh21@netbsd.org>
List: tech-userlevel
Date: 12/10/2003 00:40:45
In article <m2n.s.1ATpUq-000hYr@chiark.greenend.org.uk> you write:
>        (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 

Not quite correct.  It's closer to:

printf "(false)\n(true)\n" | sh -ev

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

Note "simple command".  A group like "(false)" is not a simple command.  The
command "false" is a simple command, but it's executed in a subshell
environment.

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

Not quite correct.  As an example (bash and NetBSD sh agree here too):

wraith:~$ bash -posix -e -c '(false; echo foo);(echo bar)'
bar

The "-e" option meant that the first "false" caused the subshell it was
executing in to exit, but the outer shell carried on, because the command
that it saw fail was a compound command.

>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 .... && ...

That will mean that the directory change is still in effect for the next
command, which is precisely what the parens are there to avoid.  I'd
suggest:

4. Change all (foo && bar) to (foo && bar) || exit $?

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

I think both behaviours are arguably correct, and since it's not terribly
hard (if slightly ugly) to write scripts that cope with both, we should just
do that.

-- 
Ben Harris                                                   <bjh21@NetBSD.org>
Portmaster, NetBSD/acorn26           <URL:http://www.NetBSD.org/Ports/acorn26/>