Subject: Re: make -j and failure modes
To: Robert Elz <kre@munnari.OZ.AU>
From: James Chacon <jmc@NetBSD.org>
List: tech-userlevel
Date: 12/10/2003 10:45:04
On Wed, Dec 10, 2003 at 10:22:09PM +0700, Robert Elz wrote:
>     Date:        Wed, 10 Dec 2003 14:48:28 +0000 (GMT)
>     From:        Ben Harris <bjh21@NetBSD.org>
>     Message-ID:  <Pine.SOL.4.58.0312101410440.12032@draco.cus.cam.ac.uk>
> 
>   | On Wed, 10 Dec 2003, James Chacon wrote:
>   | 
>   | > The subshell should exit by normal rules and based on the fact that -e
>   | > transfers to it. (and return according to the rules for subshells
>   | > which is the exit code from the last command).
>   | >
>   | > Past that I think it's obvious then that the parent would exit as it's got
>   | > the e flag set and it just had a command exit non-zero and it's not part
>   | > of the exclusion list of ones to ignore for checking on error.
>   | 
>   | So you think that that the parent should treat the entire group of
>   | commands in the subshell as a single command, and exit if it fails, yes?
> 
> I think that's what he is saying, but I believe it is clearly wrong.
> 
> It is absurd to require the shell to look inside the commands run by the
> sub-shell and see if they're the kind that should cause "set -e" mode to
> cause the shell to exit - but not doing so would mean the parent shell exiting
> if the sub-shell exits with an error code, even though that error code didn't
> actually cause the sub-shell to exit 1 because of the -e.

Actually I was saying the parent shell would exit because the sub-shell
returned non-zero for *any* reason. At that point the sub shell is just
a process returning an exit code.


> That is, a couple of examples...
> 
> delta$ sh -ec 'false && echo foo'
> 
> no output, of course, false is false...
> 
> delta$ sh -ec 'false || echo foo'
> foo
> 
> the "false" does not cause the shell to exit, because it is in a ||

Both of these are excluded from -e tests anyways. It lists exceptions for
AND and OR.

> 
> sh -ec 'false && echo foo
> echo ok'
> ok
> 
> Same here, no "foo", no exit from the shell either.

As it shouldn't (due to the && exception)

> 
> delta$ sh -ec 'false || false'
> delta$ echo $?
> 1
> 
> Shell exit's 1 from this, but that's because false does exit 1, not
> because of -e

Again, not valid for -e as || is excepted.

...

> 
> But
> 
> delta$ sh -ec '(false && echo bad) ; echo ok'
> ok
> 
> what was being requested was that this one should not do the echo ("ok")
> because of the sub-shell doing the exit 1 (because of executing the
> false command, not because of set -e).

Why the subshell returned 1 is up to the subshell (it could very well have
turned off -e, that's it's business). The fact it returned a non-zero exit
code is what's important to the parent shell.

> 
> That's too dumb to contemplate, and attempting to write either the code,
> or the specification, to make anything different happen is way too complex
> to even consider.

For what reason? The command in question exited non-zero for some reason. 
Whatever the reason was it's concern. The parent process though is set to
exit (via -e) for anything that returns non-zero and this would meet that
criteria since it isn't in the exception list for -e.

> 
> The underlying problem here, in the original example, wasn't the sub-shell
> in any case, it was the "&&" - which clearly causes the -e to be ignored
> (whether the command that fails is the first, or second, in the && sequence).
> That much is beyond doubt.

No. It was the subshell exiting non-zero that's being ignored. Run a make rule
of

all:
        (false)
        echo foo

via make -j (which feeds that into sh -ev) and echo foo will be printed.
Not exactly expected behavior from make at all.

--- all ---
(false)
echo foo
foo

James