2015年6月6日土曜日

Mac OS Xのjavaは環境変数JAVA_HOMEで切り替えられる

Mac OS Xには、最初から/usr/bin以下にJDK 6相当のコマンドがずらりと入っておりまして、なんだこりゃと思うわけですが、なかなか面白い挙動をしたのでご報告。

Javaをインストールしていない状態でこれらを実行すると、例のダイアログが出ますね。
Javaが入っていないと出るいつものダイアログ
それで「詳しい情報...」をクリックするとOracleからダウンロードしてインストールするよう指示されるので、普通の人はそうするんだと思いますが、それでもなお、何かコマンドを実行するとこのダイアログが出てきて混乱するわけです。

そのとき、Apple Java SE 6を入れるとおさまるわけですが、Oracle Java 8はどうやって実行するの? という疑問が残ります。

それで調べてみると、環境変数JAVA_HOMEで実行先を指定するのが正しいようです。そこで、~/.profileあたりに
export JAVA_HOME="/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home"
と書いて
$ . ~/.profile
などとして読むとか、試すだけならいま開いているshellで実行してもよいわけですが、そうするとあら不思議、
$ java -version
java version "1.8.0_45"
Java(TM) SE Runtime Environment (build 1.8.0_45-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.45-b02, mixed mode)
というわけで、Oracle Java 8が/usr/bin/javaから呼び出されるというわけです。

開発者なら、Oracle JDK 8を入れると思うので、そうすれば、Java 6時代のコマンドapt以外は全部Oracle Java SE 8で置き換えられるのでわりと幸せです。Java 8にしかないコマンドもあるので、/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/binをpathに入れるとかしたくなる人もいるかもしれません。

ちなみに、Oracle JRE 8を入れて環境変数JAVA_HOMEを設定して、JDKにしかないコマンドを実行するとどうなるか。例えばjavacなんかですね。
$ javac
Unable to locate an executable at "/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/bin/javac" (-1)
環境変数の先を実行しようとしてコマンドがないのでエラーになる、という動作をします。正しい動作です。

ところが、これに沿っていない困ったコマンドがひとつだけあります。/usr/libexec/java_homeです。
$ /usr/libexec/java_home
Unable to find any JVMs matching version "(null)".
No Java runtime present, try --request to install.
なんと、Apple Java SE 6を探しに行って、ないからインストールせよというわけです。まあ、Appleご謹製のコマンドなんでしょうがないですが、古い時代の、AppleがMac OS版Java公式配布をしていた時代に作られたソフトウェアでは、このコマンドでJavaの存在をチェックしているものがあるかもしれません。やめてもらいたいんですが開発止まってたらだめですね。どうにかならんもんでしょうか。

ついでなので、java_homeコマンドをもう少し深堀りしてみます。
$ /usr/libexec/java_home -h
Usage: java_home [options...]
    Returns the path to a Java home directory from the current user's settings.

Options:
    [-v/--version   ]       Filter Java versions in the "JVMVersion" form 1.X(+ or *).
    [-a/--arch      ]  Filter JVMs matching architecture (i386, x86_64, etc).
    [-d/--datamodel ]     Filter JVMs capable of -d32 or -d64
    [-t/--task      ]          Use the JVM list for a specific task (Applets, WebStart, BundledApp, JNI, or CommandLine)
    [-F/--failfast]                  Fail when filters return no JVMs, do not continue with default.
    [   --exec       ...]   Execute the $JAVA_HOME/bin/ with the remaining arguments.
    [-R/--request]                   Request installation of a Java Runtime if not installed.
    [-X/--xml]                       Print full JVM list and additional data as XML plist.
    [-V/--verbose]                   Print full JVM list with architectures.
    [-h/--help]                      This usage information.
ふむふむ、--execを通してやればよいのかと、環境変数JAVA_HOMEがOracle Java 8を指している状態で試してみます。
$ /usr/libexec/java_home -exec java
Unable to find any JVMs matching version "(null)".
No Java runtime present, try --request to install.
がーん! というか、やっぱりApple Java SE 6があることが前提なようです。

両方入れて、java_homeがうまく切り替えてくれるかは確かめておりませんが、注意喚起の意味でご報告する次第です。「java_homeには罠がある