#chiroito ’s blog

Java を中心とした趣味の技術について

Windows Subsystem for Linux を使って OpenJDK をビルド

Windows 上で Windows Subsystem for Linux (WSL) を使用して OpenJDK 14 の Windows バイナリをビルドする方法をまとめます。

やりがちですが、Windows Subsystem for Linux (WSL)側のUbuntu 側で hg するのは必須ではありません。(やった) Windows側で好きな git クライアントがあればそれを使ってダウンロードしても大丈夫です。
Windows では環境変数とかもやらなくて大丈夫です。

全体の手順は以下のとおり。

  1. Windows の環境構築
  2. Windows Subsystem for Linux (WSL) 上の Ubuntu の環境構築
  3. ソースをダウンロード
  4. Windows Subsystem for Linux (WSL) 上の Ubuntu 上でビルド

Windows の環境構築

OpenJDK14をビルドするためにWindowsでインストールする物は以下の4つです。

  • Visual Studio Community
  • Windows Subsystem for Linux (今回はUbuntu 18.04 LTS)
  • Boot JDK (今回はOracle OpenJDK 12)
  • Mercurialクライアント

Visual Studio Community

以下の URL からVisual Studio Community 2017をダウンロードしてインストールします。

以前の Visual Studio ソフトウェアのダウンロード | Visual Studio - Visual Studio

最初は何もバイナリがありませんでしたが、ログインしたらダウンロードできるようになりました。 今回はVisual Studio Community 2017 (version 15.9)を使いました。

最低限必要なコンポーネントは分からなかったのでC++によるデスクトップ開発を入れています。 f:id:chiroito:20190727172428p:plain

Windows Subsystem for Linux (WSL)

Windows Subsystem for Linux は Ubuntu 18.04 LTS を入れています。Microsoft Storeを開いてインストールします。 f:id:chiroito:20190727172749p:plain

起動してみて以下のエラーが出るようでしたら、Windows Subsystem for Linux の機能が有効化されていません。

Installing, this may take a few minutes...
WslRegisterDistribution failed with error: 0x8007019e
The Windows Subsystem for Linux optional component is not enabled. Please enable it and try again.
See https://aka.ms/wslinstall for details.
Press any key to continue...

Windows の機能の有効化または無効化で以下のようになっていると思いますのでチェックを付けて有効にしてください。

f:id:chiroito:20191019114730p:plain

Boot JDK

Boot 用に使う JDK をインストールします。インストールするのはただのJDKです。Oracle OpenJDK の 12.0.2 を入れました。普通に入れるとProgram Files以下にインストールされますが、空白があるとなんか怖いなと思ってc:\Users\xxxx\develop\jdk-12.0.2にインストールしました。

※注:Windows版のJDKが必要です。

インストール後はこんな感じです。

C:\Users\xxxx\develop\jdk-12.0.2>dir /B
bin
conf
include
jmods
legal
lib
release

Mercurial クライアント

Mercurial のクライアントはお好きな物を使ってください。TortoiseHgを使いました。

Ubuntu 18.04 上で Mercurial を使う場合には以下のようにしてインストールします。

sudo add-apt-repository ppa:mercurial-ppa/releases
sudo apt install mercurial

Windows Subsystem for Linux 上の Ubuntu の環境構築

以下の4つをインストールします。

  • zip
  • unzip
  • autoconf
  • make
sudo apt-get install zip unzip autoconf make

ソースをダウンロード

ソースのダウンロードは Windows 上でもWindows Subsystem for Linux 上でも大丈夫です。 Windows Subsystem for Linux 側でダウンロードして、ソースをWindowsのIDEで修正したり見る場合には Windows から見えるパス上にダウンロードすることを忘れないでください。

以下は Windows 上でダウンロードします。 適当なディレクトリでMercurialクライアントを使ってhttp://hg.openjdk.java.net/jdk/jdkからクローンします。hgコマンドでC:\Users\xxxx\developディレクトリへクローンする場合は、コマンドプロンプトで以下のコマンドを実行します。

cd C:\Users\xxxx\develop
hg clone http://hg.openjdk.java.net/jdk/jdk

Windows Subsystem for Linux 上の Ubuntu でビルド

