Law Kumar
Law Kumar

Reputation: 85

Load dependent .so from other shared library via JNI

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

  2. 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

Answers (2)

Andrew Henle
Andrew Henle

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

zakgof
zakgof

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

Related Questions