2016/07/31

update-java-alternatives に Oracle java も追加する

@Ubuntu 16.04 LTS

2016/8/4 追記
最新の update-java-alternatives は javac 等を更新してくれないバグがあります。 一時的なものだと思われますが、ご注意ください。

穀風: 最新版の update-java-alternatives は javac を更新してくれない

update-java-alternatives には --install のようなコマンドがないため、簡単に対象を追加することは出来ません1

ただ、その中身は単なる update-alternatives2 のラッパースクリプトなので、動作を理解すれば、任意の JDK (JRE) を手動で登録して、切り替えられるようにすることが可能です。

今回は Oracle から jdk-8u101 をダウンロードして追加してみました。

update-alternatives とは

update-alternatives について少しだけ書いておきたいと思います。 update-alternatives は複数バージョンあるコマンドを簡単に切り替えるためのツールです。

例えば、以下のように /usr/bin/java を切り替えることが出来ます3

$ update-alternatives --config java
There are 2 choices for the alternative java (providing /usr/bin/java).
 
  Selection    Path                                            Priority   Status
------------------------------------------------------------
  0            /usr/lib/jvm/jdk-1.8.0_91-oracle/jre/bin/java    1081      auto mode
  1            /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java   1081      manual mode
* 2            /usr/lib/jvm/jdk-1.8.0_91-oracle/jre/bin/java    1081      manual mode
 
Press <enter> to keep the current choice[*], or type selection number:

update-alternatives 自体は java とは関係がなく、任意のコマンドを切り替え可能なツールです。

参考
update-alternativesに管理してもらうコマンドを追加する。 - Qiita

update-java-alternatives を使う理由

バージョン違いの java を切り替えるだけなら、 update-alternatives で十分な気がします。 ところが、java の動作環境を正しく変更するには、java, javac, jar...etc と膨大な数4のコマンドを切り替えなければなりません。

これらを一気に処理してしまおうというのが、update-java-alternatives です。 具体的には /usr/lib/jvm/.*.jinfo ファイルの情報を基に update-alternatives を実行するシェルスクリプトになっています。

つまり、/usr/lib/jvm/.*.jinfo ファイルを新規作成すれば update-java-alternatives に新たな項目を追加出来るわけです5

以下が実際の /usr/lib/jvm/.java-1.8.0-openjdk-amd64.jinfo です。 後半の各項目が update-alternatives で切り替えられます。

name=java-8-openjdk-amd64
alias=java-1.8.0-openjdk-amd64
priority=1081
section=main

hl rmid /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/rmid
hl java /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java
hl keytool /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/keytool
hl jjs /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/jjs
hl pack200 /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/pack200
hl rmiregistry /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/rmiregistry
hl unpack200 /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/unpack200
hl orbd /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/orbd
hl servertool /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/servertool
hl tnameserv /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/tnameserv
hl jexec /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/jexec
jre policytool /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/policytool
jdkhl idlj /usr/lib/jvm/java-8-openjdk-amd64/bin/idlj
jdkhl jdeps /usr/lib/jvm/java-8-openjdk-amd64/bin/jdeps
jdkhl wsimport /usr/lib/jvm/java-8-openjdk-amd64/bin/wsimport
jdkhl rmic /usr/lib/jvm/java-8-openjdk-amd64/bin/rmic
jdkhl jinfo /usr/lib/jvm/java-8-openjdk-amd64/bin/jinfo
jdkhl jsadebugd /usr/lib/jvm/java-8-openjdk-amd64/bin/jsadebugd
jdkhl native2ascii /usr/lib/jvm/java-8-openjdk-amd64/bin/native2ascii
jdkhl jstat /usr/lib/jvm/java-8-openjdk-amd64/bin/jstat
jdkhl javac /usr/lib/jvm/java-8-openjdk-amd64/bin/javac
jdkhl javah /usr/lib/jvm/java-8-openjdk-amd64/bin/javah
jdkhl jstack /usr/lib/jvm/java-8-openjdk-amd64/bin/jstack
jdkhl jrunscript /usr/lib/jvm/java-8-openjdk-amd64/bin/jrunscript
jdkhl javadoc /usr/lib/jvm/java-8-openjdk-amd64/bin/javadoc
jdkhl javap /usr/lib/jvm/java-8-openjdk-amd64/bin/javap
jdkhl jar /usr/lib/jvm/java-8-openjdk-amd64/bin/jar
jdkhl extcheck /usr/lib/jvm/java-8-openjdk-amd64/bin/extcheck
jdkhl schemagen /usr/lib/jvm/java-8-openjdk-amd64/bin/schemagen
jdkhl jps /usr/lib/jvm/java-8-openjdk-amd64/bin/jps
jdkhl xjc /usr/lib/jvm/java-8-openjdk-amd64/bin/xjc
jdkhl jarsigner /usr/lib/jvm/java-8-openjdk-amd64/bin/jarsigner
jdkhl jmap /usr/lib/jvm/java-8-openjdk-amd64/bin/jmap
jdkhl jstatd /usr/lib/jvm/java-8-openjdk-amd64/bin/jstatd
jdkhl jhat /usr/lib/jvm/java-8-openjdk-amd64/bin/jhat
jdkhl jdb /usr/lib/jvm/java-8-openjdk-amd64/bin/jdb
jdkhl serialver /usr/lib/jvm/java-8-openjdk-amd64/bin/serialver
jdkhl wsgen /usr/lib/jvm/java-8-openjdk-amd64/bin/wsgen
jdkhl jcmd /usr/lib/jvm/java-8-openjdk-amd64/bin/jcmd
jdk appletviewer /usr/lib/jvm/java-8-openjdk-amd64/bin/appletviewer
jdk jconsole /usr/lib/jvm/java-8-openjdk-amd64/bin/jconsole

