Как загружать собственные библиотеки для JNI, чтобы избежать UnsatisfiedLinkError?
Я хочу использовать JNI на Ubuntu 8.10, используя 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");
Затем он работает, но я бы скорее не использовал явный путь, если это было возможно.
Ответы
Ответ 1
В соответствии с Pax вы должны установить путь библиотеки туда, где Java должна искать библиотеку. Имя вашей библиотеки должно быть libhello.so. Затем вызов для загрузки библиотеки должен быть:
System.loadLibrary("hello");
Библиотеки Linux ссылаются на соглашение lib name.so и загружаются на основе имени. Ниже приведено link о проблемах динамической компоновки в Java из документации SWIG, хотя вы не используете SWIG, этот раздел по-прежнему имеет значение.
Ответ 2
Вы вызываете System.loadLibrary()
неверно. Метод loadLibrary
принимает имя библиотеки, например. "привет" и пытается загрузить соответствующий общий объект. В Unix он попытается загрузить "libhello.so", а в окнах попытается загрузить "hello.dll". Он ожидает, что файл будет найден в java.library.path
.
Метод, который вы, вероятно, собираетесь вызывать, System.load()
, который принимает полное имя файла и загружает его. Этот метод должен принимать аргумент File
в качестве аргумента, но вместо этого он берет строку. Если вы используете load
, вам придется обрабатывать локальные соглашения об именах вручную, но вам не придется полагаться на java.library.path
, который будет установлен.
Ответ 3
Выполните следующие действия:
-
измените свой класс Java на это:
class Hello {
public native void sayHello();
static {
System.loadLibrary("hello");
}
public static void main(String[] args) {
Hello h = new Hello();
h.sayHello();
}
}
-
переименуйте hello.so в libhello.so:
cp hello.so libhello.so
или mv hello.so libhello.so
-
выполните как: java -Djava.library.path=/home/gavin/Work/workspace/JNI/ Hello
Ответ 4
И вы запускаете его с чем-то вроде:
java -Djava.library.path=/home/gavin/Work/workspace/JNI Hello
Вам нужно убедиться, что общий объект находится в вашем пути к библиотеке.
Ответ 5
ОС: 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 домой: экспорт JAVA_HOME =/usr/java/jdk1.7.0_67-cloudera/
скомпилировать класс java:
javac JNIHello.java
создать JNIHello.h:
javah JNIHello
реализовать sayHello в JNIHello.c:
#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 ref:
3.1.1. Shared Library Names
Каждая общая библиотека имеет специальное имя, называемое `` soname ''. У soname есть префикс 'lib', имя библиотеки, фраза .so ',
ссылка ссылки