Linux 向け Java(tm) バイナリのカーネルサポート v1.03 ---------------------------------------------------- Linux はすべてにおいて先んじています!他のすべての OS が、OS 内で Java バイナリの直接サポートについて議論をしている中、Linux はサポートをして います! 下記のことを行った後、他のプログラムと同じように Java アプリケーション とJava アプレットを実行できます - 1) まず、Linux 向け Java Developers Kit (JDK) をインストールしなければ なりません。Java-HOWTO は JDK の入手とインストールを説明しています。 この HOWTO は次のところから入手できます - [訳注:2001 年 12 月現在ではリンク切れになっていました。] ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/Java-HOWTO また、標準ではないクラス (アプリケーション自体と同じディレクトリに 含まれていないクラスのために) を利用している Java アプリケーションを使 用するために、合理的な CLASSPATH 環境変数を設定しなければなりません。 2) モジュールとして、あるいはカーネルに組込む (CONFIG_BINFMT_MISC) た めに、BINFMT_MISC をコンパイルし、適切に設定しなければなりません。 モジュールとしてコンパイルすることを選んだなら、kmod で binfmt_misc をサポートすることが簡単にできないので、modprobe/insmod により手動 でロードしなければなりません。設定についてもっと知りたいのなら、 Documentation ディレクトリにあるファイル 'binfmt_misc.txt' を読んで ください。 [訳注:日本語訳が http://www.linux.or.jp/JF/JFdocs/kernel-docs-2.6/binfmt_misc.txt.html にあります。] 3) binfmt_misc に次の設定項目を追加してください (いますぐ binfmt_misc.txt を読むことをお勧めします) - Java アプリケーションのサポート - ':Java:M::\xca\xfe\xba\xbe::/usr/local/bin/javawrapper:' 実行可能 jar ファイルのサポート - ':ExecutableJAR:E::jar::/usr/local/bin/jarwrapper:' Java アプレットのサポート - ':Applet:E::html::/usr/bin/appletviewer:' もしくは、より選択的にしたい場合 - ':Applet:M:: を含むよう修正しなけれ ばなりません ('<' の文字から始まらなければなりません!)。 コンパイルされた Java プログラムは、下記のようなラッパースクリプト が必要です (これは Java にファイル名の取り扱いの不具合があるためで す)。ここでも、スクリプトと上記で与えた設定文字列の両方のパス名を見 直してください。 このスクリプトの他にちょっとしたプログラムも必要です。 gcc -O2 -o javaclassname javaclassname.c のようにコンパイルし、 /usr/local/bin に置いてください。 javawrapper シェルスクリプトと javaclassname プログラムは二つとも Colin J. Watson により提供されました。 ====================== Cut here =================== #!/bin/bash # /usr/local/bin/javawrapper - binfmt_misc/java 用ラッパー if [ -z "$1" ]; then exec 1>&2 echo Usage: $0 class-file exit 1 fi CLASS=$1 FQCLASS=`/usr/local/bin/javaclassname $1` FQCLASSN=`echo $FQCLASS | sed -e 's/^.*\.\([^.]*\)$/\1/'` FQCLASSP=`echo $FQCLASS | sed -e 's-\.-/-g' -e 's-^[^/]*$--' -e 's-/[^/]*$--'` # 例えば: # CLASS=Test.class # FQCLASS=foo.bar.Test # FQCLASSN=Test # FQCLASSP=foo/bar unset CLASSBASE declare -i LINKLEVEL=0 while :; do if [ "`basename $CLASS .class`" == "$FQCLASSN" ]; then # このディレクトリで素直に動作するか確かめます cd -L `dirname $CLASS` CLASSDIR=$PWD cd $OLDPWD if echo $CLASSDIR | grep -q "$FQCLASSP$"; then CLASSBASE=`echo $CLASSDIR | sed -e "s.$FQCLASSP$.."` break; fi # ディレクトリ名を相対参照してみます cd -P `dirname $CLASS` CLASSDIR=$PWD cd $OLDPWD if echo $CLASSDIR | grep -q "$FQCLASSP$"; then CLASSBASE=`echo $CLASSDIR | sed -e "s.$FQCLASSP$.."` break; fi # 他に可能なファイル名が無い場合 if [ ! -L $CLASS ]; then exec 1>&2 echo $0: echo " $CLASS should be in a" \ "directory tree called $FQCLASSP" exit 1 fi fi if [ ! -L $CLASS ]; then break; fi # シンボリックリンクのレベルを一つ以上たどります let LINKLEVEL+=1 if [ $LINKLEVEL -gt 5 ]; then exec 1>&2 echo $0: echo " Too many symbolic links encountered" exit 1 fi CLASS=`ls --color=no -l $CLASS | sed -e 's/^.* \([^ ]*\)$/\1/'` done if [ -z "$CLASSBASE" ]; then if [ -z "$FQCLASSP" ]; then GOODNAME=$FQCLASSN.class else GOODNAME=$FQCLASSP/$FQCLASSN.class fi exec 1>&2 echo $0: echo " $FQCLASS should be in a file called $GOODNAME" exit 1 fi if ! echo $CLASSPATH | grep -q "^\(.*:\)*$CLASSBASE\(:.*\)*"; then # クラスは CLASSPATH 内にないので、CLASSPATH にクラスのディレ # クトリを追加します if [ -z "${CLASSPATH}" ] ; then export CLASSPATH=$CLASSBASE else export CLASSPATH=$CLASSBASE:$CLASSPATH fi fi shift /usr/bin/java $FQCLASS "$@" ====================== Cut here =================== ====================== Cut here =================== /* javaclassname.c * * Extracts the class name from a Java class file; intended for use in a Java * wrapper of the type supported by the binfmt_misc option in the Linux kernel. * * Copyright (C) 1999 Colin J. Watson . * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include /* From Sun's Java VM Specification, as tag entries in the constant pool. */ #define CP_UTF8 1 #define CP_INTEGER 3 #define CP_FLOAT 4 #define CP_LONG 5 #define CP_DOUBLE 6 #define CP_CLASS 7 #define CP_STRING 8 #define CP_FIELDREF 9 #define CP_METHODREF 10 #define CP_INTERFACEMETHODREF 11 #define CP_NAMEANDTYPE 12 /* Define some commonly used error messages */ #define seek_error() error("%s: Cannot seek\n", program) #define corrupt_error() error("%s: Class file corrupt\n", program) #define eof_error() error("%s: Unexpected end of file\n", program) #define utf8_error() error("%s: Only ASCII 1-255 supported\n", program); char *program; long *pool; u_int8_t read_8(FILE *classfile); u_int16_t read_16(FILE *classfile); void skip_constant(FILE *classfile, u_int16_t *cur); void error(const char *format, ...); int main(int argc, char **argv); /* Reads in an unsigned 8-bit integer. */ u_int8_t read_8(FILE *classfile) { int b = fgetc(classfile); if(b == EOF) eof_error(); return (u_int8_t)b; } /* Reads in an unsigned 16-bit integer. */ u_int16_t read_16(FILE *classfile) { int b1, b2; b1 = fgetc(classfile); if(b1 == EOF) eof_error(); b2 = fgetc(classfile); if(b2 == EOF) eof_error(); return (u_int16_t)((b1 << 8) | b2); } /* Reads in a value from the constant pool. */ void skip_constant(FILE *classfile, u_int16_t *cur) { u_int16_t len; int seekerr = 1; pool[*cur] = ftell(classfile); switch(read_8(classfile)) { case CP_UTF8: len = read_16(classfile); seekerr = fseek(classfile, len, SEEK_CUR); break; case CP_CLASS: case CP_STRING: seekerr = fseek(classfile, 2, SEEK_CUR); break; case CP_INTEGER: case CP_FLOAT: case CP_FIELDREF: case CP_METHODREF: case CP_INTERFACEMETHODREF: case CP_NAMEANDTYPE: seekerr = fseek(classfile, 4, SEEK_CUR); break; case CP_LONG: case CP_DOUBLE: seekerr = fseek(classfile, 8, SEEK_CUR); ++(*cur); break; default: corrupt_error(); } if(seekerr) seek_error(); } void error(const char *format, ...) { va_list ap; va_start(ap, format); vfprintf(stderr, format, ap); va_end(ap); exit(1); } int main(int argc, char **argv) { FILE *classfile; u_int16_t cp_count, i, this_class, classinfo_ptr; u_int8_t length; program = argv[0]; if(!argv[1]) error("%s: Missing input file\n", program); classfile = fopen(argv[1], "rb"); if(!classfile) error("%s: Error opening %s\n", program, argv[1]); if(fseek(classfile, 8, SEEK_SET)) /* skip magic and version numbers */ seek_error(); cp_count = read_16(classfile); pool = calloc(cp_count, sizeof(long)); if(!pool) error("%s: Out of memory for constant pool\n", program); for(i = 1; i < cp_count; ++i) skip_constant(classfile, &i); if(fseek(classfile, 2, SEEK_CUR)) /* skip access flags */ seek_error(); this_class = read_16(classfile); if(this_class < 1 || this_class >= cp_count) corrupt_error(); if(!pool[this_class] || pool[this_class] == -1) corrupt_error(); if(fseek(classfile, pool[this_class] + 1, SEEK_SET)) seek_error(); classinfo_ptr = read_16(classfile); if(classinfo_ptr < 1 || classinfo_ptr >= cp_count) corrupt_error(); if(!pool[classinfo_ptr] || pool[classinfo_ptr] == -1) corrupt_error(); if(fseek(classfile, pool[classinfo_ptr] + 1, SEEK_SET)) seek_error(); length = read_16(classfile); for(i = 0; i < length; ++i) { u_int8_t x = read_8(classfile); if((x & 0x80) || !x) { if((x & 0xE0) == 0xC0) { u_int8_t y = read_8(classfile); if((y & 0xC0) == 0x80) { int c = ((x & 0x1f) << 6) + (y & 0x3f); if(c) putchar(c); else utf8_error(); } else utf8_error(); } else utf8_error(); } else if(x == '/') putchar('.'); else putchar(x); } putchar('\n'); free(pool); fclose(classfile); return 0; } ====================== Cut here =================== ====================== Cut here =================== #!/bin/bash # /usr/local/java/bin/jarwrapper - the wrapper for binfmt_misc/jar java -jar $1 ====================== Cut here =================== さて、実行するために .class, .jar や .html ファイルを chmod -x してく ださい。パスに Java プログラムを追加するには、.class 拡張子を省略する ために /usr/bin (もしくは好みの別の場所) 内に、メインの .class ファイ ルのシンボリックファイルを置くのが最良です。オリジナルの .class ファイ ルを含むディレクトリは 実行の間、あなたの CLASSPATH に追加されることに なります。 新しい設定をテストするために、次の単純な Java アプリケーションを入力 し、その名前を "HelloWorld.java" としてください - class HelloWorld { public static void main(String args[]) { System.out.println("Hello World!"); } } さて、次のようにアプリケーションをコンパイルしてください - javac HelloWorld.java 次のコマンドでバイナリファイルに実行許可を設定してください - chmod 755 HelloWorld.class そして実行してください - ./HelloWorld.class Java Jar ファイルを実行するには、chmod で *.jar ファイルに実行ビットを 立て、次のコマンドを実行してください - ./Application.jar Java アプレットを実行するには、chmod で *.html ファイルに実行ビットを 立て、次のコマンドを実行してください - ./Applet.html 著者:Brian A. Lantz, brian@lantz.com binfmt_misc に関する更新:Richard Gther 日本語訳:野本浩一 日本語訳最終更新日:2004/05/11 校正:中谷千絵さん 更新:JF プロジェクト < http://www.linux.or.jp/JF/ >