4.1. JNIの開発環境

JNIにおいて最もシンプルな開発環境は、OpenCLソースコードをライブラリ(.dll、.so、.dylibファイル)にビルドしてしまい、それをJavaのランタイム実行の際にライブラリのパスを「java.library.path」で指定することです。

例えば筆者の検証環境では以下のようにJava仮想マシン引数(筆者の英語版のEclipseではVM Argsとして設定可能)を指定します。

-Djava.library.path=/Users/komatsu/JniJnaRepo/HelloJNIPackage/jni

このプロジェクトでは「java.library.path」は「.dylib」ファイルのあるフォルダを指定しています。

以下がプロジェクトフォルダの構成です。

フォルダの構成. 

HelloJNIPackage/
├── jni
│   ├── HelloJNI.o
│   ├── com_book_jni_HelloJNI.c
│   ├── com_book_jni_HelloJNI.h
│   ├── libhello.dylib //(1)
│   └── makefile //(2)
├── pom.xml //(3)
├── src
│   ├── main
│   │   └── java
│   │       └── com
│   │           └── book
│   │               └── jni
│   │                   └── HelloJNI.java //(4)
│   └── test
│       └── java
└── target
    ├── classes
    │   ├── HelloJNI.o
    │   ├── com
    │   │   └── book
    │   │       └── jni
    │   │           └── HelloJNI.class
    │   ├── com_book_jni_HelloJNI.c
    │   ├── com_book_jni_HelloJNI.h
    │   ├── libhello.dylib
    │   └── makefile
    └── test-classes

(1)

JNIが呼び出すライブラリ

(2)

プロジェクトのビルドを設定できます

(3)

Mavenプロジェクトで依存性等を記述できます。(この例ではpom.xmlは不要です。)

(4)

このプロジェクトのクラスパスに指定します。「ビルド」の項目を参照。

読者からするとフォルダ構成をじっくり見ても混乱するだけなので、この段階では以下のように、C プロジェクト(JNI) と Java プロジェクトが「独立して」併存していることに注目頂ければと思います。

クラスパスについては以下のように指定できます。

JNI のハローワールドとして使うソースコードは以下のようになります。

HelloJNI.java. 

package com.book.jni;

public class HelloJNI {

           static {
                  System.loadLibrary("hello");
           }
           private native void sayHello();
           private native void checkDevice();

           public static void main(String[] args) {
                   new HelloJNI().checkDevice();
           }

}

ここでは hello というライブラリーを System.LoadLibrary() でロードしています。

さらに native の関数の宣言をしていますね。

このソースコードから com_book_jni_HelloJNI.h というヘッダーファイルを javah 等のツールを使って自動生成します。

ヘッダーファイルの中身は com_book_jni_HelloJNI.c ファイルで実装する必要があります。

4.1.1. JDK(Mac OS X)

JNI を使うには C/C++ のソースコードで以下のヘッダーをインクルードする必要があります。

#include <jni.h>

このヘッダーファイルは筆者のMac OS Xでは、JDKパッケージ内のインクルードディレクトリ内に存在します。

まずJavaのパスを確認します。

$ echo $JAVA_HOME
/Library/Java/JavaVirtualMachines/jdk1.8.0_05.jdk/Contents/Home
$ ls
COPYRIGHT                               include
LICENSE                                 javafx-src.zip
README.html                             jre
THIRDPARTYLICENSEREADME-JAVAFX.txt      lib
THIRDPARTYLICENSEREADME.txt             man
bin                                     release
db                                      src.zip

このディレクトリが現在有効なJavaのホームパスとなります。この内のincludeの中に「jni.h」ヘッダーファイルがあります。

$ cd  /Library/Java/JavaVirtualMachines/jdk1.8.0_05.jdk/Contents/Home/include
$ ls
classfile_constants.h   jdwpTransport.h         jvmticmlr.h
darwin                  jni.h //(1)
jawt.h                  jvmti.h
$ cd darwin/
$ ls
jawt_md.h       jni_md.h

(1)

jni.hファイルです。

jniと名のつくヘッダーが複数あります。

C/C++ で OpenCL バイナリのビルドをするには下記のディレクトリをインクルードします。

  • /Library/Java/JavaVirtualMachines/jdk1.8.0_05.jdk/Contents/Home/include
  • /Library/Java/JavaVirtualMachines/jdk1.8.0_05.jdk/Contents/Home/include/darwin

c/gcc/clang では「-I」オプションでインクルードディレクトリを指定できます。

gcc -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/ その他のオプション

この方法を使うと CLI でコマンドを叩くだけで OpenCL バイナリを生成することができます。

以下の項目ではビルドの作業を Makefile に記述して簡略化します。

警告

本書では「jdk1.8.0_05」を使っていますが、読者の JDK のバージョンはほぼ間違いなく異なるためパスを調整する必要があります。例えば、JDK1.8.0_45 を使うのであれば「/Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home/include」になります。

Copyright 2018-2019, by Masaki Komatsu