Export environment variables from makefile to shell - makefile
I want to modify and export "LD_LIBRARY_PATH" environment variable in order to link libjvm.so with my code. Below is my Makefile:
all: run
helloWorld.class: helloWorld.java
javac helloWorld.java
hello_world: hello_world.c
gcc -L/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server/ -I/usr/lib/jvm/java-8-openjdk-amd64/include -I/usr/lib/jvm/java-8-openjdk-amd64/include/linux/ hello_world.c -o hello_world_c_exec -ljvm
run: helloWorld.class hello_world
export LD_LIBRARY_PATH="/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server/"
./hello_world_c_exec
clean:
rm -f helloWorld.class hello_world
In the target named "run", I export 'LD_LIBRARY_PATH' environment variable. But it wont get exported to my current shell.
I am getting the below error:
./hello_world_c_exec: error while loading shared libraries: libjvm.so: cannot open shared object file: No such file or directory
How do I export 'LD_LIBRARY_PATH' using makefile ??
Every line of a recipe is normally executed in a separate shell, meaning that your export line gets into different shell than your ./hello_world_c_exec line. See for yourself:
$ cat Makefile
JVM_DIR := /tools/opt/jdk-10.0.2/lib/server
foo: LDLIBS := -ljvm
foo: LDFLAGS := -L$(JVM_DIR)
.PHONY: run
run: foo
export LD_LIBRARY_PATH=$(JVM_DIR)
$(<D)/$(<F)
Output:
$ make run -d
...
Must remake target 'run'.
export LD_LIBRARY_PATH=/tools/opt/jdk-10.0.2/lib/server
Putting child 0x81ee20 (run) PID 18709 on the chain.
Live child 0x81ee20 (run) PID 18709
Reaping winning child 0x81ee20 PID 18709
./foo
Live child 0x81ee20 (run) PID 18710
./foo: error while loading shared libraries: libjvm.so: cannot open shared object file: No such file or directory
Reaping losing child 0x81ee20 PID 18710
make: *** [Makefile:9: run] Error 127
Note two separate processes started (18709 and 18710) for each separate line. You can make it work if it's run in a single shell with a couple of ways:
Make it a single script:
$ cat Makefile
JVM_DIR := /tools/opt/jdk-10.0.2/lib/server
foo: LDLIBS := -ljvm
foo: LDFLAGS := -L$(JVM_DIR)
.PHONY: run
run: foo
export LD_LIBRARY_PATH=$(JVM_DIR); \
$(<D)/$(<F)
$ make run -d
...
Must remake target 'run'.
export LD_LIBRARY_PATH=/tools/opt/jdk-10.0.2/lib/server; \
./foo
Putting child 0x21aa780 (run) PID 22009 on the chain.
Live child 0x21aa780 (run) PID 22009
Reaping winning child 0x21aa780 PID 22009
Removing child 0x21aa780 PID 22009 from chain.
Successfully remade target file 'run'.
Set in on the command line directly:
$ cat Makefile
JVM_DIR := /tools/opt/jdk-10.0.2/lib/server
foo: LDLIBS := -ljvm
foo: LDFLAGS := -L$(JVM_DIR)
.PHONY: run
run: foo
LD_LIBRARY_PATH=$(JVM_DIR) $(<D)/$(<F)
$ make run
LD_LIBRARY_PATH=/tools/opt/jdk-10.0.2/lib/server ./foo
Turn on One Shell so that recipe is executed in a single shell instead of separate shell for each line:
$ cat Makefile
JVM_DIR := /tools/opt/jdk-10.0.2/lib/server
foo: LDLIBS := -ljvm
foo: LDFLAGS := -L$(JVM_DIR)
.ONESHELL:
.PHONY: run
run: foo
export LD_LIBRARY_PATH=$(JVM_DIR)
$(<D)/$(<F)
$ make run -d
...
Must remake target 'run'.
export LD_LIBRARY_PATH=/tools/opt/jdk-10.0.2/lib/server
./foo
Putting child 0x25258f0 (run) PID 31367 on the chain.
Live child 0x25258f0 (run) PID 31367
Reaping winning child 0x25258f0 PID 31367
Removing child 0x25258f0 PID 31367 from chain.
Successfully remade target file 'run'.
Personally, I would choose yet different approach.
First, setting up LD_LIBRARY_PATH is cumbersome and depending on various settings may cause other things to fail, for example when your system already sets LD_LIBRARY_PATH to something else; at the very least you should be appending to the variable not setting it to a strict value.
Second, this still leaves the problem of running the executable outside of your Makefile. Even when the binary was built, it is not that trivial to run it by just a simple invocation:
$ make run
cc -L/tools/opt/jdk-10.0.2/lib/server foo.c -ljvm -o foo
export LD_LIBRARY_PATH=/tools/opt/jdk-10.0.2/lib/server
./foo
$ ./foo
./foo: error while loading shared libraries: libjvm.so: cannot open shared object file: No such file or directory
Instead, I would tell the linker to embed the hint where to find the library, so that the LD_LIBRARY_PATH is not needed at all:
$ cat Makefile
JVM_DIR := /tools/opt/jdk-10.0.2/lib/server
foo: LDLIBS := -ljvm
foo: LDFLAGS := -L$(JVM_DIR) -Wl,-rpath,$(JVM_DIR)
.PHONY: run
run: foo
$(<D)/$(<F)
$ make run
cc -L/tools/opt/jdk-10.0.2/lib/server -Wl,-rpath,/tools/opt/jdk-10.0.2/lib/server foo.c -ljvm -o foo
./foo
$ ./foo
$ echo $?
0
Related
Makefile 'missing separator' for ifneq
I know there are other issues with similar titles, but they don't seem to hold the solution. Heres my makefile: # Compiler Command CC = mpiCC CFLAGS = -c -I./header # collecting object file names src = $(wildcard source/*.cpp) src1 = $(src:.cpp=.o) objects := $(src1:source/%=bin/%) # Compile object files into binary all : $(objects) $(CC) -o run $(objects) ifneq($(n),) // <- error location , line 15 mpirun -np $(n) run endif # Generate object files by compiling .cpp and .h files bin/%.o : source/%.cpp $(CC) $(CFLAGS) $? mv *.o bin # Clean Recipe .PHONY : clean clean : rm -rf all $(objects) The goal of the ifneq is to have the binary run whenever it finishes compiling. for example, a user runs the command: make <- builds without running make n=5 <- builds and runs on 5 processes Whenever I use either of these, I get the error: makefile:15: *** missing separator. Stop. I've used cat -e -t -v to verify everything is tabbed instead of spaced. according to (https://www.gnu.org/software/make/manual/make.html#Conditional-Example) this conditional should function.
#MadScientist solved it. You need to put a space in between ifneq and its argument. For example: ifneq($(n),0) is invalid. ifneq ($(n),0) is valid.
Environment variable escaping across multiple Makefiles
What's the correct way to pass and modify environment variables through several levels of makefiles? Specifically I'm setting LDFLAGS in the parent makefile using the special $ORIGIN RPATH value, and I need to add to the variable in some of the child makefiles. The linker wants the literal string $ORIGIN, that's not another variable to expand. Makefile: # default value for all children export LDFLAGS = -Wl,-rpath='$$ORIGIN' all: env | grep LDFLAGS $(MAKE) -f child1.mk $(MAKE) -f child2.mk child1.mk: # add an additional RPATH value export LDFLAGS += -Wl,-rpath='$$ORIGIN/../..' all: env | grep LDFLAGS child2.mk: all: env | grep LDFLAGS This is what happens: $ make env | grep LDFLAGS LDFLAGS=-Wl,-rpath='$ORIGIN' make -f child1.mk make[1]: Entering directory `/build/test' env | grep LDFLAGS LDFLAGS=-Wl,-rpath='RIGIN' -Wl,-rpath='$ORIGIN/../..' make[1]: Leaving directory `/build/test' make -f child2.mk make[1]: Entering directory `/build/test' env | grep LDFLAGS LDFLAGS=-Wl,-rpath='$ORIGIN' make[1]: Leaving directory `/build/test' In the child1 output, 'RIGIN' is bad, the $$ appears to have been evaluated a second time. The documentation has this note about exports, which could be relevant, but doesn't really explain how to avoid it: In both of these forms, the arguments to export and unexport are expanded, and so could be variables or functions which expand to a (list of) variable names to be (un)exported. Using $$$$ORIGIN in the top-level Makefile "works" for child1, but not for child2 which doesn't change the LDFLAGS value and ends up with $$ORIGIN. This is GNU Make 3.81 under Linux. The RPATH post I linked to has a workaround, but feels like this shouldn't be necessary: LDFLAGS="-Wl,-rpath=XORIGIN/../lib" ./configure --prefix=/blabla/place See the X? That will be replaced by a dollar sign later when you run chrpath on the resultant binaries.
On surface, this seems like a possible unintended bug with make integration with environment variables. It seems that whenever an environment variables is passed picked up by 'make', it will 'expand' any '$v', (and potentially other constructs). Consider this very simple makefile all: echo "V=$V" env | grep V= Setting V to '$$SHELL' (bash export V='$$SHELL'), and running make will show that the internal 'V' variable is /bin/bash, while the environment variable is '$$SHELL' echo "V=$SHELL" V=/bin/bash env | grep V= V=$$SHELL Putting a side the question if this is a feature or bug, you can use the $(value var) function to access the "raw" value. In the child make use: # Append extra flags to env LDFLAGS, without 'expansion' export LDFLAGS := $(value LDFLAGS) -Wl,-rpath='$$ORIGIN/../..'
Here is a working example how to pass $ORIGIN through multiple levels of makefiles with bash: SHELL := /bin/bash ifeq (${MAKELEVEL},0) export LDFLAGS := -Wl,-rpath=`printf "%bORIGIN" "\044"` endif all : #echo MAKELEVEL=${MAKELEVEL} LDFLAGS=${LDFLAGS} #if [[ ${MAKELEVEL} -lt 3 ]]; then ${MAKE}; fi Outputs: $ make --no-print-directory MAKELEVEL=0 LDFLAGS=-Wl,-rpath=$ORIGIN MAKELEVEL=1 LDFLAGS=-Wl,-rpath=$ORIGIN MAKELEVEL=2 LDFLAGS=-Wl,-rpath=$ORIGIN MAKELEVEL=3 LDFLAGS=-Wl,-rpath=$ORIGIN Alternatively, if you are on Linux, build without $ORIGIN but then use Exodus for painless relocation of Linux binaries – and all of their dependencies – without containers.
You can also set up additional variable of O to expand to the same before appending to LDFLAGS, so that even when make expands $O in $ORIGIN, it will still result in $ORIGIN: $ cat child1.mk # add an additional RPATH value O := $$O LDFLAGS += -Wl,-rpath='$$ORIGIN/../..' all: env | grep LDFLAGS Output: $ make env | grep LDFLAGS LDFLAGS=-Wl,-rpath='$ORIGIN' make -f child1.mk make[1]: Entering directory '/home/raspy/so-62298900' env | grep LDFLAGS LDFLAGS=-Wl,-rpath='$ORIGIN' -Wl,-rpath='$ORIGIN/../..' make[1]: Leaving directory '/home/raspy/so-62298900' make -f child2.mk make[1]: Entering directory '/home/raspy/so-62298900' env | grep LDFLAGS LDFLAGS=-Wl,-rpath='$ORIGIN' make[1]: Leaving directory '/home/raspy/so-62298900'
Targets in the form of {a,b} are not recognized in my Makefile
I have the following makefile: SHELL:/bin/bash all: euro.n.{a,b} euro.{a,b}: touch euro.{a,b} euro.n.{a,b}: euro.{a,b} cat euro.a > euro.n.a cat euro.b > euro.n.b Now if I run make twice, the makefile won't recognize in the second run that the files euro.n.a and euro.n.b have already been created (and it will be executed again). What is the problem?
What is the problem? {a,b} is not syntax recognized by GNU make. SHELL := /bin/bash (you missed = there) only affects the syntax of recipes. One alternative solution: SHELL := /bin/bash all: $(addprefix euro.n.,a b) euro.%: touch $# euro.n.% : euro.% cp $< $#
Makefile - export declarations to sub-makefiles
I know variables can be exported to sub-makefiles: Communicating Variables to a Sub-make Example: Makefile: export PWD := $(shell pwd) target: #echo $(PWD) #cd somewhere; $(MAKE) somewhere/Makefile target: #echo $(PWD) Supposing that the first Makefile is located at /path/to/first/makefile, the code above will print: /path/to/first/makefile /path/to/first/makefile My question is: is there a way to let the variable PWD be implicitly evaluated inside sub-makefiles? The output should look like this: /path/to/first/makefile /path/to/first/makefile/somewhere So far I can only think of: Exporting the literal declaration and use the function eval Do it somehow with .SECONDEXPANSION Put the declaration into a separate file and include it in both the first and the second Makefile All this solution are explicits: they imply code to be added to the sub-makefiles. What I'm searching is an implicit solution which will change only the code inside the first Makefile. Plus, honestly...the first two solutions are so ugly I would rather declare manually PWD in every sub-makefile. [EDIT] Just to make it more clear: the variable PWD is just an example, I'm not trying to obtain the path of every Makefile.
Use ${MAKEFILE_LIST} variable and let make change directories for you: [max#earth:~/tmp]$ cat Makefile target: #echo $(abspath $(lastword ${MAKEFILE_LIST})) ${MAKE} -C somewhere $# [max#earth:~/tmp]$ cat somewhere/Makefile target: #echo $(abspath $(lastword ${MAKEFILE_LIST})) [max#earth:~/tmp]$ make target /home/max/tmp/Makefile make -C somewhere target make[1]: Entering directory '/home/max/tmp/somewhere' /home/max/tmp/somewhere/Makefile make[1]: Leaving directory '/home/max/tmp/somewhere' That prints the full path to the makefile being processed. Use $(dir $(abspath $(lastword ${MAKEFILE_LIST}))) to chop off filename Makefile.
Makefile: Explanation of circular dependencies on .o files
Consider the following makefile: all : a.vo a.glob a.gl%b a.v% : a.v touch a.glob a.vo When I run make -j2, I get: $ rm -f a.vo a.glob; make -j2 make: Circular a.v.o <- a.v dependency dropped. touch a.glob a.vo I see why a.v.o depends on a.v, but I don't see how a.v depends on a.v.o. Where does this dependency come from (and is there a way to disable it)?
GNU make uses Implicit Rules when no rule is defined. In particular, n is made automatically from n.o by running the linker (usually called ld) via the C compiler. The precise recipe used is ‘$(CC) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS)’. As you can see: ~ $ cat Makefile all: a.v echo "foo" a.v.o: echo "bar" ~ $ make echo "bar" bar cc a.v.o -o a.v gcc: error: a.v.o: No such file or directory gcc: fatal error: no input files compilation terminated. <builtin>: recipe for target 'a.v' failed make: *** [a.v] Error 1 cc is executed.