JNIとは

JNI(Java Native Interface)とはJava言語で開発されたプログラムから、

他の言語で開発されたネイティブコードのプログラムを利用するためのAPIである。

ネイティブコードとは、そのプラットフォームで実行可能なプログラムのこと。

JNIを利用することで、Java上で実行するのには速度面から難しいコードを、

ネイティブコードに書き換え、その部分だけ高速に実行できる。

また、JavaVMをネイティブコードから起動させることができるので、

Cのコードを実行していると見せかけてJavaのコードを呼ぶことができる。

#しかし、この場合はその環境にJREがインストールされている必要がある。

MacOSX(Tiger)でのJNI利用環境

当方の環境を以下に記す。

マシン:MacBook Intel Core2Duo 2GHz

JREのバージョン:1.5.0_07

java version “1.5.0_07″
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_07-164)

gccのバージョン:4.0.1

gcc version 4.0.1 (Apple Computer, Inc. build 5367)

JNI利用の流れ

今回はjavaコードの中でネイティブコードを呼び出す。

必要なソースは以下。

  • HelloWorld.java
  • HelloWorld.c

HelloWorld.javaの内容:

class HelloWorld {
private native void print();
static {
System.loadLibrary(“HelloWorld”);
}

public static void main(String[] args) {

new HelloWorld().print();
}
}

HelloWorld.cの内容:

#include <jni.h>
#include <stdio.h>
#include “HelloWorld.h”

JNIEXPORT void JNICALL
Java_HelloWorld_print(JNIEnv *env, jobject obj)
{
printf(“Hello World!\n”);
return;
}

実行に必要な処理をまとめる。

  1. HelloWorld.javaをコンパイルしてクラスファイル(HelloWorld.class)を生成
  2. javahを利用してHelloWorld.javaから、Cコードを生成する(HelloWorld.h)
  3. HelloWorld.hをインクルードしているHelloWorld.cをgccでコンパイルし、共有ライブラリを作る(libHelloWorld.jnilib)
  4. javaからコードを実行する

各々に対応するコマンドを示す。

1.HelloWorld.javaをコンパイルしてクラスファイル(HelloWorld.class)を生成

$javac HelloWorld.java

これでHelloWorld.classができる。

2. javahを利用してHelloWorld.javaから、Cコードを生成する(HelloWorld.h)

$javah -jni HelloWorld

.javaはつかない。おそらくclassファイルに対して実行しているからだと思われる。

このコマンドでHelloWorld.hが生成される。

3.HelloWorld.hをインクルードしているHelloWorld.cをgccでコンパイルし、共有ライブラリを作る(libHelloWorld.jnilib)

$ gcc -dynamiclib -o libHelloWorld.jnilib -I /System/Library/Frameworks/JavaVM.framework/Headers HelloWorld.c

linux向けの文書だと-sharedなどのオプションと書かれている場合が多いが、Macの場合は-dynamiclibである。

また、作成する共有ライブラリの命名はlib(名前).jnilibである必要がある。

4.javaからコードを実行する

$java HelloWorld

HelloWorld!と表示されたら成功。

ここで

Exception in thread “main” java.lang.UnsatisfiedLinkError: no HelloWorld in java.library.path
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1682)
at java.lang.Runtime.loadLibrary0(Runtime.java:822)
at java.lang.System.loadLibrary(System.java:992)
at HelloWorld.<clinit>(HelloWorld.java:4)
このようなエラーが出た場合、3.の手順での命名規則が間違っている可能性がある。

また、共有ライブラリのクラスパス(java.library.path)としてLD_LIBRARY_PATHを設定するという記事もあるが、

MacOSXの場合はDYLD_LIBRARY_PATHがそれに相当する上に、既に

.:/usr/lib:/usr/lib/java:/lib:/System/Library/Frameworks/JavaVM.framework/Versions/1.*/Libraries

が設定されているため、今回はlibHelloWorld.jnilibが同じディレクトリにあるので問題ない。

参考文献:

Java 28 – Project BuilderでJNIを作成させる:Apple Developer Connectionより
MacOSX10.4gccで共有ライブラリを作る:ブログ「がおがお」より

Java 2 Platform SE 1.3:クラスUnsatisfiedLinkError:Sun本家より

極めたい方は

Java Native Interface : Programmer’s Guide and Specification

PDFでダウンロードできる。

今後は、ネイティブからJavaVMを呼ぶコードについて記事を書くつもりだ。

Leave a Reply