diff --git a/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/JPMSExportBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/JPMSExportBuildItem.java index 0c41ac1223e65..ce44c85799013 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/JPMSExportBuildItem.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/JPMSExportBuildItem.java @@ -3,7 +3,7 @@ import java.util.Objects; import io.quarkus.builder.item.MultiBuildItem; -import io.quarkus.deployment.pkg.steps.GraalVM; +import io.quarkus.runtime.graal.GraalVM; /** * A build item that indicates that a Java package should be exported using @@ -23,6 +23,25 @@ public JPMSExportBuildItem(String moduleName, String packageName, GraalVM.Versio this(moduleName, packageName, exportSince, null); } + /** + * Creates a build item that indicates that a Java package should be exported for a specific GraalVM version range. + * + * @param moduleName the module name + * @param packageName the package name + * @param exportSince the version of GraalVM since which the package should be exported (inclusive) + * @param exportBefore the version of GraalVM before which the package should be exported (exclusive) + * @deprecated use {@link #JPMSExportBuildItem(String, String, GraalVM.Version, GraalVM.Version)} instead + */ + @Deprecated + public JPMSExportBuildItem(String moduleName, String packageName, + io.quarkus.deployment.pkg.steps.GraalVM.Version exportSince, + io.quarkus.deployment.pkg.steps.GraalVM.Version exportBefore) { + this.moduleName = moduleName; + this.packageName = packageName; + this.exportSince = exportSince; + this.exportBefore = exportBefore; + } + /** * Creates a build item that indicates that a Java package should be exported for a specific GraalVM version range. * diff --git a/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/GraalVM.java b/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/GraalVM.java index 52b90f72ec07b..21113760e3c4b 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/GraalVM.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/GraalVM.java @@ -1,6 +1,5 @@ package io.quarkus.deployment.pkg.steps; -import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.regex.Matcher; @@ -9,6 +8,7 @@ import java.util.stream.Stream; import io.quarkus.deployment.builditem.nativeimage.NativeMinimalJavaVersionBuildItem; +import io.quarkus.runtime.graal.GraalVM.Distribution; public final class GraalVM { @@ -152,7 +152,7 @@ private static String graalVersion(String buildInfo, int jdkFeature) { if (versMatcher.find()) { return matchVersion(version); } else { - return GRAAL_MAPPING.get(jdkFeature); + return Version.GRAAL_MAPPING.get(Integer.toString(jdkFeature)); } } @@ -165,15 +165,10 @@ private static String buildVersion(String buildInfo, String buildPrefix) { } } - // Temporarily work around https://github.com/quarkusio/quarkus/issues/36246, - // till we have a consensus on how to move forward in - // https://github.com/quarkusio/quarkus/issues/34161 - private static final Map GRAAL_MAPPING = Map.of(22, "24.0", - 23, "24.1", - 24, "24.2", - 25, "25.0"); + public static final class Version extends io.quarkus.runtime.graal.GraalVM.Version { - public static final class Version implements Comparable { + // Get access to GRAAL_MAPPING without making it public + private static final Map GRAAL_MAPPING = io.quarkus.runtime.graal.GraalVM.Version.GRAAL_MAPPING; /** * JDK version used with native-image tool: @@ -200,25 +195,28 @@ public static final class Version implements Comparable { /** * The minimum version of GraalVM supported by Quarkus. * Versions prior to this are expected to cause major issues. + * + * @deprecated Use {@link io.quarkus.runtime.graal.GraalVM.Version.MINIMUM} instead. */ + @Deprecated public static final Version MINIMUM = VERSION_23_0_0; /** * The current version of GraalVM supported by Quarkus. * This version is the one actively being tested and is expected to give the best experience. + * + * @deprecated Use {@link io.quarkus.runtime.graal.GraalVM.Version.CURRENT} instead. */ + @Deprecated public static final Version CURRENT = VERSION_23_1_0; /** * The minimum version of GraalVM officially supported by Quarkus. * Versions prior to this are expected to work but are not given the same level of testing or priority. + * + * @deprecated Use {@link io.quarkus.runtime.graal.GraalVM.Version.MINIMUM_SUPPORTED} instead. */ + @Deprecated public static final Version MINIMUM_SUPPORTED = CURRENT; - final String fullVersion; - public final Runtime.Version javaVersion; - final Distribution distribution; - private int[] versions; - private String suffix; - Version(String fullVersion, String version, Distribution distro) { this(fullVersion, version, "11", distro); } @@ -228,19 +226,15 @@ public static final class Version implements Comparable { } Version(String fullVersion, String version, Runtime.Version javaVersion, Distribution distro) { - this.fullVersion = fullVersion; - breakdownVersion(version); - this.javaVersion = javaVersion; - this.distribution = distro; + super(fullVersion, version, javaVersion, distro); } - private void breakdownVersion(String version) { - int dash = version.indexOf('-'); - if (dash != -1) { - this.suffix = version.substring(dash + 1); - version = version.substring(0, dash); - } - this.versions = Arrays.stream(version.split("\\.")).mapToInt(Integer::parseInt).toArray(); + public int compareTo(GraalVM.Version o) { + return compareTo((io.quarkus.runtime.graal.GraalVM.Version) o); + } + + Distribution getDistribution() { + return distribution; } String getFullVersion() { @@ -248,15 +242,11 @@ String getFullVersion() { } boolean isObsolete() { - return this.compareTo(MINIMUM) < 0; + return this.compareTo(io.quarkus.runtime.graal.GraalVM.Version.MINIMUM) < 0; } boolean isSupported() { - return this.compareTo(MINIMUM_SUPPORTED) >= 0; - } - - boolean isMandrel() { - return distribution == Distribution.MANDREL; + return this.compareTo(io.quarkus.runtime.graal.GraalVM.Version.MINIMUM_SUPPORTED) >= 0; } boolean isNewerThan(Version version) { @@ -278,26 +268,6 @@ public boolean jdkVersionGreaterOrEqualTo(String version) { return javaVersion.compareToIgnoreOptional(Runtime.Version.parse(version)) >= 0; } - @Override - public int compareTo(Version o) { - int i = 0; - for (; i < this.versions.length; i++) { - if (i >= o.versions.length) { - if (this.versions[i] != 0) { - return 1; - } - } else if (this.versions[i] != o.versions[i]) { - return this.versions[i] - o.versions[i]; - } - } - for (; i < o.versions.length; i++) { - if (o.versions[i] != 0) { - return -1; - } - } - return 0; - } - public static Version of(Stream output) { String stringOutput = output.collect(Collectors.joining("\n")); List lines = stringOutput.lines() @@ -344,43 +314,8 @@ private static boolean isMandrel(String s) { return s != null && s.contains("Mandrel Distribution"); } - /** - * Returns the Mandrel/GraalVM version as a string. e.g. 21.3.0-rc1 - */ - public String getVersionAsString() { - String version = Arrays.stream(versions).mapToObj(Integer::toString).collect(Collectors.joining(".")); - if (suffix != null) { - return version + "-" + suffix; - } - return version; - } - - public String getMajorMinorAsString() { - if (versions.length >= 2) { - return versions[0] + "." + versions[1]; - } - return versions[0] + ".0"; - } - - @Override - public String toString() { - return "Version{" + - "version=" - + getVersionAsString() + - ", fullVersion=" + fullVersion + - ", distribution=" + distribution + - ", javaVersion=" + javaVersion + - '}'; - } - public boolean isJava17() { return javaVersion.feature() == 17; } } - - enum Distribution { - GRAALVM, - LIBERICA, - MANDREL; - } } 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 c1f7f35c94252..5a6f9643ceb58 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 @@ -309,10 +309,10 @@ public NativeImageBuildItem build(NativeConfig nativeConfig, LocalesBuildTimeCon System.setProperty("native.image.path", finalExecutablePath.toAbsolutePath().toString()); return new NativeImageBuildItem(finalExecutablePath, - new NativeImageBuildItem.GraalVMVersion(graalVMVersion.fullVersion, + new NativeImageBuildItem.GraalVMVersion(graalVMVersion.getFullVersion(), graalVMVersion.getVersionAsString(), graalVMVersion.javaVersion.feature(), - graalVMVersion.distribution.name()), + graalVMVersion.getDistribution().name()), false); } catch (ImageGenerationFailureException e) { throw e; @@ -489,8 +489,8 @@ private RuntimeException imageGenerationFailed(int exitValue, boolean isContaine } private void checkGraalVMVersion(GraalVM.Version version) { - log.info("Running Quarkus native-image plugin on " + version.distribution.name() + " " + version.getVersionAsString() - + " JDK " + version.javaVersion); + log.info("Running Quarkus native-image plugin on " + version.getDistribution().name() + " " + + version.getVersionAsString() + " JDK " + version.javaVersion); if (version.isObsolete()) { throw new IllegalStateException( "Out of date version of GraalVM or Mandrel detected: " + version.getVersionAsString() + "." diff --git a/core/deployment/src/main/java/io/quarkus/deployment/steps/NativeImageFeatureStep.java b/core/deployment/src/main/java/io/quarkus/deployment/steps/NativeImageFeatureStep.java index ef91747675920..97ade7fea8806 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/steps/NativeImageFeatureStep.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/steps/NativeImageFeatureStep.java @@ -18,7 +18,6 @@ import io.quarkus.deployment.builditem.nativeimage.RuntimeInitializedPackageBuildItem; import io.quarkus.deployment.builditem.nativeimage.RuntimeReinitializedClassBuildItem; import io.quarkus.deployment.builditem.nativeimage.UnsafeAccessedFieldBuildItem; -import io.quarkus.deployment.pkg.steps.GraalVM; import io.quarkus.gizmo.CatchBlockCreator; import io.quarkus.gizmo.ClassCreator; import io.quarkus.gizmo.ClassOutput; @@ -26,6 +25,7 @@ import io.quarkus.gizmo.MethodDescriptor; import io.quarkus.gizmo.ResultHandle; import io.quarkus.gizmo.TryBlock; +import io.quarkus.runtime.graal.GraalVM; public class NativeImageFeatureStep { diff --git a/core/deployment/src/test/java/io/quarkus/deployment/pkg/steps/GraalVMTest.java b/core/deployment/src/test/java/io/quarkus/deployment/pkg/steps/GraalVMTest.java index 647bd3a28474b..8ef6ea1196b52 100644 --- a/core/deployment/src/test/java/io/quarkus/deployment/pkg/steps/GraalVMTest.java +++ b/core/deployment/src/test/java/io/quarkus/deployment/pkg/steps/GraalVMTest.java @@ -1,7 +1,8 @@ package io.quarkus.deployment.pkg.steps; -import static io.quarkus.deployment.pkg.steps.GraalVM.Distribution.GRAALVM; -import static io.quarkus.deployment.pkg.steps.GraalVM.Distribution.MANDREL; +import static io.quarkus.runtime.graal.GraalVM.Distribution.GRAALVM; +import static io.quarkus.runtime.graal.GraalVM.Distribution.LIBERICA; +import static io.quarkus.runtime.graal.GraalVM.Distribution.MANDREL; import static org.assertj.core.api.Assertions.assertThat; import java.util.stream.Stream; @@ -12,8 +13,8 @@ import org.junit.jupiter.params.provider.ValueSource; import io.quarkus.deployment.builditem.nativeimage.NativeMinimalJavaVersionBuildItem; -import io.quarkus.deployment.pkg.steps.GraalVM.Distribution; import io.quarkus.deployment.pkg.steps.GraalVM.Version; +import io.quarkus.runtime.graal.GraalVM.Distribution; public class GraalVMTest { @@ -98,10 +99,7 @@ public void testGraalVMVersionDetected() { static void assertVersion(Version graalVmVersion, Distribution distro, Version version) { assertThat(graalVmVersion.compareTo(version)).isEqualTo(0); - assertThat(version.distribution).isEqualTo(distro); - if (distro == MANDREL) { - assertThat(version.isMandrel()).isTrue(); - } + assertThat(version.toString()).contains(distro.name()); } @Test @@ -109,7 +107,7 @@ public void testGraalVM21LibericaVersionParser() { Version graalVM21Dev = Version.of(Stream.of(("native-image 21.0.1 2023-10-17\n" + "GraalVM Runtime Environment Liberica-NIK-23.1.1-1 (build 21.0.1+12-LTS)\n" + "Substrate VM Liberica-NIK-23.1.1-1 (build 21.0.1+12-LTS, serial gc)").split("\\n"))); - assertThat(graalVM21Dev.distribution.name()).isEqualTo("LIBERICA"); + assertThat(graalVM21Dev.toString()).contains(LIBERICA.name()); assertThat(graalVM21Dev.getVersionAsString()).isEqualTo("23.1.1"); assertThat(graalVM21Dev.javaVersion.toString()).isEqualTo("21.0.1+12-LTS"); assertThat(graalVM21Dev.javaVersion.feature()).isEqualTo(21); @@ -121,7 +119,7 @@ public void testGraalVM21VersionParser() { Version graalVM21Dev = Version.of(Stream.of(("native-image 21 2023-09-19\n" + "GraalVM Runtime Environment GraalVM CE 21+35.1 (build 21+35-jvmci-23.1-b15)\n" + "Substrate VM GraalVM CE 21+35.1 (build 21+35, serial gc)").split("\\n"))); - assertThat(graalVM21Dev.distribution.name()).isEqualTo("GRAALVM"); + assertThat(graalVM21Dev.toString()).contains(GRAALVM.name()); assertThat(graalVM21Dev.getVersionAsString()).isEqualTo("23.1"); assertThat(graalVM21Dev.javaVersion.toString()).isEqualTo("21+35-jvmci-23.1-b15"); assertThat(graalVM21Dev.javaVersion.feature()).isEqualTo(21); @@ -133,7 +131,7 @@ public void testGraalVM21DevVersionParser() { Version graalVM21Dev = Version.of(Stream.of(("native-image 21 2023-09-19\n" + "GraalVM Runtime Environment GraalVM CE 21-dev+35.1 (build 21+35-jvmci-23.1-b14)\n" + "Substrate VM GraalVM CE 21-dev+35.1 (build 21+35, serial gc)").split("\\n"))); - assertThat(graalVM21Dev.distribution.name()).isEqualTo("GRAALVM"); + assertThat(graalVM21Dev.toString()).contains(GRAALVM.name()); assertThat(graalVM21Dev.getVersionAsString()).isEqualTo("23.1-dev"); assertThat(graalVM21Dev.javaVersion.toString()).isEqualTo("21+35-jvmci-23.1-b14"); assertThat(graalVM21Dev.javaVersion.feature()).isEqualTo(21); @@ -145,7 +143,7 @@ public void testGraalVM22DevVersionParser() { Version graalVM22Dev = Version.of(Stream.of(("native-image 22 2024-03-19\n" + "GraalVM Runtime Environment GraalVM CE 22-dev+16.1 (build 22+16-jvmci-b01)\n" + "Substrate VM GraalVM CE 22-dev+16.1 (build 22+16, serial gc)").split("\\n"))); - assertThat(graalVM22Dev.distribution.name()).isEqualTo("GRAALVM"); + assertThat(graalVM22Dev.toString()).contains(GRAALVM.name()); assertThat(graalVM22Dev.getVersionAsString()).isEqualTo("24.0-dev"); assertThat(graalVM22Dev.javaVersion.toString()).isEqualTo("22+16-jvmci-b01"); assertThat(graalVM22Dev.javaVersion.feature()).isEqualTo(22); @@ -158,7 +156,7 @@ public void testGraalVMEE22DevVersionParser() { + "Java(TM) SE Runtime Environment Oracle GraalVM 22-dev+25.1 (build 22+25-jvmci-b01)\n" + "Java HotSpot(TM) 64-Bit Server VM Oracle GraalVM 22-dev+25.1 (build 22+25-jvmci-b01, mixed mode, sharing)") .split("\\n"))); - assertThat(graalVMEE22Dev.distribution.name()).isEqualTo("GRAALVM"); + assertThat(graalVMEE22Dev.toString()).contains(GRAALVM.name()); assertThat(graalVMEE22Dev.getVersionAsString()).isEqualTo("24.0-dev"); assertThat(graalVMEE22Dev.javaVersion.toString()).isEqualTo("22+25-jvmci-b01"); assertThat(graalVMEE22Dev.javaVersion.feature()).isEqualTo(22); @@ -171,7 +169,7 @@ public void testGraalVMEA24DevVersionParser() { + "OpenJDK Runtime Environment Oracle GraalVM 24-dev.ea+10.1 (build 24-ea+10-1076)\n" + "OpenJDK 64-Bit Server VM Oracle GraalVM 24-dev.ea+10.1 (build 24-ea+10-1076, mixed mode, sharing)") .split("\\n"))); - assertThat(graalVMEA24Dev.distribution.name()).isEqualTo("GRAALVM"); + assertThat(graalVMEA24Dev.toString()).contains(GRAALVM.name()); assertThat(graalVMEA24Dev.getVersionAsString()).isEqualTo("24.2-dev"); assertThat(graalVMEA24Dev.javaVersion.toString()).isEqualTo("24-ea+10-1076"); assertThat(graalVMEA24Dev.javaVersion.feature()).isEqualTo(24); 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 new file mode 100644 index 0000000000000..06a5e2781ac62 --- /dev/null +++ b/core/runtime/src/main/java/io/quarkus/runtime/graal/GraalVM.java @@ -0,0 +1,213 @@ +package io.quarkus.runtime.graal; + +import java.util.Arrays; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import com.oracle.svm.core.annotate.Delete; +import com.oracle.svm.core.annotate.TargetClass; + +import io.quarkus.logging.Log; + +/** + * Implements version parsing from the {@code com.oracle.svm.core.VM} property inspired by + * {@code org.graalvm.home.impl.DefaultHomeFinder}. + * This allows Quarkus to determine the GraalVM version used at build time without depending on + * {@code org.graalvm.polyglot:polyglot}. + */ +public final class GraalVM { + + static final class VersionParseHelper { + + private static final String VNUM = "(?[1-9][0-9]*(?:\\.(?:0|[1-9][0-9]*))*)"; + private static final String PRE = "(?:-(?
[a-zA-Z0-9]+))?";
+        private static final String BUILD = "\\+(?0|[1-9][0-9]*(?:\\.(?:0|[1-9][0-9]*))*)?";
+        private static final String OPT = "(?:-(?[-a-zA-Z0-9.]+))?";
+        private static final String VSTR_FORMAT = VNUM + "(?:" + PRE + BUILD + ")?" + OPT;
+
+        private static final String GRAALVM_CE_VERS_PREFIX = "GraalVM CE ";
+        private static final String LIBERICA_NIK_VERS_PREFIX = "Liberica-NIK-";
+        private static final String MANDREL_VERS_PREFIX = "Mandrel-";
+        private static final String ORACLE_GRAALVM_VERS_PREFIX = "Oracle GraalVM ";
+
+        private static final String VENDOR_PREFIX_GROUP = "VENDORPREFIX";
+
+        private static final String VENDOR_PREFIX = "(?<" + VENDOR_PREFIX_GROUP + ">" + GRAALVM_CE_VERS_PREFIX + "|"
+                + LIBERICA_NIK_VERS_PREFIX + "|" + MANDREL_VERS_PREFIX + "|" + ORACLE_GRAALVM_VERS_PREFIX + ")";
+        private static final Pattern VENDOR_VERS_PATTERN = Pattern.compile(VENDOR_PREFIX + VSTR_FORMAT);
+
+        private static final String VERSION_GROUP = "VNUM";
+
+        private static final Version UNKNOWN_VERSION = null;
+
+        static Version parse(String value) {
+            Matcher versionMatcher = VENDOR_VERS_PATTERN.matcher(value);
+            if (versionMatcher.find()) {
+                String vendor = versionMatcher.group(VENDOR_PREFIX_GROUP);
+                if (GRAALVM_CE_VERS_PREFIX.equals(vendor) || ORACLE_GRAALVM_VERS_PREFIX.equals(vendor)) {
+                    String version = versionMatcher.group(VERSION_GROUP);
+                    String jdkFeature = version.split("\\.", 2)[0];
+                    return new Version(value, Version.GRAAL_MAPPING.get(jdkFeature), Distribution.GRAALVM);
+                } else if (LIBERICA_NIK_VERS_PREFIX.equals(vendor)) {
+                    return new Version(value, versionMatcher.group(VERSION_GROUP), Distribution.LIBERICA);
+                } else if (MANDREL_VERS_PREFIX.equals(vendor)) {
+                    return new Version(value, versionMatcher.group(VERSION_GROUP), Distribution.MANDREL);
+                }
+            }
+
+            Log.warnf("Failed to parse GraalVM version from: %s. Defaulting to currently supported version %s ", value,
+                    Version.CURRENT);
+            return Version.CURRENT;
+        }
+
+    }
+
+    public static class Version implements Comparable {
+
+        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);
+
+        // Temporarily work around https://github.com/quarkusio/quarkus/issues/36246,
+        // till we have a consensus on how to move forward in
+        // https://github.com/quarkusio/quarkus/issues/34161
+        protected static final Map GRAAL_MAPPING = Map.of("22", "24.0",
+                "23", "24.1",
+                "24", "24.2",
+                "25", "25.0");
+
+        /**
+         * The minimum version of GraalVM supported by Quarkus.
+         * Versions prior to this are expected to cause major issues.
+         */
+        public static final Version MINIMUM = VERSION_23_0_0;
+        /**
+         * The current version of GraalVM supported by Quarkus.
+         * This version is the one actively being tested and is expected to give the best experience.
+         */
+        public static final Version CURRENT = VERSION_23_1_0;
+        /**
+         * The minimum version of GraalVM officially supported by Quarkus.
+         * Versions prior to this are expected to work but are not given the same level of testing or priority.
+         */
+        public static final Version MINIMUM_SUPPORTED = CURRENT;
+
+        protected final String fullVersion;
+        public final Runtime.Version javaVersion;
+        protected final Distribution distribution;
+        private int[] versions;
+        private String suffix;
+
+        Version(String fullVersion, String version, Distribution distro) {
+            this(fullVersion, version, "21", distro);
+        }
+
+        Version(String fullVersion, String version, String javaVersion, Distribution distro) {
+            this(fullVersion, version, Runtime.Version.parse(javaVersion), distro);
+        }
+
+        protected Version(String fullVersion, String version, Runtime.Version javaVersion, Distribution distro) {
+            this.fullVersion = fullVersion;
+            breakdownVersion(version);
+            this.javaVersion = javaVersion;
+            this.distribution = distro;
+        }
+
+        private void breakdownVersion(String version) {
+            int dash = version.indexOf('-');
+            if (dash != -1) {
+                this.suffix = version.substring(dash + 1);
+                version = version.substring(0, dash);
+            }
+            this.versions = Arrays.stream(version.split("\\.")).mapToInt(Integer::parseInt).toArray();
+        }
+
+        @Override
+        public int compareTo(Version o) {
+            return compareTo(o.versions);
+        }
+
+        public int compareTo(int[] versions) {
+            int i = 0;
+            for (; i < this.versions.length; i++) {
+                if (i >= versions.length) {
+                    if (this.versions[i] != 0) {
+                        return 1;
+                    }
+                } else if (this.versions[i] != versions[i]) {
+                    return this.versions[i] - versions[i];
+                }
+            }
+            for (; i < versions.length; i++) {
+                if (versions[i] != 0) {
+                    return -1;
+                }
+            }
+            return 0;
+        }
+
+        /**
+         * Returns the Mandrel/GraalVM version as a string. e.g. 21.3.0-rc1
+         */
+        public String getVersionAsString() {
+            String version = Arrays.stream(versions).mapToObj(Integer::toString).collect(Collectors.joining("."));
+            if (suffix != null) {
+                return version + "-" + suffix;
+            }
+            return version;
+        }
+
+        public String getMajorMinorAsString() {
+            if (versions.length >= 2) {
+                return versions[0] + "." + versions[1];
+            }
+            return versions[0] + ".0";
+        }
+
+        @Override
+        public String toString() {
+            return "Version{" +
+                    "version="
+                    + getVersionAsString() +
+                    ", fullVersion=" + fullVersion +
+                    ", distribution=" + distribution +
+                    ", javaVersion=" + javaVersion +
+                    '}';
+        }
+
+        public static Version getCurrent() {
+            String vendorVersion = System.getProperty("org.graalvm.vendorversion");
+            return VersionParseHelper.parse(vendorVersion);
+        }
+    }
+
+    public enum Distribution {
+        GRAALVM,
+        LIBERICA,
+        MANDREL;
+    }
+}
+
+/*
+ * This class is only meant to be used at native image build time
+ */
+@Delete
+@TargetClass(GraalVM.class)
+final class Target_io_quarkus_runtime_graal_GraalVM {
+}
+
+@Delete
+@TargetClass(GraalVM.Distribution.class)
+final class Target_io_quarkus_runtime_graal_GraalVM_Distribution {
+}
+
+@Delete
+@TargetClass(GraalVM.Version.class)
+final class Target_io_quarkus_runtime_graal_GraalVM_Version {
+}
+
+@Delete
+@TargetClass(GraalVM.VersionParseHelper.class)
+final class Target_io_quarkus_runtime_graal_GraalVM_VersionParseHelper {
+}