JNI では C 言語のコンパイル・ビルドが必要となります。ビルドについては「付録:make」(付録C Makeツール)を参照ください。
以下の Makefile では javah や gcc 等のコマンドを使ったヘッダーの生成や、コンパイル・ビルドを「部分的」に自動化しています。「部分的」にという表現には、手動の要素が残されるからです。
まず C 言語のヘッダーの自動生成を行うには、「header_gen」という名称のターゲットを実行します。
$ pwd /Users/komatsu/JniJnaRepo/HelloJNIPackage/jni $ ls makefile $ make header_gen javah -verbose -classpath ../target/classes com.book.jni.HelloJNI [Creating file RegularFileObject[com_book_jni_HelloJNI.h]] $ ls com_book_jni_HelloJNI.h makefile
これでヘッダーファイルの生成ができましたので、「com_book_jni_HelloJNI.c」を作成して、C言語のソースコードを記述します。ここが手動部分に該当します。
ソースコードが完成したら、cc/gcc/clangを使ったビルドの流れを解説します。ビルドには2つのステップがあります。
前者はソースコードのコンパイル、後者はライブラリの生成・ビルドをします。このステップは「all」という名称のターゲットで実行できます。
$ make all cc -c -I/Library/Java/JavaVirtualMachines/jdk1.8.0_05.jdk/Contents/Home/include/ -I /Library/Java/JavaVirtualMachines/jdk1.8.0_05.jdk/Contents/Home/include/darwin/ -c com_book_jni_HelloJNI.c -o HelloJNI.o cc -dynamiclib -o libhello.dylib HelloJNI.o -framework JavaVM -framework OpenCL
これでネイティブライブラリ「libhello.dylib」が生成されます。生成されたファイルは以下のように確認できます。
$ ls com_book_jni_HelloJNI.c libhello.dylib HelloJNI.o com_book_jni_HelloJNI.h makefile
最後にJNIクラスを実行します。
$ cd ../target/classes $ java com.book.jni.HelloJNI CL_DEVICE_NAME: Intel(R) Core(TM) i5-3210M CPU @ 2.50GHz CL_DEVICE_NAME: HD Graphics 4000
このOpenCL実装がサポートデバイスを検索した結果を、標準出力し正常にプログラムが実行されたことが確認できました。
makefileのソースは以下のようになります。
# クラスパスを定義 CLASS_PATH = ../target/classes # binディレクトリ内の.classファイルの仮想パスを定義 #vpath %.class $(CLASS_PATH) all : libhello.dylib mv libhello.dylib $(CLASS_PATH) # .dylib(Max OS X)を出力します。 # Windowsの場合は、hello.dll、Linuxの場合は libhello.so # 出力: libhello.dylib libhello.dylib : HelloJNI.o cc -dynamiclib -o $@ $< -framework JavaVM -framework OpenCL # 検証環境ではjdk1.8.0_05を使用しています。インクルードパスはjdkバージョンと合わせます。 # 出力:HelloJNI.o HelloJNI.o : com_book_jni_HelloJNI.c com_book_jni_HelloJNI.h cc -c -I/Library/Java/JavaVirtualMachines/jdk1.8.0_05.jdk/Contents/Home/include/ -I /Library/Java/JavaVirtualMachines/jdk1.8.0_05.jdk/Contents/Home/include/darwin/ -c $< -o $@ # ヘッダーファイルを自動生成します。 # 手動でヘッダーファイルを作る場合はこのステップは不要 # 出力:com_book_jni_HelloJNI.h header_gen : javah -verbose -classpath $(CLASS_PATH) com.book.jni.HelloJNI clean : rm com_book_jni_HelloJNI.h com_book_jni_HelloJNI.c HelloJNI.o $(CLASS_PATH)/libhello.dylib
前の項目では、ヘッダーファイルを「header_gen」というmakeターゲットを呼び出して生成しました。makeターゲットはjavahというツールをバックグランドで実行しており、ヘッダーファイルを作成しているのですが、ここではjavahの使い方について解説します。
ネイティブ関数を持つJavaクラスからC形式のヘッダーファイルを生成するJDKツールです。Javaメソッドのシグネチャーをネイティブ関数プロトタイプに適合させます。
javahはCLIで呼び出し、「package_name_classname.h 」の形式を持つC言語ヘッダーファイルを生成します。
例えば「HelloJNI.class」から生成したクラスからヘッダーを生成するには以下の手順で行います。まずソースコードとなるHelloJNI.javaをコンパイルして、クラスファイルを生成します。
javac -d target/classes/ src/main/java/com/book/jni/HelloJNI.java
この例はMavenで生成したプロジェクトのため「src/main/java」がソースコードのルートパスとなりますが、プロジェクトによっては「src」フォルダにパッケージがあるかもしれません。
次にクラスファイルが以下のように生成されたことを「ls」「cd」コマンド等で探索して確認します。
target ├── classes │ ├── com │ │ └── book │ │ └── jni │ │ └── HelloJNI.class
最後にクラスパスでjavahコマンドを発行します。
$ cd target/classes $ javah -jni com.book.jni.HelloJNI
Makefile(makefile)を使うビルドでは、以下のように事前に設定しておいたクラスパスを使うと便利です。
$ javah -verbose -classpath $(CLASS_PATH) com.book.jni.HelloJNI
このjavahはヘッダーを生成するだけのことしかしません。そのため手動で書けるだけの知識があるのであれば、必須なステップではありません。ただし、javaソースコードの関数プロトタイプの個数が多くなるのであれば、自動生成を使うのは悪い考えではないでしょう。
Mac OS XでのJNIバイナリのビルドには、「jni.h」をインクルードするために以下のようなコマンドが発行されます。
gcc -c -I/Library/Java/JavaVirtualMachines/jdk1.8.0_05.jdk/Contents/Home/include/ -I /Library/Java/JavaVirtualMachines/jdk1.8.0_05.jdk/Contents/Home/include/darwin/ -c com_book_jni_HelloJNI.c -o HelloJNI.o
Linuxでのコンパイル・ビルドは未検証です。
Linuxではコンパイルオプションは以下のように設定します。
-I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux
gccを使う場合は以下のようにすれば、ビルドできるはずです。
gcc -c -I$(JAVA_HOME)/include -I $(JAVA_HOME)/include/linux -c com_book_jni_HelloJNI.c -o HelloJNI.o
Windowsでのコンパイル・ビルドは未検証です。この項目ではMinGW32がインストールされていることを前提とします。
MinGW32をインストールする場合、Linuxと同様にコンパイルオプションを指定しますが、以下のように「linux」フォルダではなく、「win32」フォルダを指定します。
本書ではサポートしないVisual Studioですが、「追加のインクルードディレクトリ」で以下のように設定します。
"$(JAVA_HOME)\include"; "$(JAVA_HOME)\include\win32"
64bit Windowsの場合は、MinGW-w64をインストールをして、x64アーキテクチャに相当するフォルダを指定してください。
Copyright 2018-2019, by Masaki Komatsu