特にテーマは無く雑記かな。 最近は自分用メモが増えてきましたけど。
スポンサーサイト
--年--月--日 (--) | 編集 |
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。


JNIでJavaからC++を呼び出す
2009年07月18日 (土) | 編集 |
JavaからC++などのネイティブコードを呼び出すにはJNIを使うわけですが、どうもうまくいかないという方もいらっしゃるかもしれません。

…はい、私もそうでした。
先月辺りにJavaからC++を呼び出そうと思ったのですが、どうもうまくいかずに放置してたんですね。
JNIのドキュメントは説明不足な感じなのであればゴロゴロ転がってますが、その通りにやってみてもうまくいかない。
これはどうしたものかー…と思ってたのですが、やっとこさ一通り動く所までいきました。

多分、自分用メモなんですが、クォリティー低くてもよければお付き合いくださいませ。

さて、まずは環境です。

Javaは私の環境には既に入っていて、javaが1.6.0.14で、javacが1.6.0.11でした。なんかバージョンずれてるような気がしますが、気にしないことにします。
C++は、Cygwinのgccは3.4.4でした。MinGWでインストールしたgccは3.4.5でした。それからVisual Studio 2008 Express EditionのVC++も入れました。
あ、ちなみに私は普段C++は全然使わないので余り分かっていません。

それで、どこかのJNI講座をトレースする訳ですが、今回は
http://www.hellohiro.com/native.htm
に従ってやってみようと思います。

まず、以下の内容の"HelloWorldJNI.java"を作ります。
public class HelloWorldJNI {
static {
// ライブラリをロードします
System.loadLibrary("HelloWorldJNI");
}
// ネイティブメソッドを宣言します
public native String sayHelloWorld();

public static void main(String[] args) {
HelloWorldJNI hello = new HelloWorldJNI();
// メソッドを実行して表示します
System.out.println(hello.sayHelloWorld());
}
}
そしたら、コマンドラインから、
javac HelloWorldJNI.java
javah -jni HelloWorldJNI
を実行します。

ここで、System.loadLibraryがstaticで囲まれていますが、これはstaticブロック(静的初期化子)と呼ぶそうです。これを使うとstaticな変数の初期化ができるということで、最初に1度だけ確実に実行できる仕組みとして、これを使う事が多いようです。
http://www.ne.jp/asahi/hishidama/home/tech/java/jni.html
こういうフォローのある解説記事は非常に助かります。

さて次に、以下の内容の"HelloWorldJNI.cpp"を作ります。
#include "HelloWorldJNI.h"
JNIEXPORT jstring JNICALL
Java_HelloWorldJNI_sayHelloWorld (JNIEnv *env,
jobject obj ) {
return env->NewStringUTF("Hello World");
}
そして、同じ場所には"HelloWorldJNI.h"を置きます。

さて、ここが問題です。参考のサイトにある通り、
gcc -shared -I"c:\Program Files\Java\jdk1.6.0_11\include" -I"c:\Program Files\Java\jdk1.6.0_11\include\win32" HelloWorldJNI.cpp -o HelloWorldJNI.dll
と実行して、"HelloWorldJNI.dll"を作ります。エラーもなく"HelloWorldJNI.dll"が生成されました。
そして、出来上がった"HelloWorldJNI.dll"をきちんとパスの通っている所に置いて(私はjavaを実行するカレントディレクトリに置いておきました)実行します。すると、
Exception in thread "main" java.lang.UnsatisfiedLinkError: HelloWorldJNI.sayHelloWorld()Ljava/lang/String;
at HelloWorldJNI.sayHelloWorld(Native Method)
at HelloWorldJNI.main(HelloWorldJNI.java:12)
とか怒られました。UnsatisfiedLinkErrorとか出てきたのでぐぐってみますと、dllの置き場が悪いんじゃないの?っていうコメントが、そこかしこにありました。
…いやでも、no XXXX in java.library.pathとかそういうのは言われてないし、これはむしろsayHelloWorld()っていう関数が見つからないって言ってるし…。

で、こうなるとネットの大海原に船出する訳です。
最終的に辿り着いたのはココ。
http://www.sixnine.net/cygwin/translation/mingw-doc/mingwfaq.html#s1-16
なるほど、同じgccでもオプションは違うのか…

結局、こうやってコンパイルしました。細かいオプションの意味は全然分かっていません。
gcc -Wall -D_JNI_IMPLEMENTATION_ -Wl,--kill-at -I"c:\Program Files\Java\jdk1.6.0_11\include" -I"c:\Program Files\Java\jdk1.6.0_11\include\win32" -shared HelloWorldJNI.cpp -o HelloWorldJNI.dll

後は、出来上がったdllをきちんとパスの通った所に置いて、
java HelloWorld
とやれば、めでたく"HelloWorld"と出力してくれた訳です。

Cygwinのgccだと、"java HelloWorld"をやるとフリーズしてしまいました。原因は分かりませんが、別にCygwinのgccはどうせ使わないのでいいでしょう^^;
VC++の場合は、
http://www.alles.or.jp/~torutk/oojava/maneuver/2001/jni/jni.html#doc1_id85
ここを参考に、Visual Studio 2008 コマンドプロンプト上で、
cl /I"c:\Program Files\Java\jdk1.6.0_11\include" /I"c:\Program Files\Java\jdk1.6.0_11\include\win32" /c HelloWorldJNI.cpp
link /dll HelloWorld.obj
で出来ました。

…まぁ、少なくともVC++は統合開発環境を使えば良い気がします。
MinGWも、実はeclipse上で開発したかったが為に入れてた訳なので、これから環境を整えたいです。
スポンサーサイト

コメント
この記事へのコメント
コメントを投稿する
URL:
Comment:
Pass:
秘密: 管理者にだけ表示を許可する
 
トラックバック
この記事のトラックバックURL
この記事へのトラックバック
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。