ビルドは Windows Subsystem for Linux (WSL) 上の Ubuntu でやります。configureでは--with-boot-jdkでは Windows へインストールしたJDKのパスを指定します。C:\のマウントポイントは/mnt/c/なので適宜指定してください。

gtest のコンパイルで失敗するので --disable-hotspot-gtest を付けてgtest は無効化します。

以下は Slow Debug モードでのビルドです。

configureが終わったらmake imagesでビルドしましょう。

bash configure --with-boot-jdk=/mnt/c/Users/xxxx/develop/jdk-12.0.2 --enable-debug --with-native-debug-symbols=internal --disable-hotspot-gtest
make images

これで、Windows Subsystem for Linux (WSL) 上の Ubuntu を使って Windows 用のバイナリをビルドできたはずです。

エンタープライズ向けのシステムを自動構築するツール

エンタープライズで使われるミドルウェアを使うためには、環境が使えるようになるまで構築に膨大な時間がかかるほか、開発用途などでちょっと使うだけで莫大なライセンス料がかかります。

クラウドが当たり前になって、ライセンス料が非常に安価になって触りやすくなったものの、エンタープライズなシステムではInfrastructure as a Codeや自動化などといったレガシーと比べて新しい仕組みを導入するのはハードルが高く、クラウドらしさを得ているエンタープライズなシステムは多くありません。 そのため、クラウド移行というとオンプレと同じ構成・リソースをクラウドにリフトするだけのシステムが多く、開発環境においても常にうごかしっぱなしのため、インフラコストは下がるどころか高くなります。また、インフラ担当者が温かみのある手作業で環境を構築・運用するため構築や運用のコストもこれまでどおりです。その結果、システム全体のコストはクラウド移行前と比べて高くなります。

ミッションクリティカルなシステムで使われるレベルのシステムを1から構築するのは骨が折れるものです。複数環境を手作業でとなると尚更です。

なので、エンタープライズなシステムを自動化するためのベースとなるツールを作成しました。基本的な構成はツールの設定変更だけでできることを目標とし、設定変更では対応できないケースではカスタマイズするベースとなることを目的としています。ツールといってもただのTerraformのファイル群です。

GitHub - chiroito/rapid-build-tool

このツールを使うと以下のような構成のシステムを設定だけで作れるようになります。実行してしばらく待つだけで環境が構築でき不要になったらすぐに環境が削除できる上、システム全体で100~200円程度からさわり始めることができます。

f:id:chiroito:20190219014813p:plain
LB経由でアプリケーションと管理ツールへアクセスし、システムのバックアップをオブジェクトストレージに取得する

f:id:chiroito:20190219014828p:plain
アプリケーションと管理ツールへのアクセスはアプリケーションサーバが直接受け付け、システムのバックアップは取らない

システムの開発時には必要な時だけ立ち上げて、不要なときだけ停止することでかなりのコスト削減に繋がります。また、同時に複数面を構築できるので、環境の構築待ちや開放待ちなども無くなり、開発の生産性向上にも繋がります。アプリケーションの単体試験や、Java EE のコンテナとの結合試験、外部システムをモック化した結合試験などの自動テストなどは既にある場合には、このツールと組み合わせることで開発者がソースをコミットしたら環境が自動で立ち上がり、これらのテストを実施し、テストが終わったらレポートを送信して環境は無くなるという使い方がエンタープライズなシステムでも可能となります。

エンタープライズなシステムでもよりクラウドらしさが得られることを願っています。

OpenJDK を開発する流れ

自分が使うコマンドをうっかり忘れるときがあるのでその備忘録のために、開発の流れとそこで使ってる内容をメモ。

公式のガイドはこちらを参考にしてください。The OpenJDK Developers' Guide – Index

OpenJDK の開発は以下のような流れで行います。

バグを上げる

おかしい動きだなぁとか新しい機能を追加するときは Java Bug System に Issue をあげます。 System Dashboard - Java Bug System

開発の準備

開発を始めるには OpenJDK のソースコードやテストツール、レビューツールを使います。これらは OpenJDK のリポジトリからダウンロードできます。 ダウンロード先は/srcディレクトリとしますが、任意のディレクトリで大丈夫です。

OpenJDKのソースをダウンロード

