Java 我应该如何为 JNI 加载本机库以避免 UnsatisfiedLinkError?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/903530/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 20:52:45  来源:igfitidea点击:

How should I load native libraries for JNI to avoid an UnsatisfiedLinkError?

javacjava-native-interface

提问by gav

I want to use JNI on Ubuntu 8.10, using Eclipse and gcc (the standard one with Ubuntu if there are flavours).

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

I can't seem to load my library despite the make file creating it successfully.

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

The main Java class is as follows:

主要的Java类如下:

class Hello {
    public native void sayHello();

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

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

My make file is as such;

我的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

The rest of the code (Hello.c) looks like one would think.

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

The error I'm getting is as follows;

我得到的错误如下;

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

If I use an explicit path:

如果我使用显式路径:

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

Then it works, but I'd much rather not use an explicit path if possible.

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

采纳答案by Daniel Nesbitt

As per Pax you should set the library path to where ever Java should look for the library. Your library name should be libhello.so. The call to load the library should then be:

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

System.loadLibrary("hello");

Linux libraries are referenced by the convention libname.so and loaded based on the name. Here is a linkabout dynamic linking problems in Java from the SWIG documentation, although you are not using SWIG this section is still relevant.

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

回答by paxdiablo

And are you running it with something like:

您是否使用以下内容运行它:

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

You'll need to make sure the shared object is inyour library path.

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

回答by JesperE

You're calling System.loadLibrary()incorrect. The loadLibrarymethod takes a library name, e.g. "hello", and tries to load the corresponding shared object. On Unix, it will attempt to load "libhello.so", and on windows it will try to load "hello.dll". It will expect the file to be found in java.library.path.

你叫System.loadLibrary()错了。该loadLibrary方法采用库名称,例如“hello”,并尝试加载相应的共享对象。在 Unix 上,它将尝试加载“libhello.so”,而在 Windows 上,它将尝试加载“hello.dll”。它将期望在java.library.path.

The method you probably intend to be calling is System.load()which takes a fully qualified filename and loads it. This method should take a Fileas argument, but it takes a string instead. If you use load, you'll have to handle local naming conventions manually, but you won't have to rely on java.library.pathto be set.

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

回答by Nick

Do the following:

请执行下列操作:

  1. change your Java class to this:

    class Hello {
    
        public native void sayHello();
    
        static {
            System.loadLibrary("hello");
        }
    
        public static void main(String[] args) {
            Hello h = new Hello();
            h.sayHello();
        }
    }
    
  2. rename hello.so to libhello.so: cp hello.so libhello.soor mv hello.so libhello.so

  3. run as: java -Djava.library.path=/home/gavin/Work/workspace/JNI/ Hello

  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

回答by echoandlove

OS: CentOS6.5. JNIHello.java:

操作系统: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();
                }
}

export java home: export JAVA_HOME=/usr/java/jdk1.7.0_67-cloudera/

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

compile java class:

编译java类:

javac JNIHello.java

generate JNIHello.h:

生成 JNIHello.h:

javah JNIHello

implement sayHello in JNIHello.c:

在 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;
}

compile library:

编译库:

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

run JNIHello:

运行 JNIHello:

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

lib name format ref:

lib名称格式参考:

3.1.1. Shared Library Names

Every shared library has a special name called the ``soname''. The soname has the prefix 'lib', the name of the library, the phrase '.so',

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

ref link

参考链接