Jan 8, 2003 onlsbc1, Red Hat Linux 8.0 のシステムでのJNIの実行 --- ネイティブ言語メソッドからJavaメンバ変数をアクセス#6 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (http://www-online.kek.jp/~inoue/para-CAMAC/ Work/SBC-Java8.html) 高エネルギー加速器研究機構 素粒子原子核研究所 物理、オンライングループ 井上 栄二 目的 SBC、PCM-9370にインストールしてある Red Hat Linux 8.0 のシステム上で JNIを使ってネイティブ言語メソッドからJavaメンバ変数へのアクセスの 実行確認をする。 (1). 構成 (2). コンパイル (3). 実行 -------------------------------------------------------------------- (1). 構成 テストに使用するマシンは onlsbc1 である。 このマシンはアドバンテク社の SBC、PCM-9370である。 動作している OSはRed Hat Linux 8.0 で、Javaの バージョンは1.4.1_01 である。 最終的にはコンパクトフラッシュ上に構成した Linuxシステムで実行できることを目指すのであるが、ソフトウェアの開発段階 では 2.5" IDE ハードディスク上に構成したLinuxシステムを使ってテストを 行うことにする。 (2). コンパイル (2-1). Javaのチェック [inoue@onlsbc1 inoue]$ java -version java version "1.4.1_01" Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1_01-b01) Java HotSpot(TM) Client VM (build 1.4.1_01-b01, mixed mode) [inoue@onlsbc1 inoue]$ (2-2). 実行環境 [inoue@onlsbc1 inoue]$ env MANPATH=:/usr/java/man HOSTNAME=onlsbc1.kek.jp PVM_RSH=/usr/bin/rsh TERM=vt100 SHELL=/bin/bash JLESSCHARSET=japanese HISTSIZE=1000 SSH_CLIENT=130.87.153.9 33055 22 QTDIR=/usr/lib/qt3-gcc3.2 SSH_TTY=/dev/pts/1 USER=inoue LS_COLORS=no=00:fi=00:di=01;34:ln=01;36:pi=40;33:so=01;35:bd=40;33;01:cd=40;33;0 1:or=01;05;37;41:mi=01;05;37;41:ex=01;32:*.cmd=01;32:*.exe=01;32:*.com=01;32:*.b tm=01;32:*.bat=01;32:*.sh=01;32:*.csh=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31: *.taz=01;31:*.lzh=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.gz=01;31:*.bz2=01;31:* .bz=01;31:*.tz=01;31:*.rpm=01;31:*.cpio=01;31:*.jpg=01;35:*.gif=01;35:*.bmp=01;3 5:*.xbm=01;35:*.xpm=01;35:*.png=01;35:*.tif=01;35: PVM_ROOT=/usr/share/pvm3 MAIL=/var/spool/mail/inoue PATH=/usr/kerberos/bin:/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/usr/java/bin :/home/inoue/bin INPUTRC=/etc/inputrc PWD=/home/inoue LANG=ja_JP.eucJP LAMHELPFILE=/etc/lam/lam-helpfile SSH_ASKPASS=/usr/libexec/openssh/gnome-ssh-askpass SHLVL=1 HOME=/home/inoue XPVM_ROOT=/usr/share/pvm3/xpvm LOGNAME=inoue LESSOPEN=|/usr/bin/lesspipe.sh %s G_BROKEN_FILENAMES=1 _=/bin/env [inoue@onlsbc1 inoue]$ (2-3). Javaコードを書く この実行で使用するソースコードは、以下のURLから入手した。 http://java.sun.com/j2se/1.4/ja/docs/ja/guide/jni/index.html [inoue@onlsbc1 FieldAccess]$ pwd /home/inoue/JNI/FieldAccess [inoue@onlsbc1 FieldAccess]$ ls -l 合計 8 -rw-rw-r-- 1 inoue inoue 882 1月 8 10:14 FieldAccess.c -rw-rw-r-- 1 inoue inoue 453 1月 8 10:13 FieldAccess.java [inoue@onlsbc1 FieldAccess]$ cat FieldAccess.java class FieldAccess { static int si; String s; private native void accessFields(); public static void main(String args[]) { FieldAccess c = new FieldAccess(); FieldAccess.si = 100; c.s = "abc"; c.accessFields(); System.out.println("In Java:"); System.out.println(" FieldAccess.si = " + FieldAccess.si); System.out.println(" c.s = \"" + c.s + "\""); } static { System.loadLibrary("MyImpOfFieldAccess"); } } [inoue@onlsbc1 FieldAccess]$ 参考. 1. シグナチャ シグナチャの要素(クラス名や返り値、データ型など)に分解します。 メソッドの名前とパラメータの数と型の事をシグナチャといいます。 例)(Ljava/lang/String;)V ↓ "L" と "java/lang/String" と "V" に分解します。 "L" はクラスを意味します。 "java/lang/String" はパス付きクラス名です。 "V" は返り値が void 型であることを意味しています。 2. メンバ変数の概要 メンバ変数はクラス及びそのオブジェクトに属する変数でどのメソッド、 コンストラクタにも属しません。そのため、複数のメソッド、コンスト ラクタで共通して使用したい変数にメンバ変数を使用します。逆に 各メソッド、コンストラクタに限定して使用する変数をローカル変数と 呼びます。 (2-4). Javaコードをコンパイルする [inoue@onlsbc1 FieldAccess]$ ls -l 合計 8 -rw-rw-r-- 1 inoue inoue 882 1月 8 10:14 FieldAccess.c -rw-rw-r-- 1 inoue inoue 453 1月 8 10:13 FieldAccess.java [inoue@onlsbc1 FieldAccess]$ javac FieldAccess.java [inoue@onlsbc1 FieldAccess]$ ls -l 合計 12 -rw-rw-r-- 1 inoue inoue 882 1月 8 10:14 FieldAccess.c -rw-rw-r-- 1 inoue inoue 985 1月 8 10:20 FieldAccess.class -rw-rw-r-- 1 inoue inoue 453 1月 8 10:13 FieldAccess.java [inoue@onlsbc1 FieldAccess]$ 参考. Javaクラス ディスアセンブラツール、Javapを使うとクラスファイルから メンバ変数シグナチャを作成して表示できる。 これを使用することで手書き でメソッドシグナチャを書く時のミスを減らすことができる。 javapコマンド に付加する "-s"フラグは通常のJavaタイプより多くのシグナチャを出力 することを指示し、"-p"フラグはプライベートメンバも含めるように指示 していることを意味している。 [inoue@onlsbc1 FieldAccess]$ javap -s -p FieldAccess Compiled from FieldAccess.java class FieldAccess extends java.lang.Object { static int si; /* I */ java.lang.String s; /* Ljava/lang/String; */ FieldAccess(); /* ()V */ private native void accessFields(); /* ()V */ public static void main(java.lang.String[]); /* ([Ljava/lang/String;)V */ static {}; /* ()V */ } [inoue@onlsbc1 FieldAccess]$ (2-5). .hファイルの生成 C++言語のヘッダーファイルは、以下のようにjavahというコマンドで生成 できる。 オプションには-jniを指定し、引数には項目(2-4)でコンパイルした クラスの拡張子を除いたものを指定する。 [inoue@onlsbc1 FieldAccess]$ javah -jni FieldAccess [inoue@onlsbc1 FieldAccess]$ ls -l 合計 16 -rw-rw-r-- 1 inoue inoue 882 1月 8 10:14 FieldAccess.c -rw-rw-r-- 1 inoue inoue 985 1月 8 10:20 FieldAccess.class -rw-rw-r-- 1 inoue inoue 426 1月 8 10:34 FieldAccess.h -rw-rw-r-- 1 inoue inoue 453 1月 8 10:13 FieldAccess.java [inoue@onlsbc1 FieldAccess]$ cat FieldAccess.h /* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class FieldAccess */ #ifndef _Included_FieldAccess #define _Included_FieldAccess #ifdef __cplusplus extern "C" { #endif /* Inaccessible static: si */ /* * Class: FieldAccess * Method: accessFields * Signature: ()V */ JNIEXPORT void JNICALL Java_FieldAccess_accessFields (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif [inoue@onlsbc1 FieldAccess]$ (2-6). C言語のソースファイルの作成 [inoue@onlsbc1 FieldAccess]$ cat FieldAccess.c #include <stdio.h> #include <jni.h> #include "FieldAccess.h" JNIEXPORT void JNICALL Java_FieldAccess_accessFields(JNIEnv *env, jobject obj) { jclass cls = (*env)->GetObjectClass(env, obj); jfieldID fid; jstring jstr; const char *str; jint si; printf("In C:\n"); fid = (*env)->GetStaticFieldID(env, cls, "si", "I"); if (fid == 0) { return; } si = (*env)->GetStaticIntField(env, cls, fid); printf(" FieldAccess.si = %d\n", si); (*env)->SetStaticIntField(env, cls, fid, 200); fid = (*env)->GetFieldID(env, cls, "s", "Ljava/lang/String;"); if (fid == 0) { return; } jstr = (*env)->GetObjectField(env, obj, fid); str = (*env)->GetStringUTFChars(env, jstr, 0); printf(" c.s = \"%s\"\n", str); (*env)->ReleaseStringUTFChars(env, jstr, str); jstr = (*env)->NewStringUTF(env, "123"); (*env)->SetObjectField(env, obj, fid, jstr); } [inoue@onlsbc1 FieldAccess]$ (2-7). C言語のソースファイルをコンパイルしてシェアード・ライブラリを作成 [inoue@onlsbc1 FieldAccess]$ pwd /home/inoue/JNI/FieldAccess [inoue@onlsbc1 FieldAccess]$ ls -l 合計 16 -rw-rw-r-- 1 inoue inoue 882 1月 8 10:14 FieldAccess.c -rw-rw-r-- 1 inoue inoue 985 1月 8 10:20 FieldAccess.class -rw-rw-r-- 1 inoue inoue 426 1月 8 10:34 FieldAccess.h -rw-rw-r-- 1 inoue inoue 453 1月 8 10:13 FieldAccess.java [inoue@onlsbc1 FieldAccess]$ gcc -shared -I/usr/java/include -I/usr/java/include /linux FieldAccess.c -o libMyImpOfFieldAccess.so [inoue@onlsbc1 FieldAccess]$ ls -l 合計 24 -rw-rw-r-- 1 inoue inoue 882 1月 8 10:14 FieldAccess.c -rw-rw-r-- 1 inoue inoue 985 1月 8 10:20 FieldAccess.class -rw-rw-r-- 1 inoue inoue 426 1月 8 10:34 FieldAccess.h -rw-rw-r-- 1 inoue inoue 453 1月 8 10:13 FieldAccess.java -rwxrwxr-x 1 inoue inoue 6148 1月 8 11:14 libMyImpOfFieldAccess.s o [inoue@onlsbc1 FieldAccess]$ (3). 実行 [inoue@onlsbc1 FieldAccess]$ export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH [inoue@onlsbc1 FieldAccess]$ java FieldAccess In C: FieldAccess.si = 100 c.s = "abc" In Java: FieldAccess.si = 200 c.s = "123" [inoue@onlsbc1 FieldAccess]$ ok. JNIを使ってネイティブ言語メソッドからJavaメンバ変数へのアクセスの 実行は正常にできた。 ---xxxx