Oracle java を update-java-alternatives で使えるようにする

実際の手順として、Oracle java をインストールして、切り替え可能にしてみます。

まず、Java SE - Downloads より必要な jdk (jre) をダウンロードし、/usr/lib/jvm 以下に展開します。 ここでは、jdk-8u101-linux-x64.tar.gz をダウンロードし、jdk-1.8.0_101-oracle に展開したものとします。

次に、.*.jinfo を作成します。 一から作成すると大変なので、既存のものをコピーし、一部を置換するのが良いでしょう。 以下のように sed を使って置換と同時にコピーを生成すると楽です。

$ cd /usr/lib/jvm
$ sed -e "s/\(java-8-openjdk-amd64\|java-1.8.0-openjdk-amd64\)/jdk-1.8.0_101-oracle/g" .java-1.8.0-openjdk-amd64.jinfo | sudo tee .jdk-1.8.0_101-oracle.jinfo

update-java-alternatives --list を実行して認識されていれば成功です。

$ update-java-alternatives --list
java-1.8.0-openjdk-amd64       1081       /usr/lib/jvm/java-1.8.0-openjdk-amd64
jdk-1.8.0_101-oracle           1081       /usr/lib/jvm/jdk-1.8.0_101-oracle

update-alternatives に登録する

「以上で終了」だと良いのですが、残念ながら、もうひと手間かかります。 この状態で --set を実行するとそんなコマンドは登録されていない旨のエラーが出てしまうのです。

$ sudo update-java-alternatives --set jdk-1.8.0_101-oracle
update-alternatives: error: no alternatives for mozilla-javaplugin.so
update-alternatives: error: alternative /usr/lib/jvm/jdk-1.8.0_101-oracle/jre/bin/java for java not registered; not setting
update-alternatives: error: alternative /usr/lib/jvm/jdk-1.8.0_101-oracle/jre/lib/jexec for jexec not registered; not setting
update-alternatives: error: alternative /usr/lib/jvm/jdk-1.8.0_101-oracle/jre/bin/jjs for jjs not registered; not setting
update-alternatives: error: alternative /usr/lib/jvm/jdk-1.8.0_101-oracle/jre/bin/keytool for keytool not registered; not setting
update-alternatives: error: alternative /usr/lib/jvm/jdk-1.8.0_101-oracle/jre/bin/orbd for orbd not registered; not setting
update-alternatives: error: alternative /usr/lib/jvm/jdk-1.8.0_101-oracle/jre/bin/pack200 for pack200 not registered; not setting
update-alternatives: error: alternative /usr/lib/jvm/jdk-1.8.0_101-oracle/jre/bin/rmid for rmid not registered; not setting
update-alternatives: error: alternative /usr/lib/jvm/jdk-1.8.0_101-oracle/jre/bin/rmiregistry for rmiregistry not registered; not setting
update-alternatives: error: alternative /usr/lib/jvm/jdk-1.8.0_101-oracle/jre/bin/servertool for servertool not registered; not setting
update-alternatives: error: alternative /usr/lib/jvm/jdk-1.8.0_101-oracle/jre/bin/tnameserv for tnameserv not registered; not setting
update-alternatives: error: alternative /usr/lib/jvm/jdk-1.8.0_101-oracle/jre/bin/unpack200 for unpack200 not registered; not setting
update-alternatives: error: alternative /usr/lib/jvm/jdk-1.8.0_101-oracle/bin/appletviewer for appletviewer not registered; not setting
update-alternatives: error: alternative /usr/lib/jvm/jdk-1.8.0_101-oracle/bin/jconsole for jconsole not registered; not setting
update-alternatives: error: alternative /usr/lib/jvm/jdk-1.8.0_101-oracle/jre/bin/policytool for policytool not registered; not setting

