Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to set Environment variables in Makefile - to be used after

I am trying to set an Environment variable in a Makefile, so it can be used in another program running in the sam shell as make, but after make has run.

Update: This is not possible according to accepted answer with comments.

Steps:

  1. run make test setting env: export TEST_ENV_ONE=OneString
  2. run another program, that can read TEST_ENV_ONE

Tried this:

Not working:

test:
    export TEST_ENV_ONE=OneString
    $(shell export TEST_ENV_TWO=TwoString)

Afterwards this is empty:

echo $TEST_ENV_ONE
echo $TEST_ENV_TWO
like image 579
Chris G. Avatar asked Aug 31 '18 11:08

Chris G.


2 Answers

Your export TEST_ENV_ONE=OneString above is running in a dedicated shell. The subsequent commands run in other shell instances. Therefore, they don't inherit the environment variable TEST_ENV_ONE.


You could use a top-level (i.e., not in a target's recipe) export directive in the makefile:

export env_var := MyEnvVariable

.PHONY: all
all:
    echo env_var: $$env_var

This way, the variable env_var is exported to the shells that will execute the recipes.

If you run make with the makefile above:

$ make
echo env_var: $env_var
env_var: MyEnvVariable

As you can see from the output, the shell that run echo env_var: $env_var had the variable env_var in its environment.

like image 134
ネロク・ゴ Avatar answered Sep 19 '22 15:09

ネロク・ゴ


If you want the environment variables to be exported to the shell from which you invoked make things are a bit difficult because, as explained by ネロク, you cannot directly export environment variables from a child process (make) to its parent process (the shell from which you invoke make). But if you accept to invoke make like this:

eval "$(make)"

then it is indeed possible: just echo export VARIABLE1=VALUE1; export VARIABLE2=VALUE2; ... in your recipe. Warning: you will also have to guarantee that nothing else gets echoed by make on the standard input. But you can use the standard error, instead. Example:

$ cat Makefile
export TEST_ENV_ONE := OneString

all:
    @printf 'make variable TEST_ENV_ONE = %s\n' "$(TEST_ENV_ONE)" 1>&2
    @printf 'in-recipe shell variable TEST_ENV_ONE = %s\n' "$$TEST_ENV_ONE" 1>&2
    @printf 'export TEST_ENV_ONE="%s"\n' '$(TEST_ENV_ONE)'

$ unset TEST_ENV_ONE
$ printenv TEST_ENV_ONE
$ eval "$(make)"
make variable TEST_ENV_ONE = OneString
in-recipe shell variable TEST_ENV_ONE = OneString
$ printenv TEST_ENV_ONE
OneString

Note that make more or less considers environment variables as make variables. From GNU make manual:

Variables in make can come from the environment in which make is run. Every environment variable that make sees when it starts up is transformed into a make variable with the same name and value. However, an explicit assignment in the makefile, or with a command argument, overrides the environment. (If the ‘-e’ flag is specified, then values from the environment override assignments in the makefile. See Summary of Options. But this is not recommended practice.)

So, unless the value of your variable is the result of complex computations by make itself, a much more natural way to obtain the same result would be to define the environment variable in the parent shell and to use it as is in the Makefile:

$ cat Makefile
all:
    @printf 'make variable TEST_ENV_ONE = %s\n' "$(TEST_ENV_ONE)"
    @printf 'in-recipe shell variable TEST_ENV_ONE = %s\n' "$$TEST_ENV_ONE"

$ export TEST_ENV_ONE=OneString
$ make
make variable TEST_ENV_ONE = OneString
in-recipe shell variable TEST_ENV_ONE = OneString
$ printenv TEST_ENV_ONE
OneString
like image 25
Renaud Pacalet Avatar answered Sep 17 '22 15:09

Renaud Pacalet