はじめに
64bit Javaから32bitでコンパイルしたNativeは実行できないで注意。
Can't load IA 32-bit .dll on a AMD 64-bit platform
のようなエラーが出る。
共有ライブラリの検索パスについて
OS | JNI | JNA |
---|---|---|
windows | PATH環境変数 java.library.path |
PATH環境変数 jna.library.path |
Linux | LD_LIBRARY_PATH環境変数 java.library.path |
LD_LIBRARY_PATH環境変数 jna.library.path |
JNI
JavaからNativeを呼ぶためのもの。
手順は以下のとおり。
- Javaプログラムの作成とコンパイル
- Javaからヘッダファイル作成
- Cプログラムの作成とコンパイル
- 実行
Javaプログラムの作成とコンパイル
HelloWorldJNI.java
1 |
public class HelloWorldJNI { static { // ライブラリをロードします System.loadLibrary("HelloWorldJNI"); } // ネイティブメソッドを宣言します public native void sayHelloWorld(); public static void main(String[] args) { HelloWorldJNI hello = new HelloWorldJNI(); hello.sayHelloWorld(); } } |
コンパイル
javac HelloWorldJNI.java
Javaからヘッダファイル作成
ヘッダファイル作成
javah HelloWorldJNI
で HelloWorldJNI.h が作成される。
Cプログラムの作成とコンパイル
Cプログラムの作成
HelloWorldJNI.h のプロトタイプ宣言を確認してCプログラムを書く
1 |
#include "HelloWorldJNI.h" JNIEXPORT void JNICALL Java_HelloWorldJNI_sayHelloWorld ( JNIEnv *env, jobject obj ) { printf("Hello World\n"); } |
コンパイル(mingwの例)
gnupack(mingw)を使った場合
gcc -shared HelloWorldJNI.c -Id:/java/include -Id:/java/include/win32 -Wl,--enable-auto-import -Wl,--add-stdcall-alias -o HelloWorldJNI.dll
みたいな感じ。JDKのincludeとinclude/win32にincllude path を通す。
-Wl,--add-stdcall-alias
を付けないと、実行時に関数が見つけられずエラーになるので注意。
また、gnupackでもmingw の場合は
/d/java/include
のような形式ではなく
d:/java/include
のようなパスの書き方をする。
コンパイル(Linuxのgccの例)
gcc -fPIC -shared HelloWorldJNI.c -I /usr/lib/jvm/java-1.7.0-openjdk-1.7.0.25.x86_64/include -I /usr/lib/jvm/java-1.7.0-openjdk-1.7.0.25.x86_64/include/linux/ -o libHelloWorldJNI.so
Linuxの場合、共有ライブラリは lib****.so のように lib が先頭に着くので注意。
実行
Windowsの場合
Windowsの場合は共有ライブラリは
PATH環境変数 java.library.pathオプション
から検索される。以下は実行例
java HelloWorldJNI java -Djava.library.path=d:/temp
Linuxの場合
Linuxの場合は共有ライブラリは
LD_LIBRARY_PATH環境変数 java.library.pathオプション
から検索される。以下は実行例
java HelloWorldJNI java -Djava.library.path=. HelloWorldJNI
JNA
JNI より簡単にネイティブライブラリを使う。
例1
1 |
import com.sun.jna.Library; import com.sun.jna.Native; public class HelloWorld { public interface CLibrary extends Library { CLibrary INSTANCE = (CLibrary) Native.loadLibrary("msvcrt" , CLibrary.class); void printf(String format, Object... args); } public static void main(String[] args) { CLibrary.INSTANCE.printf("Hello, World\n"); } } |
例2
1 |
import com.sun.jna.Library; import com.sun.jna.Native; interface User32 extends Library { // インスタンス生成 User32 INSTANCE = (User32) Native.loadLibrary("user32", User32.class); // 関数へのインターフェース int MessageBoxA(int hWnd, byte[] lpText, byte[] lpCaption, int uType); // 定数定義 int MB_YESNO = 0x00000004; int MB_ICONASTERISK = 0x00000040; } public class test2 { public static void main(String[] args) throws Exception { User32 user32=User32.INSTANCE; user32.MessageBoxA(0, _T("終了しますか?"), _T("終了確認"), User32.MB_ICONASTERISK | User32.MB_YESNO); } // マルチバイト文字列を返す。 private static byte[] _T(final String str) throws Exception { return (str+"\0").getBytes("Windows-31J"); } } |
自分でDLLを作成し、JNAで呼び出す
hello.c
1 |
#include <stdio.h> void hello (){ printf("Hello!\n"); } |
コンパイル
Windowsの場合
gcc -shared -o hello.dll hello.c
Linuxの場合
gcc -fPIC -shared -o libhello.so hello.c
※ライブラリ名に「lib」をつける必要があるので注意
test.java
1 |
import com.sun.jna.Library; import com.sun.jna.Native; interface HelloDLL extends Library { // インスタンス生成 HelloDLL INSTANCE = (HelloDLL) Native.loadLibrary("hello", HelloDLL.class); // 関数へのインターフェース void hello(); } public class test { public static void main(String[] args){ HelloDLL hello = HelloDLL.INSTANCE; hello.hello(); } } |
実行
Windowsの場合
Linuxの場合はLD_LIBRARY_PATH環境変数で示すパスにsoファイルを置く必要がある。
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
など。
Windowsの場合
Windowsの場合は共有ライブラリは
PATH環境変数 jna.library.pathオプション
から検索される。以下は実行例
java test java -Djna.library.path=d:/temp
Linuxの場合
Linuxの場合は共有ライブラリは
LD_LIBRARY_PATH環境変数 jna.library.pathオプション
から検索される。以下は実行例
java test java -Djna.library.path=. test
[カテゴリ: プログラミング言語 > Java]
[通知用URL]
Tweet
最終更新時間:2013年12月10日 23時19分37秒