Repository: quarkusio/quarkus
Pull request #46731: native-image: Graal's ForeignAPISupport is amd64 only
Author: login: Karm
Labels: name: area/documentation
name: area/core
name: area/graphics
name: kind/bugfix
name: triage/flaky-test
name: triage/backport-3.20
Created: 2025-03-11T16:22:42Z | Merged: 2025-03-14T12:18:11Z

Fixes #46235
Fixes #46988

Summary:

* We don't have MacOS support for AWT extension yet. It might be trivial, but it's not coded in yet, so the extension needs to bail out just like on Windows. I am afraid that not having MacOS excluded via `UnsupportedOSBuildItem` is an artifact of moving DarwinFeature to AWT extension. The result is that the **build** might pass, but the Quarkus app **won't start**. If that is the desired design, we should allow the same on Windows and remove its `UnsupportedOSBuildItem`. I think the DarwinFeature previously was in core on purpose, to allow for building apps that effectively won't need to initialize AWT at runtime, i.e. don't need full AWT extension.  @zakkak ? Ideas?

* GraalVM has FFI/FFM implemented for amd64 arch only, so effectively starting Mandrel/GraalVM 24.2, i.e. Mandrel for JDK 24, we are **losing AWT support on Linux aarch64 where it used to work**

* UBI9's microdnf requires `-y`, so container tests hanged on `Is this ok [y/N]:`

* I tested all combinations that made sense to me and where I had access to HW, e.g. I skipped natively amd64 based MacOS. I used either our Mandrel 24.2 / JDK 24 ea builds or GraalVM CE 25 ea dev builds.

* :green_circle:  - run went as expected; spoiler alert: All runs went as expected.

# Tested

## Windows amd64 hosted :green_circle: 
**Expected:** :orange_circle: - SKIPPED, AWT Quarkus unsupported OS
**Actual:** :orange_circle:

```
C:\tmp\quarkus(issue-46235 -> origin)
λ mvnw verify -f integration-tests/pom.xml -pl awt  -Pnative
    -Dquarkus.native.container-build=false -Dquarkus.container-image.build=false -DskipITs=false

[ERROR] Caused by: java.lang.UnsupportedOperationException:
Windows AWT integration is not ready in Quarkus native-image and would result in java.lang.UnsatisfiedLinkError: no awt in java.library.path.
```

## Windows amd64 with Linux amd64 builder image :green_circle: 
**Expected:** :green_circle:
**Actual:**  :green_circle:

```
λ mvnw verify -f integration-tests/pom.xml -pl awt -Pnative 
    -Dquarkus.native.builder-image=quay.io/karmkarm/ubi9-quarkus-mandrel-builder-image:jdk-24-amd64
    -Dquarkus.native.container-build=true -Dquarkus.container-image.build=true 
...

Finished generating 'quarkus-integration-test-awt-999-SNAPSHOT-runner' in 15m 51s.
...
[INFO] [io.quarkus.container.image.docker.common.deployment.CommonProcessor]
Executing the following command to build image: 
'podman build -f C:\tmp\quarkus\integration-tests\awt\src\main\docker\Dockerfile.native -t karm/quarkus-integration-test-awt:999-SNAPSHOT C:\tmp\quarkus\integration-tests\awt'
...
INFO  [io.qua.tes.com.DefaultDockerContainerLauncher] (main) 
Executing "podman run --name quarkus-integration-test-GQcdk -i --rm -p 8081:8081 -p 8444:8444 --net=quarkus-integration-test-UNOtv --env QUARKUS_LOG_CATEGORY__IO_QUARKUS__LEVEL=INFO --env QUARKUS_HTTP_PORT=8081 --env QUARKUS_HTTP_SSL_PORT=8444 --env TEST_URL=http://localhost:8081 --env QUARKUS_PROFILE=prod --env QUARKUS_CONTAINER_IMAGE_BUILD=true --env QUARKUS_NATIVE_CONTAINER_BUILD=true --env QUARKUS_NATIVE_BUILDER_IMAGE=quay.io/karmkarm/ubi9-quarkus-mandrel-builder-image:jdk-24-amd64 karm/quarkus-integration-test-awt:999-SNAPSHOT"
...
[INFO] Tests run: 41, Failures: 0, Errors: 0, Skipped: 0

```

## MacOS aarch64 hosted :green_circle:
**Expected:** :orange_circle: - SKIPPED, AWT Quarkus unsupported OS
**Actual:** :orange_circle:

```
[ERROR] Caused by: java.lang.UnsupportedOperationException:
    MacOS AWT integration is not ready in Quarkus native-image and would result in
    java.lang.UnsatisfiedLinkError: Can't load library: awt | java.library.path = [.].,
    AWT needs JDK's JEP 454 FFI/FFM support and that is not available for AArch64 with GraalVM's native-image,
    see: https://www.graalvm.org/latest/reference-manual/native-image/native-code-interoperability/foreign-interface/#foreign-functions
```

## MacOS amd64 (via Rosetta) hosted :green_circle:
**Expected:** :orange_circle: - SKIPPED, AWT Quarkus unsupported OS
**Actual:** :orange_circle:

```
[ERROR] Caused by: java.lang.UnsupportedOperationException:
    MacOS AWT integration is not ready in Quarkus native-image and would result in
    java.lang.UnsatisfiedLinkError: Can't load library: awt | java.library.path = [.].
```

## MacOS amd64 with Linux amd64 builder

N/A - I don't have access to such HW and I don't want to try to
remove Podman machine from my MacOS aarch64 systems and try to run
podman there via Rosetta. It should work just like Windows above :-)


## MacOS aarch64 with Linux aarch64 builder image :green_circle:
**Expected:** :orange_circle: - SKIPPED, ForeignAPISupport is amd64 only
**Actual:** :orange_circle:

```
[ERROR] Caused by: java.lang.UnsupportedOperationException:
    AWT needs JDK's JEP 454 FFI/FFM support and that is not available for AArch64 with GraalVM's native-image,
    see: https://www.graalvm.org/latest/reference-manual/native-image/native-code-interoperability/foreign-interface/#foreign-functions
```

## Linux amd64 hosted :green_circle:
**Expected:** :green_circle:
**Actual:** :green_circle:

