bugmake - Bugs: bug #40431, .SHELLFLAGS is passed to shell as...

 
 

bug #40431: .SHELLFLAGS is passed to shell as single argument.

Submitter:  Van de Bugger <van_de_bugger>
Submitted:  Wed 30 Oct 2013 09:15:32 PM UTC
   
 
Severity:  3 - Normal Item Group:  None
Status:  Duplicate Privacy:  Public
Assigned to:  None Open/Closed:  Closed
Component Version:  3.82 Operating System:  POSIX-Based
Fixed Release:  None Triage Status:  None
* Mandatory Fields

Add a New Comment Rich Markup
   

Sun 03 Nov 2013 08:40:05 PM UTC, comment #3: 

First, having -e enabled by default for recipes is a requirement of the latest POSIX spec.  GNU make by default adheres to the previous POSIX spec in this respect, where -e was required to NOT be present.  I'm not willing to break backward-compatibility in this way, even if POSIX doesn't care.  If you use the .POSIX: pseudo-target to request POSIX-compatibility mode, then -e will be enabled by default and you don't need to change .SHELLFLAGS.

Second, the behavior of .SHELLFLAGS with multiple options is correct in the currently released version of GNU make (4.0):


$ cat Makefile
.SHELLFLAGS = -e -c
.ONESHELL :
all :
        false
        echo "OK"

$ make
false
echo "OK"
Makefile:4: recipe for target 'all' failed
make: *** [all] Error 1


Third, make's standard shell is /bin/sh, not bash.  The POSIX shell does not support flags such as -o pipefail and when bash is invoked as /bin/sh, it does not either:


$ /bin/sh -e -o pipefail -c "echo hi"
/bin/sh: 0: Illegal option -o pipefail


So, if you want to use bash features in your makefiles then you  must specifically request bash as the shell:


$ cat Makefile
SHELL = /bin/bash
.SHELLFLAGS = -o pipefail -e -c
.ONESHELL :
all :
        false | true
        echo "OK"

$ make
false | true
echo "OK"
Makefile:5: recipe for target 'all' failed
make: *** [all] Error 1


Paul D. Smith <psmith>
Group administrator
Thu 31 Oct 2013 10:41:36 PM UTC, comment #2: 

Thanks, I also found this trick independently. Unfortunately the trick does not work. Or, stricly speaking, it works, but there is an unwanted side effect which makes it useless. Look:

# Note: in current shell pipefail is not set.
$ echo $SHELLOPTS
braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor
# Starting a new shell with "-o pipefail".
$ bash -o pipefail
# In nested shell pipefail is set.
$ echo $SHELLOPTS
braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor:pipefail
# Starting one more nested shell:
$ bash
# In gransson, pipefail is not set.
$ echo $SHELLOPTS
braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor

It looks like shell options (real shell options specified in command line) are not inherited.

Now let us try to set SHELLOPTS variable:

# In current shell pipefailis not set:
$ echo $SHELLOPTS
braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor
# Starting a nested shell with modified SHELLOPTS:
$ env SHELLOPTS=$SHELLOPTS:pipefail bash
# Here pipefail is set, as expected:
$ echo $SHELLOPTS
braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor:pipefail
# Starting one more nested shell:
$ bash
# And check pipefail: it is still set!
$ echo $SHELLOPTS
braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor:pipefail

Effect of SHELLOPTS is inherited. Practically it means that many third-party shell scripts invoked from make directly or indirectly will not work, because they do not expect pipefail (or erexit).

In my real makefile there is a command:

rpmbuild -bb foo.spec

With

SHELLOPTS += pipefail:errexit

rpmbuild fails with no meanigful message. It reports something like this: "%install return non-zero status". I spend sometime to debug an issue and found that problem is in /usr/lib/rpm/check-buildroot script (it is an internal part of rpmbuild). It executes:

find ... | grep ... > $tmp

Grep finds nothing, returns status 1, and bash exits the script prematurely.

Thus, setting SHELLOPTS is not an option. :-(

Van de Bugger <van_de_bugger>
Thu 31 Oct 2013 04:30:45 AM UTC, comment #1: 

This isn't the fix you were looking for, but for the record I think placing:

export SHELLOPTS = pipefail

in the makefile would solve your particular problem. The SHELLOPTS variable is read-only to bash so it cannot be set within the shell, thus the only way to get this behavior is with set -o pipefail, but you can modify and export SHELLOPTS from a non-bash parent process (such as make).

David Boyce <boyski>
Wed 30 Oct 2013 09:15:32 PM UTC, original submission:  

I am trying to use .ONESHELL. I want shell to stop executing commands as soon as a command returns non-zero status. Here is my test Makefile:

.ONESHELL :
all :
false
echo "OK"

Ok, the test:

$ make
false
echo "OK"
OK

Oops, false returns non-zero status, but shell continues, it's bad. "set -e" as the first command of the recipe helps, but it is too boring and error-prone to add a command to every recipe. Let us try .SHELLFLAGS -- it seems it is what I need:

.SHELLFLAGS = -e -c

Oops:

$ make
false
echo "OK"
/bin/sh: - : invalid option
make: * [all] Error 1

Error message is rather unclear. "-" is an invalid option? Ok, let us try another variant:

.SHELLFLAGS = -ec

$ make
false
echo "OK"
make: * [all] Error 1

Ok, good. But it seems make treats value of .SHELLFLAGS as single argument. It may be suitable in simple cases, but it is not good in more complex scenarios.

Now let us try solve another task: Stop execution if any command in pipe fails. Here is modified Makefile:

.ONESHELL :
.SHELLFLAGS = -ec
all :
false | true
echo "OK"

By default, status of pipe is a status of the last command. Thus, "true" will hide a problem occurred before, and execution will continue:

$ make
false | true
echo "OK"
OK

I want the process stopped. It could be done by bash command

set -o pipefail

(All the commands in pipe will be completed, but execution will not go further.) Unfortunately, there is no short one-letter option to enable pipefail which can be bundled with -ec. The only way to enable pipefail is "-o pipefail", but

.SHELLFLAGS = -o pipefail -ec

does not work.

Resume: I think it would be helpful if make splits value of .SHELLFLAGS into words and pass every word to shell as a separate argument.

Van de Bugger <van_de_bugger>

 

(Note: upload size limit is set to 16384 kB, after insertion of the required escape characters.)

Attach Files:
   
   
Comment:
   

No files currently attached

 

Depends on the following items: None found

Items that depend on this one: None found

 

Carbon-Copy List
  • -email is unavailable- added by psmith (Posted a comment)
  • -email is unavailable- added by boyski (Posted a comment)
  • -email is unavailable- added by van_de_bugger (Submitted the item)
  •  

    There are 0 votes so far. Votes easily highlight which items people would like to see resolved in priority, independently of the priority of the item set by tracker managers.

    Only logged-in users can vote.

     

    Follow 2 latest changes.

    Date Changed by Updated Field Previous Value => Replaced by
    2013-11-03 psmith StatusNone Duplicate
        Open/ClosedOpen Closed

    Back to the top

    Powered by Savane 3.13-02a9.
    Corresponding source code