Java パッケージガイドライン

提供: ArchWiki
2017年12月3日 (日) 23:19時点におけるKusakata (トーク | 投稿記録)による版 (同期)
ナビゲーションに移動 検索に移動

この文章では Arch Linux における Java プログラムのパッケージングについて提唱される標準を定義しています。Java プログラムは依存関係を重ねないようにパッケージ化するのが大変難しいことで有名です。この文章ではそれをなんとか改善する方法を説明します。Java アプリケーションを扱うときは様々な場面に合わせて以下のガイドラインを臨機応変に読み替えてください。

イントロダクション

Java パッケージの処理方法について Arch Linux のパッケージ作成者が合意を取ることは不可能です。公式・非公式リポジトリや AUR に存在する PKGBUILD では様々な手段が使われています。/opt に全てのファイルを配置して、/usr/bin にシェルスクリプトを置いたり /etc/profile にプロファイルを保存する方法もあれば、/usr/share のディレクトリにファイルを配置して /usr/bin にスクリプトを置いているのもあります。システムの CLASSPATHPATH には多くの不必要なファイルが追加されています。

典型的な Java アプリケーションの構造

ほとんどの Java のデスクトップアプリケーションは同じような構造をしています。これらのアプリケーションはシステムに依存しない (ただしパッケージに依存する) インストーラーによってインストールされます。大抵は全てを単一のディレクトリにインストールして bin, lib, jar, conf などのサブディレクトリが作られます。通常、メインの jar ファイルが存在していて、メインの実行クラスが記述されています。また、Java インタプリタを直接実行しなくてもいいように、メインクラスを実行するためのシェルスクリプトも付属しているのが普通です。シェルスクリプトは様々なディストリビューションで共通して用いられ、別の環境 (例: Cygwin) 用の特殊なケースもカバーするようになっている場合が多く、非常に複雑になっています。

lib ディレクトリには jar ファイルがバンドルされているのが通例で、Java アプリケーションの依存関係を満たすようになっています。(全ての依存パッケージが含まれていることは) プログラムをインストールしたいユーザーにとっては楽ですが、パッケージの開発者にとっては悪夢です。同一の依存パッケージを複数のパッケージがバンドルしていることは無駄に他なりません。Java のデスクトップアプリケーションやライブラリの数が少なかった昔はそこまで大きな問題ではありませんでしたが、Java アプリケーションとライブラリの数が増えるにつれて避けがたい問題になっています。時代は変わったのです。

プログラムを実行するのに必要な他のファイルはメインの jar ファイルと同じフォルダに保存されるか、サブディレクトリに保存されるのが普通です。Java プログラムはどこからクラスがロードされたか関知しないので、jar ファイルがあるディレクトリ内から実行しなくてはなりません (シェルスクリプトでディレクトリに cd する必要がある)。あるいは、ディレクトリの場所を示す環境変数を設定します。

パッケージング

Arch で Java アプリケーションをパッケージ化するのは骨の折れる作業です。しかしながら、上手くパッケージ化することでファイルシステムをきれいにして同梱する依存ライブラリを減らせます (Java ライブラリがパッケージとして作り直されることで、パッケージ化も楽になります)。Arch Linux の Java パッケージを作成するときは以下のガイドラインに従ってください:

  • Java ライブラリの名前が普遍的なものである場合、パッケージの名前に java- を付けて他のライブラリと区別ができるようにしてください。ユニークな名前が付いているパッケージ (JUnit など) やエンドユーザープログラム (Eclipse など)、他のプリフィックスが存在するライブラリ (jakarta-commons-collections や apache-ant など) では必須ではありません。
  • Java アプリケーションをソースからコンパイルする必要はありません。gcc で作成されたバイナリと同じように、コンパイルによって得られる最適化は僅かです。ソースからビルドする簡単な方法がソースパッケージに用意されている場合はそれを使ってかまいませんが、バイナリリリースの jar ファイルやインストーラーを取得するほうが簡単な場合はそれで結構です。
  • プログラムと一緒に配布されている jar ファイルは全て /usr/share/java/myprogram ディレクトリに配置してください。アプリケーションの依存ライブラリとして配布されている jar ファイルも含みます。ただし、一般的に使われるライブラリや巨大なライブラリ群は独立した別のパッケージとするべきです。プログラムが特定のバージョンのライブラリに依存しない場合にこれが当てはまります。
