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

Improve toolchain selection diagnostics #332

Merged
merged 1 commit into from
Oct 14, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/src/docs/asciidoc/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ If you are using alternative build systems, see <<alternative-build-systems.adoc
* Ship the metadata repository as an artifact alongside the plugin
* Add ability to collect GraalVM metadata of dependencies to a custom location

==== Gradle plugin

* Improved diagnostics to help users figure out what GraalVM toolchain was selected

=== Release 0.9.14

==== Gradle plugin
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@
*/
@SuppressWarnings("unused")
public class GradleUtils {
private static final GradleVersion GRADLE_68 = GradleVersion.version("6.8");
private static final GradleVersion GRADLE_7 = GradleVersion.version("7.0");
private static final GradleVersion GRADLE_71 = GradleVersion.version("7.1");

public static SourceSet findSourceSet(Project project, String sourceSetName) {
SourceSetContainer sourceSetContainer = getJavaPluginConvention(project).getSourceSets();
Expand All @@ -72,6 +74,14 @@ public static boolean isAtLeastGradle7() {
return GradleVersion.current().compareTo(GRADLE_7) >= 0;
}

public static boolean isAtLeastGradle6dot8() {
return GradleVersion.current().compareTo(GRADLE_68) >= 0;
}

public static boolean isAtLeastGradle7dot1() {
return GradleVersion.current().compareTo(GRADLE_71) >= 0;
}

public static Configuration findConfiguration(Project project, String name) {
return project.getConfigurations().getByName(name);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,38 +50,45 @@
import org.gradle.process.ExecResult;

import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import static org.graalvm.buildtools.utils.SharedConstants.GU_EXE;
import static org.graalvm.buildtools.utils.SharedConstants.NATIVE_IMAGE_EXE;

public class NativeImageExecutableLocator {

public static Provider<String> graalvmHomeProvider(ProviderFactory providers) {
return providers.environmentVariable("GRAALVM_HOME")
.forUseAtConfigurationTime()
.orElse(providers.environmentVariable("JAVA_HOME").forUseAtConfigurationTime());
return graalvmHomeProvider(providers, new Diagnostics());
}

public static Provider<String> graalvmHomeProvider(ProviderFactory providers, Diagnostics diagnostics) {
return diagnostics.fromEnvVar("GRAALVM_HOME", providers)
.orElse(diagnostics.fromEnvVar("JAVA_HOME", providers));
}

public static File findNativeImageExecutable(Property<JavaLauncher> javaLauncher,
Provider<Boolean> disableToolchainDetection,
Provider<String> graalvmHomeProvider,
ExecOperations execOperations,
GraalVMLogger logger) {
GraalVMLogger logger,
Diagnostics diagnostics) {
File executablePath = null;
if (disableToolchainDetection.get() || !javaLauncher.isPresent()) {
boolean toolchainDetectionIsDisabled = Boolean.TRUE.equals(disableToolchainDetection.get());
if (toolchainDetectionIsDisabled || !javaLauncher.isPresent()) {
if (graalvmHomeProvider.isPresent()) {
diagnostics.disableToolchainDetection();
String graalvmHome = graalvmHomeProvider.get();
logger.lifecycle("Toolchain detection is disabled, will use GraalVM from {}.", graalvmHome);
executablePath = Paths.get(graalvmHome).resolve("bin/" + NATIVE_IMAGE_EXE).toFile();
}
}
if (executablePath == null) {
JavaInstallationMetadata metadata = javaLauncher.get().getMetadata();
diagnostics.withToolchain(metadata);
executablePath = metadata.getInstallationPath().file("bin/" + NATIVE_IMAGE_EXE).getAsFile();
if (!executablePath.exists() && graalvmHomeProvider.isPresent()) {
executablePath = Paths.get(graalvmHomeProvider.get()).resolve("bin").resolve(NATIVE_IMAGE_EXE).toFile();
}
}

try {
Expand All @@ -99,12 +106,77 @@ public static File findNativeImageExecutable(Property<JavaLauncher> javaLauncher
if (res.getExitValue() != 0) {
throw new GradleException("Native Image executable wasn't found, and '" + GU_EXE + "' tool failed to install it.");
}
diagnostics.withGuInstall();
}
} catch (GradleException e) {
throw new GradleException("Determining GraalVM installation failed with message: " + e.getMessage() + "\n\n"
+ "Make sure to declare the GRAALVM_HOME environment variable or install GraalVM with " +
"native-image in a standard location recognized by Gradle Java toolchain support");
+ "Make sure to declare the GRAALVM_HOME environment variable or install GraalVM with " +
"native-image in a standard location recognized by Gradle Java toolchain support");
}
diagnostics.withExecutablePath(executablePath);
return executablePath;
}

public static final class Diagnostics {
private boolean toolchainDetectionDisabled;
private String envVar;
private boolean guInstall;
private File executablePath;
private JavaInstallationMetadata toolchain;

public Provider<String> fromEnvVar(String envVar, ProviderFactory factory) {
return factory.environmentVariable(envVar)
// required for older Gradle versions support
.forUseAtConfigurationTime()
.map(ConfigurationCacheSupport.serializableTransformerOf(value -> {
this.envVar = envVar;
return value;
}));
}

public void withToolchain(JavaInstallationMetadata toolchain) {
this.toolchain = toolchain;
this.envVar = null;
}

public void disableToolchainDetection() {
toolchainDetectionDisabled = true;
}

public void withGuInstall() {
guInstall = true;
}

public void withExecutablePath(File path) {
executablePath = path;
}
public List<String> getDiagnostics() {
List<String> diags = new ArrayList<>();
diags.add("GraalVM Toolchain detection is " + (toolchainDetectionDisabled ? "disabled" : "enabled"));
if (envVar != null) {
diags.add("GraalVM location read from environment variable: " + envVar);
}
if (guInstall) {
diags.add("Native Image executable was installed using 'gu' tool");
}
if (toolchain != null) {
diags.add("GraalVM uses toolchain detection. Selected:");
diags.add(" - language version: " + toolchain.getLanguageVersion());
if (GradleUtils.isAtLeastGradle6dot8()) {
diags.add(" - vendor: " + toolchain.getVendor());
if (GradleUtils.isAtLeastGradle7dot1()) {
diags.add(" - runtime version: " + toolchain.getJavaRuntimeVersion());
}
}
}
if (executablePath != null) {
try {
diags.add("Native Image executable path: " + executablePath.getCanonicalPath());
} catch (IOException e) {
diags.add("Native Image executable path: " + executablePath.getAbsolutePath());
}
}
return Collections.unmodifiableList(diags);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
*/
public abstract class BuildNativeImageTask extends DefaultTask {
private final Provider<String> graalvmHomeProvider;
private final NativeImageExecutableLocator.Diagnostics diagnostics;

@Nested
public abstract Property<NativeImageOptions> getOptions();
Expand Down Expand Up @@ -154,7 +155,8 @@ public BuildNativeImageTask() {
setGroup(JavaBasePlugin.VERIFICATION_GROUP);
getOutputDirectory().convention(outputDir);
ProviderFactory providers = getProject().getProviders();
this.graalvmHomeProvider = graalvmHomeProvider(providers);
this.diagnostics = new NativeImageExecutableLocator.Diagnostics();
this.graalvmHomeProvider = graalvmHomeProvider(providers, diagnostics);
getDisableToolchainDetection().convention(false);
}

Expand Down Expand Up @@ -191,9 +193,11 @@ public void exec() {
getDisableToolchainDetection(),
getGraalVMHome(),
getExecOperations(),
logger);

logger.lifecycle("Using executable path: " + executablePath);
logger,
diagnostics);
for (String diagnostic : diagnostics.getDiagnostics()) {
logger.lifecycle(diagnostic);
}
String executable = executablePath.getAbsolutePath();
File outputDir = getOutputDirectory().getAsFile().get();
if (outputDir.isDirectory() || outputDir.mkdirs()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@

import org.graalvm.buildtools.agent.AgentMode;
import org.graalvm.buildtools.gradle.internal.GraalVMLogger;
import org.graalvm.buildtools.gradle.internal.NativeImageExecutableLocator;
import org.graalvm.buildtools.utils.NativeImageUtils;
import org.gradle.api.Action;
import org.gradle.api.Task;
Expand Down Expand Up @@ -100,7 +101,7 @@ private static boolean isConfigDir(String dir) {
@Override
public void execute(Task task) {
if (isMergingEnabled.get()) {
File nativeImage = findNativeImageExecutable(noLauncherProperty, disableToolchainDetection, graalvmHomeProvider, execOperations, GraalVMLogger.of(task.getLogger()));
File nativeImage = findNativeImageExecutable(noLauncherProperty, disableToolchainDetection, graalvmHomeProvider, execOperations, GraalVMLogger.of(task.getLogger()), new NativeImageExecutableLocator.Diagnostics());
File workingDir = nativeImage.getParentFile();
File launcher = new File(workingDir, nativeImageConfigureFileName());
if (!launcher.exists()) {
Expand Down