LinuxでJNIを使ってCからJavaを実行してみる(起動だけ)

先日、JavaからCを書きましたが、今度はCからJavaを実行してみます。メソッド呼び出しとかはまだちょっと置いておいて、まずはJava VMの生成、破棄から。

ソースコード(JVMクラス)

Cといいつつ、C++でクラスっぽくして書いてみました。諸々の判定なんかは簡略化してますのであしからず。

#include <jni.h>
#include <iostream>

using namespace std;

class JVM
{
  JavaVM *_vm;
  JNIEnv *_env;
  
public:
  int create();
  int destroy();
} jvm;

int JVM::create()
{
  jint ret;

  if (_vm != NULL)
    return JNI_OK;

  JavaVMInitArgs initArgs;
  initArgs.version = JNI_VERSION_1_6;

  ret = JNI_GetDefaultJavaVMInitArgs(&initArgs);
  if (ret != JNI_OK) {
    cerr << "[ERROR] JNI_GetDefaultJavaVMInitArgs : " << ret << endl;
    return ret;
  }

  JavaVMOption options[3];
  options[0].optionString = "-Djava.compile=NONE";
  options[1].optionString = "-Djava.class.path=.";
  options[2].optionString = "-verbose:jni";

  initArgs.nOptions = 2;
  initArgs.options = options;

  ret = JNI_CreateJavaVM(&_vm, (void**)&_env, &initArgs);
  if (ret != JNI_OK) {
    cerr << "[ERROR] JNI_CreateJavaVM : " << ret << endl;
    return ret;
  }

  return ret;
}

int JVM::destroy()
{
  jint ret = JNI_OK;

  if (_vm == NULL)
    return JNI_OK;
  
  ret = _vm->DestroyJavaVM();

  if (ret != JNI_OK) {
    cerr << "[ERROR] DestroyJavaVM : " << ret << endl;
  } else {
    _vm = NULL;
    _env = NULL;
  }

  return ret;
}

Java VMをクラスにしたときの名前がかなり微妙です。。。JavaVMという構造体がすでに存在するので仕方なく。で、この微妙なJVMクラスをこれを単純にグローバルにしてます。

ソースコード(main)

起動、生成は以下の通り。

int main(int argc, char *argv[])
{
  int ret;

  ret = jvm.create();
  cout << "JavaVM create  : " << ret << endl;

  ret = jvm.destroy();
  cout << "JavaVM destroy : " << ret << endl;

  return 0;
}

まぁこれだけじゃ何もできませんね。

コンパイル、実行

コンパイル、実行は以下の通り、ソースファイル名はfirststerp.c++です。(JAVA_HOMEは適切に設定しましょう。)

$> g++ -I$JAVA_HOME/include -I$JAVA_HOME/include/linux -L$JAVA_HOME/jre/lib/i386/client -ljvm -o firststep firststep.c++
$> export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$JAVA_HOME/jre/lib/i386/client
$> ./firststep
JavaVM create  : 0
JavaVM destroy : 0
$>

生成、破棄が無事にできました。

でもなぜかエラー(原因不明)

ところで、生成、破棄をしたあとさらに生成を行うと、なぜかエラーになります。JNI_ERR(unknown error)が返されるのでよく分かりません。。。
こんな感じ。

int main(int argc, char *argv[])
{
  int ret;

  ret = jvm.create();
  cout << "JavaVM create  : " << ret << endl;

  ret = jvm.destroy();
  cout << "JavaVM destroy : " << ret << endl;

  ret = jvm.create();
  cout << "JavaVM create  : " << ret << endl;

  return 0;
}

実行してみると。

JavaVM create  : 0
JavaVM destroy : 0
[ERROR] JNI_CreateJavaVM : -1
JavaVM create  : -1

んー、よく分からん。一度DestroyJavaVMをしたら、2度とCreateできないということなのだろうかなぁ。必ずプロセスの中で生成、破棄は1度ずつしかしちゃダメよってことだと勝手に理解。