【问题标题】:How to fix UnsatisfiedLinkError by making minimal changes?如何通过进行最小的更改来修复 UnsatisfiedLinkError?
【发布时间】:2020-01-06 05:00:23
【问题描述】:

我正在尝试在 RHEL 中编译和运行以下 JNI Java 文件:

package com.isprint.am.util.hsm;

public class LunaMDUtil {

    //bunch of constants

    public native int MD_Initialize();
    //...and a bunch of other native methods

    static {
        System.loadLibrary("ethsm");
        System.loadLibrary("LunaMDUtil");
    }

    public static void main(String[] args) {
       // some test code code
    }

}

(我省略了代码,因为我认为它与问题无关。)

在我的开发文件夹中,我有以下文件:

// files used to build libLunaMDUtil.so
com_isprint_am_util_hsm_LunaMDUtil.c
com_isprint_am_util_hsm_LunaMDUtil.h
ethsm.lib

libLunaMDUtil.so

LunaMDUtil.java (i.e the above Java source code file)

要构建libLunaMDUtil.so,我运行以下命令:

gcc -fPIC -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/linux" -shared -o libLunaMDUtil.so com_isprint_am_util_hsm_LunaMDUtil.c

这里没有错误。接下来我编译我的LunaMDUtil.java:

javac -cp . LunaMDUtil.java

这里没有错误。这里的最后一步是我开始遇到问题的地方。

运行java -Xdiag -cp . LunaMDUtil 给我这个错误:

Error: Could not find or load main class LunaMDUtil
java.lang.NoClassDefFoundError: LunaMDUtil (wrong name: com/isprint/am/util/hsm/LunaMDUtil)
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:468)
    at java.net.URLClassLoader.access$100(URLClassLoader.java:74)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:369)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:363)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:495)

接下来,我运行 java -Xdiag -cp . com.isprint.am.util.hsm.LunaMDUtil 并收到此错误:

Error: Could not find or load main class com.isprint.am.util.hsm.LunaMDUtil
java.lang.ClassNotFoundException: com.isprint.am.util.hsm.LunaMDUtil
    at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:495)

我将我的 .class 文件移动到文件夹 ./com/isprint/am/util/hsm(在包名之后),这次我得到了:

Exception in thread "main" java.lang.UnsatisfiedLinkError: no ethsm 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)
    at com.isprint.am.util.hsm.LunaMDUtil.<clinit>(LunaMDUtil.java:67)

此时我的手开始变得僵硬,因为ethsm.lib 是来自外部方的库,我希望尽可能避免重命名它。另外,如果可能,我想避免更改源代码。 (当然,如果唯一的解决方案涉及进行这些更改,那么至少我有一些理由。)

我应该进行哪些更改才能让LunaMDUtil.java 中的测试代码运行?

【问题讨论】:

  • ethsm 真的是 JNI 库吗?或者只是LunaMDUtil 依赖的东西?如果是后者,您根本不应该尝试加载它。
  • @user207421 ethsm 不是 JNI 库,而是包含我的 C 源文件调用的函数
  • 没错,所以不要尝试将其作为 JNI 库加载。如果它是 .lib 你的 C 代码已经静态链接到它;否则,如果它是 .so 您的 C 代码已经动态链接到它。你不需要再做任何事情了。
  • @user207421 - “如果它是 .so 你的 C 代码已经动态链接到它。你不需要再做任何事情了。” - 恐怕这并不完全正确。这取决于系统,但链接到.so 是不够的。您必须确保您链接到的 .so 位于 LD_LIBRARY_PATH 上,或者您链接到 -rpath。否则,系统将看不到该库。 java.library.path 仅对使用 loadLibrary 加载的库有效,不适用于该库依赖的其他库。在 Windows 中,此库必须位于 PATH
  • @Oo.oO 请​​注意上下文。就链接和加载而言,这已经足够了。当它不是时,您不必尝试将它作为 JNI 库加载。 当然 .so 必须在运行时出现,这是不言而喻的。关于java.library.path,我一句话也没说。不要把话放在我嘴里。

标签: gcc java-native-interface javac rhel .so


【解决方案1】:

在您的代码中,您有以下静态代码

System.loadLibrary("ethsm");

它将加载libethsm.so 库。你必须确保它存在。

你说ethsm.lib 来自外部开发者。在这种情况下,请改用此函数

String path = "/this/is/path/to/your/ethsm/";
System.load(path + "ethsm.lib");

这样,库将从load中指定的文件加载。

或者,您可以随时创建符号链接:

ln -s ethsm.lib libethsm.so

但是,这仅适用于共享库。

与共享库链接,而不是在 Java 中加载它

如果您有共享库(例如:libethsm.so),您可以随时将您的代码与该库链接

gcc -fPIC -I"$JAVA_HOME/include" \
  -I"$JAVA_HOME/include/linux" \
  -L$(ETHSM_LOCATION) 
  -lethsm 
  -shared -o libLunaMDUtil.so com_isprint_am_util_hsm_LunaMDUtil.c

但是,这需要将此库放在LD_LIBRARY_PATH 上或与-rpath 链接。

您可以在这里找到示例:http://jnicookbook.owsiak.org/recipe-No-023/

与静态库链接,而不是在 Java 中加载它

如果您的库是静态库,您可以在编译 JNI 代码时始终将其与您的代码链接

gcc -fPIC -I"$JAVA_HOME/include" \
  -I"$JAVA_HOME/include/linux" \
  -shared -o libLunaMDUtil.so \
  com_isprint_am_util_hsm_LunaMDUtil.c \
  ethsm.lib

您可以在这里找到示例:http://jnicookbook.owsiak.org/recipe-No-059/

将库直接放入共享库 - 如果您有源代码

如果你有源代码,你可以简单地将JNI和lib的源代码放在JNI基础库中

您可以在这里找到示例:http://jnicookbook.owsiak.org/recipe-No-021/

【讨论】:

  • 这很奇怪。如果是load,你应该得到不同的错误:Can't load library: 如果文件丢失。
  • 他应该得到一个UnsatisfiedLinkError,他是。实际文本取决于平台。您的代码不会通过绝对化当前工作目录来完成任何事情。
  • @user207421 - 感谢您的评论并提升我的回答 :) 感谢您的出色:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-04-13
  • 1970-01-01
  • 2015-07-16
  • 2021-01-24
  • 1970-01-01
  • 2017-05-17
  • 2021-02-10
相关资源
最近更新 更多