Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java: load shared libraries with dependencies

I am wrapping a shared library (written in C) with Java using JNA. The shared library is written internally, but that library uses functions from another external library, which again depends another external library. So the situation is something like this:

ext1 <- ext2 <- internal

I.e. the internal uses external library ext2 which again uses external library ext1. What I have tried is:

System.loadLibrary("ext1");
System.loadLibrary("ext2");
NativeLIbrary.loadLibrary("internal",xxx.class);  

This approach fails with "UnresolvedException" when loading the library "ext2"; the linker complains about symbols which are indeed present in the library "ext1". So it semmes that the System.loadLibrary() function does not make the symbols from "ext1" globally available? When using the stdlib function dlopen() as:

handle = dlopen( lib_name , RTLD_GLOBAL );

All the symbols found in @lib_name will be available for symbol resolution in subsequent loads; I guess what I would like was something similar for the java variety System.loadLibrary()?

Regards - Joakim Hove

like image 824
user422005 Avatar asked Mar 24 '11 20:03

user422005


People also ask

Can a shared library depend on another shared library?

However, most shared library systems are restricted in that they only allow a single level of dependencies. In these systems, programs may depend on shared libraries, but shared libraries may not depend on other shared libraries.

Does Java use Ld_library_path?

If a library is not explcitely loaded from java, i.e. a dependent library has to be used, then LD_LIBRARY_PATH has to be used to have that library available in the jvm.

What is .so file in Java?

The basics of using a Shared Library file A file with the . SO file extension is a Shared Library file.


2 Answers

As described at http://www.owsiak.org/?p=3640, an easy but crude solution on Linux is to use LD_PRELOAD.

If that's not acceptable, then I'd recommend the answer by Oo.oO: dlopen the library with RTLD_GLOBAL within JNI code.

like image 62
mhsmith Avatar answered Sep 22 '22 17:09

mhsmith


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.

like image 34
vagelis Avatar answered Sep 23 '22 17:09

vagelis