0
votes

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 ??

1
Try putting both commands on one line: export LD_LIBRARY_PATH=...; ./hello_world_c_exec. If that works, I'll explain why.Beta
Just for pedantry you don't need to export it if it's on the same line: just don't use a semicolon. Write it like: LD_LIBRARY_PATH=... ./hello_world_c_exec.MadScientist
@Beta - It worked as you said. raspy has provided a good explanation below so I guess that sorts it out for me. Thank you!Khilav

1 Answers

1
votes

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:

  1. 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'.
  1. 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
  1. 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