Download - Jjug night seminar201208_lt_cxxからjvm起動
そんなに難しくないC/C++からJVMの起動
JJUGナイトセミナー2012-08-29
ライトニングトーク
高橋 徹
発表者について@boochnich
http://d.hatena.ne.jp/torutk/
• 仕事では、C/C++/Javaまんべんなく– 非Web系分散処理(CORBA、マルチキャスト・・・)
– GUI(Swing, X/Motif,GTK+・・・)
– GIS(地図)
• Java読書会BOF現代表– 1998年~毎月1回開催、通算161回、24冊
http://www.javareading.com/bof/
JVMを起動するC++コード(骨子)#include <jni.h>
int main()
{
JavaVMOption options[2];
options[0].optionString = "-Xmx64m";
options[1].optionString = "-Djava.class.path=.";
JavaVMInitArgs vm_args;
vm_args.version = JNI_VERSION_1_6;
vm_args.options = options;
vm_args.nOptions = 2;
JNIEnv* env;
JavaVM* jvm;
int res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
jclass clazz = env->FindClass("Hello");
jmethodID mid = env->GetStaticMethodID(clazz, "main", "([Ljava/lang/String;)V");
env->CallStaticVoidMethod(clazz, mid, NULL);
jvm->DestroyJavaVM();
}
説明用につき、
エラー処理、動作確認ログなどは省略しています。
#include <jni.h>
int main()
{
JavaVMOption options[2];
options[0].optionString = "-Xmx64m";
options[1].optionString = "-Djava.class.path=.";
JavaVMInitArgs vm_args;
vm_args.version = JNI_VERSION_1_6;
vm_args.options = options;
vm_args.nOptions = 2;
JNIEnv* env;
JavaVM* jvm;
int res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
jclass clazz = env->FindClass("Hello");
jmethodID mid = env->GetStaticMethodID(clazz, "main", "([Ljava/lang/String;)V");
env->CallStaticVoidMethod(clazz, mid, NULL);
jvm->DestroyJavaVM();
}
JVMを起動するC++コード(骨子)
#include <jni.h>
int main()
{
JavaVMOption options[2];
options[0].optionString = "-Xmx64m";
options[1].optionString = "-Djava.class.path=.";
JavaVMInitArgs vm_args;
vm_args.version = JNI_VERSION_1_6;
vm_args.options = options;
vm_args.nOptions = 2;
JNIEnv* env;
JavaVM* jvm;
int res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
jclass clazz = env->FindClass("Hello");
jmethodID mid = env->GetStaticMethodID(clazz, "main", "([Ljava/lang/String;)V");
env->CallStaticVoidMethod(clazz, mid, NULL);
JavaVMに指定するオプションを列挙
起動したJavaVMが使用するクラスパスは、システムプロパティ java.class.pathで定義
JVMを起動するC++コード(骨子)
#include <jni.h>
int main()
{
JavaVMOption options[2];
options[0].optionString = "-Xmx64m";
options[1].optionString = "-Djava.class.path=.";
JavaVMInitArgs vm_args;
vm_args.version = JNI_VERSION_1_6;
vm_args.options = options;
vm_args.nOptions = 2;
JNIEnv* env;
JavaVM* jvm;
int res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
jclass clazz = env->FindClass("Hello");
jmethodID mid = env->GetStaticMethodID(clazz, "main", "([Ljava/lang/String;)V");
env->CallStaticVoidMethod(clazz, mid, NULL);
JavaVMを起動するAPIに渡す設定
JNIのバージョン、JavaVMオプションを指定する
JVMを起動するC++コード(骨子)
#include <jni.h>
int main()
{
JavaVMOption options[2];
options[0].optionString = "-Xmx64m";
options[1].optionString = "-Djava.class.path=.";
JavaVMInitArgs vm_args;
vm_args.version = JNI_VERSION_1_6;
vm_args.options = options;
vm_args.nOptions = 2;
JNIEnv* env;
JavaVM* jvm;
int res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
jclass clazz = env->FindClass("Hello");
jmethodID mid = env->GetStaticMethodID(clazz, "main", "([Ljava/lang/String;)V");
env->CallStaticVoidMethod(clazz, mid, NULL);
<jni.h>に定義されている定数(JDK 7u6)#define JNI_VERSION_1_1 0x00010001#define JNI_VERSION_1_2 0x00010002#define JNI_VERSION_1_4 0x00010004#define JNI_VERSION_1_6 0x00010006
JVMを起動するC++コード(骨子)
#include <jni.h>
int main()
{
JavaVMOption options[2];options[0].optionString = "-Xmx64m";
options[1].optionString = "-Djava.class.path=.";
JavaVMInitArgs vm_args;
vm_args.version = JNI_VERSION_1_6;
vm_args.options = options;
vm_args.nOptions = 2;
JNIEnv* env;
JavaVM* jvm;
int res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
jclass clazz = env->FindClass("Hello");
jmethodID mid = env->GetStaticMethodID(clazz, "main", "([Ljava/lang/String;)V");
JVMを起動するC++コード(骨子)
#include <jni.h>
int main()
{
JavaVMOption options[2];options[0].optionString = "-Xmx64m";
options[1].optionString = "-Djava.class.path=.";
JavaVMInitArgs vm_args;
vm_args.version = JNI_VERSION_1_6;
vm_args.options = options;
vm_args.nOptions = 2;
JNIEnv* env;
JavaVM* jvm;
int res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
jclass clazz = env->FindClass("Hello");
jmethodID mid = env->GetStaticMethodID(clazz, "main", "([Ljava/lang/String;)V");
JVMを起動するC++コード(骨子)
JavaVMInitArgs vm_args;
vm_args.version = JNI_VERSION_1_6;
vm_args.options = options;
vm_args.nOptions = 2;
JNIEnv* env;
JavaVM* jvm;
JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);jclass clazz = env->FindClass("Hello");
jmethodID mid = env->GetStaticMethodID(clazz, "main", "([Ljava/lang/String;)V");
env->CallStaticVoidMethod(clazz, mid, NULL);
jvm->DestroyJavaVM();
}
JavaVMを起動します
JVMを起動するC++コード(骨子)
#include <jni.h>
int main()
{
JavaVMOption options[2];
options[0].optionString = "-Xmx64m";
options[1].optionString = "-Djava.class.path=.";
JavaVMInitArgs vm_args;
vm_args.version = JNI_VERSION_1_6;
vm_args.options = options;
vm_args.nOptions = 2;
JNIEnv* env;
JavaVM* jvm;
int res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
jclass clazz = env->FindClass("Hello");jmethodID mid = env->GetStaticMethodID(clazz, "main", "([Ljava/lang/String;)V");
env->CallStaticVoidMethod(clazz, mid, NULL);
jvm->DestroyJavaVM();
}
起動したJavaVMにクラスをロードします。
クラスはFQCNで記述
JVMを起動するC++コード(骨子)
JNIEnv* env;
JavaVM* jvm;
int res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
jclass clazz = env->FindClass("Hello");
jmethodID mid = env->GetStaticMethodID(
clazz, "main", "([Ljava/lang/String;)V“
);env->CallStaticVoidMethod(clazz, mid, NULL);
jvm->DestroyJavaVM();
}
クラスのメソッドIDを取得します。
メソッド名メソッドシグニチャ(引数の型・戻り値型)
JVMを起動するC++コード(骨子)
JNIEnv* env;
JavaVM* jvm;
int res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
jclass clazz = env->FindClass("Hello");
jmethodID mid = env->GetStaticMethodID(
clazz, "main", "([Ljava/lang/String;)V“
);env->CallStaticVoidMethod(clazz, mid, NULL);
jvm->DestroyJavaVM();
}
シグニチャの調べ方
C:\work> javap -s Hello
Compiled from "Hello.java"public class Hello {public Hello();Signature: ()V
public static void main(java.lang.String[]);Signature: ([Ljava/lang/String;)V
}
JVMを起動するC++コード(骨子)
JNIEnv* env;
JavaVM* jvm;
int res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
jclass clazz = env->FindClass("Hello");
jmethodID mid = env->GetStaticMethodID(clazz, "main", "([Ljava/lang/String;)V");
env->CallStaticVoidMethod(clazz, mid, NULL);
jvm->DestroyJavaVM();
}
メソッドを実行します
JVMを起動するC++コード(骨子)
JNIEnv* env;
JavaVM* jvm;
int res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);
jclass clazz = env->FindClass("Hello");
jmethodID mid = env->GetStaticMethodID(clazz, "main", "([Ljava/lang/String;)V");
env->CallStaticVoidMethod(clazz, mid, NULL);
jvm->DestroyJavaVM();}
JavaVMを破棄します
JVMを起動するC++コード(骨子)
コンパイル・リンク
• Windows (Visual C++)の場合
cl /I"C:\Program Files (x86)\java\jdk1.7.0\include“
/I"C:\Program Files (x86)\java\jdk1.7.0\include\win32"
/EHsc
launch.cpp
/link
/LIBPATH:"C:\Program Files (x86)\Java\jdk1.7.0\lib“
jvm.lib
実行
• Windows (Visual C++)の場合
C:\work> PATH=%PATH%;”C:\Program Files (x86)\java\
jdk1.7.0\jre\bin\client”
C:\work> launch
Hello, World!
C:\work>
補足
• jvm.dllを明示的リンクせず暗黙的リンクすると柔軟性が増す
– LoadLibraryでjvm.dllを読み込む
– 複数バージョンのJavaVMを使い分ける等
• 非ASCII(日本語)文字列を渡す場合注意
– C/C++側で文字コードを扱うのは悲惨
– C++ 11で光明あり(u8”こんにちは”)
情報源
• 公式ドキュメント(日本語訳版)– http://docs.oracle.com/javase/jp/6/technotes/gui
des/jni/index.html
• 書籍(古いが日本語の唯一のも)– 「JNI Java Native Interfaceプログラミング」
(ピアソン・エデュケーション刊、1998年)
• 拙著Web記事– http://www.02.246.ne.jp/~torutk/javahow2/jni.h
tml
ご清聴を感謝します
このスライドが出るということは、しゃべりが早すぎだ!