Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AWT Extension, Decoders, Encoders, Geometry and Fonts #20850

Merged
merged 7 commits into from
Dec 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/native-tests.json
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,8 @@
{
"category": "AWT, ImageIO and Java2D",
"timeout": 20,
"test-modules": "awt",
"test-modules": "awt, no-awt",
"os-name": "ubuntu-latest"
}
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public enum Feature {
APICURIO_REGISTRY_AVRO,
ARTEMIS_CORE,
ARTEMIS_JMS,
AWT,
CACHE,
CDI,
CONFIG_YAML,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package io.quarkus.deployment.builditem.nativeimage;

import io.quarkus.builder.item.MultiBuildItem;

/**
* A build item that indicates the minimal acceptable JDK version
* the native-image tool was bundled with.
*/
public final class NativeMinimalJavaVersionBuildItem extends MultiBuildItem {
public final int minFeature;
public final int minUpdate;
public final String warning;

/**
* @param minFeature e.g. 17 for JDK 17.0.1
* @param minUpdate e.g. 1 for JDK 17.0.1
*/
public NativeMinimalJavaVersionBuildItem(int minFeature, int minUpdate, String warning) {
this.minFeature = minFeature;
this.minUpdate = minUpdate;
this.warning = warning;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package io.quarkus.deployment.builditem.nativeimage;

import static io.quarkus.dev.console.QuarkusConsole.IS_LINUX;
import static io.quarkus.dev.console.QuarkusConsole.IS_MAC;
import static io.quarkus.dev.console.QuarkusConsole.IS_WINDOWS;

import io.quarkus.builder.item.MultiBuildItem;

/**
* Native-image might not be supported for a particular
* extension on a given OS or architecture.
*/
public final class UnsupportedOSBuildItem extends MultiBuildItem {
public enum Os {
WINDOWS(IS_WINDOWS),
MAC(IS_MAC),
LINUX(IS_LINUX);

public final boolean active;

Os(boolean active) {
this.active = active;
}
}

public final Os os;
public final String error;

public UnsupportedOSBuildItem(Os os, String error) {
this.os = os;
this.error = error;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,13 @@ public class NativeConfig {
@ConfigItem(defaultValue = "true")
public boolean enableJni;

/**
* The default value for java.awt.headless JVM option.
* Switching this option affects linking of awt libraries.
*/
@ConfigItem(defaultValue = "true")
public boolean headless;

/**
* Defines the user language used for building the native executable.
* <p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,18 @@

final class GraalVM {
static final class Version implements Comparable<Version> {

/**
* JDK version used with native-image tool:
* e.g. JDK 17.0.1 is Feature version 17, Update version 1.
* * Feature: e.g. 11 as in JDK 11, JDK 17, JDK 18 etc.
* * Interim: 0 so far for the JDK versions we care about, not used here
* * Update: quarterly updates, e.g. 13 as in JDK 11.0.13.
* * Patch: emergency release, critical patch, not used here
*/
private static final Pattern PATTERN = Pattern.compile(
"(GraalVM|native-image)( Version)? (?<version>[1-9][0-9]*(\\.[0-9]+)+(-dev\\p{XDigit}*)?)(?<distro>.*?)?(\\(Java Version (?<javaVersion>[^)]+)\\))?$");
"(GraalVM|native-image)( Version)? (?<version>[1-9][0-9]*(\\.[0-9]+)+(-dev\\p{XDigit}*)?)(?<distro>.*?)?" +
"(\\(Java Version (?<jfeature>[0-9]+)(\\.(?<jinterim>[0-9]*)\\.(?<jupdate>[0-9]*))?.*)?$");

static final Version UNVERSIONED = new Version("Undefined", "snapshot", Distribution.ORACLE);
static final Version VERSION_21_2 = new Version("GraalVM 21.2", "21.2", Distribution.ORACLE);
Expand All @@ -17,20 +27,23 @@ static final class Version implements Comparable<Version> {

static final Version MINIMUM = VERSION_21_2;
static final Version CURRENT = VERSION_21_3;
public static final int UNDEFINED = -1;

final String fullVersion;
final org.graalvm.home.Version version;
final int javaVersion;
public final int javaFeatureVersion;
public final int javaUpdateVersion;
final Distribution distribution;

Version(String fullVersion, String version, Distribution distro) {
this(fullVersion, version, 11, distro);
this(fullVersion, version, 11, UNDEFINED, distro);
}

Version(String fullVersion, String version, int javaVersion, Distribution distro) {
Version(String fullVersion, String version, int javaFeatureVersion, int javaUpdateVersion, Distribution distro) {
this.fullVersion = fullVersion;
this.version = org.graalvm.home.Version.parse(version);
this.javaVersion = javaVersion;
this.javaFeatureVersion = javaFeatureVersion;
this.javaUpdateVersion = javaUpdateVersion;
this.distribution = distro;
}

Expand Down Expand Up @@ -58,6 +71,14 @@ boolean isOlderThan(Version version) {
return this.compareTo(version) < 0;
}

/**
* e.g. JDK 11.0.13 > 11.0.12, 17.0.1 > 11.0.13,
*/
public boolean jdkVersionGreaterOrEqualTo(int feature, int update) {
return this.javaFeatureVersion > feature
|| (this.javaFeatureVersion == feature && this.javaUpdateVersion >= update);
}

boolean is(Version version) {
return this.compareTo(version) == 0;
}
Expand All @@ -73,15 +94,23 @@ static Version of(Stream<String> lines) {
final String line = it.next();
final Matcher matcher = PATTERN.matcher(line);
if (matcher.find()) {
// GraalVM/Mandrel:
final String version = matcher.group("version");
final String distro = matcher.group("distro");
String javaVersionMatch = matcher.group("javaVersion");
final int javaVersion = javaVersionMatch == null ? // Old GraalVM versions, like 19, didn't report the Java version
11 : Integer.parseInt(javaVersionMatch.split("\\.")[0]);
// JDK:
// e.g. JDK 17.0.1, feature: 17, interim: 0 (not used here), update: 1
final String jFeatureMatch = matcher.group("jfeature");
final int jFeature = jFeatureMatch == null ? // Old GraalVM versions, like 19, didn't report the Java version.
11 : Integer.parseInt(jFeatureMatch);
final String jUpdateMatch = matcher.group("jupdate");
final int jUpdate = jUpdateMatch == null ? // Some JDK dev builds don't report full version string.
UNDEFINED : Integer.parseInt(jUpdateMatch);

return new Version(
line,
version,
javaVersion,
jFeature,
jUpdate,
isMandrel(distro) ? Distribution.MANDREL : Distribution.ORACLE);
}
}
Expand All @@ -90,10 +119,7 @@ static Version of(Stream<String> lines) {
}

private static boolean isMandrel(String s) {
if (s == null) {
return false;
}
return s.contains("Mandrel Distribution");
return s != null && s.contains("Mandrel Distribution");
}

@Override
Expand All @@ -102,12 +128,13 @@ public String toString() {
"version=" + version +
", fullVersion=" + fullVersion +
", distribution=" + distribution +
", javaVersion=" + javaVersion +
", javaFeatureVersion=" + javaFeatureVersion +
", javaUpdateVersion=" + javaUpdateVersion +
'}';
}

public boolean isJava17() {
return javaVersion == 17;
return javaFeatureVersion == 17;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
import io.quarkus.deployment.builditem.nativeimage.NativeImageAllowIncompleteClasspathAggregateBuildItem;
import io.quarkus.deployment.builditem.nativeimage.NativeImageSecurityProviderBuildItem;
import io.quarkus.deployment.builditem.nativeimage.NativeImageSystemPropertyBuildItem;
import io.quarkus.deployment.builditem.nativeimage.NativeMinimalJavaVersionBuildItem;
import io.quarkus.deployment.builditem.nativeimage.UnsupportedOSBuildItem;
import io.quarkus.deployment.pkg.NativeConfig;
import io.quarkus.deployment.pkg.PackageConfig;
import io.quarkus.deployment.pkg.builditem.ArtifactResultBuildItem;
Expand Down Expand Up @@ -143,6 +145,8 @@ public NativeImageBuildItem build(NativeConfig nativeConfig, NativeImageSourceJa
NativeImageAllowIncompleteClasspathAggregateBuildItem incompleteClassPathAllowed,
List<NativeImageSecurityProviderBuildItem> nativeImageSecurityProviders,
List<JPMSExportBuildItem> jpmsExportBuildItems,
List<NativeMinimalJavaVersionBuildItem> nativeMinimalJavaVersions,
List<UnsupportedOSBuildItem> unsupportedOses,
Optional<ProcessInheritIODisabled> processInheritIODisabled) {
if (nativeConfig.debug.enabled) {
copyJarSourcesToLib(outputTargetBuildItem, curateOutcomeBuildItem);
Expand Down Expand Up @@ -182,7 +186,7 @@ public NativeImageBuildItem build(NativeConfig nativeConfig, NativeImageSourceJa
return new NativeImageBuildItem(finalExecutablePath,
new NativeImageBuildItem.GraalVMVersion(graalVMVersion.fullVersion,
graalVMVersion.version.toString(),
graalVMVersion.javaVersion,
graalVMVersion.javaFeatureVersion,
graalVMVersion.distribution.name()));
}
}
Expand All @@ -204,6 +208,8 @@ public NativeImageBuildItem build(NativeConfig nativeConfig, NativeImageSourceJa
.setBrokenClasspath(incompleteClassPathAllowed.isAllow())
.setNativeImageSecurityProviders(nativeImageSecurityProviders)
.setJPMSExportBuildItems(jpmsExportBuildItems)
.setNativeMinimalJavaVersions(nativeMinimalJavaVersions)
.setUnsupportedOSes(unsupportedOses)
.setOutputDir(outputDir)
.setRunnerJarName(runnerJarName)
.setNativeImageName(nativeImageName)
Expand Down Expand Up @@ -235,7 +241,7 @@ public NativeImageBuildItem build(NativeConfig nativeConfig, NativeImageSourceJa
return new NativeImageBuildItem(finalExecutablePath,
new NativeImageBuildItem.GraalVMVersion(graalVMVersion.fullVersion,
graalVMVersion.version.toString(),
graalVMVersion.javaVersion,
graalVMVersion.javaFeatureVersion,
graalVMVersion.distribution.name()));
} catch (Exception e) {
throw new RuntimeException("Failed to build native image", e);
Expand Down Expand Up @@ -401,7 +407,7 @@ private static NativeImageBuildLocalRunner getNativeImageBuildLocalRunner(Native
// try system property first - it will be the JAVA_HOME used by the current JVM
String home = System.getProperty(JAVA_HOME_SYS);
if (home == null) {
// No luck, somewhat a odd JVM not enforcing this property
// No luck, somewhat an odd JVM not enforcing this property
// try with the JAVA_HOME environment variable
home = System.getenv(JAVA_HOME_ENV);
}
Expand Down Expand Up @@ -479,6 +485,8 @@ static class Builder {
private List<ExcludeConfigBuildItem> excludeConfigs;
private List<NativeImageSecurityProviderBuildItem> nativeImageSecurityProviders;
private List<JPMSExportBuildItem> jpmsExports;
private List<NativeMinimalJavaVersionBuildItem> nativeMinimalJavaVersions;
private List<UnsupportedOSBuildItem> unsupportedOSes;
private Path outputDir;
private String runnerJarName;
private String noPIE = "";
Expand Down Expand Up @@ -522,6 +530,18 @@ public Builder setJPMSExportBuildItems(List<JPMSExportBuildItem> JPMSExportBuild
return this;
}

public Builder setNativeMinimalJavaVersions(
List<NativeMinimalJavaVersionBuildItem> nativeMinimalJavaVersions) {
this.nativeMinimalJavaVersions = nativeMinimalJavaVersions;
return this;
}

public Builder setUnsupportedOSes(
List<UnsupportedOSBuildItem> unsupportedOSes) {
this.unsupportedOSes = unsupportedOSes;
return this;
}

public Builder setOutputDir(Path outputDir) {
this.outputDir = outputDir;
return this;
Expand Down Expand Up @@ -621,6 +641,10 @@ public NativeImageInvokerInfo build() {
nativeImageArgs.add("-H:+JNI");
nativeImageArgs.add("-H:+AllowFoldMethods");

if (nativeConfig.headless) {
nativeImageArgs.add("-J-Djava.awt.headless=true");
}

if (nativeConfig.enableFallbackImages) {
nativeImageArgs.add("-H:FallbackThreshold=5");
} else {
Expand Down Expand Up @@ -741,6 +765,28 @@ public NativeImageInvokerInfo build() {
}
}

if (nativeMinimalJavaVersions != null && !nativeMinimalJavaVersions.isEmpty()) {
if (graalVMVersion.javaUpdateVersion == GraalVM.Version.UNDEFINED) {
log.warnf(
"Unable to parse used Java version from native-image version string `%s'. Java version checks will be skipped.",
graalVMVersion.fullVersion);
} else {
nativeMinimalJavaVersions.stream()
.filter(a -> !graalVMVersion.jdkVersionGreaterOrEqualTo(a.minFeature, a.minUpdate))
.forEach(a -> log.warnf("Expected: Java %d, update %d, Actual: Java %d, update %d. %s",
a.minFeature, a.minUpdate, graalVMVersion.javaFeatureVersion,
graalVMVersion.javaUpdateVersion, a.warning));
}
}

if (unsupportedOSes != null && !unsupportedOSes.isEmpty()) {
final String errs = unsupportedOSes.stream().filter(o -> o.os.active).map(o -> o.error)
.collect(Collectors.joining(", "));
if (!errs.isEmpty()) {
throw new UnsupportedOperationException(errs);
}
}

for (ExcludeConfigBuildItem excludeConfig : excludeConfigs) {
nativeImageArgs.add("--exclude-config");
nativeImageArgs.add(excludeConfig.getJarFile());
Expand Down
Loading