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モジュール構造定義を包含していますが、明示的な依存はありません。