While loading JNI library, how the mapping happens

2019-06-24 14:43发布

问题:

We load any native library by using

System.loadLibrary("hello")

Now I came to know that this library name refers to hello.dll for windows and libhello.so for unix based system.

So where these platform dependent changes happens?

Is JRE doing this?

回答1:

tl;dr

The platform dependent library name is built in native methods of the Java Virtual Machine. The actual algorithm simply prepends/appends a platform specific prefix/suffix to the name:

  • Windows: "hello" -> "hello.dll"
  • Linux/Solaris: "hello" "libhello.so"
  • Mac: "hello" -> "libhello.dylib"

Long version:

There are a couple of JDK Java methods which deal with loading libraries and/or library names:

java.lang.System.loadLibrary(String name)
java.lang.System.mapLibraryName(String name)
java.lang.Runtime.loadLibrary(String name) 
java.lang.ClassLoader.loadLibrary(String name)

The famous System.loadLibrary actually calls Runtime.loadLibrary which calls ClassLoader.loadLibrary. In the end the implementations of these methods call the following native methods which translate the given library name into the platform specific name:

native java.lang.System.mapLibraryName(String name)
native java.lang.ClassLoader$NativeLibrary.findBuiltinLib(String name) 

The implementations of these native methods can be found in (link to the OpenJDK versions):

  • http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/native/java/lang/System.c#l466
  • http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/native/java/lang/ClassLoader.c#l495

Both methods implement the same algorithm to build the actual library name, prepending the prefix JNI_LIB_PREFIX and appending the suffix JNI_LIB_SUFFIX.

In the end the macros JNI_LIB_PREFIX and JNI_LIB_SUFFIX are defined in platform dependent include files, namely

  • http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/windows/javavm/export/jvm_md.h#l42
  • http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/solaris/javavm/export/jvm_md.h#l43
  • http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/macosx/javavm/export/jvm_md.h#l43


回答2:

Short answer: yes.

From the Javadoc for loadLibrary: "Loads the system library specified by the libname argument. The manner in which a library name is mapped to the actual system library is system dependent." System.mapLibraryName(libname) will return what the mapped library name will be.

This reflects the common conventions for library names: lib prefix in Linux and Mac OS X, no prefix in Windows, plus platform dependent file extension. Note that the extension for JNI libraries on Mac OS X is jnilib, not dylib as it is for other libraries. Also this mapping is not unique to the Java runtime, gcc ... -lhello will also look for libhello.so (or libhello.dylib on Mac OS X).

If you don't want the runtime to do this mapping, you'd have to determine the correct filename including the extension yourself and pass this to loadLibrary