先にも述べたように、update-java-alternatives は単なるラッパーなので、大元の update-alternatives に登録されていなければいけません。

これらの項目を全て手作業で登録するのは現実的ではありませんので、 以下のように .jdk-1.8.0_101-oracle.jinfo の情報を基に、各項目に対して update-alternatives --install を実行すると良いでしょう6

cat .jdk-1.8.0_101-oracle.jinfo | awk -F'[ =]' '/^priority/ { priority=$2 } /^(hl|jre|jdk)/ { print "/usr/bin/" $2 " " $2 " " $3 " " priority; "\n" }' | xargs -t -n4 sudo update-alternatives --verbose --install

参考
Linuxで複数バージョンのJavaを管理する - Yahoo!知恵袋

update-java-alternatives で切り替える

実際に使用する際は、

--list で一覧を表示

$ update-java-alternatives --list
java-1.8.0-openjdk-amd64       1081       /usr/lib/jvm/java-1.8.0-openjdk-amd64
jdk-1.8.0_101-oracle           1081       /usr/lib/jvm/jdk-1.8.0_101-oracle

--set で切り替えます

$ sudo update-java-alternatives --set jdk-1.8.0_101-oracle
$ java -version
java version "1.8.0_101"
Java(TM) SE Runtime Environment (build 1.8.0_101-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.101-b13, mixed mode)

環境変数 JAVA_HOME, JDK_HOME を設定

環境変数 JAVA_HOMEJDK_HOME を使うアプリケーションもあるため、これらも適切に変更しておく必要があります。 update-java-alternatives にそういった機能があれば良いのですが、残念ながら無いので、~/.profile 等に以下の項目を加えます。

1
2
3
4
5
JAVA_DIR=`readlink -f /usr/bin/java`
if [ -x $JAVA_DIR ]; then
   export JAVA_HOME=$(echo ${JAVA_DIR} | sed "s:/bin/java::")
   export JDK_HOME=$JAVA_HOME
fi

update-java-alternatives --set を実行したら ~/.profile を再読みこみしましょう。

$ sudo update-java-alternatives --set jdk-1.8.0_101-oracle
$ source ~/.profile

以上で Oracle java を update-java-alternatives で切り替えられるようになりました。

[参考] update-java-alternatives から削除する

削除したい場合は、以下のように update-alternatives --remove で個々のエントリーを削除した後、.*.jinfo ファイルを削除します。

$ cat .jdk-1.8.0_91-oracle.jinfo | awk -F'[ =]' '/^priority/ { priority=$2 } /^(hl|jre|jdk)/ { print $2 " " $3; "\n" }' | xargs -t -n2 sudo update-alternatives --verbose --remove
$ sudo rm .jdk-1.8.0_91-oracle.jinfo

[参考] 実際のシンボリックリンク

実際のシンボリックリンクは /etc/alternatives/ 以下に一度張られ、その先を都度書き換えるという形で実現されています。

$ ls -l /usr/bin/java
lrwxrwxrwx 1 root root 22  7月 31 13:09 /usr/bin/java -> /etc/alternatives/java*
 
$ ls -l /etc/alternatives/java
lrwxrwxrwx 1 root root 46  7月 31 18:07 /etc/alternatives/java -> /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java*
  1. 一般的にはパッケージから入れた時に自動的に追加される 
  2. -java- がついていない 
  3. 既に 古い Oracle java を追加してある 
  4. といっても 40個くらいですが 
  5. 実際はもうひと手間かかる。後述。 
  6. この機能を update-java-alternatives が持ってたら良かったのだけど 
?

0 件のコメント: