CygwinでJavaを快適に使う

2004.4.25よりアクセス


WindowsとUNIXでは、コマンドライン環境におけるさまざまな違いがあります。Cygwin環境では、基本的にUNIXと同じです。Cygwin環境においてCygwinプログラムだけを使用している限りは問題はありません。しかしながら、Cygwin環境からWindows用プログラムを使用する場合、Windows用プログラムに対してコマンドラインオプションを渡す場合や環境変数の指定内容はWindowsの流儀を使用する必要があります。Cygwin環境においてWindows流儀のコマンドラインオプション記述や環境変数設定をする場合の注意点と対処方法について整理します。

目次


java_wrapper公開

お知らせ(2010/09/09): java_wrapperは、SourceForge.JP上に開発プロジェクトを作成し、今後の開発はSourceForge.JP上の「Cygwin上でJavaコマンドを快適に使用する環境」プロジェクトで継続します。

java_wrapperスクリプト
バージョン番号 ファイル 更新日 機能内容
1.3.4  java_wrapper  2010.09.04  Cygwin 1.7.6暫定対処の削除、JAVA_HOMEに空白を含むパスを指定したときエラーとなる問題を回避
1.3.3 java_wrapper.1.3.3 2010.09.03 -jarオプションに相対パスでjarファイルを指定したときcygpathがエラーとなる問題を回避(Cygwin 1.7.6固有の問題) 
1.3.2 java_wrapper.1.3.2 2010.07.14 コマンドの引数パスにWindowsへ変換すると空白が含まれる場合の問題を回避

使い方は、java_wrapperの作成をご覧ください。


Cygwin環境とWindows環境のコマンドライン流儀

項目 Cygwin環境 Windows環境
複数パス指定時の区切り子
:
;
パス中のディレクトリ区切り子 / \
ドライブレター記述 なし ドライブレター記号+':'
一行で複数コマンド指定時の区切り子
;

Windowsは、以下のようなパス指定を使用します。Windowsのパス指定はドライブレターから開始されます。

PATH=C:\WINNT;C:\WINNT\system32;D:\usr\local\bin
      ^      ^ ^               ^ ^
複数のパスを指定するときは、区切り子に';'を使用
ドライブレターの直後は':'を使用

そこで、Windows用に提供されるJavaのコマンドでは、コマンドラインオプションは上述の書式を使用します。

D:\work> java -classpath D:\usr\java\mylib\mylib.jar;D:\work\classes myapp.Main
   :

Cygwinは、以下のようにUNIXライクなパス指定を使用します。UNIXではパスにドライブレターがなく、全てのパスが'/'(ルート)から開始されます。また、UNIXのコマンド環境では、`;`(セミコロン)は、1行で複数のコマンドを指定する際のコマンド間の区切りを意味します。

PATH=/usr/bin:/usr/local/bin:/usr/java/bin
             ^              ^
複数のパスを指定するときは、区切り子に':'を使用
$ cmd1; cmd2
      ^
複数のコマンドを一行に書いて実行する場合、コマンドの区切りに';'を使用

Java系コマンドのコマンドラインオプションの指定

例:-cp、-classpath、-jar、-sourcepath、-bootclasspath、-extdirs、-d、など

Cygwin環境においてコマンドラインからWindows用Javaコマンドを使用するときの注意点と方法です。

ディレクトリ区切り子の扱い

問題

まず、ディレクトリ区切り子にWindows環境の'\'を使うと、Cygwinでは'\'がエスケープ記号のため予期しない動作となります。例えばCygwin上でjavaコマンドの-jarオプションにWindows環境のパス指定方法でJARファイルのパスを指定すると、次のようなエラーが発生します。

torutk$ java -jar c:\j2sdk1.4.2\demo\jfc\Java2D\Java2Demo.jar
Unable to access jarfile c:j2sdk1.4.2demojfcJava2DJava2Demo.jar
torutk$

回避法1

幸いにして、Windows用Javaコマンドのほとんどは、ディレクトリ区切り子に'/'を受け付けます。そこで、ディレクトリ区切り子'/'を使用します。

torutk$ java -jar c:/j2sdk1.4.2/demo/jfc/Java2D/Java2Demo.jar
    :
