FM牛鍵屋本舗

プログラマ(弱)の日々精進系ブログ

native修飾子を使ってみる(JNI)

javaの勉強を始めた頃に 存在を知ったnative修飾子。 java.lang.Systemのソースなどなど 結構使われていたので、ちょっと学んでみました。

以下をはじめ、いろんな情報源を参考にさせてもらいました。
link

そもそもnative修飾子とは

link

nativeのメソッドは一般的にCのような別の言語で書かれた プラットホームに依存するコードにて実装されます(超意訳)

プラットホームに依存した方が 高速な演算の実現は可能、だけど
一方で環境ごとのライブラリが必要になるから “Write once, run anywhere"の思想からは外れる。
まあ元々WORAは言うほどでもないそうですが。

JNIとは

link Javaネイティブメソッドを書いたり、 Java仮想マシンをネイティブアプリケーションに組み込む 標準プログラミングインターフェース。
JREに含まれてます。

とりあえず試してみる

Javaでnativeメソッドを書いてみる

package hoge;

public class Hoge {
  
  // staticイニシャライザ
  static {
    // 共有ライブラリを読み込む
    System.loadLibrary("<span style="color:#FF0000">HogeHoge</span>");
  }

  public static void main(String[] args) {

    Hoge hoge = new Hoge();
    hoge.call();

  }

  // natice修飾子を付与したメソッド
  // 処理内容は記載しない(interface的な感じ)
  public <span style="color:#FF0000">native</span> void call();

}

普通にclassを生成する

javac hoge/Hoge.java

classファイルからヘッダファイルを生成する

javah -jni hoge.Hoge

結果として、以下のファイルが出力される。

/* DO NOT EDIT THIS FILE - it is machine generated */
#include "jni.h"
/* Header for class hoge_Hoge */

#ifndef _Included_hoge_Hoge
#define _Included_hoge_Hoge
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     hoge_Hoge
 * Method:    call
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_hoge_Hoge_call
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

実装コードを作成する

#include "hoge_Hoge.h"

JNIEXPORT void JNICALL Java_hoge_Hoge_call (JNIEnv *env, jobject obj) {
  printf("Hello, World!"); 
}

ライブラリを作る

僕の環境はMacOSXなのですが、 どうやらライブラリというのは各プラットフォームで色々違うようで。
例えば、WindowsだとDLL形式だとか、Linuxだとlib〜.soだとか。
このあたりは別途詳しく調べるとして、 Macだとdylibというらしいです。

gcc -shared -I /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/include -o lib<span style="color:#FF0000">HogeHoge</span>.dylib hoge_Hoge.c
  • sharedは共有ライブラリを作るオプション
  • -Iは使用するinclude対象を見に行く先。 今回は"jni.h"とそこから参照される"jni_md.h"が必要になるみたい。 find / -name “jni*.h"で探したけど、どうもJDKのinclude及びinclude/darwinにあるみたい。 sudo ln -sでinclude直下にjni_md.hのシンボリックリンクを作りました。
  • Macの場合、共有ライブラリはlib.dylibにしないといけないみたい。 そして、の部分がSystem.loadLibraryの引数になる、と…。

実行する

java -Djava.library.path=. hoge.Hoge

実行結果

hoge$java -Djava.library.path=. hoge.Hoge
Hello, World!%