Reputation: 85
I want to call some function of liba.so from other libb.so. libb.so is dynamic so library that implement native method which i have loaded using System.loadLibrary("b") inside JNI. first i have set complete path for both of .so inside jni using java.library.path but when i run my java programs , while loading shared library libb.so, it gives below error:
Exception in thread "main" java.lang.UnsatisfiedLinkError: x/y/z/libb.so: liba.so: cannot open shared object file: No such file or directory.
at java.lang.ClassLoader$NativeLibrary.load(Native Method)
at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1941)
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1857)
at java.lang.Runtime.loadLibrary0(Runtime.java:870)
at java.lang.System.loadLibrary(System.java:1122)
first i have linked shared library liba.so with other shared library libb.so during compilation using
g++ -shared -o libb.so -fPIC b.cc -L/x/y/z -la
(say complete path of liba.so is /x/y/z)
In JNI, i have set java.library.path pragmatically that contains complete path of liba.so, libb.so and then i used to load JNI native library libb.so as
(say complete path of libb.so is a/b/c and complete path of liba.so is x/y/z.)
String libpath = "x/y/z" + "a/b/c";
System.setProperty( "java.library.path", libpath);
try {
Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");
fieldSysPath.setAccessible( true );
fieldSysPath.set( null, null );
}
catch (Exception e)
{
System.out.println(e);
}
// here i am able to print/fetch correct java.library.path. (path of both shared library saved correctly into java.library.path)
static {
System.loadLibrary("b");
}
when my java programs load this dynamic library of static block , it gives below error:
Exception in thread "main" java.lang.UnsatisfiedLinkError: x/y/z/liba.so: libb.so: cannot open shared object file: No such file or directory.
Note: When i set path of liba.so in LD_LIBRARY_PATH, this work fine without any error. but i don't want to set LD_LIBRARY_PATH in SHELL. just i want to set java.library.path or LD_LIBRARY_PATH in program itself.
Thanks in Advance!
Upvotes: 3
Views: 2505
Reputation: 1
Assuming you control the location of the shared objects liba.so
and libb.so
, compile your libb.so
shared object with an embedded RPATH
set so that it can locate liba.so
.
If the two shared objects are located in the shame directory, this would work:
g++ -shared -o libb.so -fPIC b.cc -L/x/y/z -la -Wl,-rpath,'$ORIGIN/.'
($ORIGIN
by itself would work, but I like to use $ORIGIN/.
to clearly show the result is a directory. If you have the common bin
and lib
directory tree, always using $ORIGIN/../lib
for both executables and shared object is also IMO a good idea.)
The -Wl,-rpath,'$ORIGIN/.
will set an RPATH
in the libb.so
shared object so that the runtime linker searches the same directory libb.so
is located in for liba.so
.
Upvotes: 2
Reputation: 301
Loading a dependent library from a native library is a purely OS action so it's outside of Java control. Unfortunately, you cannot fix this issue with Java-provided instruments.
As you noted, in Linux library search path can be set by the LD_LIBRARY_PATH environment variable, but it's not possible to modify the environment variable of the already running JVM process (see here with a suggestion for a hack using gdb not really usable for the non-debug case).
The issue you described is filed as a JDK bug for Windows https://bugs.openjdk.java.net/browse/JDK-8213772 with a comment there is really nothing we can do.
However, there should be a simple solution for your case:
Load the dependent library liba.so explicitly prior to loading libb.so:
static {
System.loadLibrary("a");
System.loadLibrary("b");
}
In the case of multiple dependent libraries and deeper dependency hierarchy levels, load all the dependent libraries manually one by one in reverse order.
Upvotes: 1