2011-09-22 4 views
1

私はC++ライブラリxyzを持っています。 xyzA,xyzBなど多くのクラスがあります。xyzライブラリにあるxyzAクラスのメソッドgetAge()を使いたいと思います。JNIを使​​用してC++ライブラリから特定のクラスのメソッドを読み込む

xyz.soファイルは既に存在します。 Javaクラスのヘッダーを作成し

  1. Javaクラスを作成し

    xyz.java

    class xyz { 
    
        public native int getAge(); 
    
        public static void main(String[] args) { 
         new xyz().getAge(); 
        } 
        static { 
         System.loadLibrary("xyz"); 
        } 
    } 
    
  2. を:私は続いている

    手順。

    /* DO NOT EDIT THIS FILE - it is machine generated */ 
    #include <jni.h> 
    /* Header for class xyz */ 
    
    #ifndef _Included_xyz 
    #define _Included_xyz 
    #ifdef __cplusplus 
    extern "C" { 
    #endif 
    /* 
    * Class:  xyz 
    * Method: getAge 
    * Signature:()I 
    */ 
    JNIEXPORT jint JNICALL Java_xyz_getAge 
        (JNIEnv *, jobject); 
    
    #ifdef __cplusplus 
    } 
    #endif 
    #endif 
    
  3. CPPラッパークラスは次のようになります。次のように

    #include <stdio.h> 
    #include "xyz.h" 
    #include <jni.h> 
    
    JNIEXPORT jint JNICALL Java_xyz_getAge(JNIEnv *, jobject) 
    { 
        // some code 
    } 
    
  4. 私は正常にクラスをコンパイル:

    java -Djava.library.path=/grid/0/tmp/direct/lib xyz 
    

    gcc -fPIC -shared -l stdc++ -I/grid/0/gs/java/jdk64/current/include -I/grid/0/gs/java/jdk64/current/include/linux xyz.cpp 
    
  5. 次にとしてのJava PROGを実行します

    は、私は次のエラーを取得する:

    Exception in thread "main" java.lang.UnsatisfiedLinkError: xyz.getAge()I 
         at xyz.getAge(Native Method) 
         at xyz.main(xyz.java:6) 
    

それはクラスxyzAに固有の方法getAge()を見つけることができません。そのメソッドにはどのようにアクセスできますか?また、ライブラリはラッパークラスを介してリンクされていますか?

何か指摘していただければ幸いです。

ありがとうございました。

答えて

2

Unixで実行している場合、共有ライブラリの名前はで、xyz.soではありません。

+0

もう1つの方法は、 'System.load(String)'を使用し、フルパスとファイル名を指定する方法です。しかし、共有ライブラリ命名のためのプラットフォーム規約に従うことは、今でも良い考えです。 –

+0

'strace'は、jvmがロードしようとしているものを見つけるのに便利です。 – msandiford

0

C++ライブラリのエクスポート関数名はです。:プレーン関数名は、クラスと名前空間の名前、パラメータと戻り値の型で修飾されています。たとえば、ブーストライブラリのメソッドの1つは次のとおりです。

この形式の名前は標準化されておらず、コンパイラによって異なります。最終的には、C++で別のモジュールを作成し、同じコンパイラを使用してコンパイルしない限り、エクスポートされたC++メンバ関数を呼び出すことは困難です。 Javaからの呼び出しを試みることは、それが価値があるよりも面倒です。代わりに

、C++ライブラリは、extern "C"呼び出し規約を使用してエクスポートするヘルパー関数あなたの場合:

Foo * foo; 

extern "C" 
{ 
    void myfunc() 
    { 
    foo->bar(); // Call C++ function within a C-style function. 
    } 
} 

ライブラリは、サードパーティである場合は、使用して必要な機能を公開する独自のライブラリでそれをラップする必要があります上記のようなCスタイルのエクスポート。

+1

ヘッダファイルを見てください: 'extern" C "' stuffはすでにそこにあります。 –

+0

おっと。はい、今見ます。 – RobH

0

このエラーは通常、ライブラリが正常にロードされたことを意味しますが、 が機能のシグネチャに矛盾があります。 コードは全体的に正しいと思われますが、extern "C"を の表記JNIEXPORTにコードベースで置きます。生成された ヘッダーを使用しないので、関数の定義は と指定できるextern "C"の唯一の場所です。あなたのケースでは、私はコンパイラは、 は、.cppに定義されている が同じであることを認識し、関数を extern "C"と定義していることを認識しているはずです。私は100%確信していません。あなた は次のような何かを行うことによって確認することができます。

nm -C libxyz.so | egrep getAge 

を関数が二 列目のTで、Cの関数として表示されます。 -Cがなければ、それは抱かれていないように見えるはずです。 の定義と宣言のわずかな違いは、別の関数を定義していることを意味します( )。投稿したコード には表示されませんが、二重チェックの価値があります。

(私も念のために、tryブロックでのLoadLibraryへの呼び出しをラップと思います。)

EDITEDいくつかの追加情報を追加するために:

いつ、どのようにLinuxのリンク、私はわからないんだけど追加のライブラリが必要です。 私たちはすべてのライブラリを常に明示的に読み込んでいます。 dlopenへのコールをJNI_OnLoadまたは スタティックオブジェクトのコンストラクタのいずれかに追加してみてください。 ( の引数をdlopenに制御するためにこれをとにかくお勧めします。いくつかの異なるものをロードするときに、 .soが見つからなかった場合、RTTIはライブラリの境界を越えて機能しませんでした。)I は、ローダーエラーが発生しますが、すべて はLinuxがロードしようとしたときに依存しますlibxyz.so; JVMがdlsymを呼び出したときにのみそうであれば、上記のエラーが発生します。 (私はこの あなたは java.lang.System.LoadLibraryを呼び出すときにJVMがdlopenに渡す引数に依存だと思う:それはRTLD_LAZYまたはRTLD_NOWに合格した場合 JNI_OnLoadにおける負荷または静的 オブジェクトのコンストラクタを強制することで、あなたは多かれ少なかれ、そのローダーを保証しますエラーはローダー エラーとして表示され、後でリンクエラーは発生しません。

関連する問題