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

Diagnose incompatible Java system classpaths #19547

Closed
wants to merge 1 commit into from
Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import static com.google.common.collect.MoreCollectors.toOptional;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Comparator.comparing;
import static java.util.Locale.ENGLISH;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
Expand Down Expand Up @@ -72,6 +73,9 @@
*/
public class BlazeJavacMain {

private static final Pattern INCOMPATIBLE_SYSTEM_CLASS_PATH_ERROR =
Pattern.compile(
"(?s)bad class file: /modules/.*class file has wrong version (?<version>[4-9][0-9])\\.");
private static final Pattern UNSUPPORTED_CLASS_VERSION_ERROR =
Pattern.compile(
"^(?<class>[^ ]*) has been compiled by a more recent version of the Java Runtime "
Expand Down Expand Up @@ -183,6 +187,12 @@ public static BlazeJavacResult compile(BlazeJavacArguments arguments) {
errWriter.flush();
ImmutableList<FormattedDiagnostic> diagnostics = diagnosticsBuilder.build();

diagnostics.stream()
.map(d -> maybeGetJavaConfigurationError(arguments, d))
.flatMap(Optional::stream)
.findFirst()
.ifPresent(errOutput::append);

boolean werror =
diagnostics.stream().anyMatch(d -> d.getCode().equals("compiler.err.warnings.and.werror"));
if (status.equals(Status.OK)) {
Expand Down Expand Up @@ -279,6 +289,33 @@ private static boolean shouldReportDiagnostic(boolean werror, FormattedDiagnosti
return false;
}

private static Optional<String> maybeGetJavaConfigurationError(
BlazeJavacArguments arguments, Diagnostic<?> diagnostic) {
if (!diagnostic.getKind().equals(Diagnostic.Kind.ERROR)) {
return Optional.empty();
}
Matcher matcher;
if (!diagnostic.getCode().equals("compiler.err.cant.access")
|| arguments.system() == null
|| !(matcher = INCOMPATIBLE_SYSTEM_CLASS_PATH_ERROR.matcher(diagnostic.getMessage(ENGLISH)))
.find()) {
return Optional.empty();
}
// The output path is of the form $PRODUCT-out/$CPU-$MODE[-exec-...]/bin/...
boolean isForTool = arguments.classOutput().subpath(1, 2).toString().contains("-exec-");
// Java 8 corresponds to class file major version 52.
int systemClasspathVersion = Integer.parseUnsignedInt(matcher.group("version")) - 44;
return Optional.of(
String.format(
"error: [BazelJavaConfiguration] The Java %d runtime used to run javac is not recent "
+ "enough to compile for the Java %d runtime in %s. Either register a Java "
+ "toolchain with a newer java_runtime or specify a lower %s.\n",
Runtime.version().feature(),
systemClasspathVersion,
arguments.system(),
isForTool ? "--tool_java_runtime_version" : "--java_runtime_version"));
}

/** Processes Plugin-specific arguments and removes them from the args array. */
@VisibleForTesting
static void processPluginArgs(
Expand Down
88 changes: 88 additions & 0 deletions src/test/shell/bazel/bazel_java17_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -186,4 +186,92 @@ EOF
"--tool_java_language_version\."
}

function test_incompatible_system_classpath() {
mkdir -p pkg
# This test defines a custom Java toolchain as it relies on the availability of a runtime that is
# strictly newer than the one specified as the toolchain's java_runtime.
cat >pkg/BUILD <<'EOF'
load("@bazel_tools//tools/jdk:default_java_toolchain.bzl", "default_java_toolchain")
java_binary(
name = "Main",
srcs = ["Main.java"],
main_class = "com.example.Main",
)
default_java_toolchain(
name = "java_toolchain",
source_version = "17",
target_version = "17",
java_runtime = "@bazel_tools//tools/jdk:remotejdk_17",
)
EOF

cat >pkg/Main.java <<'EOF'
package com.example;
import java.net.URI;
public class Main {
public static void main(String[] args) {
System.out.println("Hello, world!");
}
}
EOF

bazel build //pkg:Main \
--extra_toolchains=//pkg:java_toolchain_definition \
--java_language_version=17 \
--java_runtime_version=remotejdk_20 \
&>"${TEST_log}" && fail "Expected build to fail"

expect_log "error: \[BazelJavaConfiguration\] The Java 17 runtime used to run javac is not " \
"recent enough to compile for the Java 20 runtime in external/remotejdk20_[a-z0-9]*\. Either " \
"register a Java toolchain with a newer java_runtime or specify a lower " \
"--java_runtime_version\."
}

function test_incompatible_tool_system_classpath() {
mkdir -p pkg
# This test defines a custom Java toolchain as it relies on the availability of a runtime that is
# strictly newer than the one specified as the toolchain's java_runtime.
cat >pkg/BUILD <<'EOF'
load("@bazel_tools//tools/jdk:default_java_toolchain.bzl", "default_java_toolchain")
java_binary(
name = "Main",
srcs = ["Main.java"],
main_class = "com.example.Main",
)
genrule(
name = "gen",
outs = ["gen.txt"],
tools = [":Main"],
cmd = "$(location :Main) > $@",
)
default_java_toolchain(
name = "java_toolchain",
source_version = "17",
target_version = "17",
java_runtime = "@bazel_tools//tools/jdk:remotejdk_17",
)
EOF

cat >pkg/Main.java <<'EOF'
package com.example;
import java.net.URI;
public class Main {
public static void main(String[] args) {
System.out.println("Hello, world!");
}
}
EOF

bazel build //pkg:gen \
--extra_toolchains=//pkg:java_toolchain_definition \
--tool_java_language_version=17 \
--tool_java_runtime_version=remotejdk_20 \
&>"${TEST_log}" && fail "Expected build to fail"

expect_log "error: \[BazelJavaConfiguration\] The Java 17 runtime used to run javac is not " \
"recent enough to compile for the Java 20 runtime in external/remotejdk20_[a-z0-9]*\. Either " \
"register a Java toolchain with a newer java_runtime or specify a lower " \
"--tool_java_runtime_version\."
}

run_suite "Tests Java 17 language features"
Loading