2010-12-06 5 views
0

Я получаю UnsatisfiedLinkError при вызове функций C из JNI, хотя моя настройка кажется правильной. Вот что я сделал:Сбой JNI с UnsatisfiedLinkError

Там есть класс Java:

package com.mycompany.myproduct; 

public class Foo { 
    static { 
     System.loadLibrary("external"); 
    } 

    public void native do_foo(); 
} 

Я поместил libexternal.so в LD_LIBRARY_PATH, составленный класс, и выполняется javah над ним. Результирующая com_mycompany_myproduct_Foo.h файл:

/* DO NOT EDIT THIS FILE - it is machine generated */ 
#include <jni.h> 
/* Header for class com_mycompany_myproduct_Foo */ 

#ifndef _Included_com_mycompany_myproduct_Foo 
#define _Included_com_mycompany_myproduct_Foo 
#ifdef __cplusplus 
extern "C" { 
#endif 
/* 
* Class:  com_com_mycompany_myproduct_Foo 
* Method: do_foo 
* Signature:()V 
*/ 
JNIEXPORT void JNICALL Java_com_mycompany_myproduct_Foo_do_1foo(JNIEnv *, jobject); 

Реализован делегацию C в ctinative.c (не уверен, что если extern "C" нужен там):

#include "com_mycompany_myproduct_Foo.h" 

#include "External.h" 

#ifdef __cplusplus 
extern "C" { 
#endif 

/* 
* Class:  com_com_mycompany_myproduct_Foo 
* Method: do_foo 
* Signature:()V 
*/ 
JNIEXPORT void JNICALL Java_com_mycompany_myproduct_Foo_do_1foo(JNIEnv *, jobject) { 
    do_foo(); // this is a function that defined in External.h 
} 

#ifdef __cplusplus 
} 
#endif 

Составитель что и получил ctinative.o:

gcc -x c -g -m64 -DUNIX=1 -DUSE_SBUF=1 -DMAIN_VERSION=0 -DC_VER=7 -I$(EXTERNAL_SDK_ROOT)/include -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux -o ctinative.o -c ctinative.c 

Вот результат nm ctinative.o (есть U там нормальный?):

0000000000000000 T Java_com_mycompany_myproduct_Foo_do_1foo 
       U do_foo 

Размещено с ctinative.o по LD_LIBRARY_PATH. Теперь при вызове Foo.do_foo() я получаю UnsatisfiedLinkError:

java.lang.UnsatisfiedLinkError: com.mycompany.myproduct.Foo.do_foo()V 
at com.mycompany.myproduct.Foo.do_foo(Native Method) 

Если удалить ctinative.o из LD_LIBRARY_PATH ошибка не меняется. Если удалить libexternal.so из LD_LIBRARY_PATH тогда, конечно, я получаю:

java.lang.UnsatisfiedLinkError: no external in java.library.path 
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1734) 
at java.lang.Runtime.loadLibrary0(Runtime.java:823) 
at java.lang.System.loadLibrary(System.java:1028) 
at com.mycompany.myproduct.Foo.<clinit> 

Любую идею о том, что я делаю неправильно?

+0

One Try: Позволяет проверить его, явно передавая путь lib, либо передать его таким образом `-Djava.library.path =/YOUR/PATH/TOLIB/DIR /` или предоставить полный путь в `loadLibrary()`, дайте мне знать результат – 2010-12-06 12:12:42

+0

Какой код, если он есть, находится в libexternal.so? – msandiford 2010-12-06 12:13:47

ответ

2

ОК, мой опыт работы с родными библиотеками на Linux ограничен игрушечными тестами, однако я довольно широко использовал их в Windows. Я ожидаю, что механизм схож, но продолжайте с осторожностью :)

Java завершает вызов функции Java_com_mycompany_myproduct_Foo_do_1foo(), когда вы выполняете метод fooInstance.do_foo(). Это нативная функция, которая должна быть определена в libexternal.so (или что вы решите загрузить с loadLibrary()).

Если я правильно понял ваш вопрос, вы скомпилировали функцию Java_com_mycompany_myproduct_Foo_do_1foo() в ctinative.o, а реализация не указана в libexternal.so. Вы можете проверить это с помощью objdump --dynamic-reloc libexternal.so.

Я считаю, что вам нужно, чтобы ваша родная реализация Java_com_mycompany_myproduct_Foo_do_1foo() скомпилирована в libexternal.so, или в качестве альтернативы вы можете связать ctinative.o производить динамическую библиотеку что-то вроде libctinative.so.

EDIT: Для того, чтобы соединить точки, полный механизм будет:

  1. Ваш Java код вызывает loadLibrary() на .so файл, который реализует функцию Java_com_mycompany_myproduct_Foo_do_1foo(). Назовем это libctinative.so.
  2. libctinative.so динамически загружает libexternal.so через/динамический механизм связующей O S в --- вам не нужно делать ничего особенного, чтобы это произошло помимо компиляции и компоновки libctinative.so в правильном направлении
  3. Ваша программа работает корректно, если предположить, нет других вопросов :)
0

У вас есть Java_com_mycompany_myproduct_Foo_do_1foo(), но native void do_foo(). Было ли имя do_1foo(), когда вы сгенерировали файлы .h/.c? Если вы изменили его, вам нужно регенерировать.

Смежные вопросы