```
$ ./mvnw verify -f integration-tests/pom.xml -pl awt  -Pnative
    -Dquarkus.native.container-build=false -Dquarkus.container-image.build=false -DskipITs=false 
OK
```

## Linux amd64 with Linux amd64 builder image :green_circle:
**Expected:** :green_circle:
**Actual:** :green_circle:

```
$ ./mvnw verify -f integration-tests/pom.xml -pl awt -Pnative
    -Dquarkus.native.builder-image=quay.io/karmkarm/ubi9-quarkus-mandrel-builder-image:jdk-24-amd64
    -Dquarkus.native.container-build=true -Dquarkus.container-image.build=true
OK
```

## Linux aarch64 hosted :green_circle:
**Expected:** :orange_circle: - SKIPPED, ForeignAPISupport is amd64 only
**Actual:** :orange_circle:

```
$ ./mvnw verify -f integration-tests/pom.xml -pl awt  -Pnative
    -Dquarkus.native.container-build=false -Dquarkus.container-image.build=false -DskipITs=false 

[ERROR] Caused by: java.lang.UnsupportedOperationException:
    AWT needs JDK's JEP 454 FFI/FFM support and that is not available for AArch64 with GraalVM's native-image,
    see: https://www.graalvm.org/latest/reference-manual/native-image/native-code-interoperability/foreign-interface/#foreign-functions
```

## Linux aarch64 with Linux aarch64 builder image :green_circle:
**Expected:** :orange_circle: - SKIPPED, ForeignAPISupport is amd64 only
**Actual:** :orange_circle:

```
$ ./mvnw verify -f integration-tests/pom.xml -pl awt -Pnative
    -Dquarkus.native.builder-image=quay.io/karmkarm/ubi9-quarkus-mandrel-builder-image:jdk-24-aarch64
    -Dquarkus.native.container-build=true -Dquarkus.container-image.build=true -DskipITs=false

[ERROR] Caused by: java.lang.UnsupportedOperationException:
    AWT needs JDK's JEP 454 FFI/FFM support and that is not available for AArch64 with GraalVM's native-image,
    see: https://www.graalvm.org/latest/reference-manual/native-image/native-code-interoperability/foreign-interface/#foreign-functions
```

Thanks for feedback

Linked issue #46235: Native images fail to build on aarch64 mac with latest GraalVM master
Error:

```
Internal exception: com.oracle.svm.core.util.UserError$UserException: Support for the Foreign Function and Memory API is currently available only on the AMD64 architecture.
```

This is probably caused by the Quarkus code in https://github.com/quarkusio/quarkus/blob/main/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/NativeImageBuildStep.java#L857-L865 combined with latest changes in GraalVM master.

Linked issue comments: user: login: quarkus-bot[bot]
created_at: 2025-02-12T15:09:28Z
body: /cc @Karm (native-image), @zakkak (native-image)
author_association: NONE
user: login: Karm
created_at: 2025-02-12T15:11:13Z
body: https://www.graalvm.org/latest/reference-manual/native-image/native-code-interoperability/foreign-interface/#foreign-functions
author_association: MEMBER
user: login: Karm
created_at: 2025-03-11T13:17:37Z
body: Fixing it now, prior to JDK 24 / Mandrel 24.2.0 release...
author_association: MEMBER

Diff:
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/UnsupportedOSBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/UnsupportedOSBuildItem.java
index b3663d1768fd9..60d770f3e71c6 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/UnsupportedOSBuildItem.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/UnsupportedOSBuildItem.java
@@ -11,10 +11,14 @@
  * extension on a given OS or architecture.
  */
 public final class UnsupportedOSBuildItem extends MultiBuildItem {
+
+    public static String ARCH = System.getProperty("os.arch");
+
     public enum Os {
         WINDOWS(IS_WINDOWS),
         MAC(IS_MAC),
-        LINUX(IS_LINUX);
+        LINUX(IS_LINUX),
+        NONE(false);
 
         public final boolean active;
 
@@ -23,11 +27,37 @@ public enum Os {
         }
     }
 
+    public enum Arch {
+        AMD64("amd64".equalsIgnoreCase(ARCH)),
+        AARCH64("aarch64".equalsIgnoreCase(ARCH)),
+        NONE(false);
+
+        public final boolean active;
+
+        Arch(boolean active) {
+            this.active = active;
+        }
+    }
+
     public final Os os;
+    public final Arch arch;
     public final String error;
 
     public UnsupportedOSBuildItem(Os os, String error) {
         this.os = os;
+        this.arch = Arch.NONE;
+        this.error = error;
+    }
+
+    public UnsupportedOSBuildItem(Arch arch, String error) {
+        this.os = Os.NONE;
+        this.arch = arch;
+        this.error = error;
+    }
+
+    public UnsupportedOSBuildItem(Os os, Arch arch, String error) {
+        this.os = os;
+        this.arch = arch;
         this.error = error;
     }
 
@@ -35,10 +65,14 @@ public boolean triggerError(boolean isContainerBuild) {
         return
         // When the host OS is unsupported, it could have helped to
         // run in a Linux builder image (e.g. an extension unsupported on Windows).
-        (os.active && !isContainerBuild) ||
+        ((os.active && !isContainerBuild) ||
         // If Linux is the OS the extension does not support,
         // it fails in a container build regardless the host OS,
         // because we have only Linux based builder images.
-                (isContainerBuild && os == Os.LINUX);
+                (isContainerBuild && os == Os.LINUX)) ||
+        // We don't do cross-compilation, even builder images have to be
+        // of the same arch, e.g. aarch64 Mac using aarch64 Linux builder image.
+        // So if the arch is unsupported, it fails.
+                arch.active;
     }
 }
diff --git a/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/NativeImageBuildStep.java b/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/NativeImageBuildStep.java
index a2d57bf31bcff..1166999ef90e7 100644
--- a/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/NativeImageBuildStep.java
+++ b/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/NativeImageBuildStep.java
@@ -1,5 +1,7 @@
 package io.quarkus.deployment.pkg.steps;
 
+import static io.quarkus.deployment.builditem.nativeimage.UnsupportedOSBuildItem.Arch.AMD64;
+
 import java.io.File;
 import java.io.IOException;
 import java.io.UncheckedIOException;
