1
votes

Make fails to export the 'SHELL' variable.

The docs reads:

Furthermore, when you do set 'SHELL' in your makefile that value is not exported in the environment to recipe lines that 'make' invokes. Instead, the value inherited from the user's environment, if any, is exported. You can override this behavior by explicitly exporting 'SHELL' (*note Communicating Variables to a Sub-'make': Variables/Recursion.), forcing it to be passed in the environment to recipe lines.

And further elsewhere, we have:

The value of the 'make' variable 'SHELL' is not exported. Instead, the value of the 'SHELL' variable from the invoking environment is passed to the sub-'make'. You can force 'make' to export its value for 'SHELL' by using the 'export' directive, described below.

ifeq "$(MAKELEVEL)" "0"

export SHELL

all:
    @$(MAKE)

else

all:
    @-foo;

endif


.PHONY: all

running as:

$ make SHELL=bash -e

We get:

make[1]: Entering directory '/home/myname'
/bin/sh: 1: foo: not found
makefile:13: recipe for target 'all' failed
make[1]: [all] Error 127 (ignored)
make[1]: Leaving directory '/home/myname'

If you take a close look at the 2nd line above, you'll see that the default (/bin/sh) shell executed the commands.

Now, that's despite of an explicit export on the SHELL variable, as advised by the docs, cited above. Why?

Make version is the latest!

1

1 Answers

1
votes

This is kind of odd. The problem is you're using -e (allow environment variables to override make variables). If you don't use that flag, then it works as expected.

When you do specify -e, then the sub-make does get the exported value of SHELL, and it does pass that value to its commands, but it uses /bin/sh itself to run commands.

Consider this makefile:

ifeq "$(MAKELEVEL)" "0"

export SHELL

all: ; @env | grep ^SHELL; $(MAKE)

else

$(info submake SHELL = $(SHELL))
all: ; @-env | grep ^SHELL; foo

endif

.PHONY: all

Now if we run without -e we get what we expect:

$ make SHELL=bash
SHELL=bash
submake SHELL = bash
SHELL=bash
bash: foo: command not found
Makefile:10: recipe for target 'all' failed
make[1]: [all] Error 127 (ignored)

But if we run with -e, then all is the same relative to exported SHELL values but the sub-make uses /bin/sh to run recipes:

$ make -e SHELL=bash
SHELL=bash
submake SHELL = /bin/sh
SHELL=bash
/bin/sh: foo: command not found
Makefile:10: recipe for target 'all' failed
make[1]: [all] Error 127 (ignored)

I'm not really sure why the -e has this effect; I'd need to look at the code.