torutk$

回避法2

UNIXでは文字としての'\'を表すときは、エスケープをキャンセルために"\\"と2つ連続で表現します。

torutk$ java -jar c:\\j2sdk1.4.2\\demo\\jfc\\Java2D\\Java2Demo.jar
    :
torutk$

複数パス指定の扱い

問題

複数のパスをコマンドラインオプションで渡す場合には、各パスをセミコロン';'で区切って指定します。しかし、Cygwinではセミコロンはコマンドライン上でコマンドを指定する場合の区切りとして扱われてしまうので、エラーとなってしまいます。

torutk$ java -cp c:/cygwin/usr/local/lib/alpha.jar;c:/cygwin/usr/local/lib/beta.jar;. Main
Usage: java [-options] class [args...]
           (to execute a class)
   or  java [-options] -jar jarfile [args...]
           (to execute a jar file)

where options include:
    -client       to select the "client" VM
    -server       to select the "server" VM
    -hotspot      is a synonym for the "client" VM  [deprecated]
                  The default VM is client.

    -cp <class search path of directories and zip/jar files>
    -classpath <class search path of directories and zip/jar files>
                  A ; separated list of directories, JAR archives,
                  and ZIP archives to search for class files.
    -D<name>=<value>
                  set a system property
    -verbose[:class|gc|jni]
                  enable verbose output
    -version      print product version and exit
    -showversion  print product version and continue
    -? -help      print this help message
    -X            print help on non-standard options
    -ea[:<packagename>...|:<classname>]
    -enableassertions[:<packagename>...|:<classname>]
                  enable assertions
    -da[:<packagename>...|:<classname>]
    -disableassertions[:<packagename>...|:<classname>]
                  disable assertions
    -esa | -enablesystemassertions
                  enable system assertions
    -dsa | -disablesystemassertions
                  disable system assertions
c:/cygwin/usr/local/lib/beta.jar: 1: Syntax error: "(" unexpected

bash: Main: No such file or directory
torutk$

これもエラーメッセージをちょっと見ただけだと何が原因だか分かりにくいですが、3つのエラーメッセージが表示されています。一つはjavaコマンドのオプション指定が間違っているため使用法が表示されており、二つ目は最初のセミコロンの直後からの文字列c:/usr/local/lib/beta.jarをコマンドとして実行しようとしてのSyntax error、三つ目はさらにその後のセミコロンの後の文字列. Mainを実行しようとしてのエラーです。

回避法

セミコロンの前にエスケープ記号'\'をつけて、セミコロンがコマンドラインの区切りとして解釈されないようにします。

torutk$ java -cp c:/cygwin/usr/local/lib/alpha.jar\;c:/cygwin/usr/local/lib/beta.jar\;. Main
Hello, Main!
I'm an Alpha
I'm an Beta
torutk$

Cygwin上の仮想パスの扱い

問題

Cygwin上で仮想的なディレクトリを使用しているときに、いちいちWindows上の実ディレクトリに変換して使用するのは手間がかかってしまいます。
例えば、UNIX風にディレクトリを使用していると、/usr/local/libの下にライブラリファイルを集めます。ここで/usr/localは、Windows上では<Cygwinインストールディレクトリ>\usr\localがマウントされています。他にも設定でいろいろなマウントがあります。これをJavaコマンド実行時には常に実際のパスを意識しなくてはならないのでは作業効率が落ちてしまいます。

回避法

Cygwinのコマンドcygpathを使用して、仮想パスから実パスに変換させます。pオプション指定で複数パスの区切り子の変換も自動的にやってくれます。

torutk$ java -cp `cygpath -wp /usr/local/lib/alpha.jar:/usr/local/lib/beta.jar:.` Main
Hello, Main!
I'm an Alpha
I'm an Beta
torutk$

環境変数のコマンドラインオプションへの引渡し

問題

環境変数にパスがWindows流儀で記述されていればよいのですが、UNIX流儀で環境変数にパスを指定した場合、Javaコマンドのコマンドラインオプションに環境変数を指定するとエラーが発生します。

