1

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?

ksclarke
  • 489
  • 5
  • 16
  • 2
    Is the definition of JNI_OnLoad_kdu_1jni wrapped in `extern "C"`? The only other thing I would suggest trying is naming the library something simple like "L.a". – Robert Prévost Oct 03 '16 at 23:57
  • You can't load statically compiled libraries. You have to link them into a .so or .dll. Your question doesn't make sense. – user207421 Oct 04 '16 at 00:16
  • @EJP Java8 now comes with support to load static libraries. I was about to chime in with a comment like yours, but JEP 178 changes things. – Edwin Buck Oct 04 '16 at 00:28
  • @EdwinBuck Impossible. A static library is designed as an input to a linker, not as an executable. For example, intra-library references are not resolved. What is described in JEP 178 is a library *statically linked to the JVM.*. The link step remains essential. – user207421 Oct 04 '16 at 00:41
  • I can't find a good explanation, but I believe that this does not work in general: see [here](http://openjdk.java.net/jeps/178). – Robert Prévost Oct 04 '16 at 00:55
  • @RobertPrévost Correct. Everything that has been cited so far is about libraries statically linked into the executable. You cannot dynamically load a .a file by any means whatsoever, whether in Java or at the native level. – user207421 Oct 04 '16 at 00:59
  • @EJP Okay, I may have misunderstood what's possible, then. Any pointers to how one would statically link to the JVM? Is that for regular developers or something for people working on the JVM itself? – ksclarke Oct 04 '16 at 01:16

2 Answers2

2

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.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • So I guess I'm stuck compiling the dynamic lib for platforms with different glibc versions. That's probably simpler than compiling one executable with the JVM included. – ksclarke Oct 04 '16 at 01:28
  • 1
    You could statically link your preferred glibc into the dynamic library instead of it using a dynamic one itself. – user207421 Oct 04 '16 at 01:29
  • Thanks, I'm in new territory here. I'll research in that direction if that's possible then. – ksclarke Oct 04 '16 at 01:32
0

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.

Edwin Buck
  • 69,361
  • 7
  • 100
  • 138
  • *'Statically linked to the JVM'* is not the same as 'statically compiled library'. – user207421 Oct 04 '16 at 00:44
  • @EJP Thanks for pointing it out. I glossed over that and yes, it seems that one is trying to dynamically load a static library when in fact it isn't supported. – Edwin Buck Oct 04 '16 at 03:24