Michael Pankov
Michael Pankov

Reputation: 3701

Defining recursively expanded variable with same name as environment variable

I'm trying to lazily evaluate configuration option. I want to issue a Make error only if the variable is actually used (substituted).

Consider the following Makefile:

VAR = $(error "E")

NFS_DIR = NFS_DIR is $(VAR)

T = $(NFS_DIR) is 1

all:
    echo Test

If I run it with my environment (which has /srv/nfs value), the output is following:

➜  ~  make
echo Test
Makefile:3: *** "E".  Stop.

So the recursive definition acts like simple definition.

If I clear the environment, it works as expected:

➜  ~  env -i make  
echo Test
Test

I couldn't find any mention that recursively-expanded variable, when defined with same name as environment variable, will act like simply-expanded variable.

So the questions are:

  1. Why the observed behavior?
  2. How to implement the desired behavior?

Update: to clarify — I don't want to use ?= since the options are configuration options I want them to come strictly from Makefile and not from environment.

Upvotes: 0

Views: 1426

Answers (2)

ceztko
ceztko

Reputation: 15207

The question appear to be extremely clear in the title but the actual request get lost in details so the only other reply left it mostly unanswered. Directly answering to the question in the title, which is very interesting, to define a variable in a Makefile with same name as environment variable you can get its value with printenv:

PATH=${shell printenv PATH}:/opt/bin

echo:
    echo $(PATH)

Other techniques to achieve the same result without relying on evaluation with external commands are welcome.

Upvotes: 0

MadScientist
MadScientist

Reputation: 100836

Any variable which is in the environment when make starts, will be exported to the environment of any command make runs (as part of a recipe, etc.) In order for make to send the value of the variable to the command, make first has to expand it. It's not acting like a simply-expanded variable. It's just that running a command forces the expansion.

This is kind of a nasty side-effect but I'm not sure there's anything that can be done directly: this behavior is traditional and mandated by POSIX and lots of makefiles would break if it were changed.

You have two choices I can think of. The first is to use the unexport make command to tell make to not send that variable in the command's environment.

The second is to change the name of the variable in make to something that is not a valid environment variable: make will only export variables whose names are legal shell variables (contain only alphanumeric plus _). So using a name like VAR-local instead of VAR would do it.

Upvotes: 1

Related Questions