GraalVM version on macOS Sonoma 14.5
:
java -version
java version "21" 2023-09-19
Java(TM) SE Runtime Environment Oracle GraalVM 21+35.1 (build 21+35-jvmci-23.1-b15)
Java HotSpot(TM) 64-Bit Server VM Oracle GraalVM 21+35.1 (build 21+35-jvmci-23.1-b15, mixed mode, sharing)
gradle version:
gradle --v
------------------------------------------------------------
Gradle 8.7
------------------------------------------------------------
Build time: 2024-03-22 15:52:46 UTC
Revision: 650af14d7653aa949fce5e886e685efc9cf97c10
Kotlin: 1.9.22
Groovy: 3.0.17
Ant: Apache Ant(TM) version 1.10.13 compiled on January 4 2023
JVM: 21 (Oracle Corporation 21+35-jvmci-23.1-b15)
OS: Mac OS X 14.5 aarch64
build.gradle.kts
:
plugins {
kotlin("jvm") version "1.9.23"
}
group = "com.example"
version = "1.0-SNAPSHOT"
tasks.withType<Jar> {
manifest {
attributes["Main-Class"] = "com.example.SampleCli"
}
}
repositories {
mavenCentral()
}
dependencies {
implementation("com.github.ajalt.clikt:clikt:4.3.0")
testImplementation(kotlin("test"))
}
tasks.test {
useJUnitPlatform()
}
kotlin {
jvmToolchain(21)
}
fun getClasspath() = "libs/" + file("$buildDir/libs").list()?.joinToString(":libs/")
task<Exec>("buildNativeImage") {
description = "Build native image using GraalVM"
dependsOn(tasks.getByName("build"))
workingDir(buildDir)
commandLine(
"native-image",
"-cp", getClasspath(),
"-H:+ReportExceptionStackTraces",
"-H:+AddAllCharsets",
// "--report-unsupported-elements-at-runtime",
// "--allow-incomplete-classpath",
"--no-server",
"--no-fallback",
"--enable-http",
"--enable-https",
"com.example.SampleCli",
"com.example"
)
}
Main-Class
:
package com.example
import com.github.ajalt.clikt.core.CliktCommand
import com.github.ajalt.clikt.parameters.options.default
import com.github.ajalt.clikt.parameters.options.help
import com.github.ajalt.clikt.parameters.options.option
import com.github.ajalt.clikt.parameters.options.prompt
import com.github.ajalt.clikt.parameters.types.int
class SampleCli() : CliktCommand(name="cli") {
val count: Int by option().int().default(1).help("Number of greetings")
val name: String by option().prompt("Your name").help("The person to greet")
override fun run() {
repeat(count) {
echo("Hello $name!")
}
}
}
fun main(args: Array<String>) = SampleCli().main(args)
Whereas I am to build this from the command line and also via IntellIJ using ./gradlew build
:
BUILD SUCCESSFUL in 647ms
3 actionable tasks: 3 executed
It fails when I try to generate a GraalVM native-image (same error when I try ./gradlew buildNativeImage
):
native-image -jar build/libs/SampleCli-1.0-SNAPSHOT.jar cli
Error:
========================================================================================================================
GraalVM Native Image: Generating 'cli' (executable)...
========================================================================================================================
[1/8] Initializing... (0.0s @ 0.15GB)
The build process encountered an unexpected error:
> java.lang.NoClassDefFoundError: com/github/ajalt/clikt/core/CliktCommand
Please inspect the generated error report at:
/Users/user1/SampleProject/svm_err_b_20240603T04124.720_pid14052.md
If you are unable to resolve this problem, please file an issue with the error report at:
https://graalvm.org/support
Despite your question title, you are not building a bad-practice fat jar, but your jar only contains your own code.
One way to fix this is to use the -cp
argument to native-image
to properly give your dependencies to the tool. With your manual call you do not give any -cp
argument at all, with your buildNativeImage
task you give a -cp
argument, but most probably it does not have the correct value. You can easily check that by printing the value you give or by using --info
or --debug
to see the arguments given to the JavaExec
task.
Another possibility would most probably be to use the GraalVM Gradle plugin which you can find at https://graalvm.github.io/native-build-tools/latest/gradle-plugin.html, which most probably handles the dependencies properly.