トップ 差分 一覧 ソース 置換 検索 ヘルプ PDF RSS ログイン

JNI、JNAの使い方

はじめに

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を呼ぶためのもの。
手順は以下のとおり。

  1. Javaプログラムの作成とコンパイル
  2. Javaからヘッダファイル作成
  3. Cプログラムの作成とコンパイル
  4. 実行

 Javaプログラムの作成とコンパイル

HelloWorldJNI.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
2
3
4
#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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  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
2
3
4
5
#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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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]



  • Hatenaブックマークに追加
  • livedoorクリップに追加
  • del.icio.usに追加
  • FC2ブックマークに追加

最終更新時間:2013年12月10日 23時19分37秒