Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to bundle a native library and a JNI library inside a JAR?

The library in question is Tokyo Cabinet.

I want is to have the native library, JNI library, and all Java API classes in one JAR file to avoid redistribution headaches.

There seems to be an attempt at this at GitHub, but

  1. It does not include the actual native library, only JNI library.
  2. It seems to be specific to Leiningen's native dependencies plugin (it won't work as a redistributable).

The question is, can I bundle everything in one JAR and redistribute it? If yes, how?

P.S.: Yes, I realize it may have portability implications.

like image 504
Alex B Avatar asked May 30 '10 03:05

Alex B


People also ask

What is a JNI wrapper?

JNI is the Java Native Interface. It defines a way for the bytecode that Android compiles from managed code (written in the Java or Kotlin programming languages) to interact with native code (written in C/C++).

What is native shared library?

Native libraries are platform-specific library files, including . dll, . so, or *SRVPGM objects, that can be configured within shared libraries. Native libraries are visible to an application class loader whenever the shared library is associated with an application.

How does system loadLibrary work?

The System. load() method takes as a parameter a fully qualified path to the native library and loads the specified native library. The System. loadLibrary() takes as parameter a library name, locates a native library that corresponds to that name, and loads the native library.


2 Answers

It is possible to create a single JAR file with all dependencies including the native JNI libraries for one or more platforms. The basic mechanism is to use System.load(File) to load the library instead of the typical System.loadLibrary(String) which searches the java.library.path system property. This method makes installation much simpler as the user does not have to install the JNI library on his system, at the expense, however, that all platforms might not be supported as the specific library for a platform might not be included in the single JAR file.

The process is as follows:

  • include the native JNI libraries in the JAR file at a location specific to the platform, for example at NATIVE/${os.arch}/${os.name}/libname.lib
  • create code in a static initializier of the main class to
    • calc the current os.arch and os.name
    • look for the library in the JAR file at the predefined location using Class.getResource(String)
    • if it exists, extract it to a temp file and load it with System.load(File).

I added functionality to do this for jzmq, the Java bindings of ZeroMQ (shameless plug). The code can be found here. The jzmq code uses a hybrid solution so that if an embedded library cannot be loaded, the code will revert to searching for the JNI library along the java.library.path.

like image 188
kwo Avatar answered Nov 06 '22 18:11

kwo


https://www.adamheinrich.com/blog/2012/12/how-to-load-native-jni-library-from-jar/

is great article, which solves my issue ..

In my case I've got the following code for initialize the library:

static {     try {         System.loadLibrary("crypt"); // used for tests. This library in classpath only     } catch (UnsatisfiedLinkError e) {         try {             NativeUtils.loadLibraryFromJar("/natives/crypt.dll"); // during runtime. .DLL within .JAR         } catch (IOException e1) {             throw new RuntimeException(e1);         }     } } 
like image 38
davs Avatar answered Nov 06 '22 17:11

davs