macOS で Gradle Plugin for GraalVM Native Image を動かすための抜け道


はじめに

macOS 上の Gradle で GraalVM ネイティブイメージを作成する際のハマりポイントを記しておきます。

Gradle プラグインは Graal 公式のもので、バージョン 0.9.25 です。

github.com

Native Image 自体もそうだけど、プラグインもまだまだ途上です。


Gradle のツールチェーンでプロビジョニングした GraalVM はシンボリックリンクが壊れている

settings.gradle.kts は以下のように定義。

pluginManagement {
    repositories {
        mavenCentral()
        gradlePluginPortal()
    }
}
plugins {
    id("org.gradle.toolchains.foojay-resolver-convention") version "0.7.0"
}
rootProject.name = "example"
include("app")

build.gradle.kts にてツールチェーンに JvmVendorSpec.GRAAL_VM を指定。

plugins {
    application
    id("org.graalvm.buildtools.native") version "0.9.25"

}

repositories {
    mavenCentral()
}

java {
    toolchain {
        languageVersion.set(JavaLanguageVersion.of(20))
        vendor.set(JvmVendorSpec.GRAAL_VM)
    }
}

application {
    mainClass.set("example.App")
}

GraalVMを導入済みでない場合は、foojay-resolver-convention で定義された https://github.com/graalvm/graalvm-ce-builds/releases から graalvm-community-jdk-20.0.2_macos-x64_bin.tar.gz をダウンロードして、自動的に ~/.gradle/jdks に配備してくれる。

本来は、graalvm-community-openjdk-20.0.2+9.1/Contents/Home/bin/native-image はシンボリックリンクで、lib/svm/bin/native-image にリンクするが、実体は0バイトのファイルになりシンボリックリンクが壊れている。 そのため、native-image のコマンド呼び出しが何も行うことなく終了してネイティブイメージは生成できない。

これは、古くからある以下の Issue にある通り、Gradle がシンボリックリンクを理解しないため。

github.com


ワークアラウンドとしては、別途 GraalVM をインストールするか、~/.gradle/jdks に残る graalvm-community-jdk-20.0.2_macos-x64_bin.tar.gz をOS上で解凍して上書いてやれば良い。


Native Image Plugin(0.9.25)は、Gradle 8.3 では動かない

Gradle 8.3 では、ネイティブ・イメージ・プラグインは以下のエラーとなり動作しない。

The value for property 'languageVersion' is final and cannot be changed any further.

原因はこちらで、プラグイン側の修正待ちの状態。

github.com

ワークアラウンドとしては、GraalVM Native Image Plugin (<0.9.25) を使うには、Gradle 8.2 を使えば良い。

本事象は GraalVM Native Image Plugin 0.9.26 で改善されたようです


Native Image Plugin のトレースエージェントは GRAALVM_HOME / JAVA_HOME が必須

トレースエージェントで実行する場合は以下のタスクを実行する。

$ ./gradlew -Pagent run

$ ./gradlew metadataCopy --task run --dir src/main/resources/META-INF/native-image

しかし、いずれも以下のエラーとなる。

Execution failed for task ':app:run'.
> Cannot query the value of this property because it has no value available.

Native Image Plugin のタスクで以下のようになっており、環境変数が必須になってしまっている。

public class NativeImageExecutableLocator {
    public static Provider<String> graalvmHomeProvider(ProviderFactory providers, Diagnostics diagnostics) {
        return diagnostics.fromEnvVar("GRAALVM_HOME", providers)
                .orElse(diagnostics.fromEnvVar("JAVA_HOME", providers));
    }

ツールチェーン指定しているにも関わらず、環境変数のエクスポートが必要。

$ export GRAALVM_HOME=~/.gradle/jdks/graalvm_community-20-x86_64-os_x/graalvm-community-openjdk-20.0.2+9.1/Contents/Home