Java: load shared libraries with dependencies

OK;

I have found an acceptable solution in the end, but not without significant amount of hoops. What I do is

  1. Use the normal JNA mechanism to map the dlopen() function from the dynamic linking library (libdl.so).
  2. Use the dlopen() function mapped in with JNA to load external libraries "ext1" and "ext2" with the option RTLD_GLOBAL set.

It actually seems to work :-)


It's an old question, but I've found an acceptable solution, which should also be portable, and I thought I should post an answer. The solution is to use JNA's NativeLibrary#getInstance(), because on Linux this will pass RTLD_GLOBAL to dlopen() (and on Windows this is not needed).

Now, if you are using this library to implement a Java native method, you will also need to call System.load() (or Sysem.loadLibrary()) on the same library, after calling NativeLibrary#getInstance().

First, a link to a JNA bug: JNA-61

A comment in there says that basically one should load dependencies before the actual library to use from within JNA, not the standard Java way. I'll just copy-paste my code, it's a typical scenario:

String libPath =
        "/path/to/my/lib:" + // My library file
        "/usr/local/lib:" +  // Libraries lept and tesseract
        System.getProperty("java.library.path");

System.setProperty("jna.library.path", libPath);

NativeLibrary.getInstance("lept");
NativeLibrary.getInstance("tesseract");
OcrTesseractInterf ocrInstance = (OcrTesseractInterf)
        Native.loadLibrary(OcrTesseractInterf.JNA_LIBRARY_NAME, OcrTesseractInterf.class);

I've written a small library to provide OCR capability to my Java app using Tesseract. Tesseract dependes on Leptonica, so to use my library, I need to load libraries lept and tesseract first. Loading the libraries with the standard means (System.load() and System.loadLibrary()) doesn't do the trick, neither does setting properties jna.library.path or java.library.path. Obviously, JNA likes to load libraries its own way.

This works for me in Linux, I guess if one sets the proper library path, this should work in other OSs as well.


There is yet another solution for that. You can dlopen directly inside JNI code, like this:

void loadLibrary() {
  if(handle == NULL) {
    handle = dlopen("libname.so", RTLD_LAZY | RTLD_GLOBAL);
    if (!handle) {
      fprintf(stderr, "%s\n", dlerror());
      exit(EXIT_FAILURE);
    }
  }
}

...
...

loadLibrary();

This way, you will open library with RTLD_GLOBAL.

You can find detailed description here: http://www.owsiak.org/?p=3640