kotlingradlegraalvmgraalvm-native-image

GraalVM native gradle plugin using nativeCompile fails using nativeCompile task


Am able to build a sample console Kotlin project using ./gradlew clean build but am unable to generate a native image using the GraalVM native gradle plugin...

After a successful build, the subsequent step is to run ./gradlew nativeCompile, this is what fails.

build.gradle.kts:

plugins {
    kotlin("jvm") version "1.9.23"
    id("org.graalvm.buildtools.native") version "0.10.2"
    kotlin("plugin.serialization") version "2.0.0"
}

group = "com.sample"
version = "1.0-SNAPSHOT"

graalvmNative {
    toolchainDetection.set(true)
    binaries {
        named("main") {
            imageName.set("sample-cli")
            mainClass.set("com.sample.ApplicationKt")
            buildArgs.add("--enable-http")
            buildArgs.add("--enable-url-protocols=https")
            buildArgs.add("--report-unsupported-elements-at-runtime")
            buildArgs.add("--no-fallback")
            buildArgs.add("--no-server")
            buildArgs.add("-H:ReflectionConfigurationFiles=${rootProject.projectDir}/src/main/resources/reflection.json")
            buildArgs.add("-H:+UnlockExperimentalVMOptions")
        }
        named("test") {
            buildArgs.add("-O0")
        }
    }
    binaries.all {
        resources.autodetect()
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation("org.slf4j:slf4j-simple:2.0.13")
    implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1")
    testImplementation(kotlin("test"))
}

tasks.test {
    useJUnitPlatform()
}
kotlin {
    jvmToolchain(21)
}

Domain object:

Customer.kt:

package com.sample.domain

import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonElement

@Serializable
data class Customer(val name: String? = null, val email: String? = null, val customerId: Int? = 0)


Required config file src/main/resources/reflection.json:

[
  {
    "name": "com.sample.domain.Customer",
    "unsafeAllocated": true
  }
]

Trying to generate a native image:

./gradlew nativeCompile

Error:

> Task :generateResourcesConfigFile
[native-image-plugin] Resources configuration written into /Users/pnwlover/sample/build/native/generated/generateResourcesConfigFile/resource-config.json

> Task :nativeCompile
[native-image-plugin] GraalVM Toolchain detection is enabled
[native-image-plugin] GraalVM uses toolchain detection. Selected:
[native-image-plugin]    - language version: 21
[native-image-plugin]    - vendor: Oracle
[native-image-plugin]    - runtime version: 21+35-jvmci-23.1-b15
[native-image-plugin] Native Image executable path: /Library/Java/JavaVirtualMachines/graalvm-jdk-21+35.1/Contents/Home/lib/svm/bin/native-image
Warning: Ignoring server-mode native-image argument --no-server.
Warning: The option '-H:ReflectionConfigurationFiles=/Users/pnwlover/sample/src/main/resources/reflection.json' is experimental and must be enabled via '-H:+UnlockExperimentalVMOptions' in the future.
Warning: Please re-evaluate whether any experimental option is required, and either remove or unlock it. The build output lists all active experimental options, including where they come from and possible alternatives. If you think an experimental option should be considered as stable, please file an issue.
========================================================================================================================
GraalVM Native Image: Generating 'sample' (executable)...
========================================================================================================================
For detailed information and explanations on the build output, visit:
https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/BuildOutput.md
------------------------------------------------------------------------------------------------------------------------
[1/8] Initializing...                                                                                    (3.8s @ 0.30GB)
 Java version: 21+35, vendor version: Oracle GraalVM 21+35.1
 Graal compiler: optimization level: 2, target machine: armv8-a, PGO: off
 C compiler: cc (apple, arm64, 15.0.0)
 Garbage collector: Serial GC (max heap size: 80% of RAM)
 1 user-specific feature(s):
 - com.oracle.svm.thirdparty.gson.GsonFeature
------------------------------------------------------------------------------------------------------------------------
 1 experimental option(s) unlocked:
 - '-H:ReflectionConfigurationFiles' (origin(s): command line)
------------------------------------------------------------------------------------------------------------------------
Build resources:
 - 26.49GB of memory (27.6% of 96.00GB system memory, determined at start)
 - 12 thread(s) (100.0% of 12 available processor(s), determined at start)
[2/8] Performing analysis...  [*]                                                                        (9.1s @ 1.52GB)
    7,479 reachable types   (83.7% of    8,938 total)
    9,628 reachable fields  (56.4% of   17,068 total)
   37,525 reachable methods (52.8% of   71,036 total)
    2,417 types,   119 fields, and 1,859 methods registered for reflection
        1 native library: -framework CoreServices

Error: Classes that should be initialized at run time got initialized during image building:
 kotlin.DeprecationLevel was unintentionally initialized at build time. To see why kotlin.DeprecationLevel got initialized use --trace-class-initialization=kotlin.DeprecationLevel
To see how the classes got initialized, use --trace-class-initialization=kotlin.DeprecationLevel
------------------------------------------------------------------------------------------------------------------------
                        1.7s (12.3% of total time) in 40 GCs | Peak RSS: 2.82GB | CPU load: 7.49
========================================================================================================================
Finished generating 'sample' in 13.1s.

> Task :nativeCompile FAILED

The actual program runs via IntelliJ its just the native image generation is broken for some odd reason...


Solution

  • As mentioned in the comments section, the solution was the inclusion of the --initialize-at-build-time parameter/flag inside the graalvmNative plug-in section of build.gradle.kts:

    graalvmNative {
        toolchainDetection.set(true)
        binaries {
            named("main") {
                imageName.set("sample-cli")
                mainClass.set("com.sample.ApplicationKt")
                buildArgs.add("--initialize-at-build-time")
                buildArgs.add("--enable-http")
                buildArgs.add("--enable-url-protocols=https")
                buildArgs.add("--report-unsupported-elements-at-runtime")
                buildArgs.add("--no-fallback")
                buildArgs.add("--no-server")
                buildArgs.add("-H:ReflectionConfigurationFiles=${rootProject.projectDir}/src/main/resources/reflection.json")
                buildArgs.add("-H:+UnlockExperimentalVMOptions")
            }
            named("test") {
                buildArgs.add("-O0")
            }
        }
        binaries.all {
            resources.autodetect()
        }
    }