SWIGの導入と使用

公式ウェブサイト: https://www.swig.org/ github: https://github.com/swig

SWIG は、C および C++ で書かれたプログラムをさまざまな高レベル プログラミング言語とインターフェースするソフトウェア開発ツールです。

SWIG は、JavaScript、Perl、PHP、Python、Tcl、Ruby などの一般的なスクリプト言語を含む、さまざまなタイプのターゲット言語で動作します。サポートされる言語のリストには、C#、D、Go 言語、Android を含む Java、Lua、OCaml、Octave、Scilab、R などの非スクリプト言語も含まれます。さまざまな解釈およびコンパイルされた Scheme 実装もサポートされています (Guile、MzScheme/Racket)。SWIG は、高レベルの解釈またはコンパイルされたプログラミング環境、ユーザー インターフェイスの作成、および C/C++ ソフトウェアのテストとプロトタイピングのためのツールとして最もよく使用されます。SWIG は通常、C/C++ インターフェイスを解析し、上記のターゲット言語が C/C++ コードを呼び出すために必要な「グルー コード」を生成するために使用されます。SWIG は、その解析ツリーを XML としてエクスポートすることもできます。SWIG はフリー ソフトウェアであり、SWIG によって生成されたコードは商用および非商用プロジェクトと互換性があります。

ダウンロードとインストール:

https://www.swig.org/download.html

./configure --prefix=/usr \
            --without-maximum-compile-warnings &&
make
make install 

1、Java 用 SWIG:

公式ウェブサイト: SWIG および Java

SWIG の Java 拡張機能を使用すると、SWIG が Java Native Interface (JNI) コードを作成するため、Java から既存の C/C++ コードに非常に簡単にアクセスできます。「javah」ツールの使用とは異なります。SWIG は既存の C/C++ コードをラップしますが、javah は「ネイティブ」Java 関数宣言を受け取り、C/C++ 関数プロトタイプを作成します。SWIG は C/C++ コードを Java プロキシ クラスでラップします。これは、Java から多くの C/C++ コードにアクセスする場合に便利です。必要な JNI 関数が 1 つまたは 2 つだけの場合、SWIG を使用するのは過剰になる可能性があります。SWIG により、Java プログラムは Java から C/C++ コードを簡単に呼び出すことができます。これまで、SWIG は C++ から Java コードを呼び出すコードを生成できませんでした。ただし、SWIG は言語間のポリモーフィズムを完全にサポートし、C++ 仮想メソッドをラップするときに C++ から Java に呼び出すコードを生成します。

LightGBM4j: SWIG を使用した LightGBM の Java ラッパー。

https://github.com/metarank/lightgbm4j

1) SWIG と JNA の違い:

2) SWIG for Java では何ができるのですか?

SWIG は、C および C++ で書かれたライブラリを呼び出すことができる他のプログラミング言語の中間コードを生成します。たとえば、Java が JNI を介して C および C++ を呼び出すことができることがわかっている場合、SWIG は「JNI のことを行っている」ことになります。

ここで「JNI を実行する」ことについて説明します。Java を開発しているとき、場合によっては C で開発されたライブラリを呼び出す必要があります。ただし、Java コードが C によって開発されたライブラリを直接呼び出す方法はありません。これは、およそ 2 つの手順で開発する必要があります。

最初のステップでは、Java レイヤー コードを作成し、so ライブラリをロードし、ネイティブ メソッドを宣言する必要があります。

//MyFunJNI.java文件,包名为: com.my.fun
public class MyFunJNI {
  static {
      System.loadLibrary("myfun");
  }
  public final static native int doFun();
}

2 番目のステップでは、最初のステップ MyFunJNI の doFun メソッドに対応する C レイヤー コードを記述し、使用する C ライブラリ内の関数 int c_fun() を呼び出す必要があります。

/myjni.c
jint Java_com_my_fun_MyFunJNI_doFun(JNIEnv *env,jobject thiz){
    return c_fun();
}

次に、libmyfun.so などの myjni.c プログラミング ライブラリを配置し、この libmyfun.so と C で記述されたライブラリを、Java プログラムの実行時にロードできる場所に配置します。

