How to Pass Env Variables Between Make Targets

How can i pass ENV variables between make targets

By default make invokes a new shell environment for each recipe, the exported variable on the first line isn't in scope for the second.

You can fix this in multiple ways:

Export the variable with make's export directive

target1: export var1 := test
target1:
$(MAKE) target2

Use make's command line variable assignment

target1:
$(MAKE) target2 var1=test

Use shell command variable assignment

target1:
var1=test $(MAKE) target2

Combine the two commands in a single recipe

target1:
export var1=test; $(MAKE) target2

Force make to pass all recipes to the same shell instance

.ONESHELL:

target1:
export var1=test
$(make) target2

Pass environment variables to dependent targets in Makefile

I ended up doing the following:

.PHONY: lint test teamcity

lint:
# commands here

test:
# commands here

teamcity: export TEAMCITY_VERSION=1
teamcity: lint test

Here TEAMCITY_VERSION is declared as a target-specific variable, and the export directive exports it into the environment for prerequisite targets.

How to set child process' environment variable in Makefile

Make variables are not exported into the environment of processes make invokes... by default. However you can use make's export to force them to do so. Change:

test: NODE_ENV = test

to this:

test: export NODE_ENV = test

(assuming you have a sufficiently modern version of GNU make >= 3.77 ).

exporting env variables from a common target to all targets in Makefile

Just don't put the assignments in a rule:

# file common.mk

export LD_LIBRARY_PATH=${MY_HOME}/LIBS:${LD_LIBRARY_PATH}
export MY_VERSION=2.2
...

and don't bother with the prerequisite setup:

#file Makefile

include ${MY_RUN_DIR}/common.mk
run:
# do something, such as
@echo my version is $$MY_VERSION

Passing additional variables from command line to make

You have several options to set up variables from outside your makefile:

  • From environment - each environment variable is transformed into a makefile variable with the same name and value.

    You may also want to set -e option (aka --environments-override) on, and your environment variables will override assignments made into makefile (unless these assignments themselves use the override directive . However, it's not recommended, and it's much better and flexible to use ?= assignment (the conditional variable assignment operator, it only has an effect if the variable is not yet defined):

    FOO?=default_value_if_not_set_in_environment

    Note that certain variables are not inherited from environment:

    • MAKE is gotten from name of the script
    • SHELL is either set within a makefile, or defaults to /bin/sh (rationale: commands are specified within the makefile, and they're shell-specific).
  • From command line - make can take variable assignments as part of his command line, mingled with targets:

    make target FOO=bar

    But then all assignments to FOO variable within the makefile will be ignored unless you use the override directive in assignment. (The effect is the same as with -e option for environment variables).

  • Exporting from the parent Make - if you call Make from a Makefile, you usually shouldn't explicitly write variable assignments like this:

    # Don't do this!
    target:
    $(MAKE) -C target CC=$(CC) CFLAGS=$(CFLAGS)

    Instead, better solution might be to export these variables. Exporting a variable makes it into the environment of every shell invocation, and Make calls from these commands pick these environment variable as specified above.

    # Do like this
    CFLAGS=-g
    export CFLAGS
    target:
    $(MAKE) -C target

    You can also export all variables by using export without arguments.

set env variable from a Makefile command and use in another Make command

Let me suggest this:

get_env ::
$(eval MY_ENV := $somevalue)

cmd_1 cmd_2 :: get_env
MY_ENV=$(MY_ENV) python myscript.py $@

Some explanations:

  • :: makes the targets phony, so you won't have to add a line .PHONY: get_env cmd_1 cmd_2 in the Makefile;
  • $@ is the current target

The key point is to add a dependency to get_env in the rule, so that MY_ENV is kept.

For a simpler trial, run make bar or make baz with this toy Makefile:

foo ::
$(eval qux := `pwd`)

bar baz :: foo
@echo "qux = $(qux) and target = $@"

Makefile environment variable for specific target

I would do it this way:

test: export GOOS=
test: export GOARCH=
test: fmt vet
go test ./...

workaround to make exporting environment variable from makefile possible

As Andreas says, there is no "workaround" for this. It's a fundamental feature of a POSIX operating system. The only way for the parent process (e.g. a shell) to have its environment modified is by doing something different than simply run make. If you're willing to do that, then you have options.

For example, if your makefile does this:

target:
@echo 'export VAR=test'

then in your shell you can do this:

$ eval $(make target)

and now that variable will be set. Of course, this will fail miserably if your makefile prints ANYTHING except valid shell syntax so you can only do a very limited set of things.

Alternatively you can have the makefile write stuff to a file then source the file, like this:

target:
echo 'export VAR=test' > target

then:

$ make target
$ . target


Related Topics



Leave a reply



Submit