吉方位確認サービス「楽方位」α版を公開しました。

Raspberry Pi 3 用の OpenJDK 11 を Ubuntu 18.04.2 上でクロスコンパイルで作成

Sponsored Links

このポストでは、https://jdk.java.net/ で提供されるオラクルの OpenJDK 11 を、単に OpenJDK 11 と記述しています。

はじめに

Raspberry Pi Foundation の公式 OS である Raspbian で Java 11 のアプリケーションを動かしてみます。

しかし、Raspberry Pi の CPU は ARM です。Raspbian は Debian ベースですが、32bit OS です。Raspbian は hard-foat です。

OpenJDK 11 のダウンロードサイト https://jdk.java.net/11/ では、Linux, macOS, Windows の 64 bit 向けのバイナリしか提供されていません。

その背景としては、2018 年 5 月のオラクルのブログを見てみます。

https://blogs.oracle.com/jtc/build-jdk-10-for-your-raspberry-pi-right-on-your-device

オラクルは JDK 9 以降、サポートするハードウェアや OS を減らしました。32bit 版は提供されませんし、Raspberry Pi を含む ARM 向けのバイナリも提供されません。しかし、ソースコードには 32bit armhf もサポートするように組み込まれているようです。ただし、言及されているのは OpenJDK 10 までです。このオラクルのブログ記事が OpenJDK 11 がリリースされる前の 2018 年 5 月のものですが、その後、OpenJDK 11 については言及された情報を目にしたことがありません。

よって、Raspberry Pi のようなデバイスでも最新の Java を動かすには 2 つの選択肢が存在することになります。

  1. 自分が望むものを、誰かがビルドして提供してくれるのを待つ
  2. 自分が望むものを、自分でビルドする

1 のような都合の良い話は無いでしょう。そのため、Raspberry Pi で OpenJDK 11 を動かしたい場合、ソースコードを取得して自分でビルドしなければなりません。しかし、処理能力が貧弱である Raspberry Pi 上での OpenJDK 11 のビルドは、非常に時間がかかることが予想されます。

その課題を解決するために、Linux PC 上に Raspberry Pi のツールチェーンを作成し、クロスコンパイル環境を構築し、Linux PC 上で Raspberry Pi 用の OpenJDK 11 をビルドします。

今回使用する Raspberry Pi は、Raspberry Pi 3 Model B です。

Raspbian は、Raspbian Stretch Lite の Version : April 2019 です。

ちなみに、Raspberry Pi Foundation の公式 OS である、Debian ベースの Raspbian は 32bit であり、当分 64bit はサポートしない雰囲気です。

https://www.raspberrypi.org/blog/raspbian-stretch/
https://www.raspberrypi.org/forums/viewtopic.php?f=63&&&&t=208314

よって、Raspbian on Raspberry Pi で動くように、ARM hard-float 32bit 用の OpenJDK 11 をビルドします。

クロスコンパイル環境を構築した OS

  • Ubuntu 18.04.2

過去に、VirtualBox 上に、2 Core CPU, 2 GB Mem, 30 GB Disk で作成したクロスコンパイル環境では、クロスコンパイル時にメモリ不足のエラーとなりました。そのため、メモリは 4GB 程度必要でしょう。

クロスコンパイル環境の構築

Ubuntu 18.04.2 で、crosstool-NG の Raspberry Pi 3 用のツールチェーンを使用してクロスコンパイル環境を構築したメモです。注意点としては、下記のメモ中にもあるように、glibc のバージョンを 2.24 に設定する必要があります。

OpenJDK 11 のビルドに必要なパッケージのダウンロード

Raspberry Pi 向けに OpenJDK 11 をビルドするために必要な armhf のパッケージをダウンロードして展開しておきます。なお、各パッケージのバージョンは、2019-05-10 時点のものです。

最新のものは、

https://www.debian.org/distrib/packages

で検索してみてください。