このようにして、Java プログラムは C で開発されたライブラリ内のメソッドを呼び出すことができます。ほとんどの場合、コーディングの 2 番目のステップは、特にある種の変換作業が含まれる場合、Java から C に変換するという退屈な作業です。記述に慣れていない場合は、自分でチェックするか、他の場所からコピーする必要があります。 。ただし、SWIG を使用すると、SWIG が生成できるため、最初のステップと 2 番目のステップで関連するコードを自分で記述する必要はありません。したがって、SWIG が行うことは、「重い、退屈、エラーが発生しやすい」仕事からあなたを解放することだと思います。

 2. SWIG は以下を使用します。

1) パッケージ化する C/C++ ファイルが次のとおり、example.c という名前であると仮定します。

#include <time.h>
 double My_variable = 3.0;
 
 int fact(int n) {
     if (n <= 1) return 1;
     else return n*fact(n-1);
 }
 
 int my_mod(int x, int y) {
     return (x%y);
 }
 	
 char *get_time()
 {
     time_t ltime;
     time(&ltime);
     return ctime(&ltime);
 }

2) さらに、インターフェイス定義スクリプト i ファイル (example.i) を定義する必要もあります。

%module example
 %{
 /* Put header files here or function declarations like below */
 extern double My_variable;
 extern int fact(int n);
 extern int my_mod(int x, int y);
 extern char *get_time();
 %}
 
 extern double My_variable;
 extern int fact(int n);
 extern int my_mod(int x, int y);
 extern char *get_time();

3) SWIG コマンドを実行して、Java に対応するファイルを生成します。

swig -java example.i

次の 2 つの Java ファイルが生成されます。 

チェック:

public class example {
  public static void setMy_variable(double value) {
    exampleJNI.My_variable_set(value);
  }
  public static double getMy_variable() {
    return exampleJNI.My_variable_get();
  }
  public static int fact(int n) {
    return exampleJNI.fact(n);
  }
  public static int my_mod(int x, int y) {
    return exampleJNI.my_mod(x, y);
  }
  public static String get_time() {
    return exampleJNI.get_time();
  }
}
public class exampleJNI {
  public final static native void My_variable_set(double jarg1);
  public final static native double My_variable_get();
  public final static native int fact(int jarg1);
  public final static native int my_mod(int jarg1, int jarg2);
  public final static native String get_time();
}

JAVA の観点から見ると、インターフェイスのカプセル化は完了していますが、ネイティブ メソッドは、次のコマンドを通じて、対応するダイナミック ライブラリを呼び出してパッケージ化する必要があります。ここがピットポイントであることに注意してください。次のコマンドは、ローカル JAVA 環境の include ディレクトリ内のダイナミック ライブラリを通じてコン​​パイルされており、異なる環境を適切なパスに変更する必要があるため、コピーできません。

4) gcc でコンパイルします。

gcc -c -fPIC example.c example_wrap.c -I/usr/lib/jvm/jdk-11.0.9/include -I/usr/lib/jvm/jdk-11.0.9/include/linux

生成された example.o と example_Wrap.o

5) ダイナミック リンク ライブラリを生成します。

gcc -shared -o example.so example.o example_wrap.o

生成された example.so

6) Java で呼び出します。

SWIG によって生成された 2 つの Java ファイル (example.java と example_JNI.java) を Java プロジェクトにコピーし、次のようにします。

public class main {
   public static void main(String argv[]) {
     System.load("/home/kevin/Documents/Cpp/example.so");
     System.out.println(example.getMy_variable());
     System.out.println(example.fact(5));
     System.out.println(example.get_time());
   }
 }

なお、ここにも落とし穴があり、ダイナミックライブラリを読み込むには、System.loadで絶対パスでファイルを読み込む方法と、System.loadLibraryでシステムライブラリのデフォルトパスを読み込む方法の2通りがあります。 。

SWIG の初体験 - Zhihu

おすすめ

転載: blog.csdn.net/liuxiao723846/article/details/131216385