torutk$ echo $MYJAR_HOME
/usr/local/lib
torutk$ java -cp $MYJAR_HOME/alpha.jar\;$MYJAR_HOME/beta.jar\;. Main
Hello, Main!
Exception in thread "main" java.lang.NoClassDefFoundError: Alpha
        at Main.main(Main.java:5)
torutk$

回避策1

環境変数には、Windows流儀でパスを指定します。

torutk$ MYJAR_HOME=c:/cygwin/usr/local/lib
torutk$ java -cp $MYJAR_HOME/alpha.jar\;$MYJAR_HOME/beta.jar\;. Main
Hello, Main!
I'm an Alpha
I'm an Beta
torutk$

回避策2

Cygwinのツール"cygpath"を使ってUNIX流儀のパス記述をWindows流儀に変換します。

torutk$ MYJAR_HOME=/usr/local/lib
torutk$ java -cp `cygpath -wp $MYJAR_HOME/alpha.jar:$MYJAR_HOME/beta.jar:.` Main
Hello, Main!
I'm an Alpha
I'm an Beta
torutk$

Windowsパスに空白が含まれる場合

問題

CygwinでマウントしていたパスがWindows側では空白が含まれる場合、cygpathでCygwinパスをWindowsパスに変換してJavaコマンドのコマンドラインオプションに渡すと、空白によってオプションが分断されエラーとなってしまいます。

例えば、C:\Program Files\Java/javaにマウントしていた場合、以下のようになります。

torutk$ java -cp `cygpath -wp /java/lib/alpha.jar` Main
java.lang.NoClassDefFoundError: Files\Java\lib\alfa/jar
Caused by: java.lang.ClassNotFoundException: Files\Java\lib\alfa.jar
        at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
Could not find the main class: Files\Java\lib\alpha.jar.  Program will exit.
Exception in thread "main"

torutk$

回避策

torutk$ java -cp `cygpath -wps /java/lib/alpha.jar` Main
Hello, Main!
I'm an Alpha
torutk$

cygpathに-sオプションを追加します。-sオプションは、Windowsのパスを短い名前(MS-DOS形式:8文字+3文字)に変換する指定です。

文字コードの扱い

UTF-8ターミナル使用時にJava系コマンドの出力文字が化ける

問題

Cygwinのコマンド環境を、Teraterm等の汎用ターミナル上で使用するとき、UTF-8に設定していると、WindowsのJavaがCP932で出力するので文字化けとなってしまいます。

回避策1

ck terminal等、文字コードを自動認識して表示するターミナルソフトウェアを使用する。

回避策2

javaコマンド実行時、システムプロパティのファイルエンコーディングをUTF-8に変更します。

torutk$ java -Dfile.encoding=UTF-8 Mail
    :
torutk$

Cygwinの~/.bashrc に、エイリアスで設定を書いておくのも便利です。

alias javau='java -Dfile.encoding=UTF-8'

cygpathを使った汎用的な対処

はじめに

前章で述べた回避策は、いずれもコマンドを使用する都度毎回指定しなくてはなりません。そこで、Javaコマンドを実行する際、コマンドラインオプションの中にあるパス指定を自動的にCygwin環境からWindows環境の流儀に変換するような仕組みを考えていきます。

参考URL

java_wrapperの作成

上記参考URLで紹介した「CygwinでJava」のページをヒントに、java_wrapperスクリプトを作成していきます。いくつか機能を加えています。

これを/usr/local/binの下において、/usr/local/binにいくつかシンボリックリンクを作成します。手作業で作成する例を以下に示します。J2SE SDKに含まれるコマンドについて一通り指定します。

torutk$ cd /usr/local/bin
bin$ ln -s java_wrapper java
bin$ ln -s java_wrapper javac
bin$ ln -s java_wrapper javaw
bin$ ln -s java_wrapper jar
bin$ ln -s java_wrapper javah
bin$ ln -s java_wrapper javap
  :
bin$

面倒なのでJ2SE SDKのコマンドをまとめてシンボリックリンク作成することもできます。

torutk$ cd /usr/local/bin
bin$ for cmd in `/bin/ls /usr/java/j2sdk1.5.0/bin/*.exe`; do \
 ln -s java_wrapper `basename $cmd .exe`; done
