graal icon indicating copy to clipboard operation
graal copied to clipboard

[Native Image] System.loadLibrary("awt") failed

Open YagodinArtem opened this issue 3 months ago • 5 comments

Describe the Issue

Hello guys! First of all thank you for graal technology it is realy fast and powerful, but iam struggling with confusing problem, i am using open cv lib to work with rtsp video stream, which uses java.awt inside, when i try to use BufferedImage, which uses java.awt.image.ColorModel it calls:

static void loadLibraries() {
        if (!loaded) {
            java.security.AccessController.doPrivileged(
                new java.security.PrivilegedAction<Void>() {
                    public Void run() {
                        System.loadLibrary("awt");
                        return null;
                    }
                });
            loaded = true;
        }
    }

And this System.loadLibrary("awt"); cause to error (see below)

What am i missing?

Using the latest version of GraalVM can resolve many issues.

GraalVM Version

java version "21.0.8" 2025-07-15 LTS Java(TM) SE Runtime Environment Oracle GraalVM 21.0.8+12.1 (build 21.0.8+12-LTS-jvmci-23.1-b72) Java HotSpot(TM) 64-Bit Server VM Oracle GraalVM 21.0.8+12.1 (build 21.0.8+12-LTS-jvmci-23.1-b72, mixed mode, sharing)

Operating System and Version

Ubuntu 25.04

Troubleshooting Confirmation

Run Command

tried:

./gradlew :pkuback:nativeCompile -PgraalvmNativeImage=true --no-daemon --info -Dnative-image.show-build-time=true --console=verbose

also tried:

./gradlew :pkuback:nativeBuild -PgraalvmNativeImage=true --no-daemon --info -Dnative-image.show-build-time=true --console=verbose

also i build jni and reflect configs with:

java -agentlib:native-image-agent=config-output-dir=META-INF/native-image
-Dhibernate.bytecode.provider=none
-jar ./pkuback/build/libs/pkuback-all-optimized.jar

they are pretty big, so if it necessary i could provide it fully or partial

Expected Behavior

private fun loadNativeLibraries() {
        try {
            
            System.loadLibrary("awt")

        } catch (e: Exception) {
            println("Failed to load native libraries: ${e.message}")
            throw e
        }
    }

cause no exception

Actual Behavior

Stacktrace for the failing thread 0x00007f6c3c000b80 (A=AOT compiled, J=JIT compiled, D=deoptimized, i=inlined): A SP 0x00007f6c1bfed2a0 IP 0x00005a42a6cf09b9 size=80 com.oracle.svm.core.code.IsolateEnterStub.JNIFunctions_FatalError_2d6e7de51007501356372d87ae0cc671dc9d1a91(IsolateEnterStub.java:0) i SP 0x00007f6c1bfee350 IP 0x00005a42a6dca1e0 size=64 com.oracle.svm.core.jni.JNIOnLoadFunctionPointer.invoke(JNILibraryInitializer.java) A SP 0x00007f6c1bfee350 IP 0x00005a42a6dca1e0 size=64 com.oracle.svm.core.jni.JNILibraryInitializer.callOnLoadFunction(JNILibraryInitializer.java:71) A SP 0x00007f6c1bfee390 IP 0x00005a42a6dca083 size=32 com.oracle.svm.core.jni.JNILibraryInitializer.initialize(JNILibraryInitializer.java:132) A SP 0x00007f6c1bfee3b0 IP 0x00005a42a6d407f5 size=96 com.oracle.svm.core.jdk.NativeLibrarySupport.addLibrary(NativeLibrarySupport.java:204) A SP 0x00007f6c1bfee410 IP 0x00005a42a6d40cb8 size=32 com.oracle.svm.core.jdk.NativeLibrarySupport.loadLibrary0(NativeLibrarySupport.java:160) A SP 0x00007f6c1bfee430 IP 0x00005a42a6d412ba size=144 com.oracle.svm.core.jdk.NativeLibrarySupport.loadLibraryRelative(NativeLibrarySupport.java:123) i SP 0x00007f6c1bfee4c0 IP 0x00005a42a906eb65 size=16 java.lang.ClassLoader.loadLibrary(ClassLoader.java:106) i SP 0x00007f6c1bfee4c0 IP 0x00005a42a906eb65 size=16 java.lang.Runtime.loadLibrary0(Runtime.java:916) i SP 0x00007f6c1bfee4c0 IP 0x00005a42a906eb65 size=16 java.lang.System.loadLibrary(System.java:2063) i SP 0x00007f6c1bfee4c0 IP 0x00005a42a906eb65 size=16 java.awt.image.ColorModel$1.run(ColorModel.java:211) A SP 0x00007f6c1bfee4c0 IP 0x00005a42a906eb65 size=16 java.awt.image.ColorModel$1.run(ColorModel.java:209) i SP 0x00007f6c1bfee4d0 IP 0x00005a42a906f096 size=32 java.security.AccessController.executePrivileged(AccessController.java:129) i SP 0x00007f6c1bfee4d0 IP 0x00005a42a906f096 size=32 java.security.AccessController.doPrivileged(AccessController.java:319) i SP 0x00007f6c1bfee4d0 IP 0x00005a42a906f096 size=32 java.awt.image.ColorModel.loadLibraries(ColorModel.java:208) A SP 0x00007f6c1bfee4d0 IP 0x00005a42a906f096 size=32 java.awt.image.ColorModel.(ColorModel.java:221)

