はじめに
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秒