Javaネイティブインターフェイス C ++。 Linux 最初のステップ

ハブには既に同様の記事がありましたが、Windowsの場合と、私のような初心者には「明確ではありません」。 原則として、複雑なことは何もありませんが、私がそうであったように、長い間つまずいて検索エンジンに座る場所があります。



JavaアプリケーションでC / C ++を使用する方法と方法については、誰もが自分で思い付くでしょう、私はこれにこだわることはありません、どんな機器で作業するときでも、そのようなバンドルは本当に便利です。



また、データ型のニュアンスについては触れません。プリミティブ型(jintやjdoubleなど)は、C ++のネイティブな型とはまったく何も違いません。



など。 まず、その仕組みについて簡単に説明します。 たとえば、特定の画像を処理して子猫の数を返すC ++コードを作成します。 次に、動的にロードされたライブラリをコンパイルし、それをJavaアプリケーションにロードします。これにより、VKから画像がダウンロードされます。 難しくありません。



接続されたライブラリから関数を呼び出すには、クラスで対応するメソッドを宣言し、ネイティブとしてマークする必要があります。 さらに、対応する署名を持つ関数プロトタイプを含むヘッダーファイルが生成されます。



NativeCode.java
public class NativeCode { //            loadLibrary //        NativeCode static { System.loadLibrary( "nativecode" ); } public NativeCode() { //   srand    srand(); } //      public native int getInt(); //     int public native void showInt(int i); //     int public native void showIntArray(int[] array); //    public native int getRandomInt(); //       public native void addOneToArray(int[] array); private native void srand(); }
      
      









ヘッダーは、コンパイルされたクラスファイルからjavahユーティリティによって取得されます。



 javac NativeCode.java javah -jni -o NativeCode.h NativeCode
      
      







NativeCode.h
 /* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class by_framework_nativeapp_NativeCode */ #ifndef _Included_by_framework_nativeapp_NativeCode #define _Included_by_framework_nativeapp_NativeCode #ifdef __cplusplus extern "C" { #endif /* * Class: by_framework_nativeapp_NativeCode * Method: getInt * Signature: ()I */ JNIEXPORT jint JNICALL Java_by_framework_nativeapp_NativeCode_getInt (JNIEnv *, jobject); /* * Class: by_framework_nativeapp_NativeCode * Method: showInt * Signature: (I)V */ JNIEXPORT void JNICALL Java_by_framework_nativeapp_NativeCode_showInt (JNIEnv *, jobject, jint); /* * Class: by_framework_nativeapp_NativeCode * Method: showIntArray * Signature: ([I)V */ JNIEXPORT void JNICALL Java_by_framework_nativeapp_NativeCode_showIntArray (JNIEnv *, jobject, jintArray); /* * Class: by_framework_nativeapp_NativeCode * Method: getRandomInt * Signature: ()I */ JNIEXPORT jint JNICALL Java_by_framework_nativeapp_NativeCode_getRandomInt (JNIEnv *, jobject); /* * Class: by_framework_nativeapp_NativeCode * Method: addOneToArray * Signature: ([I)V */ JNIEXPORT void JNICALL Java_by_framework_nativeapp_NativeCode_addOneToArray (JNIEnv *, jobject, jintArray); /* * Class: by_framework_nativeapp_NativeCode * Method: srand * Signature: ()V */ JNIEXPORT void JNICALL Java_by_framework_nativeapp_NativeCode_srand (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif
      
      









結果のヘッダーファイルにまったく手を触れない方がよいでしょう。なぜなら、 プロジェクトのアセンブリ中に変更される場合があります。 それをcppファイルに含めて、そこにある関数を説明するだけです。主なことは、関数名とパラメーターを台無しにすることではなく、このIDEをコピーまたは指示することです。



NativeCode.cpp
 #include <iostream> #include <ctime> #include <cstdlib> #include <iomanip> #include "NativeCode.h" JNIEXPORT jint JNICALL Java_by_framework_nativeapp_NativeCode_getInt (JNIEnv *enc, jobject obj) { int input = 1; std::cout<<"Input number: "; std::cin>>input; if(input<0) input = 0; return input; } JNIEXPORT void JNICALL Java_by_framework_nativeapp_NativeCode_showInt (JNIEnv *env, jobject obj, jint i) { std::cout<<"Output number: "<<i<<std::endl; } JNIEXPORT void JNICALL Java_by_framework_nativeapp_NativeCode_showIntArray (JNIEnv *env, jobject obj, jintArray jarray) { int len = env->GetArrayLength(jarray); std::cout<<"Array length: "<<len<<std::endl; jint* arr = env->GetIntArrayElements(jarray, 0); for(int i = 0; i < len; i++) { std::cout<<std::setw(5)<<i<<": "<<std::setw(4)<<arr[i]<<std::endl; } env->ReleaseIntArrayElements(jarray, arr, 0); } JNIEXPORT jint JNICALL Java_by_framework_nativeapp_NativeCode_getRandomInt (JNIEnv *env, jobject obj) { int i = rand()%100; return i; } JNIEXPORT void JNICALL Java_by_framework_nativeapp_NativeCode_addOneToArray (JNIEnv *env, jobject obj, jintArray jarray) { int len = env->GetArrayLength(jarray); jint* arr = env->GetIntArrayElements(jarray, 0); for(int i = 0; i < len; i++) { ++(*(arr+i)); } // .. GetIntArrayElements    ,  //    Java   env->ReleaseIntArrayElements(jarray, arr, 0); } JNIEXPORT void JNICALL Java_by_framework_nativeapp_NativeCode_srand (JNIEnv *env, jobject obj) { srand(time(NULL)); }
      
      









動的ライブラリを構築しています。