But the actual lib is created during native build nearly native image is beign:

zeus@zeus-aorus16x9sg:~/zeus/PKU_backend/pkuback/build/native/nativeCompile$ ls -la total 585852 drwxrwxr-x 3 zeus zeus 4096 Sep 11 11:38 . drwxrwxr-x 5 zeus zeus 4096 Sep 10 22:56 .. -rwxrwxr-x 1 zeus zeus 595710120 Sep 11 11:38 app -rw-rw-r-- 1 zeus zeus 42584 Sep 11 11:38 libawt_headless.so -rw-rw-r-- 1 zeus zeus 895608 Sep 11 11:38 libawt.so -rw-rw-r-- 1 zeus zeus 584272 Sep 11 11:38 libawt_xawt.so -rw-rw-r-- 1 zeus zeus 1849272 Sep 11 11:38 libfontmanager.so -rw-rw-r-- 1 zeus zeus 235872 Sep 11 11:38 libjavajpeg.so -rwxrwxr-x 1 zeus zeus 14944 Sep 11 11:38 libjava.so -rwxrwxr-x 1 zeus zeus 14944 Sep 11 11:38 libjvm.so -rw-rw-r-- 1 zeus zeus 528544 Sep 11 11:38 liblcms.so drwxrwxr-x 2 zeus zeus 4096 Sep 11 11:37 reports

Documentation says clearly:

Image

Steps to Reproduce

could run in sample project which use any class of awt package:

private fun loadNativeLibraries() {
        try {
            
            System.loadLibrary("awt")

        } catch (e: Exception) {
            println("Failed to load native libraries: ${e.message}")
            throw e
        }
    }

Additional Context

Main app gradle build:

import org.jetbrains.kotlin.gradle.dsl.JvmTarget


plugins {
    id("buildsrc.convention.kotlin-jvm")
    id("com.google.devtools.ksp") version "2.1.21-2.0.1"
    id("io.micronaut.application") version "4.5.4"
    id("io.micronaut.aot") version "4.5.4"
    id("io.micronaut.docker") version "4.5.4"
    id("com.gradleup.shadow") version "8.3.7"
    id("org.jetbrains.kotlin.kapt")
    application
}

java {
    sourceCompatibility = JavaVersion.toVersion("21")
}


