加载 JNI 库时,映射如何与实际库名称发生
While loading JNI library, how the mapping happens with the actual library name
我们使用
加载任何本机库
System.loadLibrary("hello")
现在我知道这个库名指的是 hello.dll for windows
libhello.so 用于基于 unix 的系统。
那么这些依赖于平台的变化发生在哪里?
JRE 是这样做的吗?
简答:是。
来自 JavaloadLibrary
的文档:"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)
将 return 映射的库名称。
这反映了库名称的通用约定:lib
Linux 和 Mac 中的前缀 OS X,Windows 中没有前缀,加上平台依赖文件扩展名。请注意,Mac OS X 上的 JNI 库的扩展名是 jnilib
,而不是其他库的 dylib
。此外,此映射并非 Java 运行时所独有,gcc ... -lhello
还将查找 libhello.so
(或 Mac OS X 上的 libhello.dylib
)。
如果您不希望运行时执行此映射,您必须自己确定正确的文件名(包括扩展名)并将其传递给 loadLibrary
tl;dr
依赖于平台的库名称内置于 Java 虚拟 Machine 的本机方法中。
实际算法只是 prepends/appends 特定于平台的 prefix/suffix 名称:
- Windows:
"hello"
-> "hello.dll"
- Linux/Solaris:
"hello"
"libhello.so"
- Mac:
"hello"
-> "libhello.dylib"
长版:
有几个 JDK Java 方法处理加载库 and/or 库名称:
java.lang.System.loadLibrary(String name)
java.lang.System.mapLibraryName(String name)
java.lang.Runtime.loadLibrary(String name)
java.lang.ClassLoader.loadLibrary(String name)
著名的System.loadLibrary
实际上调用Runtime.loadLibrary
而调用ClassLoader.loadLibrary
。
最后,这些方法的实现调用以下本地方法来翻译给定的库名称
进入平台特定名称:
native java.lang.System.mapLibraryName(String name)
native java.lang.ClassLoader$NativeLibrary.findBuiltinLib(String name)
这些本地方法的实现可以在(link 到 OpenJDK 版本)中找到:
- 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
两种方法实现相同的算法来构建实际的库名称,
在前缀 JNI_LIB_PREFIX
前加上后缀 JNI_LIB_SUFFIX
.
最后宏JNI_LIB_PREFIX
和JNI_LIB_SUFFIX
定义在平台相关的包含文件中,即
我们使用
加载任何本机库System.loadLibrary("hello")
现在我知道这个库名指的是 hello.dll for windows libhello.so 用于基于 unix 的系统。
那么这些依赖于平台的变化发生在哪里?
JRE 是这样做的吗?
简答:是。
来自 JavaloadLibrary
的文档:"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)
将 return 映射的库名称。
这反映了库名称的通用约定:lib
Linux 和 Mac 中的前缀 OS X,Windows 中没有前缀,加上平台依赖文件扩展名。请注意,Mac OS X 上的 JNI 库的扩展名是 jnilib
,而不是其他库的 dylib
。此外,此映射并非 Java 运行时所独有,gcc ... -lhello
还将查找 libhello.so
(或 Mac OS X 上的 libhello.dylib
)。
如果您不希望运行时执行此映射,您必须自己确定正确的文件名(包括扩展名)并将其传递给 loadLibrary
tl;dr
依赖于平台的库名称内置于 Java 虚拟 Machine 的本机方法中。 实际算法只是 prepends/appends 特定于平台的 prefix/suffix 名称:
- Windows:
"hello"
->"hello.dll"
- Linux/Solaris:
"hello"
"libhello.so"
- Mac:
"hello"
->"libhello.dylib"
长版:
有几个 JDK Java 方法处理加载库 and/or 库名称:
java.lang.System.loadLibrary(String name)
java.lang.System.mapLibraryName(String name)
java.lang.Runtime.loadLibrary(String name)
java.lang.ClassLoader.loadLibrary(String name)
著名的System.loadLibrary
实际上调用Runtime.loadLibrary
而调用ClassLoader.loadLibrary
。
最后,这些方法的实现调用以下本地方法来翻译给定的库名称
进入平台特定名称:
native java.lang.System.mapLibraryName(String name)
native java.lang.ClassLoader$NativeLibrary.findBuiltinLib(String name)
这些本地方法的实现可以在(link 到 OpenJDK 版本)中找到:
- 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
两种方法实现相同的算法来构建实际的库名称,
在前缀 JNI_LIB_PREFIX
前加上后缀 JNI_LIB_SUFFIX
.
最后宏JNI_LIB_PREFIX
和JNI_LIB_SUFFIX
定义在平台相关的包含文件中,即