【问题标题】:Linking static library with JNI使用 JNI 链接静态库
【发布时间】:2014-06-30 15:11:33
【问题描述】:

Java 8 之前的 Java 版本要求本地代码位于共享库中,但我已经读过 Java 8 可以将静态链接库与 JNI 一起使用。我已经搜索了示例,但找不到任何示例。

如何将 JNI 库静态链接到我的 java 应用程序中?

【问题讨论】:

  • 你在哪里读到的?请提供一些证据:-)
  • 在 Wikipedia 的 Java 版本历史记录页面上看到了它,他们的来源:openjdk.java.net/jeps/178

标签: java java-native-interface static-libraries java-8 static-linking


【解决方案1】:

Java SE 8 规范已更改为支持静态链接,静态链接在 JDK 中实现。这在System.loadLibrary 的规范中被简要提及。它引用的 JNI 规范的部分是 herehere

本地方法签名和数据类型对于静态和动态链接的方法是相同的。不过,您可能必须破解 JDK makefile 才能使其静态链接您的库。

一个显着的区别是静态库的初始化方式。动态库通过调用JNI_OnLoad 函数进行初始化,并通过调用JNI_OnUnload 取消初始化。每个动态库都可以有自己的这些函数版本。如果有多个静态链接库,显然它们不能都有具有这些相同名称的函数。对于名为libname 的静态库,加载/卸载函数是JNI_OnLoad_libnameJNI_OnUnload_libname

JNI_OnLoad_libname 函数必须返回 JNI_VERSION_1_8 或更高的值。如果没有,JVM 将忽略静态库。

基本上,如果您调用System.loadLibrary("foo"),系统会在运行的可执行映像中查找函数JNI_OnLoad_foo,如果找到,则假定库是静态链接的,并在运行图像。如果未找到JNI_OnLoad_foo,则进行通常的动态库搜索和加载,并从找到的动态库链接本地方法。

【讨论】:

  • 感谢您的回答。但现在我有点不确定。我仍然可以使用javah 为源创建标题还是我需要自己命名方法等?
  • @chmod 编写本机方法本身的机制应该与动态本机相同。与 static 的区别在于您必须编译和链接您的本机代码以生成静态库,然后执行第二步将该静态库链接到 JVM 本身。
  • 好的,你知道如何修改我的 JDK 以使其与我的库一起使用吗?
  • @chmod 我认为您不能修改预构建的 JDK,因为(我相信)无法将其他静态库链接到可执行文件中。如果您是从源代码构建的,您可能需要使用附加参数或变量设置来破解生成文件,以便为链接器命令提供静态库。参见 OpenJDK 中的vm.make,例如,在第 320 行附近及以下。
  • 别忘了让你的JNI_OnLoad_X函数至少返回JNI_VERSION_1_8,否则这个库会被忽略。
【解决方案2】:

根据您在评论中链接到的 JEP 178,您不必做任何不同的事情。 System.loadLibrary 现在将同时加载动态和静态库。

无需更改现有 Java 代码即可使用静态本机库,而不是动态本机库。特别是 System.loadLibrary("foo") 形式的方法调用应该能够加载“foo”库,而不管该库是以静态还是动态形式提供的。

您可能只需要确保您的 java.library.path 设置正确。

【讨论】:

  • 那么与共享库相比,我唯一需要做的就是编译不同的库? C/C++ 代码没有变化?
  • @user3525110 Java 或 C 代码均未更改。只需使用您通常使用的任何编译器选项来从 C 编译的目标文件创建共享或静态库。
  • 这真的有效吗?我有一个静态库(.a 文件),但即使我正确设置了 java.library.path,也找不到该库:“线程“主”java.lang.UnsatisfiedLinkError 中的异常:java.library 中没有 。小路”。我正在使用 Java 8 和 Debian。
  • @little_planet :不,您不能简单地将静态库复制到路径中。新方法只适用于那些将 JVM 嵌入到他们的可执行文件中的人。
【解决方案3】:

Java 8 增强 https://openjdk.java.net/jeps/178 是为 JVM 设计的。

给定两个文件:

  • Main.java
  • Main.c

创建 libnative.so:

javac Main.java
javah Main
gcc -c Main.c
gcc -c Main.c -I /home/dx/.sdkman/candidates/java/current/include/linux -I /home/dx/.sdkman/candidates/java/current/include
gcc -shared -o libnative.so Main.o

创建 libnative.a:

ar -cvq libnative.a Main.o

对于每个 libnative.a、libnative.so 测试运行方式:

java -Djava.library.path=.  Main

结果:

  • libnative.so时成功执行
  • libnative.a 时执行失败

这证明178是针对JVM的。

参考资料:

【讨论】:

  • 那么在linux上不能使用静态库吗?这适用于窗户
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-05-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多