加载 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 版本)中找到:

两种方法实现相同的算法来构建实际的库名称, 在前缀 JNI_LIB_PREFIX 前加上后缀 JNI_LIB_SUFFIX.

最后宏JNI_LIB_PREFIXJNI_LIB_SUFFIX定义在平台相关的包含文件中,即