JNAを使えば、Javaから簡単にネイティブライブラリを呼び出すことができることを書きました。
Javaからネイティブライブラリを簡単に呼び出せるJNA
このブログではC言語の標準ライブラリを呼び出しましたが、このシリーズの最後として、作成した動的ライブラリをJavaから呼び出してみます。
C言語のヘッダーをJavaのインターフェースに変換する。
作成した動的ライブラリの関数の宣言をC言語的に書くなら次のようになります。
int hello();
Javaからこの関数を呼び出すためには、Javaのインターフェースに置きかえる必要があります。
変換ツールjnaerator
JNAのインターフェースへの変換ツールとして、jnaeratorがあります。これはC言語の関数宣言を入力として、Javaのインターフェースを変換出力するツールです。
そして、変換された結果がこちらです。
package test;
import com.ochafik.lang.jnaerator.runtime.LibraryExtractor;
import com.ochafik.lang.jnaerator.runtime.MangledFunctionMapper;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.NativeLibrary;
/**
* JNA Wrapper for library test
* This file was autogenerated by JNAerator,
* a tool written by Olivier Chafik that uses a few opensource projects..
* For help, please visit NativeLibs4Java , Rococoa, or JNA.
*/
public interface TestLibrary extends Library {
public static final String JNA_LIBRARY_NAME = LibraryExtractor.getLibraryPath("test", true, TestLibrary.class);
public static final NativeLibrary JNA_NATIVE_LIB = NativeLibrary.getInstance(TestLibrary.JNA_LIBRARY_NAME, MangledFunctionMapper.DEFAULT_OPTIONS);
public static final TestLibrary INSTANCE = (TestLibrary)Native.loadLibrary(TestLibrary.JNA_LIBRARY_NAME, TestLibrary.class, MangledFunctionMapper.DEFAULT_OPTIONS);
/**
* Original signature : int hello()
* native declaration : line 2
*/
int hello();
}
コメントが大半なのでカオスに見えますが、大切なのはhello関数がちゃんとJavaのインターフェースとして定義されている点です。
依存の解決
jnaeratorで生成されたインターフェースを使うには、jnaeratorのランタイムライブラリが必要です。Mavenで依存解決することができます。
com.nativelibs4java
jnaerator-runtime
0.11
実際に使ってみる
ここまでできれば、これを使うのは、C言語のprintfと呼ぶのと同じです。
public class App {
public static void main(String[] args) {
System.exit(TestLibrary.INSTANCE.hello());
}
}
この時に、動的ライブラリは、クラスパスに配置することで読み出すことができるようになります。
たとえば次のように、プラットフォームごとにディレクトリをわけて配置することで、マルチプラットフォームで実行することができます。
darwin/libdylibexample.dylib linux-ia64/libdylibexample.so win32-x86/dylibexample.dll
こうして、JNAを使ってJavaからネイティブの動的ライブラリを呼び出すことができました!