プロジェクト

全般

プロフィール

調査 #274

未完了

Gradleでjpackageコマンドを使った自己完結型Javaアプリケーションをパッケージ化する方法を調べる

高橋 徹 さんが2年以上前に追加. 2年以上前に更新.

ステータス:
進行中
優先度:
通常
担当者:
カテゴリ:
-
対象バージョン:
-
開始日:
2021/10/03
期日:
進捗率:

50%

予定工数:

説明

調査目的

JDK 14でお試し導入(Incubator)され、JDK 16で正式搭載された jpackage ツールをGradleから利用して自己完結型Javaアプリケーションをパッケージ化する方法を明らかにする。
主な対象は、Windows OS向けのネイティブインストーラ(MSI形式)とする。

調査結果

  • サードパーティ・プラグイン The Badass JLink Plugin を使用
    • jpackage タスクでインストーラを生成
Windows MSI形式インストーラを作成する最小限の build.gradle 記述

build.gradle を表示

インストーラオプションの指定

起動時のJVMオプションおよびコマンドラインオプション

build.gradle の抜粋を表示

インストーラ生成オプションを表示

完了条件

Gradle のプロジェクトから ネイティブインストーラを生成できること。

調査経過(概要)

高橋 徹 さんが2年以上前に更新

  • 説明 を更新 (差分)
  • ステータス新規 から 進行中 に変更
  • 進捗率0 から 50 に変更

Gradle から OpenJDK の jlink ツールおよび jpackage ツールを呼び出すサードパーティ・プラグインが存在する。

The Badass JLink Plugin

build.gradleの書き方(ミニマム)

最低限、プラグインの指定、Javaモジュールシステムのメインモジュール名、メインクラス名の指定をすれば、デフォルトの設定でインストーラが生成されます。

プラグイン指定
plugins {
    id 'org.beryx.jlink' version "2.24.2" 
}
  • application を暗黙で使用するので記述は jlinkプラグインだけとなりすっきり
アプリケーション指定
application {
    mainModule = 'com.torutk.gadget.analogclock'
    mainClass = 'com.torutk.gadget.analogclock.AnalogClockApp'
}
  • モジュール(JPMS)対応アプリケーションの、メインモジュールおよびメインクラスを指定
ビルド
D:\work\analogclock> gradlew jpackage

少々時間がかかりますが、build\jpackageディレクトリ下に、次の2つのインストーラファイルが生成されました。

AnalogClockGadget-1.0.exe
AnalogClockGadget-1.0.msi
インストール

ミニマムの設定で作成したAnalogClockGadget-1.0.msi をインストールすると、C:¥Program Files\AnalogClockGadget にインストールされます。
バージョンは1.0、発行元不明でインストール一覧に表示されています。
スタートメニューにはショートカットがないので、フォルダを開いて直接exeファイルをたたいて起動となります。

高橋 徹 さんが2年以上前に更新

最低限の build.gradle 記述で生成した MSI形式インストーラでインストールしたプログラムには、

  • スタートメニューにショートカットが存在しない
  • インストールされたプログラム一覧で、発行元(作成者)が不明
  • プログラムを改訂し、新しいバージョンを作成してインストールした際、古いバージョンが残ったまま新しいバージョンがインストールされる
  • プログラムにJVMオプション、コマンドラインオプションを渡したいときの記述

がありません。そこで、これらを build.gradle に追加していきます。

build.gradleの書き方(追加)

jlink {
    launcher {
        jvmArgs = [
            '-Xms32m', '-Xmx64m', '-Xss256k', '-XX:TieredStopAtLevel=1',
            '-XX:CICompilerCount=2', '-XX:CompileThreshold=1500',
            '-XX:InitialCodeCacheSize=160k', '-XX:ReservedCodeCacheSize=32m',
            '-XX:MetaspaceSize=12m', '-XX:+UseSerialGC'
        ]
        args = [
            '--x=0', '--y=0', '--scale=1.0', '--fps=5.0', '--on-top=false'
        ]
    }
    jpackage {
        installerName = 'AnalogClock'
        appVersion = '0.8.1'
        if (org.gradle.internal.os.OperatingSystem.current().windows) {
            installerType = 'msi'
            installerOptions += [
                '--win-menu-group', 'High Bridge',
                '--win-menu',
                '--win-shortcut',
                '--win-upgrade-uuid', 'fe287b25-e03d-4744-90f4-96b05dc36bf0',
                '--vendor', 'High Bridge'
            ]
        }
    }
}
  • プログラム実行時のJVMオプション、コマンドラインオプションは、launcher ブロックに記述しておくと、jpackage に引き継がれる
    • jvmArgs、args にリスト形式でオプションを列挙、コマンドライン上で空白(オプションの区切り)があるものはリストの別要素
  • jpackageツールのオプションは、jpackage ブロックに記述
  • Windows固有の設定は、if文で実行している環境のOSがWindowsの時に適用すべく条件式でくくる

高橋 徹 さんが2年以上前に更新

高橋 徹 さんが2年以上前に更新

Gitリポジトリにgradle-wrapper.jar が登録されていないため(.gitignoreでjarファイルが無視対象)、リポジトリからcloneしたディレクトリでgradlewがエラーとなってしまった。

高橋 徹 さんが2年以上前に更新

AnalogClockGadget でインストーラファイルのサイズを確認

ケーススタディ

ケース1 37MB jlinkオプションなし
ケース2 38MB jlinkオプションに次のオプション指定

ケース2で追加したオプション

jlink {
    options = [
        '--strip-debug', '--compress', '2',
        '--no-header-files', '--no-man-pages'
    ]
    launcher {
    : 

なぜかケース2の方が微増・・・

前に書いたブログで、jpackageツールはjlinkを内部的に呼出し、その際、--strip-debug、--no-header-files、--no-manpages、--strip-native-commands のオプションをjlinkに使用するとある。
https://torutk.hatenablog.jp/entry/2020/08/21/092658

他の形式にエクスポート: Atom PDF