【问题标题】:Load statically compiled library in Java在 Java 中加载静态编译的库
【发布时间】:2016-10-03 23:45:29
【问题描述】:

我在使用 System.loadLibrary("") 从 Java 加载静态编译库时遇到问题,但我可以将它作为动态编译库加载(当我以这种方式构建时)就可以了。我正在使用 JDK 8,我的理解是,如果您在 *.cpp 和 *.h 文件中提供 JNI_OnLoad_L,它可以通过 System.loadLibrary("") 加载静态库。

我的 kdu_jni.h 有:

extern "C"
JNIEXPORT jint JNICALL JNI_OnLoad_kdu_1jni(JavaVM *, void *);

我的 kdu_jni.cpp 有:

JNIEXPORT jint JNICALL JNI_OnLoad_kdu_1jni(JavaVM *vm, void *reserved)
{
  return JNI_VERSION_1_8;
}

当我尝试使用已编译版本运行时,我的 java.library.path 目录中有 libkdu_jni.a 文件。当我尝试动态加载它时,它与同一目录中的 libkdu_jni.so 文件一起工作正常。尝试使用静态文件 (libkdu_jni.a) 时,我得到:

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)

在尝试加载 .a 文件之前,我已取出 .so 文件。

我不确定我做错了什么。我认为它甚至没有看到 libkdu_jni.a 文件的 JNI_OnLoad_kdu_1jni() 因为我在其中放置了一个异常并且我没有看到它被抛出。我已经对该名称进行了多次迭代:JNI_OnLoad_kdu_jni()、JNI_OnLoad_kdu_1jni()、JNI_OnLoad() 等。

有什么想法吗?

【问题讨论】:

  • JNI_OnLoad_kdu_1jni 的定义是否包裹在extern "C" 中?我建议尝试的唯一另一件事是将库命名为简单的名称,例如“L.a”。
  • 您无法加载静态编译的库。您必须将它们链接到 .so 或 .dll 中。你的问题没有意义。
  • @EJP Java8 现在支持加载静态库。我正要插话你的评论,但 JEP 178 改变了一切。
  • @EdwinBuck 不可能。静态库被设计为链接器的输入,而不是可执行文件。例如,不解析库内引用。 JEP 178 中描述的是一个库静态链接到 JVM。。链接步骤仍然必不可少。
  • 我找不到很好的解释,但我相信这通常不起作用:见here

标签: java c++ java-native-interface


【解决方案1】:

我的理解是,如果您在 *.cpp 和 *.h 文件中提供 JNI_OnLoad_L,它可以通过 System.loadLibrary("") 加载静态库。

你的理解不正确。您不能动态加载.a 文件。它不能以任何形式或形式执行:

  • 基础库引用未解析
  • 库外部的引用也无法解析:例如,C 库。

链接步骤是必不可少的,JVM 不会为您完成。您所阅读的内容适用于静态链接到 JVM 的库。

【讨论】:

  • 所以我想我一直在为具有不同 glibc 版本的平台编译动态库。这可能比编译一个包含 JVM 的可执行文件更简单。
  • 您可以将首选 glibc 静态链接到动态库中,而不是使用动态库本身。
  • 谢谢,我来到了新的领域。如果可能的话,我会朝那个方向研究。
【解决方案2】:

我建议你试试JNI_OnLoad_kdu_jni 作为函数名。如果这不起作用,它可能不适用于包含下划线的库名称。

--- 原帖如下---

在 Java 8 之前,仅支持共享对象库。

这意味着要知道静态库是否是Java 8,必须在库中实现一个新函数。

JNI_OnLoad_libname must return a value of JNI_VERSION_1_8 or higher.

我猜是因为你的代码是动态工作的,但不是静态的,也许这个函数不存在。下面的 JEP 178 部分让我相信这一点:

java.lang.System.loadLibrary 的规范和 java.lang.Runtime.loadLibrary 方法将修改为:

加载由 libname 参数指定的本机库。 libname 不得包含任何特定于平台的前缀、文件扩展名、 或路径。

如果名为 libname 的本机库与 VM 静态链接,则由 库被调用。有关详细信息,请参阅 JNI 规范。

否则,libname 将从系统库位置加载并映射到本地库映像中 依赖于实现的方式。

Also the notes in the enhancement echo this sentiment

The source code for the loader is helpful

我会在调试 (gdb) 下启动 java 并在 Java_java_lang_ClassLoader_00024NativeLibrary_findBuiltinLib 处设置一个断点。没错,好的例子并不多。

【讨论】:

  • '静态链接到 JVM' 与'静态编译库'不同。
  • @EJP 感谢您的指出。我忽略了这一点,是的,似乎有人试图动态加载静态库,而实际上它不受支持。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-21
  • 2012-05-24
  • 1970-01-01
  • 1970-01-01
  • 2011-02-13
相关资源
最近更新 更多