作業用に適当なディレクトリを作成します。

mkdir ~/openjdk11tmp

作成したディレクトリにパッケージを放り込んでいきます。

ALSA, Advanced Linux Sound Architecture

mkdir ~/openjdk11tmp/alsa
cd ~/openjdk11tmp/alsa
curl -O http://ftp.jp.debian.org/debian/pool/main/a/alsa-lib/libasound2_1.1.3-5_armhf.deb
curl -O http://ftp.jp.debian.org/debian/pool/main/a/alsa-lib/libasound2-dev_1.1.3-5_armhf.deb
mkdir ~/x-tools/alsa
cd ~/x-tools/alsa
dpkg-deb -x ~/openjdk11tmp/alsa/libasound2_1.1.3-5_armhf.deb .
dpkg-deb -x ~/openjdk11tmp/alsa/libasound2-dev_1.1.3-5_armhf.deb .

X11

mkdir ~/openjdk11tmp/x11
cd ~/openjdk11tmp/x11
curl -O http://ftp.jp.debian.org/debian/pool/main/libx/libxi/libxi6_1.7.9-1_armhf.deb
curl -O http://ftp.jp.debian.org/debian/pool/main/libx/libxi/libxi-dev_1.7.9-1_armhf.deb
curl -O http://ftp.jp.debian.org/debian/pool/main/x/x11proto-core/x11proto-core-dev_7.0.31-1_all.deb
curl -O http://ftp.jp.debian.org/debian/pool/main/x/x11proto-input/x11proto-input-dev_2.3.2-1_all.deb
curl -O http://ftp.jp.debian.org/debian/pool/main/x/x11proto-kb/x11proto-kb-dev_1.0.7-1_all.deb
curl -O http://ftp.jp.debian.org/debian/pool/main/x/x11proto-render/x11proto-render-dev_0.11.1-2_all.deb
curl -O http://ftp.jp.debian.org/debian/pool/main/x/x11proto-xext/x11proto-xext-dev_7.3.0-1_all.deb
curl -O http://ftp.jp.debian.org/debian/pool/main/libi/libice/libice-dev_1.0.9-2_armhf.deb
curl -O http://ftp.jp.debian.org/debian/pool/main/libx/libxrender/libxrender1_0.9.10-1_armhf.deb
curl -O http://ftp.jp.debian.org/debian/pool/main/libx/libxrender/libxrender-dev_0.9.10-1_armhf.deb
curl -O http://ftp.jp.debian.org/debian/pool/main/libs/libsm/libsm-dev_1.2.2-1+b3_armhf.deb
curl -O http://ftp.jp.debian.org/debian/pool/main/libx/libxt/libxt-dev_1.1.5-1_armhf.deb
curl -O http://ftp.jp.debian.org/debian/pool/main/libx/libx11/libx11-6_1.6.4-3+deb9u1_armhf.deb
curl -O http://ftp.jp.debian.org/debian/pool/main/libx/libx11/libx11-dev_1.6.4-3+deb9u1_armhf.deb
curl -O http://ftp.jp.debian.org/debian/pool/main/libx/libxtst/libxtst6_1.2.3-1_armhf.deb
curl -O http://ftp.jp.debian.org/debian/pool/main/libx/libxtst/libxtst-dev_1.2.3-1_armhf.deb
curl -O http://ftp.jp.debian.org/debian/pool/main/libx/libxext/libxext6_1.3.3-1+b2_armhf.deb
curl -O http://ftp.jp.debian.org/debian/pool/main/libx/libxext/libxext-dev_1.3.3-1+b2_armhf.deb
mkdir ~/x-tools/x11
cd ~/x-tools/x11
for deb in ~/openjdk11tmp/x11/*.deb ; do dpkg-deb -x $deb . ; done

この際、libICE.so libSM.so libXt.so へのシンボリックリンクが張られていませんが、ビルドには影響しないため、気にしないでください。

CUPS, Common UNIX Printing System

mkdir ~/openjdk11tmp/cups
cd ~/openjdk11tmp/cups
curl -O http://ftp.jp.debian.org/debian/pool/main/c/cups/libcups2-dev_2.2.1-8+deb9u3_armhf.deb
mkdir ~/x-tools/cups
cd ~/x-tools/cups
dpkg-deb -x ~/openjdk11tmp/cups/libcups2-dev_2.2.1-8+deb9u3_armhf.deb .

fontconfig

mkdir ~/openjdk11tmp/fontconfig
cd ~/openjdk11tmp/fontconfig
curl -O http://ftp.jp.debian.org/debian/pool/main/f/fontconfig/libfontconfig1-dev_2.11.0-6.7+b1_armhf.deb
mkdir ~/x-tools/fontconfig
cd ~/x-tools/fontconfig
dpkg-deb -x ~/openjdk11tmp/fontconfig/libfontconfig1-dev_2.11.0-6.7+b1_armhf.deb .

cupsimage2

mkdir ~/openjdk11tmp/cupsimage2
cd ~/openjdk11tmp/cupsimage2
curl -O http://ftp.jp.debian.org/debian/pool/main/c/cups/libcupsimage2-dev_2.2.1-8+deb9u3_armhf.deb
dpkg-deb -x libcupsimage2-dev_2.2.1-8+deb9u3_armhf.deb .
cp usr/include/cups/* ~/x-tools/cups/usr/include/cups/
cp usr/lib/arm-linux-gnueabihf/* ~/x-tools/cups/usr/lib/arm-linux-gnueabihf/

下記のようなメッセージが表示されるかもしれませんが、ビルドには影響しないため、気にしないでください。

cp: cannot stat 'usr/lib/arm-linux-gnueabihf/libcupsimage.so': No such file or directory

freetype2

mkdir ~/openjdk11tmp/freetype2
cd ~/openjdk11tmp/freetype2
curl -O http://ftp.jp.debian.org/debian/pool/main/f/freetype/libfreetype6_2.6.3-3.2_armhf.deb
curl -O http://ftp.jp.debian.org/debian/pool/main/f/freetype/libfreetype6-dev_2.6.3-3.2_armhf.deb
mkdir ~/x-tools/freetype2
cd ~/x-tools/freetype2
dpkg-deb -x ~/openjdk11tmp/freetype2/libfreetype6_2.6.3-3.2_armhf.deb .
dpkg-deb -x ~/openjdk11tmp/freetype2/libfreetype6-dev_2.6.3-3.2_armhf.deb .

Linux 向けの OpenJDK 11 のインストール

OpenJDK 11 をソースコードからビルドするためには、予めビルドを行うマシンに OpenJDK のバイナリがインストールされている必要があります。そのため、Linux 向けの OpenJDK 11 のバイナリをインストールしておきます。例えば、下記の通りです。

~/openjdk11tmp
curl -O https://download.java.net/java/GA/jdk11/9/GPL/openjdk-11.0.2_linux-x64_bin.tar.gz
sudo mkdir /usr/lib/jvm
sudo tar zxvf openjdk-11.0.2_linux-x64_bin.tar.gz -C /usr/lib/jvm/
sudo sh -c "echo 'export JAVA_HOME=/usr/lib/jvm/jdk-11.0.2' >> /etc/profile.d/jdk.sh"
sudo sh -c "echo 'export PATH=\$JAVA_HOME/bin:\$PATH' >> /etc/profile.d/jdk.sh"
source /etc/profile.d/jdk.sh

OpenJDK 11 のソースコードのダウンロード

続いて、OpenJDK 11 のソースコードを取得します。OpenJDK 11 のソースコードは、Mercurial で管理されています。

https://hg.openjdk.java.net/jdk-updates/jdk11u

取得方法は、圧縮ファイルをダウンロードする方法と Mercurial でクローンする方法があります。

圧縮ファイルをダウンロード

リポジトリから特定のリビジョンのソースコードをダウンロードすることができます。2019-05-10 時点で最新の GA タグ jdk-11.0.3-ga が打たれているリビジョン 175eb80c253a の zip をダウンロードしました。

https://hg.openjdk.java.net/jdk-updates/jdk11u/rev/175eb80c253a

リポジトリ画面の左側の zip をクリックすると、jdk11u-175eb80c253a.zip というファイル名でダウンロードされます。

Mercurial でクローン

Mercurial を APT でインストールします。

sudo apt-get -y install mercurial

適当な作業用ディレクトリを作成し、hg コマンドで OpenJDK 11 のソースコードをダウンロードします。例えば下記の通り。この例ではバージョン 11.0.1 としてリリースされたタグを指定してダウンロードしています。

mkdir ~/openjdk11build
cd ~/openjdk11build
hg clone -r jdk-11.0.3-ga https://hg.openjdk.java.net/jdk-updates/jdk11u

これが曲者で、私の環境では何度もダウンロードに途中で失敗しました。何度も何度も繰り返し、数時間以上要しました。私の Mercurial の使い方が適切ではないのでしょうか?

destination directory: jdk11u
adding changesets
adding manifests                                                                                                                                                                                               
adding file changes                                                                                                                                                                                            
added ... changesets with ... changes to ... files                                                                                                                                                     
new changesets ...
updating to branch default
(warning: large working directory being used without fsmonitor enabled; enable fsmonitor to improve performance; see "hg help -e fsmonitor")
... files updated, 0 files merged, 0 files removed, 0 files unresolved

OpenJDK 11 のビルド

いよいよビルドです。ダウンロードした圧縮ファイルを解凍したディレクトリ、あるいはクローンしたディレクトリに入ります。

chmod 755 configure
./configure --openjdk-target=armv8-rpi3-linux-gnueabihf \
  --with-tools-dir=/home/$USER/x-tools/armv8-rpi3-linux-gnueabihf/bin \
  --with-alsa=/home/$USER/x-tools/alsa/usr \
  --with-alsa-include=/home/$USER/x-tools/alsa/usr/include \
  --with-alsa-lib=/home/$USER/x-tools/alsa/usr/lib/arm-linux-gnueabihf \
  --with-x=/home/$USER/x-tools/x11/usr \
  --x-includes=/home/$USER/x-tools/x11/usr/include \
  --x-libraries=/home/$USER/x-tools/x11/usr/lib/arm-linux-gnueabihf \
  --with-cups=/home/$USER/x-tools/cups/usr \
  --with-fontconfig=/home/$USER/x-tools/fontconfig/usr \
  --disable-warnings-as-errors \
  --with-freetype-include=/home/$USER/x-tools/freetype2/usr/include \
  --with-freetype-lib=/home/$USER/x-tools/freetype2/usr/lib/arm-linux-gnueabihf
make JOBS=$(nproc)

ビルドは、Core i3-4170 の Linux PC 上で 12 分程度かかりました。ビルドが完了すると、下記のようなメッセージが表示されます。

Finished building target 'default (exploded-image)' in configuration 'linux-arm-normal-server-release'

build という名前のディレクトリが作成され、その下に linux-arm-normal-server-release という名前のディレクトリが作成されます。

ディレクトリの内容は、

ls -al build/linux-arm-normal-server-release/
total 604
drwxrwxr-x  8 hirooka hirooka   4096  5月  9 23:56 .
drwxrwxr-x  4 hirooka hirooka   4096  5月  9 23:56 ..
-rw-rw-r--  1 hirooka hirooka   2707  5月  9 23:56 bootcycle-spec.gmk
-rw-rw-r--  1 hirooka hirooka   7565  5月  9 23:56 buildjdk-spec.gmk
-rw-rw-r--  1 hirooka hirooka 496539  5月 10 00:09 build.log
drwxrwxr-x 12 hirooka hirooka   4096  5月 10 00:02 buildtools
-rwxrwxr-x  1 hirooka hirooka   3867  5月  9 23:56 compare.sh
-rw-rw-r--  1 hirooka hirooka  16803  5月  9 23:56 configure.log
drwxrwxr-x  2 hirooka hirooka   4096  5月  9 23:56 configure-support
drwxrwxr-x  3 hirooka hirooka   4096  5月  9 23:56 hotspot
drwxrwxr-x  7 hirooka hirooka   4096  5月 10 00:08 jdk
-rw-rw-r--  1 hirooka hirooka   1305  5月  9 23:56 Makefile
drwxrwxr-x  6 hirooka hirooka   4096  5月  9 23:56 make-support
-rw-rw-r--  1 hirooka hirooka  38696  5月  9 23:56 spec.gmk
drwxrwxr-x 12 hirooka hirooka   4096  5月 10 00:08 support

さらにその下の jdk ディレクトリの内容は、

ls -al build/linux-arm-normal-server-release/jdk/
total 32
drwxrwxr-x  7 hirooka hirooka 4096  5月 10 00:08 .
drwxrwxr-x  8 hirooka hirooka 4096  5月  9 23:56 ..
drwxrwxr-x  2 hirooka hirooka 4096  5月 10 00:09 bin
drwxrwxr-x  4 hirooka hirooka 4096  5月  9 23:56 conf
drwxrwxr-x  3 hirooka hirooka 4096  5月  9 23:56 include
drwxrwxr-x  6 hirooka hirooka 4096  5月 10 00:09 lib
drwxrwxr-x 68 hirooka hirooka 4096  5月 10 00:04 modules
-rw-rw-r--  1 hirooka hirooka   89  5月  9 23:56 release

Raspberry Pi (Raspbian) での動作確認

Raspberry Pi に Raspbian をインストールする手順は過去にポストしています。

ビルドで作成された OpenJDK 11 を tar で固めて圧縮するなりして、SSH なりで Raspberry Pi へ送信します。例えば下記の通り。

cd build
tar zcvf linux-arm-normal-server-release.tar.gz linux-arm-normal-server-release
scp linux-arm-normal-server-release.tar.gz pi@192.168.xxx.yyy:/home/pi/

Raspberry Pi にログインし、送信されたファイルを解凍し、java コマンドを実行してみます。

ssh pi@192.168.xxx.yyy
tar zxvf linux-arm-normal-server-release.tar.gz
./linux-arm-normal-server-release/jdk/bin/java --version

実行結果です。

openjdk 11.0.3-internal 2019-04-16
OpenJDK Runtime Environment (build 11.0.3-internal+0-adhoc.hirooka.jdk11u-175eb80c253a)
OpenJDK Server VM (build 11.0.3-internal+0-adhoc.hirooka.jdk11u-175eb80c253a, mixed mode)

Raspberry Pi (Raspbian) にインストール

例えば下記の通りです。

sudo mkdir /usr/lib/jvm
sudo mv linux-arm-normal-server-release/jdk /usr/lib/jvm/
sudo mv linux-arm-normal-server-release/support /usr/lib/jvm/ 
sudo sh -c "echo 'export JAVA_HOME=/usr/lib/jvm/jdk' >> /etc/profile.d/jdk.sh"
sudo sh -c "echo 'export PATH=\$JAVA_HOME/bin:\$PATH' >> /etc/profile.d/jdk.sh"
source /etc/profile.d/jdk.sh

Java コマンドを実行できることを確認します。

$ java --version
openjdk 11.0.3-internal 2019-04-16
OpenJDK Runtime Environment (build 11.0.3-internal+0-adhoc.hirooka.jdk11u-175eb80c253a)
OpenJDK Server VM (build 11.0.3-internal+0-adhoc.hirooka.jdk11u-175eb80c253a, mixed mode)