bin$

java_wrapperスクリプトにシンボリックリンク作成機能を追加しました(Ver.1.2)。

torutk$ cd /usr/local/bin
bin$ ./java_wrapper createsymlinks
bin$

java_wrapperの使用方法

環境設定

  1. 使用するJ2SE SDKがインストールされているパスを環境変数JAVA_HOMEに指定
  2. 環境変数PATHの指定において、/usr/local/binが/usr/binより前にあること
環境変数JAVA_HOMEの設定

JDKのインストール場所を、環境変数JAVA_HOMEに設定します。設定は、~/.bashrcなどに記述します。

JDKのインストール場所が空白を含むパスである場合(例:C:\Program Files\Java\jdk1.6.0_21)、シンボリックリンクかジャンクションで空白を含まないパスから空白を含むパスを参照するようにして、JAVA_HOMEはシンボリックリンク(ジャンクション)のパスを指定すると便利です。

シンボリックリンク作成の例

torutk$ ln -s /cygdrive/c/Program\ Files/Java /java
torutk$ export JAVA_HOME=/java/jdk1.6.0_21
torutk$

ジャンクション作成の例(Windows Vista/7)

C:\> mklink /J java C:\Program Files\Java
C:\> dir
    :
2010/09/04  03:29  <JUNCTION>  java [c:\Program Files\Java]
    :
C:\>

※ Windows XPの場合、標準ではジャンクション作成コマンドが搭載されていないので、リソースキットのlinkdコマンドを取得するとよさそうです。

torutk$ export JAVA_HOME=c:/java/jdk1.6.0_21
torutk$

複数バージョンのJDKを持っていて随時切り替えたい場合は、環境設定用のスクリプトを記述します。以下に、JDKのバージョンを指定して環境変数JAVA_HOMEを設定する.bashrcのスクリプトを示します。

function setjdk() {
    if [ "$1" = "32" ]; then
        echo "- Setting 32bit JAVA Environment"
        JDK_BASE=d:/java32
        shift
    else
        echo "- Setting 64bit JAVA Environment"
        JDK_BASE=d:/java
    fi

    case $1 in
        1.4)
            echo "- Setting JAVA_HOME for JDK1.4.2"
            JDK_HOME=$JDK_BASE/j2sdk1.4.2
            ;;
        1.5)
            echo "- Setting JAVA_HOME for JDK1.5.0"
            JDK_HOME=$JDK_BASE/jdk1.5.0
            ;;
        1.6)
            echo "- Setting JAVA_HOME for JDK1.6.0"
            JDK_HOME=$JDK_BASE/jdk1.6.0
            ;;
        *)
            echo "Usage: setjdk [32] <1.4|1.5|1.6>"
            ;;
    esac
    export JAVA_HOME=$JDK_HOME
}

32bit版JDK、64bit版JDKのバージョン1.4.2、5.0、6が入っている環境で、Cygwinのコンソール(bash)上でJava(JDK)のパスを切り替えます。

実行

javacの場合
torutk$ javac -d ~torutk -cp /usr/local/lib/alpha.jar:/usr/local/lib/beta.jar Main.java
torutk$

パスの指定に、~ユーザ名 とかも指定できるようになりました。Cygwin流にパスが指定できるので、コマンドラインで補完もバシバシ効いて快適です。


CygwinとJavaの問題解決

jpsコマンドで実行中のJavaプロセスが見えない

Cygwinでjpsコマンドを実行すると、Cygwin以外から実行しているJavaのプロセスのIDが表示されません。(Cygwin 1.7以降と思われる)

原因

Java VMを起動すると、Windows OSでは環境変数TMPまたはTEMPをベースにしたディレクトリにJava VMの起動情報を書き込みます。Cygwinはデフォルトの.bashrc設定で、環境変数TMPとTEMPをunsetしているため、Cygwin以外で実行したJavaの情報とCygwin上で実行したJavaの情報が異なる場所に書き込まれるからです。

回避策

Cygwinのデフォルトで生成された$HOME/.bashrc および /etc/profile の中に記述されている unset TMPおよびunset TEMPを削除します。