2010-12-06 19 views
0

設定が正しいように見えますが、JNIからC関数を呼び出すときにUnsatisfiedLinkErrorが表示されます。ここで私がやったものだ:UnsatisfiedLinkErrorでJNI呼び出しが失敗する

Javaクラスがあります:

package com.mycompany.myproduct; 

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

    public void native do_foo(); 
} 

私は、LD_LIBRARY_PATHlibexternal.soを置いたクラスをコンパイルし、その上にjavahを実行してきました。

/* 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); 

は(extern "C"がそこに必要とされているかどうかわからない)ctinative.cでCの委任を実装:

それをコンパイルし、 ctinative.oを得た
#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 

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 

ここで出力だcom_mycompany_myproduct_Foo.hファイルを結果nm ctinative.oUが正常ですか?):

0000000000000000 T Java_com_mycompany_myproduct_Foo_do_1foo 
       U do_foo 

これは、ctinative.o~LD_LIBRARY_PATHとなります。 Foo.do_foo()を呼び出すときに今、私はないUnsatisfiedLinkErrorを取得しています:私はLD_LIBRARY_PATHからctinative.oを削除

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

場合はエラーは変更されません。私はLD_LIBRARY_PATHからlibexternal.soを削除する場合は、もちろん私は取得しています:

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

1つの試み:明示的にlibパスを指定してチェックしてみましょう。-Djava.library.path =/YOUR/PATH/TOLIB/DIR/'または' loadLibrary() 'でフルパスを指定するか、結果を教えてください –

+0

libexternal.soにはどのようなコードがありますか? – msandiford

+0

@spong:私のC実装ファイルにincludeしているExternal.hは、libexternal.soのヘッダファイルです。とりわけ、私が呼び出そうとしているC関数do_foo()を宣言しています。 –

答えて

2

OK、Linuxのネイティブライブラリでの私の経験は、おもちゃのテストに限られていますが、私はWindows上でかなり広く使っています。私はそのメカニズムが似ていると思いますが、慎重に進めてください:) fooInstance.do_foo()メソッドを実行すると、JavaはJava_com_mycompany_myproduct_Foo_do_1foo()ネイティブ関数を呼び出すことになります。

これは、libexternal.so(あるいは、loadLibrary()でロードすることを選択したもの)で定義する必要があるネイティブ関数です。

あなたの質問が正しく理解されている場合は、Java_com_mycompany_myproduct_Foo_do_1foo()ctinative.oにコンパイルしています。実装はlibexternal.soには表示されません。これはobjdump --dynamic-reloc libexternal.soで確認できます。

私はあなたがlibexternal.soにコンパイルJava_com_mycompany_myproduct_Foo_do_1foo()のネイティブ実装を持っている必要があります信じるか、あるいはあなたがダイナミックリンクライブラリにlibctinative.soのようなものを生成するためにctinative.oをリンクすることができます。

編集:ドットに参加するには、完全なメカニズムは次のようになります。

  1. Javaコードは機能Java_com_mycompany_myproduct_Foo_do_1foo()を実装.soファイルにloadLibrary()を呼び出します。これをlibctinative.soとしましょう。
  2. libctinative.so動的にあなたのプログラムが想定して、正しく実行さ
  3. 正しい方法であなたは、これはlibctinative.soをコンパイルとリンクから離れて実現するために特別なことをする必要はありません--- O/Sの動的リンク機構を介してlibexternal.soをロードしますその他の問題はありません。
+0

うん、そうだった。基本的に、ctinative.oはlibexternal.soを囲む単なるJNIラッパーでした。もちろんSystem.loadLibrary( "external")を呼び出していましたが、これにはJNIエントリーポイントがありません。 ctinative.oをlibctinative.soに再リンクし、System.loadLibrary( "ctinative")を呼び出すと、エラーはなくなりました。もちろん、コアライブラリではなく、読み込み/呼び出すラッパーです。お返事をありがとうございます! –

0

Java_com_mycompany_myproduct_Foo_do_1foo()がネイティブvoid do_foo()です。 .h/.cファイルを生成したときのdo_1foo()の名前は?あなたがそれを変更した場合は、再生する必要があります。

関連する問題