はじめに
JDK 8でのJavaFXアプリケーションは、javapackagerコマンドを使ってアプリケーションとアプリケーションの実行に必要なJava実行環境をまとめて固めて配布することができました。固め方には、zipアーカイブの他、Windows、Linux、MacOSそれぞれのソフトウェアパッケージ形式(インストーラー)とすることも可能です。
しかし、JDK 11からはJavaFXが分離した際にjavapackagerコマンドも外されてしまいました。OpenJDKでは、javapackagerを代替する新しい機能を開発中*1ですが、早くてJDK 12からとなります。それまでの間、jlinkコマンドを使ってアプリケーションとアプリケーションの実行に必要なJava実行環境をまとめることとします。なお、jlinkはOS固有のパッケージ形式(インストーラー)を作成することはできません。
jlinkコマンドを使った実行イメージの作成
jlinkコマンドは、指定したモジュールが依存するモジュール群をJDKから抜きだして、実行イメージまとめるのに使います。
モジュール対応したJavaFXアプリケーションの実行イメージの作成
JavaFXアプリケーションが、モジュール対応している場合はjlinkコマンドで簡単に実行イメージを作成することができます。
ただし、モジュールパスでJavaFXライブラリのパスを指定するときは、JavaFX SDKを展開したディレクトリではなく、JavaFX jmodsを展開したディレクトリを指定します。
D:\work\EarthGadget> jlink --module-path "C:\Program Files\Java\JavaFX\javafx-jmods-11.0.1";dist ^ --add-modules com.torutk.gadget.earth ^ --output runtime ^ --launcher earthgadget=com.torutk.gadget.earth/com.torutk.gadget.earth.EarthGadgetApp
- --module-pathでは、JDK標準以外のモジュールを収容するディレクトリを指定します。ここでは、JavaFX jmodsファイルのあるディレクトリ(C:\Program Files\Java\JavaFX\javafx-jmods-11.0.1)と、アプリケーションのモジュール化JARファイルのあるディレクトリ(カレントディレクトリ下のdist)を指定しています。
- --add-modulesでは、アプリケーションのメインモジュール(com.torutk.gadget.earth)を指定しています。
- --outputでは、実行イメージを生成するディレクトリを指定しています。
- --launcherでは、実行イメージの中にアプリケーション起動用のコマンド(シェルスクリプト/バッチファイル)の名前と起動するモジュールおよびメインクラス名を指定しています。
実行イメージが展開されるディレクトリに、JavaFX関係のライブラリ(ネイティブライブラリのdllファイル、クラスライブラリのJARファイル等)も展開されます。
outputオプションで指定したruntimeディレクトリ下のbinディレクトリには、launcherオプションで指定した起動スクリプトファイル(earthgadget)/起動バッチファイル(earthgadget.bat)があるので、UNIX系OSなら前者を、Windows OSなら後者を実行するとJavaFXアプリケーションが立ち上がります。
jlinkコマンドのmodule-pathオプションで、JavaFXのSDKのlibディレクトリを指定すると、実行イメージの中にネイティブライブラリが含まれないので実行時にエラーとなってしまいます。jlinkコマンドでJavaFXを指定する場合は、JavaFXのjmodsを指定します。
モジュール対応していないJavaFXアプリケーションの実行イメージ作成(改訂)
JavaFXアプリケーションがモジュール対応していない場合は、JavaFXアプリケーションが必要とするモジュールをjdepsコマンドでリストアップしてからjlinkコマンドでリストアップされたモジュールをそれぞれ指定します。
ただし現時点ではJDKのモジュールから必要なものを抜粋した実行イメージを生成することができますが、実行イメージにJavaFXライブラリとアプリケーションを含めることはできませんでした。
jdepsでアプリケーションの実行に必要なモジュールを調べる
まず、アプリケーションJARファイル(非モジュール対応)をjdepsで解析します。
ここで、非モジュールJARの依存関係を解析する場合、jdepsコマンドのオプション--print-module-depsおよび--list-depsは使用しないのがミソです(id:skrbさんの次のブログ参照)。
まずは、アプリケーションJARファイルだけを指定した場合の実行例です。
D:\work\EarthGadget> jdeps -s dist\EarthGadget.jar EarthGadget.jar -> java.base EarthGadget.jar -> java.prefs EarthGadget.jar -> 見つかりません D:\work\EarthGadget>
アプリケーションJARが依存するJDKのモジュールのみ表示されます。JavaFXのモジュールはリストされません。また、JavaFXライブラリが必要とするJDKのモジュールもリストされていません。
そこで、JavaFXライブラリを解析対象に追加します。
D:\work\EarthGadget> jdeps -s --module-path "C:\Program Files\Java\JavaFX\javafx-sdk-11.0.1\lib" dist\EarthGadget.jar EarthGadget.jar -> java.base EarthGadget.jar -> java.prefs EarthGadget.jar -> javafx.base EarthGadget.jar -> javafx.controls EarthGadget.jar -> javafx.graphics EarthGadget.jar -> 見つかりません javafx.base -> java.base javafx.base -> java.desktop javafx.controls -> java.base javafx.controls -> javafx.base javafx.controls -> javafx.graphics javafx.fxml -> java.base javafx.fxml -> java.scripting javafx.fxml -> java.xml javafx.fxml -> javafx.base javafx.fxml -> javafx.graphics javafx.graphics -> java.base javafx.graphics -> java.desktop javafx.graphics -> java.xml javafx.graphics -> javafx.base javafx.graphics -> jdk.unsupported javafx.media -> JDK removed internal API javafx.media -> java.base javafx.media -> javafx.base javafx.media -> javafx.graphics javafx.swing -> java.base javafx.swing -> java.datatransfer javafx.swing -> java.desktop javafx.swing -> javafx.base javafx.swing -> javafx.graphics javafx.swing -> jdk.unsupported.desktop javafx.swt -> java.base javafx.swt -> javafx.base javafx.swt -> javafx.graphics javafx.swt -> 見つかりません javafx.web -> java.base javafx.web -> java.desktop javafx.web -> java.xml javafx.web -> javafx.base javafx.web -> javafx.controls javafx.web -> javafx.graphics javafx.web -> javafx.media javafx.web -> jdk.jsobject javafx.web -> jdk.xml.dom
なお、--module-pathに、JavaFXのSDKではなく、JMODの方を指定すると何故か依存が解析されませんでした。
D:\work\EarthGadget> jdeps -s --module-path "C:\Program Files\Java\javafx\javafx-jmods-11.0.1" dist\EarthGadget.jar EarthGadget.jar -> java.base EarthGadget.jar -> java.prefs EarthGadget.jar -> 見つかりません D:\work\EarthGadget>
非モジュール対応アプリケーションJARファイル(EarthGadget.jar)が依存しているのは
となります。よって、jlink でこれらを指定すればあとは依存関係を辿って必要なモジュールが取り込まれた実行イメージが生成されます。なお、java.baseは暗黙で使用されるモジュールなので指定を省略できます。javafx.graphicsはjavafx.controlsが依存しているのでこちらも省略できます。javafx.baseはjavafx.controlsが依存しているのでこちらも省略できます。
jlinkで非モジュール対応アプリケーションJARのための実行イメージを生成する
D:\work\EarthGadget> jlink --add-modules javafx.controls,java.prefs ^ --module-path "C:\Program Files\Java\JavaFX\javafx-jmods-11.0.1" ^ --output runtime
生成された runtime ディレクトリの容量は約87MBとなりました。
JavaFXライブラリ(クラスライブラリおよびネイティブライブラリ)も含まれています。
なお、アプリケーションはこのruntimeには含まれません。
jlinkで作成した実行イメージを使ってアプリケーションを実行する
D:\work\EarthGadget> runtime\bin\java -jar dist\EarthGadget.jar
まとめ
*1:JEP 343: Packaging Tool