Windows 環境にて、 graalvm-native-image-plugin を利用している際に、タイトルにあるようなエラーが発生することがあるようです。
どのような形にするのが良いか解決方法を検討中ですが、一時的に回避する方法として、 jar の Class-Path
アトリビュートに jar ファイルのリストを記述する方法が簡単な回避方法かと思われるので、そちらについて紹介します。
時間のない方のために 3 行でまとめると
- Windows でコマンドが長いためにエラーになるケースがある
native-image
コマンドの-cp
オプションではなく、 jar ファイルのClass-Path
属性で依存ライブラリーを指定する- プラグインでこの方法を反映させるかどうかを悩んでる(対応させるのは可能だけど、わりと泥臭くて黒魔術っぽいコードになりそうな予感)
コマンドの -cp
に指定するクラスパスのパス文字列が絶対パスで記述しているために、 Windows のコマンドの最大長を超えてしまうことがあるというのが原因です。
これを回避するために、 なるべく jar ファイルのパスをコマンドに記述しない方法が求められます。
そこで、 jar ファイルの仕様にある Class-Path
属性にて依存ライブラリーを指定する方法を採用します。
ここで指定する依存ライブラリーはメインの jar ファイルからの相対パスで指定する必要がありますので、 依存ライブラリーをすべて libs
ディレクトリーにコピーするタスクを作ります。
task copyDependencies(type: Copy, group: 'build') { from configurations.runtimeClasspath destinationDir = file("$buildDir/libs") }
次に nativeImage
タスクが実行された際に作ったタスクが必ず実行されるように、タスクグラフを構築しておきます。
今回は、 jar
タスクにて上記でコピーされるファイルを扱っていくので、 jar
タスクが上記タスクに依存するようにしておくのが良いでしょう。
jar {
dependsOn 'copyDependencies'
}
また、 jar
タスクでは Class-Path
属性に依存ライブラリーを相対パスで記述するので、 manifest
ブロックでマニフェストファイルに記述を追加します
jar { dependsOn 'copyDependencies' manifest { def classpathString = configurations .runtimeClasspath .collect { File f -> f.name } .join(' ') attributes 'Class-Path': classpathString } }
nativeImage
タスクでは、デフォルトでアプリケーションのランタイムクラスパスをコマンドに指定するように設定がなされているので、これをクラスパスが空になるように設定を上書きする必要があります。そこで、空の Configuration
(gradle の依存管理のグループ) を作って、それで上書きします。
configurations {
emptyConfiguration
}
nativeImage {
runtimeClasspath = configurations.emptyConfiguration
// その他の設定は省略
}
これにより、コマンドの長さを短く抑えられるようになります。
作成された実行ファイルは実際に実行可能であったことは確認してあります(mac)。
なお、参考までに、内部的に実行していたコマンドは次のようなコマンドでした。