 g++ -o libnativecode.o -I"/usr/lib/jvm/java-1.7.0-openjdk-amd64/include" -I"/usr/lib/jvm/java-1.7.0-openjdk-amd64/include/linux" -fpic -c NativeCode.cpp g++ -o libnativecode.so -shared libnativecode.o
      
      







-fpic -c -sharedフラグは、適切なコンパイルに必要です。



ライブラリ名がテンプレートlib [name] .soに一致する必要があります。Linuxに精通している人は、これを明白なものと考えている可能性が高いですが、ここでは長い間ハングしました。 win32の既存の記事では、libプレフィックスについての言葉ではありません。



mainメソッドを使用してJavaでクラスを記述し、それをコンパイルしてアプリケーションを実行します。



Appclass.java
 public class AppClass { public static void main(String[] args) { //    NativeCode     //     NativeCode nc = new NativeCode(); int i = nc.getInt(); nc.showInt(++i); int[] array = new int[i]; //     for(int j = 0; j < i; j++) { array[j] = nc.getRandomInt(); } nc.showIntArray(array); nc.addOneToArray(array); nc.showIntArray(array); } }
      
      









 javac AppClass.java
      
      







起動時に、動的ライブラリを含むディレクトリへのパスを仮想マシンに示します。 デフォルトでは、環境変数に記録されたパスのみで検索します。

 java -Djava.library.path="." AppClass
      
      







各ファイルを個別に手動でコンパイルしないように、単純なMakefileを作成できます。これは、後でEclipseで使用できます



メイクファイル
 all : NativeCode.so NativeCode.so : NativeCode.obj g++ -o bin/libnativecode.so -shared bin/libnativecode.o NativeCode.obj: cpp_src/NativeCode.cpp java_headers g++ -o bin/libnativecode.o -I"/usr/lib/jvm/java-1.7.0-openjdk-amd64/include" -I"/usr/lib/jvm/java-1.7.0-openjdk-amd64/include/linux" -fpic -c cpp_src/NativeCode.cpp java_headers: java_class_files javah -jni -o cpp_src/NativeCode.h -classpath bin by.framework.nativeapp.NativeCode java_class_files: src/by/framework/nativeapp/NativeCode.java src/by/framework/nativeapp/AppClass.java mkdir -p bin javac -d bin -cp bin src/by/framework/nativeapp/NativeCode.java javac -d bin -cp bin src/by/framework/nativeapp/AppClass.java
      
      









GitHubですべてのコードをダウンロードできます



All Articles