cd /src
hg clone http://hg.openjdk.java.net/jdk/jdk

参考:The OpenJDK Developers' Guide – Repositories

jtregをダウンロード

次に、テストツールである jtreg をダウンロードします。

cd /src
hg clone http://hg.openjdk.java.net/code-tools/jtreg

webrevをダウンロード

最後に、レビューツールである webrev をダウンロードします。

$ cd /src/jdk
$ wget http://hg.openjdk.java.net/code-tools/webrev/raw-file/tip/webrev.ksh

パッチを書く

お好きな方法でパッチを書いてください。私は Java の API やテストコードは IntelliJ IDEA で書いて、Hotspot JVM は Eclipse で書いてます。世の中には Vim や Emacs で開発してる人もいます。

IDE を使う方法はこちらで紹介されてます。

ビルド

jtreg のビルド

まずはテストツールからビルドします。これはとりあえず一回だけで良いです。

cd /src/jtreg
bash make/build-all.sh /usr/lib/jvm/java-1.8.0

OpenJDKのビルド

次に OpenJDK をビルドします。以下はデバッグするためのオプションを付けてます。 ビルドをするまでの設定はとてつもなく長いのでこちらを参照して下さい。

Building the JDK

cd /src/jdk
bash configure --enable-debug --with-native-debug-symbols=internal --with-boot-jdk=/usr/lib/jvm/java-11 --with-jtreg=/src/jtreg/build/images/jtreg

make images

configure が再度必要になったらmake reconfigureで前の引数などを引き継いで実行してくれます。

テスト

コードを書いて、ビルドして、テストしてということを繰り返すことになりますが、OpenJDK には大量のテストが含まれているため最初から全てのテストを実行すると途方も無い時間が掛かります。なので、開発中は自分が書いている部分のテストだけを実行して、デバッグしてます。

参考:Testing the JDK

自分が書いたテストを実行

特定のテストの実行はmake test TEST="自分が書いたテストのファイル"で実行します。以下のように実行します。

cd /src/jdk
make test TEST="test/jdk/jdk/jfr/jcmd/TestJcmdConfigure.java"

出力

Building target 'test' in configuration 'linux-x86_64-server-fastdebug'
Skip building of Graal unit tests because 3rd party libraries directory is not specified
Skip building of Graal unit tests because 3rd party libraries directory is not specified
Test selection 'test/jdk/jdk/jfr/jcmd/TestJcmdConfigure.java', will run:
* jtreg:test/jdk/jdk/jfr/jcmd/TestJcmdConfigure.java

Running test 'jtreg:test/jdk/jdk/jfr/jcmd/TestJcmdConfigure.java'
Passed: jdk/jfr/jcmd/TestJcmdConfigure.java
Test results: passed: 1
Report written to /src/jdk/build/linux-x86_64-server-fastdebug/test-results/jtreg_test_jdk_jdk_jfr_jcmd_TestJcmdConfigure_java/html/report.html
Results written to /src/jdk/build/linux-x86_64-server-fastdebug/test-support/jtreg_test_jdk_jdk_jfr_jcmd_TestJcmdConfigure_java
Finished running test 'jtreg:test/jdk/jdk/jfr/jcmd/TestJcmdConfigure.java'
Test report is stored in build/linux-x86_64-server-fastdebug/test-results/jtreg_test_jdk_jdk_jfr_jcmd_TestJcmdConfigure_java

==============================
Test summary
==============================
   TEST                                              TOTAL  PASS  FAIL ERROR   
   jtreg:test/jdk/jdk/jfr/jcmd/TestJcmdConfigure.java
                                                         1     1     0     0   
==============================
TEST SUCCESS

Finished building target 'test' in configuration 'linux-x86_64-server-fastdebug'

レグレッションテスト

自分で書いたテストが通るようになったら、レグレッションテストのためにtier1と言われるテストを全部実行します。

cd /src/jdk
make test-tier1

レビューの作成

webrevを使ってwebレビューを作成します。-cオプションで指定するのはIssueの番号です。JDK-の部分は不要で番号だけで大丈夫です。

cd /src/jdk
ksh ./webrev.ksh -m -N -c XXXXXX

