Share Environment Variables in GNU Make


I think writing up a cheat sheet for GNU Make and environment variables before Christmas is a good idea, right?

In GNU Make, by default a single line runs in its own shell. ie.

# Makefile
test1:
  export key=asdf
  # GNU make's variable appears as $(key) while bash environment variable appears as $${key}, as the $ needs to be escaped
  echo $${key}
  
# run it
make test1

# the value `asdf` doesn't get passed to the next line because the next line runs in a separate shell

We can use backslash to fake multi-line like this:

# Makefile
test1:
  export key=asdf; \
  echo $${key}
  
 # run it
 make test1
 asdf

With .ONESHELL directive multiple lines in one target run in a same shell, which I prefer a lot:

# Makefile
.ONESHELL

test1:
  export key=asdf
  echo $${key}
  
# run it
make test1
asdf

A shell environment variable can be accessed inside a Makefile as a make variable with same name, eg.:

# Makefile
test1:
  echo $(key)
  
# run it with the required environment variable
key=asdf make test1
asdf

Here it’s getting more interesting, as shell environment variables will be copied into its sub-shell, in this case the make command runs in a sub-shell of current session. However if an environment variable is set in one target, the result is not available in a sibling target or its parent target. eg.:

# Makefile
test1:
  export key=asdf
  
test2: test1
  echo $${key}
  
# run it, can you guess the result?
make test2

# yep, blank again. the `test1` target in `test2` runs in a sub-shell and doesn't share environment variables with `test2`

To let test1 “export” environment variables to test2 target, I learned that eval command is quite handy in this situation:

# Makefile
.ONESHELL
test1:
  echo export key=asdf
  
test2:
  eval $$(make test1)
  echo $${key}
  
# run it
make test2
asdf

The reason this works is that the eval command will construct a new shell command using the arguments it gets, in this case, it’s export key=asdf from the output of test1 target. Then by running it, the value ‘asdf’ has been assigned to the variable ‘key’.

Hope this helps 🙂