http://openjdk.java.net/jeps/201 をテキトーに訳した。
下記Updated 2014/08/11 18:40にあるとおりホットトピックなので、最新の情報については原文などを当たって頂くようお願いします。また、ビミョーな翻訳部分についても、原文を参照して頂けると幸いです。
JEP 201: Modular Source Code
Author Mark Reinhold Owner Alan Bateman Created 2014/07/22 14:08 Updated 2014/08/11 18:40 Type Feature Status Proposed to Target Scope Implementation Discussion jigsaw dash dev at openjdk dot java dot net Effort L Duration L Priority 1 Reviewed by Alan Bateman, Alex Buckley, Mandy Chung, Paul Sandoz Endorsed by Brian Goetz Release 9 Issue 8051619 Blocks JEP 200: The Modular JDK Relates to 8049382: Script to aid porting of patches between JDK 9 and JDK 8u
Summary
JDKソースコードをモジュールへ再編成し、モジュールをコンパイルするためのビルドシステムを改良し、ビルド時のモジュール境界を強化します。
Non-Goals
本JEPではJREとJDKのバイナリイメージの構造は変更しませんし、モジュールシステムの導入も行いません。そうした作業は関連JEPと適切なJSRが担当します。
本JEPはJDK用の新しいソースコードレイアウトを定義します。このレイアウトはJDK外で利用可能ですが、本JEPは広範に受け入れられるユニバーサルなモジュールソースコードレイアウトの設計は目的ではありません。
Motivation
Project Jigsawの目的は、Java SE Platform用の標準モジュールシステムの設計と実装、および、そのモジュールシステムのJava SE PlatformとJDK自体への適用を行うことです。その主要目的は、プラットフォーム実装のスモールデバイスへのスケールダウン簡易化・セキュリティとメンテナンス性の改善・アプリケーションパフォーマンスの改善可能化・大規模プログラミングにおけるより良いツールの開発者への提供、です。
本JEPはProject Jigsawの初期フェーズの一部です。これ以降のJEPで、JREとJDKイメージのモジュール化、それからモジュールシステムの導入、を行います。
初期段階でソースコードを再編成する動機は以下の通りです。
- JDK開発者がシステムのモジュール構造に慣れるための機会を提供する。
- モジュールシステムの導入前であっても、ビルド時のモジュール境界を設定することで構造を保持する。
- "乱雑な(shuffle)"現行の非モジュールソースコードをモジュール形式にすることなくProject Jigsawの開発を続行可能にする。
Description
Current scheme
今日のJDKソースコードの大半は、1997年に遡るスキーマでおおむね組織化されています。略記形式では以下になります。
src/{share,$OS}/{classes,native}/$PACKAGE/*.{java,c,h,cpp,hpp}
shareディレクトリには、共有でクロスプラットフォームのコードが含まれます。$OSディレクトリには、OS固有のコードが含まれており、$OSはsolaris,windows, などの内の一つです。classesディレクトリには、Javaソースファイルとリソースファイルが含まれます。nativeディレクトリには、CかC++ソースファイルが含まれます。$PACKAGEは関連するJava APIパッケージ名で、ピリオドはスラッシュで置換されます。
例をあげると、jdkリポジトリのjava.lang.Objectクラスのソースコードは二つのファイルが存在し、一つはJavaでもう一つはCです。
src/share/classes/java/lang/Object.java
native/java/lang/Object.c
他の例では、パッケージプライベートなjava.lang.ProcessImplとProcessEnvironmentクラスのソースコードはOS固有であり、Unix系システム向けに三つのファイルが含まれています。
src/solaris/classes/java/lang/ProcessImpl.java
ProcessEnvironment.java
native/java/lang/ProcessEnvironment_md.c
(上記のコードはすべてのUnix派生システムに関連するけれども、二階層目のディレクトリがsolarisになっています。この詳細については以降の文章を参照してください。)
以下に示すsrc/{share,$OS}下の一部のディレクトリはこの構造にマッチしません。
Directory Content
-------------------------- --------------------------
src/{share,$OS}/back JDWP back end
bin Java launcher
instrument Instrumentation support
javavm Exported JVM include files
lib Files for $JAVA_HOME/lib
transport JDWP transports
New scheme
メンテナンスを容易にするために、JDKのモジュール化はソースコードの完全な再編を行う貴重な機会を提供します。我々はhotspotを除くJDK大森林*1の全リポジトリを以下のスキーマで実装することを提案します。以下は簡略化した記述です。
src/$MODULE/{share,$OS}/classes/$PACKAGE/*.java
native/include/*.{h,hpp}
$LIBRARY/*.{c,cpp}
conf/*
- $MODULEはモジュール名です(例
java.base)。 shareディレクトリには、以前同様、共有、クラスプラットフォームのコードが含まれます。$OSディレクトリには、以前同様、OS固有のコードが含まれており、$OSはunix,windows, などの内の一つです。classesディレクトリには、以前同様、APIの$PACKAGE階層を反映するディレクトリツリーに編成されたJavaソースファイルとリソースファイルが含まれます。nativeディレクトリには、以前同様、CやC++のソースファイルが含まれますが、異なる点として、confディレクトリには、エンドユーザが編集するための設定ファイルが含まれます。(例:net.propertiesなど)
前の例を書き直すために、java.lang.Objectクラスのソースコードは以下のようなレイアウトになります。
src/java.base/share/classes/java/lang/Object.java
native/libjava/Object.c
パッケージプライベートなjava.lang.ProcessImplとProcessEnvironmentクラスのソースコードは以下のようなレイアウトになります。
src/java.base/unix/classes/java/lang/ProcessImpl.java
ProcessEnvironment.java
native/libjava/ProcessEnvironment_md.c
(我々はこの機会に、最終的にはsolarisをunixにリネームしておきたい)
現在の構造にマッチしないsrc/{share,$OS}ディレクトリ下にあるコンテンツは適切なモジュールに移動します。
Directory Module
-------------------------- --------------------------
src/{share,$OS}/back jdk.jdwp.agent
bin java.base
instrument java.instrument
javavm java.base
lib $MODULE/{share,$OS}/conf
transport jdk.jdwp.agent
エンドユーザが編集することを目的としないlibディレクトリのファイルはリソースファイルに変換されます。
Build-system changes
ビルドシステムの修正は、一度に一つのリポジトリではなく、一度に一つのモジュールをコンパイルするようになります。また、モジュールグラフのトポロジカルソートの逆順に沿ってモジュールをコンパイルします。モジュールは直接間接問わず相互に依存しないため、可能であればコンカレントにコンパイルされます。
リポジトリでなくモジュール単位にコンパイルするもう一つの利点は、corba, jaxp, jaxwsリポジトリのコードで新しいJava言語の機能やAPIを利用可能になります。これらのリポジトリはjdkリポジトリの前にコンパイルされるため、以前は禁止されていました。
中間ビルド*2でコンパイルされるクラスはモジュールに分割されます。現在は下記のようです。
jdk/classes/*.class
改良後のビルドシステムは以下のような結果を生成します。
jdk/modules/$MODULE/*.class
上述のように、構造化イメージビルド(structure image builds)は変更しません。内容はわずかに異なります*3。
モジュール境界は、ビルドシステムによって可能な限りビルド時に設定されます。モジュール境界が違反している場合、ビルドは失敗します。境界はJEP 200のmodule.xmlで定義します。このファイルはソースコードと共にメンテナンスされます。このファイルに対する変更はProject Jigsawのコミッターのレビューが必要です。
Alternatives
ソースレイアウトのスキーマについては多数の代替案が存在します。
1. トップの{share,$OS}はそのままで、モジュールクラスファイルを含めるためのmodulesディレクトリを設ける。
src/{share,$OS}/modules/$MODULE/$PACKAGE/*.java
native/include/*.{h,hpp}
$LIBRARY/*.{c,cpp}
conf/*
2. 適切な$MODULEディレクトリ下にすべてを収めるが、{share,$OS}がトップなのはそのままにする。
src/{share,$OS}/$MODULE/classes/$PACKAGE/*.java
native/include/*.{h,hpp}
$LIBRARY/*.{c,cpp}
conf/*
3. この提案同様に$MODULEディレクトリ下に{share,$OS}を移動するが、中間classesディレクトリを削除してnativeとconfディレクトリのプレフィクスにアンダースコアをつけます。これは純粋なJavaモジュールの良くあるケースを簡潔にするためです。
src/$MODULE/{share,$OS}/$PACKAGE/*.java
_native/include/*.{h,hpp}
$LIBRARY/*.{c,cpp}
_conf/*
4. 3番目のバリエーションで、{share,$OS}をトップにします。
src/{share,$OS}/$MODULE/$PACKAGE/*.java
_native/include/*.{h,hpp}
$LIBRARY/*.{c,cpp}
_conf/*
5. 3番目の更に別のバリエーションで、$OS固有コードの無い純粋なJavaモジュールのケースを更に簡潔にするために、{share,$OS}をより深い階層に下げます。
src/$MODULE/$PACKAGE/*.java
_native/include/*.{h,hpp}
$LIBRARY/*.{c,cpp}
_conf/*
_$OS/$PACKAGE/*.java
_native/include/*.{h,hpp}
$LIBRARY/*.{c,cpp}
_conf/*
アンダースコアを含む3番から5番を我々は却下しており、その理由はナビゲートしにくく不親切なためです。1番と2番よりも現在の提案を選んでおり、その理由は現在のスキーマから最小の変更で単一ディレクトリ下にモジュールの全ソースコードを配置できるためです。現在のスキーマに依存するツールとスクリプトは改修が必要ですが、少なくとも、各$MODULEディレクトリ下のJavaソースコード用の構造は以前と同じままです。
以下は我々が把握しているその他の問題です。
- Javaソースファイルとは切り離しておきたいリソースファイル用のディレクトリを別途定義すべきでは? - いいえ。別途定義するメリットがありません。
- 異なるリポジトリにまたがるコンテンツを持つモジュールは問題ではないか? - 厄介な話ですが、ビルドシステムは
VPATHメカニズムによって解決が可能です。いずれ我々はクロスリポジトリ(cross-repo)モジュールを削除ないし削減するためにリポジトリの再編成に取り組みますが、それはこのJEPの範囲外です。 - 複数のネイティブライブラリを含むモジュールが存在します。各モジュールが最大一つのネイティブライブラリを持つようにマージすべきですか? - いいえ。ある種の場合には、我々は一つのモジュールに複数のネイティブライブラリを持つ柔軟性が必要です。たとえば、AWTの"headless" vs. "headful"など。
Testing
上述したように、本JEPはJREとJDKのバイナリイメージの構造は変更せず、コンテンツのマイナーチェンジのみ行います。よって、我々はビルドされたイメージを比較し、マイナーチェンジ検証用のテストを実行することで、変更内容を検証します。
Risks and Assumptions
我々は、変更を実装するための大量のファイルリネーム操作を扱うことができて、処理のすべての履歴情報を保持するために、Mercurialを使う予定です。予備テストではMercurialは十分でしたが、依然としてマイナーリスクがあり、それは新旧ファイル間の関係が正しく記録されない点です。古いロケーションのファイルの履歴がリポジトリに残ったままになる場合があります。これは発見が困難です。
新しいスキーマを使用するリポジトリに、直接古いスキーマを使用するように、リポジトリに対してパッチを適用するのは不可能です*4。逆も同様です。この点を緩和するために、我々は古いロケーションから新しいロケーションへファイル名を変換するスクリプトを開発する予定です。
Dependences
本JEPはProject Jigsaw用に存在するJEPのうち、二番目のものです。JEP 200のJDKモジュール構造定義を包含していますが、明示的な依存はありません。