導入
酷いタイトルですね。
最近JNIに触れる機会があったので、備忘を兼ねて、
「JNIビギナーがJNIでネイティブコード(dll)を動かすまで」
を簡単に書きたいと思います。
おことわり
※筆者の脳内Javaは6からアップデートされていません。
なぜだか自動アップデートされないんですよね。ふしぎ。
よって、内容に誤りを含んでいる可能性が多分にあります。
(Javaのソースほぼ出てこないのでたぶん大丈夫と思いたい)
開発環境
- Windows 10 Pro 64bit
- Java 8
- Eclipse Neon
- Visual Studio 2015
JNI #とは
リンククリックして読んでください。
「ネイティブコードをJavaから実行するやーつ」です(適当)
ほな早速JNIを…
使う前に…
そのコード、Javaで書けるよ
あとで「なんでJavaで書けるのにJNI使ったの」とか突っ込まれて困りそうなら、それは「JNIを使わずに、Javaで書いた方が良い」ということかもしれないですね。
JNAとかSWIGのほうが(たぶん)簡単に書ける
JNIはネイティブコード側に手を加える必要があります。
パフォーマンスとか気にしないのであれば、JNAやSWIGを検討してみると幸せになれます。
きっと。
【悲報】64bit Javaさん、32bit dllを呼べない
ということなのでちゃんと合わせましょう。
64bit Javaで動かすなら64bit dllにしましょう。
そのネイティブコード、マルチスレッド対応してる?
もし対応していなかったら、悲劇が起きるかも知れません。
必要なら対応しましょう。無理ならラッパー書いて排他制御するなり…(つらいね…)。
やっとJNIを使います
呼び出し側Javaソース(JNISample.java
)
package com.hoge.jnisample;
public class JNISample {
// ネイティブの関数宣言
private native String nativeFunction(String name);
// 実行するモジュールをロード
static {
System.loadLibrary("libfuga");
}
// ネイティブコード実行
public String executeNative(String name) {
return this.nativeFunction(name);
}
}
classファイル(JNISample.class)生成
先のソースをコンパイルして、classファイル(JNISample.class)を生成します。
javac JNISample.java
ネイティブ側のヘッダを生成
javah
コマンドを使用して、C(C++)のヘッダを生成します。コマンドの構文は、
javah -classpath {classpath} -d {ヘッダ出力ディレクトリ} {(パッケージ名.)クラス名}
今回は、以下のようなディレクトリ構成です。
java
└ com
└ hoge
└ jnisample
├ JNISample.java
└ JNISample.class
コマンドはこうなります。(java
ディレクトリで実行します)
javah -classpath .\ -d ..\jniheader com.hoge.jnisample.JNISample
これで、java
ディレクトリと同階層のjniheader
ディレクトリにヘッダファイルが生成されます。
生成されたヘッダファイル(com_hoge_jnisample_JNISample.h
)
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_hoge_jnisample_JNISample */
#ifndef _Included_com_hoge_jnisample_JNISample
#define _Included_com_hoge_jnisample_JNISample
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_hoge_jnisample_JNISample
* Method: nativeFunction
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_hoge_jnisample_JNISample_nativeFunction
(JNIEnv *, jobject, jstring);
#ifdef __cplusplus
}
#endif
#endif
あとはC(C++)で関数を実装してビルドするだけ!
ですが、
-
jni.h
のパスを「追加のインクルードディレクトリ」へ忘れず追加しましょう。- 手順はググればいくらでも出てくるのでここでは割愛します。
- 詳細な実装についてはこれまた割愛しますが、jナントカ型(
jobject
,jstring
等)は変換が必要です。- ググればいくらでも出てk(ry
最後の一仕事:環境変数PATHにネイティブモジュールのパスを追加
- 手順はググればいくらでもd(ry
いざ、実行
動きました?
まとめ
JNI、意外と難しくないですよね。
もっと小難しいイメージでしたが、ぽんこつえんじにあでもあんしんでした。
この投稿が、JNIビギナーの皆様のお役に立ちましたら幸いです。
編集後記
後半の手抜きっぷり。正直反省しています。
スライドモード向けに書いてみたけど、通常モードで読みにくいかな。