出力

   SCM detected: mercurial

 No outgoing, perhaps you haven't committed.
      Workspace: /src/jdk
      Output to: /src/jdk/webrev
   Output Files:
    (略)
     index.html: grep: /home/chito/.hgrc: No such file or directory
Done.
Output to: /src/jdk/webrev

webレビューのアップロード

> scp -i <秘密鍵> -r JDK-8216565/webrev xxx@cr.openjdk.java.net:~xxx/JDK-8216565/

レビュー依頼

Request for review の略語であるRFR:とissueの番号とタイトルを付けてメールします。

コミット・プッシュ

ユーザ情報を追加

コミットするには hg にユーザの登録が必要です。/src/jdk/.hg/hgrc に自分のユーザを設定します。(Author以上?)[ui]usernameを設定しましょう。

[paths]
default = http://hg.openjdk.java.net/jdk/jdk

[ui]
username = xxx

参考:The OpenJDK Developers' Guide – Repositories

コミット

コミットメッセージを作成します。必須なのは、issue番号とタイトル、レビューしてくれた人のusernameです。

参考:The OpenJDK Developers' Guide – Producing a Changeset

message.txt

8216565: Specifying the same path creates a new directory in JFR.configure
Reviewed-by: ysuenaga, egahlin

コミットしましょう。

hg commit -l message.txt

コミッタになればここで push します。

チェンジセット作成とアップロード

Author 以下の場合は push を誰かに頼みます。 頼むためのチェンジセットを作成します。

hg export -g > changeset

チェンジセットをアップロードします。

> scp -i <秘密鍵> -r changeset xxx@cr.openjdk.java.net:~xxx/JDK-XXXXX/

連絡

チェンジセットの URL を添えて「push してと」メールを送ります。

コミッターになったら

コミッターになると、Oracle が開発者向けに公開している自動テスト環境が使えるようになります。これはSubmitリポジトリと呼ばれます。このSubmitリポジトリにpushすると、様々な環境で並行してテストをしてくれます。レビューを投げる前にこの自動テスト環境でテストを通します。

参考:Submit Repo - Build - OpenJDK Wiki

  1. Submitリポジトリからソースを取得
  2. Submitリポジトリの設定を変更
  3. SSH クライアントに鍵を登録
  4. ソースコードをプッシュ

Submitリポジトリからソースを取得

中身は同じですがパッチを書いたリポジトリとは別のリポジトリ (http://hg.openjdk.java.net/jdk/submit)を使用します。まずはそこからソースコードをクローンします。

$ hg clone --branch default http://hg.openjdk.java.net/jdk/submit

Submitリポジトリの設定を変更

OpenJDK のリポジトリでは push は SSH を使います。そのため、パスの変更やユーザの設定をします。これらの設定は OpenJDK が用意している defpath という hg のプラグインを使うことで実現します。

wget http://hg.openjdk.java.net/code-tools/defpath/raw-file/tip/defpath.py
cat > ~/.hgrc <<EOF
[extensions]
defpath=/mnt/c/Users/c_hir/develop/jdk-code-tools/defpath.py
EOF
hg defpath -du <OpenJDK user id>

これで SSH を使ってソースを push する設定は完成です。

SSH クライアントに鍵を登録

OpenJDK のリポジトリなどの環境は鍵認証をします。そのため、HG クライアント経由で使用される SSH クライアントがこの鍵を使えるようにしましょう。

私の環境は Windows なので HGクライアントに TortoiseHG を使っており、SSH クライアントはどうやら putty を使っているようです。鍵を管理する仕組みとして、Pagent が TortoiseHG のインストールディレクトリにありましたのでそれを使います。

f:id:chiroito:20200719191307p:plain

参考:The OpenJDK Developers' Guide – Producing a Changeset

ソースコードをプッシュ

$ hg branch "JDK-7000001"
$ echo "Make the README longer." >> README
$ hg commit
$ hg push --new-branch

これであとは 2 時間ぐらい待つとテスト結果が届きます。

テストも通って、レビューも通ったらコミットしてプッシュします。

hg push

最後に、テストで使ったSubmitリポジトリを閉じます。

$ hg update -C "JDK-7000001"
$ hg commit --close-branch -m "Closing branch"
$ hg update default
$ hg push