8
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

JustSystemsAdvent Calendar 2017

Day 21

JNIビギナーの役に立つかも知れない投稿

Last updated at Posted at 2017-12-20
1 / 22

導入

酷いタイトルですね。
最近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はネイティブコード側に手を加える必要があります。
パフォーマンスとか気にしないのであれば、JNASWIGを検討してみると幸せになれます。
きっと。


【悲報】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ビギナーの皆様のお役に立ちましたら幸いです。


編集後記

後半の手抜きっぷり。正直反省しています。
スライドモード向けに書いてみたけど、通常モードで読みにくいかな。

8
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?