diff --git a/java/BUILD b/java/BUILD index eb4f228..d3ac13e 100644 --- a/java/BUILD +++ b/java/BUILD @@ -1,9 +1,18 @@ load("@bazel_skylib//:bzl_library.bzl", "bzl_library") +load("@bazel_skylib//rules:common_settings.bzl", "bool_flag") package(default_visibility = ["//visibility:public"]) licenses(["notice"]) +# If enabled, the bootclasspath for Java compilation will be extracted from a Java runtime matching +# the version specified with `--java_language_version` rather than the runtime specified with +# `--java_runtime_version`. +bool_flag( + name = "incompatible_language_version_bootclasspath", + build_setting_default = False, +) + filegroup( name = "srcs", srcs = glob(["**"]) + [ diff --git a/toolchains/BUILD b/toolchains/BUILD index 3f22e28..f554ccc 100644 --- a/toolchains/BUILD +++ b/toolchains/BUILD @@ -1,3 +1,7 @@ +load( + "@bazel_skylib//rules:common_settings.bzl", + "string_setting", +) load("@rules_cc//cc:defs.bzl", "cc_library") load( ":default_java_toolchain.bzl", @@ -6,6 +10,7 @@ load( "bootclasspath", "default_java_toolchain", "java_runtime_files", + "language_version_bootstrap_runtime", ) load( ":java_toolchain_alias.bzl", @@ -250,10 +255,41 @@ alias( }), ) +config_setting( + name = "incompatible_language_version_bootclasspath", + flag_values = { + "//java:incompatible_language_version_bootclasspath": "True", + }, + visibility = ["//visibility:private"], +) + +string_setting( + name = "java_language_version", + build_setting_default = "", + visibility = ["//visibility:private"], +) + +string_setting( + name = "java_runtime_version", + build_setting_default = "", + visibility = ["//visibility:private"], +) + +language_version_bootstrap_runtime( + name = "language_version_bootstrap_runtime", + java_language_version = ":java_language_version", + java_runtime_version = ":java_runtime_version", + visibility = ["//visibility:private"], +) + bootclasspath( name = "platformclasspath", src = "DumpPlatformClassPath.java", java_runtime_alias = ":current_java_runtime", + language_version_bootstrap_runtime = select({ + ":incompatible_language_version_bootclasspath": ":language_version_bootstrap_runtime", + "//conditions:default": None, + }), ) default_java_toolchain( diff --git a/toolchains/default_java_toolchain.bzl b/toolchains/default_java_toolchain.bzl index 721192d..8fce344 100644 --- a/toolchains/default_java_toolchain.bzl +++ b/toolchains/default_java_toolchain.bzl @@ -14,6 +14,7 @@ """Rules for defining default_java_toolchain""" +load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo") load("//java:defs.bzl", "java_toolchain") # JVM options, without patching java.compiler and jdk.compiler modules. @@ -207,6 +208,87 @@ def java_runtime_files(name, srcs): tags = ["manual"], ) +# TODO: This provider and the its usage is only necessary since --java_{language,runtime}_version +# are not available directly to Starlark. +_JavaVersionsInfo = provider( + "Exposes the --java_{language,runtime}_version value as extracted from a transition to a dependant.", + fields = { + "java_language_version": "The value of --java_language_version", + "java_runtime_version": "The value of --java_runtime_version", + }, +) + +def _language_version_bootstrap_runtime(ctx): + providers = [ + _JavaVersionsInfo( + java_language_version = ctx.attr.java_language_version[BuildSettingInfo].value, + java_runtime_version = ctx.attr.java_runtime_version[BuildSettingInfo].value, + ), + ] + + bootstrap_runtime = ctx.toolchains["@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type"] + if bootstrap_runtime: + providers.append(bootstrap_runtime.java_runtime) + + return providers + +language_version_bootstrap_runtime = rule( + implementation = _language_version_bootstrap_runtime, + attrs = { + "java_language_version": attr.label( + providers = [BuildSettingInfo], + ), + "java_runtime_version": attr.label( + providers = [BuildSettingInfo], + ), + }, + toolchains = [ + config_common.toolchain_type("@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type", mandatory = False), + ], +) + +def _get_bootstrap_runtime_version(*, java_language_version, java_runtime_version): + """Returns the runtime version to use for bootstrapping the given language version. + + If the runtime version is not versioned, e.g. "local_jdk", it is used as is. + Otherwise, the language version replaces the numeric part of the runtime version, e.g., + "remotejdk_17" becomes "remotejdk_8". + """ + prefix, separator, version = java_runtime_version.rpartition("_") + if version and version.isdigit(): + new_version = java_language_version + else: + # The runtime version is not versioned, e.g. "local_jdk". Use it as is. + new_version = version + + return prefix + separator + new_version + +def _bootclasspath_transition_impl(settings, _): + java_language_version = settings["//command_line_option:java_language_version"] + java_runtime_version = settings["//command_line_option:java_runtime_version"] + + return { + "//command_line_option:java_runtime_version": _get_bootstrap_runtime_version( + java_language_version = java_language_version, + java_runtime_version = java_runtime_version, + ), + "//toolchains:java_language_version": java_language_version, + "//toolchains:java_runtime_version": java_runtime_version, + } + +_bootclasspath_transition = transition( + implementation = _bootclasspath_transition_impl, + inputs = [ + "//command_line_option:java_language_version", + "//command_line_option:java_runtime_version", + ], + outputs = [ + "//command_line_option:java_runtime_version", + "//toolchains:java_language_version", + "//toolchains:java_runtime_version", + ], +) + _JAVA_BOOTSTRAP_RUNTIME_TOOLCHAIN_TYPE = Label("@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type") # Opt the Java bootstrap actions into path mapping: @@ -250,7 +332,36 @@ def _bootclasspath_impl(ctx): args.add("DumpPlatformClassPath") args.add(bootclasspath) - any_javabase = ctx.toolchains[_JAVA_BOOTSTRAP_RUNTIME_TOOLCHAIN_TYPE].java_runtime + incompatible_language_version_bootclasspath = ctx.attr._incompatible_language_version_bootclasspath[BuildSettingInfo].value + if incompatible_language_version_bootclasspath: + # The attribute is subject to a split transition. + language_version_bootstrap_runtime = ctx.attr.language_version_bootstrap_runtime[0] + if java_common.JavaRuntimeInfo in language_version_bootstrap_runtime: + any_javabase = language_version_bootstrap_runtime[java_common.JavaRuntimeInfo] + else: + java_versions_info = language_version_bootstrap_runtime[_JavaVersionsInfo] + bootstrap_runtime_version = _get_bootstrap_runtime_version( + java_language_version = java_versions_info.java_language_version, + java_runtime_version = java_versions_info.java_runtime_version, + ) + is_exec = "-exec" in ctx.bin_dir.path + tool_prefix = "tool_" if is_exec else "" + fail(""" +No Java runtime found to extract the bootclasspath from for --{tool_prefix}java_language_version={language_version} and --{tool_prefix}java_runtime_version={runtime_version}. +You can: + + * register a Java runtime with name "{bootstrap_runtime_version}" to provide the bootclasspath or + * set --java_language_version to the Java version of an available runtime. + +Rerun with --toolchain_resolution_debug='@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type' to see more details about toolchain resolution. +""".format( + language_version = java_versions_info.java_language_version, + runtime_version = java_versions_info.java_runtime_version, + bootstrap_runtime_version = bootstrap_runtime_version, + tool_prefix = tool_prefix, + )) + else: + any_javabase = ctx.toolchains[_JAVA_BOOTSTRAP_RUNTIME_TOOLCHAIN_TYPE].java_runtime args.add(any_javabase.java_home) system_files = ("release", "modules", "jrt-fs.jar") @@ -283,11 +394,17 @@ _bootclasspath = rule( cfg = "exec", providers = [java_common.JavaRuntimeInfo], ), + "language_version_bootstrap_runtime": attr.label( + cfg = _bootclasspath_transition, + ), "output_jar": attr.output(mandatory = True), "src": attr.label( cfg = "exec", allow_single_file = True, ), + "_incompatible_language_version_bootclasspath": attr.label( + default = "//java:incompatible_language_version_bootclasspath", + ), }, toolchains = [_JAVA_BOOTSTRAP_RUNTIME_TOOLCHAIN_TYPE], )