【问题标题】:How should I load native libraries for JNI to avoid an UnsatisfiedLinkError?我应该如何为 JNI 加载本机库以避免 UnsatisfiedLinkError?
【发布时间】:2009-05-24 10:58:02
【问题描述】:

我想在 Ubuntu 8.10 上使用 JNI,使用 Eclipse 和 gcc(Ubuntu 的标准版本,如果有的话)。

尽管 make 文件成功创建了我的库,但我似乎无法加载它。

主要的Java类如下:

class Hello {
    public native void sayHello();

    static {
        System.loadLibrary("hello.so");
    }

    public static void main(String[] args) {
        Hello h = new Hello();
        h.sayHello();
    }
}

我的make文件就是这样的;

    all : hello.so

hello.so : Hello.o
    gcc -shared -o hello.so Hello.o

Hello.o : Hello.c Hello.h
    gcc -I/usr/lib/jvm/java-6-sun/include -I/usr/lib/jvm/java-6-sun/include/linux -c Hello.c -o Hello.o

Hello.h : Hello.class
    javah -jni Hello

clean :
    -del Hello.h
    -del Hello.o

其余代码 (Hello.c) 看起来像人们想象的那样。

我得到的错误如下;

Exception in thread "main" java.lang.UnsatisfiedLinkError: no hello.so in java.library.path

如果我使用显式路径:

System.loadLibrary("/home/gavin/Work/workspace/JNI/hello.so");

然后它可以工作,但如果可能的话,我宁愿不使用显式路径。

【问题讨论】:

标签: java c java-native-interface


【解决方案1】:

你打电话给System.loadLibrary() 不正确。 loadLibrary 方法采用库名称,例如“你好”,并尝试加载相应的共享对象。在 Unix 上,它将尝试加载“libhello.so”,而在 Windows 上,它将尝试加载“hello.dll”。它将期望在java.library.path 中找到该文件。

您可能打算调用的方法是System.load(),它采用完全限定的文件名并加载它。此方法应采用 File 作为参数,但它采用字符串代替。如果您使用load,则必须手动处理本地命名约定,但不必依赖java.library.path 来设置。

【讨论】:

    【解决方案2】:

    根据 Pax,您应该将库路径设置为 Java 应该查找该库的位置。您的库名称应该是 libhello.so。加载库的调用应该是:

    System.loadLibrary("hello");
    

    Linux 库由约定 libname.so 引用并根据名称加载。这是 SWIG 文档中关于 Java 中动态链接问题的link,尽管您没有使用 SWIG,但此部分仍然相关。

    【讨论】:

    • 链接没问题,但是关于使用'-rpath'的注释是假的。要使 'rpath 工作,必须在编译该 java 虚拟机本身时指定它。
    【解决方案3】:

    操作系统:CentOS6.5。 JNIHello.java:

    public class JNIHello {
                    static {
                                    System.loadLibrary("JNIHello");
                    }
                    private native void sayHello();
                    public static void main(String args[]) {
                                    JNIHello jniHello = new JNIHello();
                                    jniHello.sayHello();
                    }
    }
    

    导出 java 主页: export JAVA_HOME=/usr/java/jdk1.7.0_67-cloudera/

    编译java类:

    javac JNIHello.java
    

    生成 JNIHello.h:

    javah JNIHello
    

    在 JNIHello.c 中实现 sayHello:

    #include <jni.h>
    #include <stdio.h>
    #include "JNIHello.h"
    /*
     * Class:     JNIHello
     * Method:    sayHello
     * Signature: ()V
     */
    JNIEXPORT void JNICALL Java_JNIHello_sayHello
      (JNIEnv *env, jobject obj) {
            printf("Hello world!\n");
            return;
    }
    

    编译库:

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

    运行 JNIHello:

    java -Djava.library.path=/home/ldp/caffe/test/ JNIHello
    Hello world!
    

    lib 名称格式参考:

    3.1.1. Shared Library Names
    

    每个共享库都有一个特殊的名称,称为“soname”。 soname 有前缀'lib'、库的名称、短语'.so'

    ref link

    【讨论】:

      【解决方案4】:

      执行以下操作:

      1. 将您的 Java 类更改为:

        class Hello {
        
            public native void sayHello();
        
            static {
                System.loadLibrary("hello");
            }
        
            public static void main(String[] args) {
                Hello h = new Hello();
                h.sayHello();
            }
        }
        
      2. 将 hello.so 重命名为 libhello.so: cp hello.so libhello.somv hello.so libhello.so

      3. 运行为:java -Djava.library.path=/home/gavin/Work/workspace/JNI/ Hello

      【讨论】:

        【解决方案5】:

        你是否使用类似的东西来运行它:

        java -Djava.library.path=/home/gavin/Work/workspace/JNI Hello
        

        您需要确保共享对象在您的库路径中

        【讨论】:

        • 如果通过 JNA(不是 JNI)访问原生库,则必须改为定义 jna.library.path。
        猜你喜欢
        • 1970-01-01
        • 2013-02-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多