ksp {
    arg("jvmTarget", "21")
}

val kotlinVersion = project.properties["kotlinVersion"]

repositories {
    mavenCentral()
}

dependencies {
    ksp("io.micronaut:micronaut-http-validation")
    ksp("io.micronaut.serde:micronaut-serde-processor")
    ksp("io.micronaut.data:micronaut-data-processor")

    implementation(project(":videomodule"))

    implementation("io.micronaut.kotlin:micronaut-kotlin-runtime")
    implementation("io.micronaut.serde:micronaut-serde-jackson")
    implementation("io.micronaut:micronaut-http-client")
    implementation("io.micronaut:micronaut-runtime")
    implementation("io.micronaut.cache:micronaut-cache-core")
    implementation("io.micronaut.cache:micronaut-cache-caffeine")
    implementation("io.micronaut.redis:micronaut-redis-lettuce")


    implementation("jakarta.validation:jakarta.validation-api:${libs.versions.jakartaV}")
    implementation("io.micronaut.validation:micronaut-validation:${libs.versions.micronautValidationV}")
    annotationProcessor("io.micronaut.validation:micronaut-validation-processor:${libs.versions.micronautValidationV}")

    implementation("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}")
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:${kotlinVersion}")

    implementation("ch.qos.logback:logback-classic:${libs.versions.logback}")
    implementation("ch.qos.logback:logback-core:${libs.versions.logback}")

    //TODO move to libs.versions

    implementation("io.micronaut.data:micronaut-data-processor")
    implementation("io.micronaut.data:micronaut-data-jdbc")
    implementation("io.micronaut.sql:micronaut-jdbc-hikari")
    implementation("com.mysql:mysql-connector-j:8.4.0")

    implementation("io.projectreactor:reactor-core:3.8.0-M5")
    implementation("commons-codec:commons-codec:1.15")
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2")
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor:1.10.2")
    implementation("net.java.dev.jna:jna:5.17.0")

    runtimeOnly("org.yaml:snakeyaml")
    compileOnly("io.micronaut:micronaut-http-client")
    runtimeOnly("ch.qos.logback:logback-classic")

    //TODO move to libs.version


    testImplementation("io.micronaut.testresources:micronaut-test-resources-extensions-core")
    testImplementation("org.testcontainers:testcontainers:1.19.0")
    testImplementation("org.testcontainers:mysql:1.19.0")
    testImplementation("org.testcontainers:junit-jupiter:1.19.0")

    testImplementation("io.micronaut.test:micronaut-test-junit5")
    testImplementation("org.junit.jupiter:junit-jupiter-api")
    testImplementation("org.junit.jupiter:junit-jupiter-engine")
    testImplementation("org.junit.jupiter:junit-jupiter-params")
    testImplementation("org.mockito:mockito-core:5.18.0")
    testImplementation(kotlin("test"))

}

application {
    mainClass = "ru.zeus.app.AppKt"
}


configurations {
    nativeImageCompileOnly {
        isCanBeResolved = true
    }
}


graalvmNative {
    binaries {
        named("main") {
            imageName.set("app")
            mainClass.set("ru.zeus.app.AppKt")
            buildArgs.addAll(listOf(

                "-Djava.awt.headless=true",

                "--initialize-at-run-time=org.bytedeco",

                "--enable-url-protocols=http,https,rtsp,rtmp,tcp",

                "-H:EnableURLProtocols=rtsp,rtmp,tcp,http,https",

               
                "-H:IncludeResources=libjava\\.so",
                "-H:IncludeResources=libjvm\\.so",
                "-H:IncludeResources=libawt\\.so",
                "-H:IncludeResources=libawt_headless\\.so",
                "-H:IncludeResources=libawt_xawt\\.so",
                "-H:IncludeResources=libjawt\\.so",

                "-H:IncludeResourceBundles=com.sun.jna",

                "-H:+ReportExceptionStackTraces",
                "-H:+AddAllCharsets",
                "--verbose",
                "-H:+PrintClassInitialization"
            ))
        }
    }
}