This rule makes it possible to iteratively refactor dependencies. That is, the package and all its dependencies can be placed into one directory at first. After this has been tested, major dependencies can be refactored out one at a time. Note that some applications include bundled dependencies inside the main jar file. That is, they unjar the bundled dependencies and include them in the main jar. Such dependencies are usually very small and there is little point in refactoring them.
  • ユーザーがプログラムを実行するようになっている場合、メインの jar ファイルを起動するカスタムシェルスクリプトを書いてください。実行スクリプトは /usr/bin に配置します。ライブラリは基本的にシェルスクリプトを必要としません。プログラムに付属しているスクリプトを使うよりも、スクラッチからシェルスクリプトを書くことを推奨します。(Cygwin など) カスタム環境をテストするコードや、JAVA_HOME が設定されているかどうか確認するコードは削除してください (Arch では JAVA_HOME使用せずarchlinux-java を使って /usr/bin/java シンボリックリンクを設定します)。
jar ファイルのスクリプトは以下のようになります:
#!/bin/sh
exec /usr/bin/java -jar '/usr/share/java/PROGRAMNAME/PROGRAMNAME.jar' "$@"
クラスファイルのスクリプトは以下のようになります:
#!/bin/sh
exec /usr/bin/java '/usr/share/java/PROGRAMNAME/PROGRAMCLASSNAME' "$@"
  • Set the CLASSPATH using the -cp option to the Java interpreter unless there is an explicit reason not to (ie: the CLASSPATH is used as a plugin mechanism). The CLASSPATH should include all jar files in the /usr/share/java/myprogram direcory, as well as jar files that are from dependency libraries that have been refactored to other directories. You can use something like the following code:
for name in /usr/share/java/myprogram/*.jar ; do
  CP=$CP:$name
done
CP=$CP:/usr/share/java/dep1/dep1.jar
java -cp $CP myprogram.java.MainClass
  • Make sure the shell script is executable!
  • Other files distributed with the package should be stored in a directory named after the package under /usr/share. You may need to set the location of this directory in a variable like MYPROJECT_HOME inside the shell script. This guideline assumes that the program expects all files to be in the same directory (as is standard with Java packages). If it seems more natural to put a configuration file elsewhere (for example, logs in /var/log), then feel free to do so.
環境によっては /usr は読み取り専用でマウントされる場合もあるので注意してください。アプリケーションによる書き込みが必要なファイルが共有ディレクトリに存在する場合、/etc/var、あるいはユーザーのホームディレクトリに再配置できないか確認してください。
  • As is standard with Arch Linux packages, if the above standards cannot be adhered to without a serious amount of work, the package should be installed in its preferred manner, with the resulting directory located in /opt. This is useful for programs that bundle JREs or include customized versions of dependencies, or do other strange or painful tasks.

複数の API 実装

一般的に使われる API 実装 (JDBC ドライバーなど) を配布するパッケージは /usr/share/java/apiname にライブラリを配置してください。アプリケーションからユーザーが実装を選択できるようにするためです。/usr/share/java/apiname を使用できるのはライブラリしか含まないパッケージだけです。アプリケーションの一部として実装が含まれる場合、通常のパッケージツリーと同じ場所に配置してください。

ディレクトリ構造の例

以下は foo という仮のプログラムのディレクトリ構造の例です。foo は一般的な名前なので、パッケージの名前は java-foo としていますが、以下のディレクトリではその名前は使っていません:

  • /usr/share/java/foo/
  • /usr/share/java/foo/foo.jar
  • /usr/share/java/foo/bar.jar (java-foo の依存ライブラリ)
  • /usr/share/foo/
  • /usr/share/foo/*.* (java-foo が必要とする汎用のファイル)
  • /usr/bin/foo (実行可能なシェルスクリプト)

依存パッケージ

Java パッケージには、必要に応じて、java-runtime あるいは java-environment を依存パッケージとして指定します。

大抵のパッケージでは、Java で書かれたソフトウェアを実行するのに java-runtime が必要になります。java-runtime は以下のパッケージに含まれている仮想パッケージです:

Java のソースコードをバイトコードにコンパイルする必要があるパッケージでは java-environment (例: JDK) が必須になります。java-environment は以下のパッケージに含まれている仮想パッケージです: