The Basics: Getting environment variables into GNU Make

[article]

Makefile:

FOO=bar

all:

    @echo FOO is $$FOO

If you run this with FOO undefined in the environment you'll see the output FOO is.  Without specifically exported FOO into the environment its value is not set in the environment used when GNU Make runs the echo command for the all rule.

If FOO had been set to foo in the environment before GNU Make was run you would see the output FOO is bar.  FOO has picked up the value inside the Makefile, but has been placed in the environment because it was already present.

If you are not sure whether FOO is in the environment, but want to ensure that it does make its way into the environment used for commands use the export
directive (see [url http://www.gnu.org/software/make/manual/html_node/Variables_002fRecursio...
for more on export). 

For example, we can ensure that FOO appears in the environment of sub-processes like this:

export FOO=bar

all:

    @echo FOO is $$FOO

Alternatively, you can just put export FOO on a line by itself. 

On the other hand, you can remove a variable from the environment with unexport.   To ensure that FOO is excluded from the sub-process environment (no matter whether it was set or not in the parent environment) do the following:

FOO=bar

unexport FOO

all:

    @echo FOO is $$FOO

Run that and you'll always see the output FOO is.

You might be wondering what happens if you export and unexport a variable.  The answer is that the last directive wins.

The export and unexport directives can also be used with target-specific variables to modify the environment just for a particular rule.  For example, here I'm setting FOO to just for all and bar for any other rule:

export FOO=bar

all: export FOO=just for all

all:

   @echo FOO is $$FOO

You can't remove FOO environment of a specific rule with a target-specifc unexport.  If you write all: unexport FOO you'll get an error.

I also said that GNU Make adds a number of variables to the sub-process environment.  Specifically, GNU Make adds MAKEFLAGS, MFLAGS and MAKELEVEL to the environment.  For more detail on those variables see http://www.gnu.org/software/autoconf/manual/make/Options_002fRecursion.html.

There are also ways to get every single Makefile variable exported (either by writing export on a line on its own, or by specifying .EXPORT_ALL_VARIABLES:), but these shotgun approaches are probably a bad idea as the sub-process environment will be filled with useless (and perhaps harmful) variables.

The Gotcha: $(shell) doesn't have the same environment as a sub-process

You might expect that the environment used by a call to $(shell) would be the same as that used in the execution of a rule's commands.  In fact, the environment used by $(shell) is exactly the same as the environment when GNU Make was started.

You can verify this with the following Makefile that gets the value of FOO from within a $(shell) and a rule (here I ran it with FOO set to foo in the parent environment):

export FOO=bar

$(warning $(shell printenv | grep FOO))

all:

   @printenv | grep FOO

That outputs:

Makefile:3: FOO=foo

FOO=bar

No matter what you do $(shell) gets the parent environment.

This is, in fact, a bug in GNU Make (it's bug #10593, see http://savannah.gnu.org/bugs/?10593 for details).  Part of the reason this hasn't been fixed is that the obvious solution ('just do whatever you do for a rule') has a rather nasty consequence.  Suppose, I do the following:

export FOO=$(shell echo fooey)

all:

    @echo FOO is $$FOO

What's the value of FOO in the rule for all?  In order to get the value of FOO in the environment for all it has to be expanded

About the author

John Graham-Cumming's picture John Graham-Cumming

John Graham-Cumming is Co-Founder at Electric Cloud, Inc . Prior to joining Electric Cloud, John was a Venture Consultant with Accel Partners, VP of Internet Technology at Interwoven, Inc. (IWOV), VP of Engineering at Scriptics Corporation (acquired by Interwoven), and Chief Architect at Optimal Networks, Inc. John holds BA and MA degrees in Mathematics and Computation and a Doctorate in Computer Security from Oxford University. John is the creator of the highly acclaimed open source POPFile project. He also holds two patents in network analysis and has others pending.

AgileConnection is one of the growing communities of the TechWell network.

Featuring fresh, insightful stories, TechWell.com is the place to go for what is happening in software development and delivery.  Join the conversation now!

Upcoming Events

Sep 22
Sep 24
Oct 12
Nov 09