diff --git a/toolchains/BUILD b/toolchains/BUILD index b8cb35d3..b208e7b7 100644 --- a/toolchains/BUILD +++ b/toolchains/BUILD @@ -29,14 +29,56 @@ filegroup( srcs = glob(["*.bzl"]), ) -# Used to distinguish toolchains used for Java development, ie the JavaToolchainProvider. +# A single binary distribution of a JDK (e.g., OpenJDK 17 for Windows arm64) provides three +# different types of toolchains from the perspective of Bazel: + +# The compilation toolchain, which provides the Java runtime used to execute the Java compiler, as +# well as various helper tools and settings. +# +# Toolchains of this type typically have constraints on the execution platform so that their Java +# runtime can run the compiler, but not on the target platform as Java compilation outputs are +# platform independent. +# +# Obtain the associated JavaToolchainInfo via: +# ctx.toolchains["@bazel_tools//tools/jdk:toolchain_type"].java # TODO: migrate away from using @bazel_tools//tools/jdk:toolchain_type ? # toolchain_type(name = "toolchain_type") -# Used to distinguish toolchains used for Java execution, ie the JavaRuntimeInfo. +# The Java runtime that executable Java compilation outputs (e.g., java_binary with +# create_executable = True) will run on. +# +# Toolchains of this type typically have constraints on the target platform so that the runtime's +# native 'java' binary can be run there, but not on the execution platform as building an executable +# Java target only requires copying or symlinking the runtime, which can be done on any platform. +# +# Obtain the associated JavaRuntimeInfo via: +# ctx.toolchains["@bazel_tools//tools/jdk:runtime_toolchain_type"].java_runtime # TODO: migrate away from using @bazel_tools//tools/jdk:runtime_toolchain_type ? # toolchain_type(name = "runtime_toolchain_type") +# The Java runtime to extract the bootclasspath from that is then used to compile Java sources. +# +# As the bootclasspath is platform independent, toolchains of this type may have no constraints. +# Purely as an optimization to prevent unnecessary fetches of remote runtimes for other +# architectures, toolchains of this type may have constraints on the execution platform that match +# those on the corresponding compilation toolchain. +# +# Toolchains of this type are only consumed internally by the bootclasspath rule and should not be +# accessed from Starlark. +# TODO: migrate away from using @bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type ? +# toolchain_type(name = "bootstrap_runtime_toolchain_type") + +# The Java runtime to extract the bootclasspath from that is then used to compile Java sources. +# +# As the bootclasspath is platform independent, toolchains of this type may have no constraints. +# Purely as an optimization to prevent unnecessary fetches of remote runtimes for other +# architectures, toolchains of this type may have constraints on the execution platform that match +# those on the corresponding compilation toolchain. +# +# Toolchains of this type are only consumed internally by the bootclasspath rule and should not be +# accessed from Starlark. +# toolchain_type(name = "bootstrap_runtime_toolchain_type") + # Points to toolchain[":runtime_toolchain_type"] (was :legacy_current_java_runtime) java_runtime_alias(name = "current_java_runtime") @@ -201,8 +243,7 @@ alias( bootclasspath( name = "platformclasspath", src = "DumpPlatformClassPath.java", - host_javabase = ":current_java_runtime", - target_javabase = ":current_java_runtime", + java_runtime_alias = ":current_java_runtime", ) default_java_toolchain( diff --git a/toolchains/default_java_toolchain.bzl b/toolchains/default_java_toolchain.bzl index 846302ee..e6969884 100644 --- a/toolchains/default_java_toolchain.bzl +++ b/toolchains/default_java_toolchain.bzl @@ -204,8 +204,10 @@ def java_runtime_files(name, srcs): tags = ["manual"], ) +_JAVA_BOOTSTRAP_RUNTIME_TOOLCHAIN_TYPE = Label("@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type") + def _bootclasspath_impl(ctx): - host_javabase = ctx.attr.host_javabase[java_common.JavaRuntimeInfo] + exec_javabase = ctx.attr.java_runtime_alias[java_common.JavaRuntimeInfo] class_dir = ctx.actions.declare_directory("%s_classes" % ctx.label.name) @@ -220,17 +222,15 @@ def _bootclasspath_impl(ctx): args.add(ctx.file.src) ctx.actions.run( - executable = "%s/bin/javac" % host_javabase.java_home, + executable = "%s/bin/javac" % exec_javabase.java_home, mnemonic = "JavaToolchainCompileClasses", - inputs = [ctx.file.src] + ctx.files.host_javabase, + inputs = [ctx.file.src] + ctx.files.java_runtime_alias, outputs = [class_dir], arguments = [args], ) bootclasspath = ctx.outputs.output_jar - inputs = [class_dir] + ctx.files.host_javabase - args = ctx.actions.args() args.add("-XX:+IgnoreUnrecognizedVMOptions") args.add("--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED") @@ -240,16 +240,17 @@ def _bootclasspath_impl(ctx): args.add("DumpPlatformClassPath") args.add(bootclasspath) + any_javabase = ctx.toolchains[_JAVA_BOOTSTRAP_RUNTIME_TOOLCHAIN_TYPE].java_runtime + args.add(any_javabase.java_home) + system_files = ("release", "modules", "jrt-fs.jar") - system = [f for f in ctx.files.target_javabase if f.basename in system_files] + system = [f for f in any_javabase.files.to_list() if f.basename in system_files] if len(system) != len(system_files): system = None - if ctx.attr.target_javabase: - inputs.extend(ctx.files.target_javabase) - args.add(ctx.attr.target_javabase[java_common.JavaRuntimeInfo].java_home) + inputs = depset([class_dir] + ctx.files.java_runtime_alias, transitive = [any_javabase.files]) ctx.actions.run( - executable = str(host_javabase.java_executable_exec_path), + executable = str(exec_javabase.java_executable_exec_path), mnemonic = "JavaToolchainCompileBootClasspath", inputs = inputs, outputs = [bootclasspath], @@ -267,7 +268,7 @@ def _bootclasspath_impl(ctx): _bootclasspath = rule( implementation = _bootclasspath_impl, attrs = { - "host_javabase": attr.label( + "java_runtime_alias": attr.label( cfg = "exec", providers = [java_common.JavaRuntimeInfo], ), @@ -276,10 +277,8 @@ _bootclasspath = rule( cfg = "exec", allow_single_file = True, ), - "target_javabase": attr.label( - providers = [java_common.JavaRuntimeInfo], - ), }, + toolchains = [_JAVA_BOOTSTRAP_RUNTIME_TOOLCHAIN_TYPE], ) def bootclasspath(name, **kwargs): diff --git a/toolchains/local_java_repository.bzl b/toolchains/local_java_repository.bzl index 45603ec3..64991852 100644 --- a/toolchains/local_java_repository.bzl +++ b/toolchains/local_java_repository.bzl @@ -107,6 +107,12 @@ def local_java_runtime(name, java_home, version, runtime_name = None, visibility toolchain_type = Label("@bazel_tools//tools/jdk:runtime_toolchain_type"), toolchain = runtime_name, ) + native.toolchain( + name = "bootstrap_runtime_toolchain_definition", + target_settings = [":%s_settings_alias" % name], + toolchain_type = Label("@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type"), + toolchain = runtime_name, + ) if type(version) == type("") and version.isdigit() and int(version) > 8: for version in range(8, int(version) + 1): @@ -253,6 +259,12 @@ toolchain( toolchain_type = "@bazel_tools//tools/jdk:runtime_toolchain_type", toolchain = ":jdk", ) +toolchain( + name = "bootstrap_runtime_toolchain_definition", + target_settings = [":localjdk_setting"], + toolchain_type = "@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type", + toolchain = ":jdk", +) ''' _local_java_repository_rule = repository_rule( diff --git a/toolchains/remote_java_repository.bzl b/toolchains/remote_java_repository.bzl index 86916ec1..65bbe482 100644 --- a/toolchains/remote_java_repository.bzl +++ b/toolchains/remote_java_repository.bzl @@ -82,6 +82,16 @@ toolchain( toolchain_type = "@bazel_tools//tools/jdk:runtime_toolchain_type", toolchain = "{toolchain}", ) +toolchain( + name = "bootstrap_runtime_toolchain", + # These constraints are not required for correctness, but prevent fetches of remote JDK for + # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in + # the same configuration, this constraint will not result in toolchain resolution failures. + exec_compatible_with = {target_compatible_with}, + target_settings = [":version_or_prefix_version_setting"], + toolchain_type = "@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type", + toolchain = "{toolchain}", +) """.format( prefix = prefix, version = version,