Reputation: 2270
I came across some odd behavior when using Make recently (v3.81).
Suppose I have the following Makefile:
FOOBAR = $(shell find nonexistentdirectory -iname "foobar" | tr '\n' ' ')
all:
@echo "Hi"
clean:
@echo "Hi again"
Seems straightforward enough, right? Notably, FOOBAR
is a "recursively-expanded variable", so it should not be evaluated until I refer to it. Note that I never refer to it. Also note that nonexistentdirectory
does not exist as you might expect.
Now suppose I set FOOBAR
in the shell before I invoke a Make target:
compy386$ FOOBAR="stuff" make clean
find: nonexistentdirectory: No such file or directory
Hi again
Why is FOOBAR
being evaluated? Clearly it has something to do with the fact that the variable is defined in the shell. Am I supposed to anticipate that a user might have set variables in their shell? What am I doing wrong here?!
Upvotes: 7
Views: 2218
Reputation: 241971
FOOBAR
is being evaluated because you are running a recipe (for clean
) and FOOBAR
existed in the environment on entry to make
. Because FOOBAR
existed in the environment on entry, it becomes an exported variable, which means that make
will provide it as part of the environment to any program in the recipe. make
doesn't special-case echo
; it just uses the one found in your path. And it can't know whether or not that utility will reference a particular environment variable, so it has to export all exported variables, which means it has to evaluate FOOBAR
.
(For the official word, see the third paragraph of Variables from the Environment in the make manual. Also see the recipe on recursive make invocation.)
To answer the direct question, you can tell make
to ignore the fact that a variable came from the environment, so that it doesn't re-export it, by unexporting it:
unexport FOOBAR
Upvotes: 3
Reputation: 8829
Add a ?
before the =
like:
FOOBAR ?= $(shell find nonexistentdirectory -iname "foobar" | tr '\n' ' ')
This will use the environment variable if set and only evaluate if unset or empty.
Upvotes: 0