I have a bash shell script which I usually source into my shell, with lots of environment variables defined, which are not exported. I do not want to:
I would like to source the same shell script into the environment of the makefile, so that I can access those variables. Is this possible? How can I do that? Ideally I would do in the makefile:
source setup-env.sh
There is not source
command for makefiles, but maybe something equivalent? Any special hack I can use to simulate the same effect?
So put SHELL := /bin/bash at the top of your makefile, and you should be good to go. See "Target-specific Variable Values" in the documentation for more details. That line can go anywhere in the Makefile, it doesn't have to be immediately before the target.
If you've not exported the environment variable, it is not accessible until you do export it, or unless you pass it explicitly on the command line: make DEMOPATH="${demoPath}" … If you are using a C shell derivative, substitute setenv demoPath /usr/local/demo for the export command.
Commands and executionIf you want a string to have a dollar sign, you can use $$ . This is how to use a shell variable in bash or sh . Note the differences between Makefile variables and Shell variables in this next example.
As per the additional question in the comment, here is one way to effectively mark the whole environment as exported:
for var in $(compgen -v); do export $var; done
compgen -v
simply outputs all variable names, as per the bash manual, section 8.7 Programmable Completion Builtins. Then we simply loop over this list and export
each one.
Credit to https://stackoverflow.com/a/16337687/2113226 - compgen
is new to me.
There are two ways I can think of to integrate this into your make workflow:
Simply write a shell script which sources your setup-env.sh, exports all variables as above, then calls make
itself. Something like:
#!/bin/bash
./source setup-env.sh
for var in $(compgen -v); do export $var; done
make $@
It may be that you don't want a shell script wrapper, and want to directly invoke make for whatever reason. You can do this all in one Makefile which calls itself recursively:
$(info MAKELEVEL=$(MAKELEVEL) myvar=$(myvar))
ifeq ($(MAKELEVEL), 0)
all:
bash -c "source ./setup-env.sh; \
for var in \$$(compgen -v); do export \$$var; done; \
$(MAKE) $@"
else
all: myprog
myprog:
echo "Recipe for myprog. myvar=$(myvar)"
endif
Output for this Makefile is:
$ make
MAKELEVEL=0 myvar=
bash -c "source ./setup-env.sh; \
for var in \$(compgen -v); do export \$var; done; \
make all"
MAKELEVEL=1 myvar=Hello World
make[1]: Entering directory `/home/ubuntu/makesource'
echo "Recipe for myprog. myvar=Hello World"
Recipe for myprog. myvar=Hello World
make[1]: Leaving directory `/home/ubuntu/makesource'
$
We check the GNU Make builtin variable MAKELEVEL to see what level of recursion we are at. if the level is 0, then we recursively call make for all targets, but first source ./setup-env.sh and export all variables. If the recursion level is anything else, we just do the normal makefile stuff, but you see that the variables you need are now available. This is highlighted by the $(info )
line at the top of the Makefile, which shows the recursion level, and the value (or not) of myvar.
We have to use bash -c
because compgen
is strictly a bash builtin, and not available in Posix mode - i.e. when make invokes the shell as sh -c
by default.
The $
in the first all:
recipe need to be escaped very carefully. The $$
escapes the $
from being expanded by make, and the \$$
escapes the $
from being expanded by the implicit sh
There is plenty of literature arguing that "Recursive make is considered harmful". E.g. http://aegis.sourceforge.net/auug97.pdf
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With