ksclarke
ksclarke

Reputation: 488

Load statically compiled library in Java

I'm having trouble loading a statically compiled library from Java using System.loadLibrary("") but I can load it as a dynamically compiled library (when I build it that way) just fine. I'm using JDK 8 and my understanding is it can load static libraries via System.loadLibrary("") if you provide a JNI_OnLoad_L in the *.cpp and *.h files.

My kdu_jni.h has:

extern "C"
JNIEXPORT jint JNICALL JNI_OnLoad_kdu_1jni(JavaVM *, void *);

My kdu_jni.cpp has:

JNIEXPORT jint JNICALL JNI_OnLoad_kdu_1jni(JavaVM *vm, void *reserved)
{
  return JNI_VERSION_1_8;
}

I have the libkdu_jni.a file in my java.library.path directory when I try to run with the compiled version. It's working fine with a libkdu_jni.so file in that same directory when I try to load it dynamically. When trying with the static file (libkdu_jni.a), I get:

Exception in thread "main" java.lang.UnsatisfiedLinkError: no kdu_jni in java.library.path
    at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1867)
    at java.lang.Runtime.loadLibrary0(Runtime.java:870)
    at java.lang.System.loadLibrary(System.java:1122)

I've taken out the .so file before trying to load the .a file.

I'm not sure what I'm doing wrong. I don't think it's even seeing the libkdu_jni.a file's JNI_OnLoad_kdu_1jni() because I put an exception in there and I don't see that getting thrown. I've tried several iterations on that name: JNI_OnLoad_kdu_jni(), JNI_OnLoad_kdu_1jni(), JNI_OnLoad(), etc.

Any ideas?

Upvotes: 1

Views: 2518

Answers (2)

user207421
user207421

Reputation: 310893

my understanding is it can load static libraries via System.loadLibrary("") if you provide a JNI_OnLoad_L in the *.cpp and *.h files.

Your understanding is incorrect. You can't load a .a file dynamically. It isn't executable in any way shape or form:

  • infra-library references are not resolved
  • references outside the library are not resolved either: for example, to the C library.

The link step is essential, and the JVM doesn't do it for you. What you have read applies to libraries statically linked into the JVM.

Upvotes: 2

Edwin Buck
Edwin Buck

Reputation: 70909

I suggest you try JNI_OnLoad_kdu_jni as the function name. If that doesn't work, it might not work with library names that contain an underscore.

--- Original post follows ---

Prior to Java 8, only shared object libraries were supported.

This means that to know if the static library is Java 8, a new function must be implemented in the library.

JNI_OnLoad_libname must return a value of JNI_VERSION_1_8 or higher.

I'm guessing since your code works dynamically, but not staticly, perhaps this function is not present. The portion of JEP 178 below lead me to believe this:

The specifications of the java.lang.System.loadLibrary and java.lang.Runtime.loadLibrary methods will be revised to read:

Loads the native library specified by the libname argument. The libname must not contain any platform-specific prefix, file extension, or path.

If a native library called libname is statically linked with the VM, then the JNI_OnLoad_libname function exported by the library is invoked. See the JNI Specification for more details.

Otherwise, the libname is loaded from a system library location and mapped to a native-library image in an implementation-dependent manner.

Also the notes in the enhancement echo this sentiment

The source code for the loader is helpful

I'd fire up java under debug (gdb) and put a break point in at Java_java_lang_ClassLoader_00024NativeLibrary_findBuiltinLib. You're right, there aren't many great examples.

Upvotes: 0

Related Questions