0
votes

I've bumped up against an unexpected oddity in GNU Make and can't find a way to configure it sanely. I'm assigning SHELL to a custom shell of my own design, but the problem with what variables are exported is readily reproducibly with a simple bash shell:

SHELL := /bin/bash

export FOO := bar

.PHONY: all a b c

all: a b

a:
    @echo A: $$(env | grep FOO)

b:
    @echo B: $(shell env | grep FOO)

c:
    @echo === main target ===
    @echo $$(env | sed -e 's/=.*//')
    @echo === shell function ===
    @echo $(shell env | sed -e 's/=.*//')

This produces a somewhat unexpected result:

$ make
A: FOO=bar
B:
$ FOO=baz make
A: FOO=bar
B: FOO=baz

As documented in communicating variables the exported FOO variable is exposed as an environment variable to the shell that runs lines in a recipe. What is unexpected is that the shell function does not get the same treatment! In fact a quick look at what turns up in make c there are several variables that just don't get passed through. I could work around this for every variable by manually passing it in (e.g. $(shell FOO="$(FOO)" env)) but that gets silly (and dangerous) fast.

This is particularly problematic because the variable I was hoping to export is PATH. The fact that shells building my targets have one PATH‌ variable while anything is run in a shell function has a different PATH is problematic. If you look at the complete env

How can I‌ mark some variables from my Makefile environment so that they get automatically passed as part of the environment to shells run from the shell function?

1
You can't. No make-exported values are ever passed to the shell function.MadScientist
Buggers. @MadScientist Is there a way to set a different SHELL value for targets vs. the shell function?Caleb
Sorry, I don't understand the question. You can specify a different value for SHELL using target-specific variables... is that what you want?MadScientist
@MadScientist I realize I can change the per-target value for SHELL, but that changes both the shell used to run the recipe and the shell used to run $(shell ...) functions. I was hoping to change them independently...one for running recipes and one for functions. I could use that to bootstrap all my shell functions with the necessary environment.Caleb
There is no way to control which shell is invoked by $(shell ...) separately from the shell invoked for recipes.MadScientist

1 Answers

0
votes

As noted by @MadScientist, the $(shell ...) is not passed exported variables. Depending on the situation, if the number of environment variables is known, possible to use explicit variables to the shell command. e.g.

c:
    @echo === shell function ===
    @echo $(shell FOO=$FOO env | sed -e 's/=.*//')

Of course, this solution assumes that the it is possible to enumerate all the variables to be passed down, and that the number of variables is reasonably small, otherwise the code will get ugly.

As an alternative, consider using a temporary file, instead of make values to pass values

c:
    # env var are set, store result in var.txt
    do-something > var.txt
    # Uses the result of the previous step, from var.txt
    step2 $$(cat var.txt)