@@ -855,12 +857,15 @@ public NativeImageInvokerInfo build() {
                 addExperimentalVMOption(nativeImageArgs, "-H:+AllowFoldMethods");
 
                 /*
+                 * @formatter:off
                  * Foreign Function and Memory API in Native Image, JDK's JEP 454
                  * This is needed for JDK 24+ internal native calls due to AWT,
                  * e.g. JDK-8337237 et al.
-                 *
+                 * Note GraalVM FFI/FFM support per platform:
+                 * https://www.graalvm.org/latest/reference-manual/native-image/native-code-interoperability/foreign-interface/#foreign-functions
+                 * @formatter:on
                  */
-                if (graalVMVersion.compareTo(GraalVM.Version.VERSION_24_2_0) >= 0) {
+                if (graalVMVersion.compareTo(GraalVM.Version.VERSION_24_2_0) >= 0 && AMD64.active) {
                     addExperimentalVMOption(nativeImageArgs, "-H:+ForeignAPISupport");
                 }
 
diff --git a/core/runtime/src/main/java/io/quarkus/runtime/graal/GraalVM.java b/core/runtime/src/main/java/io/quarkus/runtime/graal/GraalVM.java
index 4a127e33a214b..945f26324bbc6 100644
--- a/core/runtime/src/main/java/io/quarkus/runtime/graal/GraalVM.java
+++ b/core/runtime/src/main/java/io/quarkus/runtime/graal/GraalVM.java
@@ -68,6 +68,7 @@ public static class Version implements Comparable<Version> {
 
         public static final Version VERSION_23_0_0 = new Version("GraalVM 23.0.0", "23.0.0", "17", Distribution.GRAALVM);
         public static final Version VERSION_23_1_0 = new Version("GraalVM 23.1.0", "23.1.0", "21", Distribution.GRAALVM);
+        public static final Version VERSION_24_2_0 = new Version("GraalVM 24.2.0", "24.2.0", "24", Distribution.GRAALVM);
 
         // Temporarily work around https://github.com/quarkusio/quarkus/issues/36246,
         // till we have a consensus on how to move forward in
diff --git a/extensions/awt/deployment/src/main/java/io/quarkus/awt/deployment/AwtProcessor.java b/extensions/awt/deployment/src/main/java/io/quarkus/awt/deployment/AwtProcessor.java
index e9664e1cb25e4..16cd9ff472703 100644
--- a/extensions/awt/deployment/src/main/java/io/quarkus/awt/deployment/AwtProcessor.java
+++ b/extensions/awt/deployment/src/main/java/io/quarkus/awt/deployment/AwtProcessor.java
@@ -1,6 +1,9 @@
 package io.quarkus.awt.deployment;
 
+import static io.quarkus.deployment.builditem.nativeimage.UnsupportedOSBuildItem.Arch.AARCH64;
+import static io.quarkus.deployment.builditem.nativeimage.UnsupportedOSBuildItem.Os.MAC;
 import static io.quarkus.deployment.builditem.nativeimage.UnsupportedOSBuildItem.Os.WINDOWS;
+import static io.quarkus.runtime.graal.GraalVM.Version.CURRENT;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -27,6 +30,8 @@
 import io.quarkus.deployment.pkg.builditem.ProcessInheritIODisabled;
 import io.quarkus.deployment.pkg.builditem.ProcessInheritIODisabledBuildItem;
 import io.quarkus.deployment.pkg.steps.NativeOrNativeSourcesBuild;
+import io.quarkus.deployment.pkg.steps.NoopNativeImageBuildRunner;
+import io.quarkus.runtime.graal.GraalVM;
 
 class AwtProcessor {
 
@@ -44,10 +49,28 @@ void nativeImageFeatures(BuildProducer<NativeImageFeatureBuildItem> nativeImageF
     }
 
     @BuildStep(onlyIf = NativeOrNativeSourcesBuild.class)
-    UnsupportedOSBuildItem osSupportCheck() {
-        return new UnsupportedOSBuildItem(WINDOWS,
-                "Windows AWT integration is not ready in native-image and would result in " +
-                        "java.lang.UnsatisfiedLinkError: no awt in java.library.path.");
+    void supportCheck(BuildProducer<UnsupportedOSBuildItem> unsupported,
+            NativeImageRunnerBuildItem nativeImageRunnerBuildItem) {
+        unsupported.produce(new UnsupportedOSBuildItem(WINDOWS,
+                "Windows AWT integration is not ready in Quarkus native-image and would result in " +
+                        "java.lang.UnsatisfiedLinkError: no awt in java.library.path."));
+        unsupported.produce(new UnsupportedOSBuildItem(MAC,
+                "MacOS AWT integration is not ready in Quarkus native-image and would result in " +
+                        "java.lang.UnsatisfiedLinkError: Can't load library: awt | java.library.path = [.]."));
+        final GraalVM.Version v;
+        if (nativeImageRunnerBuildItem.getBuildRunner() instanceof NoopNativeImageBuildRunner) {
+            v = CURRENT;
+            log.warnf("native-image is not installed. " +
+                    "Using the default %s version as a reference to build native-sources step.", v.getVersionAsString());
+        } else {
+            v = nativeImageRunnerBuildItem.getBuildRunner().getGraalVMVersion();
+        }
+        if (v.compareTo(GraalVM.Version.VERSION_24_2_0) >= 0) {
+            unsupported.produce(new UnsupportedOSBuildItem(AARCH64,
+                    "AWT needs JDK's JEP 454 FFI/FFM support and that is not available for AArch64 with " +
+                            "GraalVM's native-image, see: " +
+                            "https://www.graalvm.org/latest/reference-manual/native-image/native-code-interoperability/foreign-interface/#foreign-functions"));
+        }
     }
 
     @BuildStep(onlyIf = NativeOrNativeSourcesBuild.class)


Reviews:
user: login: zakkak
body: LGTM.

>  I think the DarwinFeature previously was in core on purpose, to allow for building apps that effectively won't need to initialize AWT at runtime, i.e. don't need full AWT extension.

By `DarwinFeature` are you referring to https://github.com/quarkusio/quarkus/blob/main/extensions/awt/runtime/src/main/java/io/quarkus/awt/runtime/graal/DarwinAwtFeature.java ?

AFAIS it was always under the awt extension https://github.com/quarkusio/quarkus/pull/21566

> The result is that the build might pass, but the Quarkus app won't start. If that is the desired design,

No, I don't think this is desired. Reporting it as unsupported seems the right thing to me.

> GraalVM has FFI/FFM implemented for amd64 arch only, so effectively starting Mandrel/GraalVM 24.2, i.e. Mandrel for JDK 24, we are losing AWT support on Linux aarch64 where it used to work

We will need to list this as a known issue, in the migration guide I guess.

> UBI9's microdnf requires `-y`, so container tests hanged on `Is this ok [y/N]:`

Good catch, I think we need this in ASAP. So if this PR ends up being delayed I would suggest openning a separate PR with just 1de05f29046ad663704bcbd6e96b7c8f0ccff9d4

Thank you @Karm 
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-12T08:56:07Z
user: login: Karm
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-12T13:06:19Z
user: login: Karm
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-12T13:07:23Z
user: login: Karm
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-12T13:08:03Z
user: login: zakkak
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-12T18:51:33Z

Review comments:
diff_hunk: @@ -855,12 +857,15 @@ public NativeImageInvokerInfo build() {
                 addExperimentalVMOption(nativeImageArgs, "-H:+AllowFoldMethods");
 
                 /*
+                 * @formatter:off
                  * Foreign Function and Memory API in Native Image, JDK's JEP 454
                  * This is needed for JDK 24+ internal native calls due to AWT,
                  * e.g. JDK-8337237 et al.
-                 *
+                 * Note GraalVM FFI/FFM support per platform:
+                 * https://www.graalvm.org/latest/reference-manual/native-image/native-code-interoperability/foreign-interface/#foreign-functions
+                 * @formatter:on
                  */
-                if (graalVMVersion.compareTo(GraalVM.Version.VERSION_24_2_0) >= 0) {
+                if (graalVMVersion.compareTo(GraalVM.Version.VERSION_24_2_0) >= 0 && AMD64.active) {
path: core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/NativeImageBuildStep.java
user: login: zakkak
body: Given that we now handle AArch64 as unsupported, under which configuration do you expect to reach this? I would expect the build to fail sooner than this.
created_at: 2025-03-12T08:48:17Z
author_association: MEMBER
diff_hunk: @@ -855,12 +857,15 @@ public NativeImageInvokerInfo build() {
                 addExperimentalVMOption(nativeImageArgs, "-H:+AllowFoldMethods");
 
                 /*
+                 * @formatter:off
                  * Foreign Function and Memory API in Native Image, JDK's JEP 454
                  * This is needed for JDK 24+ internal native calls due to AWT,
                  * e.g. JDK-8337237 et al.
-                 *
+                 * Note GraalVM FFI/FFM support per platform:
+                 * https://www.graalvm.org/latest/reference-manual/native-image/native-code-interoperability/foreign-interface/#foreign-functions
+                 * @formatter:on
                  */
-                if (graalVMVersion.compareTo(GraalVM.Version.VERSION_24_2_0) >= 0) {
+                if (graalVMVersion.compareTo(GraalVM.Version.VERSION_24_2_0) >= 0 && AMD64.active) {
path: core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/NativeImageBuildStep.java
user: login: Karm
body: I am not sure I follow. It is not AWT specific, it's just that AWT was the first obvious hit. 
AMD64 Linux, Windows and also MacOS are able to use [FFI/FFM](https://www.graalvm.org/latest/reference-manual/native-image/native-code-interoperability/foreign-interface/#foreign-functions).

e.g. if jline hadn't some other issue, this would have made it work on Windows amd64.

created_at: 2025-03-12T13:06:19Z
author_association: MEMBER
diff_hunk: @@ -855,12 +857,15 @@ public NativeImageInvokerInfo build() {
                 addExperimentalVMOption(nativeImageArgs, "-H:+AllowFoldMethods");
 
                 /*
+                 * @formatter:off
                  * Foreign Function and Memory API in Native Image, JDK's JEP 454
                  * This is needed for JDK 24+ internal native calls due to AWT,
                  * e.g. JDK-8337237 et al.
-                 *
+                 * Note GraalVM FFI/FFM support per platform:
+                 * https://www.graalvm.org/latest/reference-manual/native-image/native-code-interoperability/foreign-interface/#foreign-functions
+                 * @formatter:on
                  */
-                if (graalVMVersion.compareTo(GraalVM.Version.VERSION_24_2_0) >= 0) {
+                if (graalVMVersion.compareTo(GraalVM.Version.VERSION_24_2_0) >= 0 && AMD64.active) {
path: core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/NativeImageBuildStep.java
user: login: Karm
body: >  I would expect the build to fail sooner than this.

Build doesn't fail, it just doesn't include the unsupported feature, flag.
created_at: 2025-03-12T13:07:23Z
author_association: MEMBER
diff_hunk: @@ -855,12 +857,15 @@ public NativeImageInvokerInfo build() {
                 addExperimentalVMOption(nativeImageArgs, "-H:+AllowFoldMethods");
 
                 /*
+                 * @formatter:off
                  * Foreign Function and Memory API in Native Image, JDK's JEP 454
                  * This is needed for JDK 24+ internal native calls due to AWT,
                  * e.g. JDK-8337237 et al.
-                 *
+                 * Note GraalVM FFI/FFM support per platform:
+                 * https://www.graalvm.org/latest/reference-manual/native-image/native-code-interoperability/foreign-interface/#foreign-functions
+                 * @formatter:on
                  */
-                if (graalVMVersion.compareTo(GraalVM.Version.VERSION_24_2_0) >= 0) {
+                if (graalVMVersion.compareTo(GraalVM.Version.VERSION_24_2_0) >= 0 && AMD64.active) {
path: core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/NativeImageBuildStep.java
user: login: Karm
body: It's the AWT extension that actively fails the build with an error message *if* you happen to use AWT extension.
created_at: 2025-03-12T13:08:03Z
author_association: MEMBER
diff_hunk: @@ -855,12 +857,15 @@ public NativeImageInvokerInfo build() {
                 addExperimentalVMOption(nativeImageArgs, "-H:+AllowFoldMethods");
 
                 /*
+                 * @formatter:off
                  * Foreign Function and Memory API in Native Image, JDK's JEP 454
                  * This is needed for JDK 24+ internal native calls due to AWT,
                  * e.g. JDK-8337237 et al.
-                 *
+                 * Note GraalVM FFI/FFM support per platform:
+                 * https://www.graalvm.org/latest/reference-manual/native-image/native-code-interoperability/foreign-interface/#foreign-functions
+                 * @formatter:on
                  */
-                if (graalVMVersion.compareTo(GraalVM.Version.VERSION_24_2_0) >= 0) {
+                if (graalVMVersion.compareTo(GraalVM.Version.VERSION_24_2_0) >= 0 && AMD64.active) {
path: core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/NativeImageBuildStep.java
user: login: zakkak
body: Uh right we are always enabling FFM not just for AWT. Sorry for the noise.
created_at: 2025-03-12T18:51:33Z
author_association: MEMBER

PR comments:
user: login: quarkus-bot[bot]
created_at: 2025-03-11T16:22:46Z
body: Thanks for your pull request!

Your pull request does not follow our editorial rules. Could you have a look?

- title should preferably start with an uppercase character (if it makes sense!)

<sub>This message is automatically generated by a bot.</sub>
author_association: NONE
user: login: quarkus-bot[bot]
created_at: 2025-03-11T16:23:03Z
body: /cc @galderz (awt)
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-03-11T20:25:51Z
body: 🎊 PR Preview 784377702aac39824e932ff4c48ce44f0e68b3bd has been successfully built and deployed to https://quarkus-pr-main-46731-preview.surge.sh/version/main/guides/

- Images of blog posts older than 3 months are not available.
- Newsletters older than 3 months are not available.

<img width="300" src="https://user-images.githubusercontent.com/507615/90250366-88233900-de6e-11ea-95a5-84f0762ffd39.png">


<!-- Preview status comment marker -->
author_association: NONE
user: login: quarkus-bot[bot]
created_at: 2025-03-11T23:39:52Z
body: ---
> :waning_crescent_moon: **_This workflow status is outdated as a new workflow run has been triggered._**
---

# Status for workflow `Quarkus CI`

This is the status report for running `Quarkus CI` on commit 1de05f29046ad663704bcbd6e96b7c8f0ccff9d4.



:white_check_mark: The latest workflow run for the pull request has completed successfully.

It should be safe to merge provided you have a look at the other checks in the summary.

You can consult the [Develocity build scans](https://github.com/quarkusio/quarkus/runs/38601308891).


---

## Flaky tests - <a href="https://ge.quarkus.io/scans/tests">Develocity</a>

### :gear: JVM Tests - JDK 17

#### :package: core/deployment

<p>✖ <code>io.quarkus.deployment.dev.FileSystemWatcherTestCase.testFileSystemWatcher</code> - <a href="https://ge.quarkus.io/scans/tests?tests.container=io.quarkus.deployment.dev.FileSystemWatcherTestCase&tests.test=testFileSystemWatcher">History</a></p>

- `expected: not <null>` - `org.opentest4j.AssertionFailedError`

<details>

```
org.opentest4j.AssertionFailedError: expected: not <null>
	at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:152)
	at org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:132)
	at org.junit.jupiter.api.AssertNotNull.failNull(AssertNotNull.java:49)
	at org.junit.jupiter.api.AssertNotNull.assertNotNull(AssertNotNull.java:35)
	at org.junit.jupiter.api.AssertNotNull.assertNotNull(AssertNotNull.java:30)
	at org.junit.jupiter.api.Assertions.assertNotNull(Assertions.java:304)
	at io.quarkus.deployment.dev.FileSystemWatcherTestCase.consumeEvents(FileSystemWatcherTestCase.java:169)
```

</details>


#### :package: extensions/smallrye-reactive-messaging-kafka/deployment

<p>✖ <code>io.quarkus.smallrye.reactivemessaging.kafka.deployment.testing.KafkaDevServicesContinuousTestingWorkingAppPropsTestCase.testContinuousTestingScenario3</code> - <a href="https://ge.quarkus.io/scans/tests?tests.container=io.quarkus.smallrye.reactivemessaging.kafka.deployment.testing.KafkaDevServicesContinuousTestingWorkingAppPropsTestCase&tests.test=testContinuousTestingScenario3">History</a></p>

- `io.quarkus.builder.BuildException: Build failure: Build failed due to errors
 [error]: Build step io.quarkus.redis.deployment.client.DevServicesRedisProcessor\#startRedisContainers threw an exception: java.lang.RuntimeException: org.testcontainers.containers.ContainerLaunchException: Container startup failed for image docker.io/redis:7
 at io.quarkus.redis.deployment.client.DevServicesRedisProcessor.startRedisContainers(DevServicesRedisProcessor.java:124)
 at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:732)
 at io.quarkus.deployment.ExtensionLoader$3.execute(ExtensionLoader.java:856)` - `java.lang.RuntimeException`

<details>

```
java.lang.RuntimeException: 
io.quarkus.builder.BuildException: Build failure: Build failed due to errors
	[error]: Build step io.quarkus.redis.deployment.client.DevServicesRedisProcessor#startRedisContainers threw an exception: java.lang.RuntimeException: org.testcontainers.containers.ContainerLaunchException: Container startup failed for image docker.io/redis:7
	at io.quarkus.redis.deployment.client.DevServicesRedisProcessor.startRedisContainers(DevServicesRedisProcessor.java:124)
	at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:732)
	at io.quarkus.deployment.ExtensionLoader$3.execute(ExtensionLoader.java:856)
	at io.quarkus.builder.BuildContext.run(BuildContext.java:255)
	at org.jboss.threads.ContextHandler$1.runWith(ContextHandler.java:18)
```

</details>



---

### :gear: JVM Tests - JDK 21

#### :package: extensions/micrometer-opentelemetry/deployment

<p>✖ <code>io.quarkus.micrometer.opentelemetry.deployment.compatibility.MicrometerTimedInterceptorTest.testTimeMethod_LongTaskTimer_UniFailed</code> - <a href="https://ge.quarkus.io/scans/tests?tests.container=io.quarkus.micrometer.opentelemetry.deployment.compatibility.MicrometerTimedInterceptorTest&tests.test=testTimeMethod_LongTaskTimer_UniFailed">History</a></p>

- `expected: <0> but was: <1>` - `org.opentest4j.AssertionFailedError`

<details>

```
org.opentest4j.AssertionFailedError: expected: <0> but was: <1>
	at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:151)
	at org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:132)
	at org.junit.jupiter.api.AssertEquals.failNotEqual(AssertEquals.java:197)
	at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:166)
	at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:161)
	at org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:632)
	at io.quarkus.micrometer.opentelemetry.deployment.compatibility.MicrometerTimedInterceptorTest.testTimeMethod_LongTaskTimer_UniFailed(MicrometerTimedInterceptorTest.java:286)
```

</details>



---

### :gear: JVM Tests - JDK 17 Windows

#### :package: extensions/micrometer/deployment

<p>✖ <code>io.quarkus.micrometer.deployment.binder.VertxTcpMetricsNoClientMetricsTest.testTcpMetricsWithoutClientMetrics</code> - <a href="https://ge.quarkus.io/scans/tests?tests.container=io.quarkus.micrometer.deployment.binder.VertxTcpMetricsNoClientMetricsTest&tests.test=testTcpMetricsWithoutClientMetrics">History</a></p>

- `event executor terminated` - `java.util.concurrent.RejectedExecutionException`

<details>

```
java.util.concurrent.RejectedExecutionException: event executor terminated
	at io.netty.util.concurrent.SingleThreadEventExecutor.reject(SingleThreadEventExecutor.java:934)
	at io.netty.util.concurrent.SingleThreadEventExecutor.offerTask(SingleThreadEventExecutor.java:353)
	at io.netty.util.concurrent.SingleThreadEventExecutor.addTask(SingleThreadEventExecutor.java:346)
	at io.netty.util.concurrent.SingleThreadEventExecutor.execute(SingleThreadEventExecutor.java:836)
	at io.netty.util.concurrent.SingleThreadEventExecutor.execute0(SingleThreadEventExecutor.java:827)
	at io.netty.util.concurrent.SingleThreadEventExecutor.execute(SingleThreadEventExecutor.java:817)
	at io.vertx.core.impl.EventLoopExecutor.execute(EventLoopExecutor.java:35)
```

</details>


#### :package: extensions/websockets-next/deployment

<p>✖ <code>io.quarkus.websockets.next.test.telemetry.MicrometerWebSocketsOnErrorTest.testClientEndpointError_ExceptionInsideOnTextMessage_WithOverloadedOnError</code> - <a href="https://ge.quarkus.io/scans/tests?tests.container=io.quarkus.websockets.next.test.telemetry.MicrometerWebSocketsOnErrorTest&tests.test=testClientEndpointError_ExceptionInsideOnTextMessage_WithOverloadedOnError">History</a></p>

- `Assertion condition defined as a Lambda expression in io.quarkus.websockets.next.test.telemetry.MetricsAsserter 1 expectation failed.
Response body doesn't match expectation.
Expected: Key 'quarkus_websockets_server_endpoint_count_errors_total' with value '4' and direction 'null'
  Actual: \# TYPE netty_allocator_pooled_cache_size gauge
\# HELP netty_allocator_pooled_cache_size  ` - `org.awaitility.core.ConditionTimeoutException`

<details>

```
org.awaitility.core.ConditionTimeoutException: 
Assertion condition defined as a Lambda expression in io.quarkus.websockets.next.test.telemetry.MetricsAsserter 1 expectation failed.
Response body doesn't match expectation.
Expected: Key 'quarkus_websockets_server_endpoint_count_errors_total' with value '4' and direction 'null'
  Actual: # TYPE netty_allocator_pooled_cache_size gauge
# HELP netty_allocator_pooled_cache_size  
netty_allocator_pooled_cache_size{allocator_type="PooledByteBufAllocator",cache_type="small",name="pooled"} 256.0
netty_allocator_pooled_cache_size{allocator_type="PooledByteBufAllocator",cache_type="normal",name="vertx-pooled"} 64.0
```

</details>


<p>✖ <code>io.quarkus.websockets.next.test.telemetry.MicrometerWebSocketsOnErrorTest.testClientEndpointError_ExceptionInsideOnTextMessage_noExplicitOnErrorDefined</code> - <a href="https://ge.quarkus.io/scans/tests?tests.container=io.quarkus.websockets.next.test.telemetry.MicrometerWebSocketsOnErrorTest&tests.test=testClientEndpointError_ExceptionInsideOnTextMessage_noExplicitOnErrorDefined">History</a></p>

- `Assertion condition defined as a Lambda expression in io.quarkus.websockets.next.test.telemetry.MetricsAsserter 1 expectation failed.
Response body doesn't match expectation.
Expected: Key 'quarkus_websockets_server_endpoint_count_errors_total' with value '3' and direction 'null'
  Actual: \# TYPE netty_allocator_pooled_cache_size gauge
\# HELP netty_allocator_pooled_cache_size  ` - `org.awaitility.core.ConditionTimeoutException`

<details>

```
org.awaitility.core.ConditionTimeoutException: 
Assertion condition defined as a Lambda expression in io.quarkus.websockets.next.test.telemetry.MetricsAsserter 1 expectation failed.
Response body doesn't match expectation.
Expected: Key 'quarkus_websockets_server_endpoint_count_errors_total' with value '3' and direction 'null'
  Actual: # TYPE netty_allocator_pooled_cache_size gauge
# HELP netty_allocator_pooled_cache_size  
netty_allocator_pooled_cache_size{allocator_type="PooledByteBufAllocator",cache_type="small",name="pooled"} 256.0
netty_allocator_pooled_cache_size{allocator_type="PooledByteBufAllocator",cache_type="normal",name="vertx-pooled"} 64.0
```

</details>


<p>✖ <code>io.quarkus.websockets.next.test.telemetry.MicrometerWebSocketsOnErrorTest.testServerEndpointError_ExceptionInsideOnOpen</code> - <a href="https://ge.quarkus.io/scans/tests?tests.container=io.quarkus.websockets.next.test.telemetry.MicrometerWebSocketsOnErrorTest&tests.test=testServerEndpointError_ExceptionInsideOnOpen">History</a></p>

- `io.vertx.core.impl.NoStackTraceThrowable: WebSocket is closed` - `java.util.concurrent.CompletionException`

<details>

```
java.util.concurrent.CompletionException: io.vertx.core.impl.NoStackTraceThrowable: WebSocket is closed
	at java.base/java.util.concurrent.CompletableFuture.reportJoin(CompletableFuture.java:413)
	at java.base/java.util.concurrent.CompletableFuture.join(CompletableFuture.java:2118)
	at io.quarkus.websockets.next.test.utils.WSClient.await(WSClient.java:137)
	at io.quarkus.websockets.next.test.utils.WSClient.sendAndAwait(WSClient.java:96)
	at io.quarkus.websockets.next.test.telemetry.Connection.openConnectionThenSend(Connection.java:34)
	at io.quarkus.websockets.next.test.telemetry.MicrometerWebSocketsOnErrorTest.testServerEndpointError_ExceptionInsideOnOpen(MicrometerWebSocketsOnErrorTest.java:201)
	at java.base/java.lang.reflect.Method.invoke(Method.java:569)
```

</details>


<p>✖ <code>io.quarkus.websockets.next.test.telemetry.MicrometerWebSocketsOnErrorTest.testServerEndpointError_GlobalErrorHandler</code> - <a href="https://ge.quarkus.io/scans/tests?tests.container=io.quarkus.websockets.next.test.telemetry.MicrometerWebSocketsOnErrorTest&tests.test=testServerEndpointError_GlobalErrorHandler">History</a></p>

- `Assertion condition defined as a Lambda expression in io.quarkus.websockets.next.test.telemetry.MetricsAsserter 1 expectation failed.
Response body doesn't match expectation.
Expected: Key 'quarkus_websockets_server_endpoint_count_errors_total' with value '4' and direction 'null'
  Actual: \# TYPE netty_allocator_pooled_cache_size gauge
\# HELP netty_allocator_pooled_cache_size  ` - `org.awaitility.core.ConditionTimeoutException`

<details>

```
org.awaitility.core.ConditionTimeoutException: 
Assertion condition defined as a Lambda expression in io.quarkus.websockets.next.test.telemetry.MetricsAsserter 1 expectation failed.
Response body doesn't match expectation.
Expected: Key 'quarkus_websockets_server_endpoint_count_errors_total' with value '4' and direction 'null'
  Actual: # TYPE netty_allocator_pooled_cache_size gauge
# HELP netty_allocator_pooled_cache_size  
netty_allocator_pooled_cache_size{allocator_type="PooledByteBufAllocator",cache_type="small",name="pooled"} 256.0
netty_allocator_pooled_cache_size{allocator_type="PooledByteBufAllocator",cache_type="normal",name="vertx-pooled"} 64.0
```

</details>



<!-- Build-Reporter/msg-id:workflow-run-status-hidden:Quarkus CI -->
<!-- Build-Reporter/workflow-run-id:13797618306 -->
author_association: NONE
user: login: Karm
created_at: 2025-03-12T07:26:34Z
body: No idea why would Micrometer get flaky on this PR.  Do you understand the CI results @ebullient @brunobat?
author_association: MEMBER
user: login: gsmet
created_at: 2025-03-12T09:10:51Z
body: @Karm could you create a specific PR for the `microdnf` changes? This is something we want to backport right away. The rest of the PR requires more thoughts.
author_association: MEMBER
user: login: Karm
created_at: 2025-03-12T12:57:00Z
body: > @Karm could you create a specific PR for the `microdnf` changes? This is something we want to backport right away. The rest of the PR requires more thoughts.

@gsmet 

https://github.com/quarkusio/quarkus/pull/46763
author_association: MEMBER
user: login: Karm
created_at: 2025-03-12T14:16:31Z
body: @zakkak   Thanks for the review

> > I think the DarwinFeature previously was in core on purpose, to allow for building apps that effectively won't need to initialize AWT at runtime, i.e. don't need full AWT extension.
> 
> By `DarwinFeature` are you referring to https://github.com/quarkusio/quarkus/blob/main/extensions/awt/runtime/src/main/java/io/quarkus/awt/runtime/graal/DarwinAwtFeature.java ?
> 
> AFAIS it was always under the awt extension #21566

Hmm, I confused it with [AwtImageIO.java](https://github.com/quarkusio/quarkus/blob/main/core/runtime/src/main/java/io/quarkus/runtime/graal/AwtImageIO.java) as I was trying to reason about why wasn't macOS excluded too. You are right.
 
> > The result is that the build might pass, but the Quarkus app won't start. If that is the desired design,
> 
> No, I don't think this is desired. Reporting it as unsupported seems the right thing to me.

Ack.

> 
> > GraalVM has FFI/FFM implemented for amd64 arch only, so effectively starting Mandrel/GraalVM 24.2, i.e. Mandrel for JDK 24, we are losing AWT support on Linux aarch64 where it used to work
> 
> We will need to list this as a known issue, in the migration guide I guess.

Do I just edit this directly or is it generated?
https://github.com/quarkusio/quarkus/wiki/Migration-Guide-3.19
 
> > UBI9's microdnf requires `-y`, so container tests hanged on `Is this ok [y/N]:`
> 
> Good catch, I think we need this in ASAP. So if this PR ends up being delayed I would suggest openning a separate PR with just [1de05f2](https://github.com/quarkusio/quarkus/commit/1de05f29046ad663704bcbd6e96b7c8f0ccff9d4)

Ack. Done.
author_association: MEMBER
user: login: Karm
created_at: 2025-03-12T14:17:16Z
body: > The rest of the PR requires more thoughts.

@gsmet , any specific pointers?
author_association: MEMBER
user: login: zakkak
created_at: 2025-03-12T18:37:45Z
body: > Do I just edit this directly or is it generated?

Directly
author_association: MEMBER
user: login: brunobat
created_at: 2025-03-12T18:55:03Z
body: > No idea why would Micrometer get flaky on this PR. Do you understand the CI results @ebullient @brunobat?

Nope.
author_association: MEMBER
user: login: gsmet
created_at: 2025-03-13T16:02:51Z
body: > The rest of the PR requires more thoughts.

@Karm sorry, it was "more thoughts" as "if it was safe to be backported or not" :). Do you think we need a backport for this one?

I rebased to drop the additional commit and will merge when CI is green.
author_association: MEMBER
user: login: quarkus-bot[bot]
created_at: 2025-03-13T19:28:30Z
body: # Status for workflow `Quarkus CI`

This is the status report for running `Quarkus CI` on commit a04a213487ca0fa38f9dc6a506486770f78a4279.



:white_check_mark: The latest workflow run for the pull request has completed successfully.

It should be safe to merge provided you have a look at the other checks in the summary.

You can consult the [Develocity build scans](https://github.com/quarkusio/quarkus/runs/38734864086).


---

## Flaky tests - <a href="https://ge.quarkus.io/scans/tests">Develocity</a>

### :gear: JVM Tests - JDK 17 Windows

#### :package: extensions/micrometer-opentelemetry/deployment

<p>✖ <code>io.quarkus.micrometer.opentelemetry.deployment.compatibility.MicrometerTimedInterceptorTest.testTimeMethod_Uni</code> - <a href="https://ge.quarkus.io/scans/tests?tests.container=io.quarkus.micrometer.opentelemetry.deployment.compatibility.MicrometerTimedInterceptorTest&tests.test=testTimeMethod_Uni">History</a></p>

- `Stream has no elements` - `java.lang.IllegalArgumentException`

<details>

```
java.lang.IllegalArgumentException: Stream has no elements
	at io.quarkus.micrometer.opentelemetry.deployment.common.MetricDataFilter.lambda$lastReading$2(MetricDataFilter.java:213)
	at java.base/java.util.Optional.orElseThrow(Optional.java:403)
	at io.quarkus.micrometer.opentelemetry.deployment.common.MetricDataFilter.lastReading(MetricDataFilter.java:213)
	at io.quarkus.micrometer.opentelemetry.deployment.common.MetricDataFilter.lastReadingDataPoint(MetricDataFilter.java:231)
	at io.quarkus.micrometer.opentelemetry.deployment.compatibility.MicrometerTimedInterceptorTest.testTimeMethod_Uni(MicrometerTimedInterceptorTest.java:174)
	at java.base/java.lang.reflect.Method.invoke(Method.java:569)
	at io.quarkus.test.QuarkusUnitTest.runExtensionMethod(QuarkusUnitTest.java:521)
```

</details>



<!-- Build-Reporter/msg-id:workflow-run-status-active:Quarkus CI -->
<!-- Build-Reporter/workflow-run-id:13839126666 -->
author_association: NONE
user: login: zakkak
created_at: 2025-03-13T19:51:18Z
body: @gsmet I would only consider the part that handles

> We don't have MacOS support for AWT extension yet. It might be trivial, but it's not coded in yet, so the extension needs to bail out just like on Windows.

for backporting, but IMO it's not worth it. 
author_association: MEMBER
user: login: zakkak
created_at: 2025-03-13T20:57:02Z
body: @Karm it looks like AArch64 support will land in GraalVM for JDK 25, see https://github.com/oracle/graal/pull/10856
author_association: MEMBER
user: login: Karm
created_at: 2025-03-14T00:35:00Z
body: @gsmet 

> @Karm sorry, it was "more thoughts" as "if it was safe to be backported or not" :). Do you think we need a backport for this one?

I don't think so. 
author_association: MEMBER
user: login: Karm
created_at: 2025-03-14T00:37:25Z
body: > @Karm it looks like AArch64 support will land in GraalVM for JDK 25, see [oracle/graal#10856](https://github.com/oracle/graal/pull/10856)

@zakkak 

Aww, great.  Gonna give their branch a shot.  I will make a note to see to removing these if-else version checks for 25 if it's sound.
author_association: MEMBER
user: login: Karm
created_at: 2025-03-14T07:33:50Z
body: @zakkak 

Migration guide updated as https://github.com/quarkusio/quarkus/wiki/Migration-Guide-3.19/_compare/8ffa458b7951b8da1e26a86958243dd6edb4b55d...0d6004747c902b7e230e8e8a3209c765d6e8266c
author_association: MEMBER
user: login: zakkak
created_at: 2025-03-14T12:16:23Z
body: > @zakkak
> 
> Migration guide updated as https://github.com/quarkusio/quarkus/wiki/Migration-Guide-3.19/_compare/8ffa458b7951b8da1e26a86958243dd6edb4b55d...0d6004747c902b7e230e8e8a3209c765d6e8266c

@karm there is a typo in your update. "To switch back to UBI 8" suggests using ubi9

Furthermore, we need to add a note about

> GraalVM has FFI/FFM implemented for amd64 arch only, so effectively starting Mandrel/GraalVM 24.2, i.e. Mandrel for JDK 24, we are losing AWT support on Linux aarch64 where it used to work

author_association: MEMBER
user: login: Karm
created_at: 2025-03-14T12:20:19Z
body: > > @zakkak
> > Migration guide updated as https://github.com/quarkusio/quarkus/wiki/Migration-Guide-3.19/_compare/8ffa458b7951b8da1e26a86958243dd6edb4b55d...0d6004747c902b7e230e8e8a3209c765d6e8266c
> 
> @Karm there is a typo in your update. "To switch back to UBI 8" suggests using ubi9
> 
> Furthermore, we need to add a note about
> 
> > GraalVM has FFI/FFM implemented for amd64 arch only, so effectively starting Mandrel/GraalVM 24.2, i.e. Mandrel for JDK 24, we are losing AWT support on Linux aarch64 where it used to work

1)  gonna fix copy-paste typo
2) I'm waiting for my build to test AWT with the recently merged FFM/FFI aarch64 JDK 25 support, gonna update text presently
author_association: MEMBER
user: login: Karm
created_at: 2025-03-14T15:36:15Z
body: @zakkak @gsmet 

AWT Linux aarch64 note regarding JDK 24:

https://github.com/quarkusio/quarkus/wiki/Migration-Guide-3.19/_compare/2ae1c89052997e6679e3e970035f8b5cd02c5395...7b5faaeccbec05c436d19fb8f0f940a381376d72
author_association: MEMBER
user: login: zakkak
created_at: 2025-03-14T18:23:04Z
body: Thank you @Karm 
author_association: MEMBER
user: login: Karm
created_at: 2025-04-02T11:30:30Z
body: @zakkak @gsmet added backport label to help with adopting JDK 24.
author_association: MEMBER
user: login: Karm
created_at: 2025-04-02T11:31:25Z
body: JDK 25 won't have this limitation any more though... 
author_association: MEMBER