はじめに
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ライブラリのパスを指定するときは、JavaFXSDKを展開したディレクトリではなく、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で解析します。
D:\work\EarthGadget> jdeps --print-module-deps dist\EarthGadget.jar java.base,java.prefs D:\work\EarthGadget>
- --print-module-deps は、jlinkコマンドのオプションで指定するモジュールリスト形式で出力するオプションです。今回はjdepsコマンドで解析した結果をjlinkで指定するのでこのオプションを指定しました。
アプリケーションが依存するJDKのモジュールのみ表示されます。JavaFXのモジュールはリストされません。また、JavaFXライブラリが必要とするJDKのモジュールもリストされていません。
そこで、JavaFXライブラリを解析対象に追加します。
D:\work\EarthGadget> jdeps --print-module-deps ^ --module-path "C:\Program Files\Java\JavaFX\javafx-sdk-11.0.1\lib" ^ --add-modules javafx.controls ^ dist\EarthGadget.jar Exception in thread "main" java.lang.NullPointerException at jdk.jdeps/com.sun.tools.jdeps.ModuleGraphBuilder.requiresTransitive(ModuleGraphBuilder.java:124)
うーん、ヌルポが出てしまいました。原因はよく分かりませんが、--print-module-deps を--list-depsに置き換えると回避できました。
D:\work\EarthGadget> jdeps --list-deps ^ --module-path "C:\Program Files\Java\JavaFX\javafx-sdk-11.0.1\lib" ^ --add-modules javafx.controls ^ dist\EarthGadget.jar JDK removed internal API/com.sun.media.jfxmediaimpl.platform.ios JDK removed internal API/com.sun.media.jfxmediaimpl.platform.osx java.base java.datatransfer java.desktop/java.awt.dnd.peer java.desktop/sun.awt java.desktop/sun.awt.dnd java.desktop/sun.swing java.prefs java.scripting java.xml jdk.jsobject jdk.unsupported jdk.unsupported.desktop jdk.xml.dom
ちなみにリストされるモジュールは、JDKのモジュールのみでした。JavaFXライブラリのモジュールも表示されるのを期待していましたが、このオプション指定では出ませんでした。
jlinkでアプリケーションの実行に必要なJDKのイメージを作成する
先のjdepsコマンドで、このJavaFXアプリケーション実行に必要なJDKモジュールを抜粋して実行イメージを作成します。
D:\work\EarthGadget> jlink --add-modules java.base,java.datatransfer,java.desktop,java.prefs,java.scripting,java.xml,jdk.jsobject,jdk.unsupported,jdk.unsupported.desktop,jdk.xml.dom --output runtime
生成された runtime ディレクトリの容量は約70MBとなりました。
ただし、JavaFXライブラリとアプリケーションはこのruntimeには含まれません。
jlinkで作成したJDKの実行イメージを使ってアプリケーションを実行する
D:\work\EarthGadget> runtime\bin\java --module-path "C:\Program Files\Java\JavaFX\javafx-sdk-11.0.1\lib" --add-modules javafx.controls -jar dist\EarthGadget.jar
まとめ
*1:JEP 343: Packaging Tool