micronaut {
    runtime("netty")
    testRuntime("junit5")
    processing {
        incremental(true)
        annotations("ru.zeus.*")
    }
    aot {
        optimizeServiceLoading = true
        convertYamlToJava = true
        precomputeOperations = true
        cacheEnvironment = true
        optimizeClassLoading = true
        deduceEnvironment = true
        optimizeNetty = true
        replaceLogbackXml = false
    }
}


tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
    compilerOptions {
        jvmTarget.set(JvmTarget.JVM_21)
    }
}

tasks.named<io.micronaut.gradle.docker.NativeImageDockerfile>("dockerfileNative") {
    jdkVersion = "21"
}


tasks.test {
    useJUnitPlatform()

    reports {
        html.required = true
        junitXml.required = false
    }

    testLogging {
        events("passed", "skipped", "failed")
        showStandardStreams = true
    }
}

tasks.withType<Copy> {
    duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}

tasks.optimizedNativeJar {
    duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}

tasks.optimizedJitJar {
    duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}

tasks.jar {
    duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
tasks.runnerJar {
    duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}

videomodule gradle build:

plugins {
    id("buildsrc.convention.kotlin-jvm")
    id("com.google.devtools.ksp") version "2.1.21-2.0.1"
    id("org.jetbrains.kotlin.kapt")
}

dependencies {
    // video module deps
    implementation("org.bytedeco:javacv:1.5.12")
    implementation("org.bytedeco:ffmpeg-platform:7.1.1-1.5.12")
    implementation("org.yaml:snakeyaml:2.5")

}

Run-Time Log Output and Error Messages

No response

YagodinArtem avatar Sep 11 '25 08:09 YagodinArtem

Thank you for reaching out about this, we will take a look into this shortly

oubidar-Abderrahim avatar Sep 12 '25 09:09 oubidar-Abderrahim

Hi all. I have the exact same issue and struggle since 3 weeks to get this work in vain. The code works in JIT mode but fails to load library awt in native.

meetynee avatar Oct 08 '25 16:10 meetynee

I don't think this is an issue at all. Using AWT merely requires some reflective access, JNI access etc., so native tracing agent is needed to assess what json config your app needs.

Karm avatar Oct 09 '25 12:10 Karm

Hi Karm,

Thanks for your response. I just succeeded to make it works 10 mn ago by compiling the native image with the option --static-nolibc / -H:+StaticExecutableWithDynamicLibC, copying the shared libraries (.so) alongside the executable (same directory). The list is provided by the native-image console output (see below my particular case) and by providing the -Djava.library.path=./ as arg of the executable (not sure yet that the later is mandatory).


#46 166.4 12.9s (9.1% of total time) in 1854 GCs | Peak RSS: 4.40GB | CPU load: 7.61 #46 166.4 ------------------------------------------------------------------------------------------------------------------------ #46 166.4 Build artifacts: #46 166.4 //target/libawt.so (jdk_library) #46 166.4 //target/libawt_headless.so (jdk_library) #46 166.4 //target/target/libawt_xawt.so (jdk_library) #46 166.4 //target/libfontmanager.so (jdk_library) #46 166.4 //target/libjava.so (jdk_library_shim) #46 166.4 //target/libjavajpeg.so (jdk_library) #46 166.4 //target/libjvm.so (jdk_library_shim) #46 166.4 //target/liblcms.so (jdk_library) #46 166.4 //target/my-native-binary (executable)

Thanks a lot for your help and the great work provided by the GraalVM squad. Cheers. J-Hugues

meetynee avatar Oct 09 '25 12:10 meetynee

thank`s for your response guys, i am already get rid of this dependency, so that issue is no more affecting my project.

YagodinArtem avatar Oct 13 '25 14:10 YagodinArtem