-
Notifications
You must be signed in to change notification settings - Fork 69
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add
incompatible_language_version_bootclasspath
flag
Copybara Import from #182 BEGIN_PUBLIC Add `incompatible_language_version_bootclasspath` flag (#182) With `--@rules_java//java:incompatible_language_version_bootclasspath`, the bootclasspath used for Java compilation is now determined based on the numeric version specified in `--java_language_version` and the type specified in `--java_runtime_version` rather than just using the target runtime. For example, with `--java_language_version=8` and `--java_runtime_version=remotejdk_21`, the bootclasspath would be extracted from `remotejdk_8`. For unversioned runtime versions such as `local_jdk`, the behavior doesn't change. If a matching runtime is not available, analysis fails with a customized error message explaining the various options to the user. Work towards bazelbuild/bazel#21769 Closes #182 END_PUBLIC COPYBARA_INTEGRATE_REVIEW=#182 from fmeum:java-language-version de27506 PiperOrigin-RevId: 703396804 Change-Id: Ieb1def97a5eee59763336eb61deaf584f341a1d4
- Loading branch information
Showing
4 changed files
with
346 additions
and
112 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,246 @@ | ||
# Copyright 2024 The Bazel Authors. All rights reserved. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
"""Rules for extracting a platform classpath from Java runtimes.""" | ||
|
||
load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo") | ||
load("//java/common:java_common.bzl", "java_common") | ||
load(":utf8_environment.bzl", "Utf8EnvironmentInfo") | ||
|
||
visibility("private") | ||
|
||
# TODO: This provider and 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: | ||
# https://github.com/bazelbuild/bazel/commit/a239ea84832f18ee8706682145e9595e71b39680 | ||
_SUPPORTS_PATH_MAPPING = {"supports-path-mapping": "1"} | ||
|
||
def _java_home(java_executable): | ||
return java_executable.dirname[:-len("/bin")] | ||
|
||
def _bootclasspath_impl(ctx): | ||
exec_javabase = ctx.attr.java_runtime_alias[java_common.JavaRuntimeInfo] | ||
env = ctx.attr._utf8_environment[Utf8EnvironmentInfo].environment | ||
|
||
class_dir = ctx.actions.declare_directory("%s_classes" % ctx.label.name) | ||
|
||
args = ctx.actions.args() | ||
args.add("-source") | ||
args.add("8") | ||
args.add("-target") | ||
args.add("8") | ||
args.add("-Xlint:-options") | ||
args.add("-J-XX:-UsePerfData") | ||
args.add("-d") | ||
args.add_all([class_dir], expand_directories = False) | ||
args.add(ctx.file.src) | ||
|
||
ctx.actions.run( | ||
executable = "%s/bin/javac" % exec_javabase.java_home, | ||
mnemonic = "JavaToolchainCompileClasses", | ||
inputs = [ctx.file.src] + ctx.files.java_runtime_alias, | ||
outputs = [class_dir], | ||
arguments = [args], | ||
env = env, | ||
execution_requirements = _SUPPORTS_PATH_MAPPING, | ||
) | ||
|
||
bootclasspath = ctx.outputs.output_jar | ||
|
||
args = ctx.actions.args() | ||
args.add("-XX:+IgnoreUnrecognizedVMOptions") | ||
args.add("-XX:-UsePerfData") | ||
args.add("--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED") | ||
args.add("--add-exports=jdk.compiler/com.sun.tools.javac.platform=ALL-UNNAMED") | ||
args.add("--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED") | ||
args.add_all("-cp", [class_dir], expand_directories = False) | ||
args.add("DumpPlatformClassPath") | ||
args.add(bootclasspath) | ||
|
||
if ctx.attr.language_version_bootstrap_runtime: | ||
# 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 | ||
any_javabase_files = any_javabase.files.to_list() | ||
|
||
# If possible, add the Java executable to the command line as a File so that it can be path | ||
# mapped. | ||
java_executable = [f for f in any_javabase_files if f.path == any_javabase.java_executable_exec_path] | ||
if len(java_executable) == 1: | ||
args.add_all(java_executable, map_each = _java_home) | ||
else: | ||
args.add(any_javabase.java_home) | ||
|
||
system_files = ("release", "modules", "jrt-fs.jar") | ||
system = [f for f in any_javabase_files if f.basename in system_files] | ||
if len(system) != len(system_files): | ||
system = None | ||
|
||
inputs = depset([class_dir] + ctx.files.java_runtime_alias, transitive = [any_javabase.files]) | ||
ctx.actions.run( | ||
executable = str(exec_javabase.java_executable_exec_path), | ||
mnemonic = "JavaToolchainCompileBootClasspath", | ||
inputs = inputs, | ||
outputs = [bootclasspath], | ||
arguments = [args], | ||
env = env, | ||
execution_requirements = _SUPPORTS_PATH_MAPPING, | ||
) | ||
return [ | ||
DefaultInfo(files = depset([bootclasspath])), | ||
java_common.BootClassPathInfo( | ||
bootclasspath = [bootclasspath], | ||
system = system, | ||
), | ||
OutputGroupInfo(jar = [bootclasspath]), | ||
] | ||
|
||
_bootclasspath = rule( | ||
implementation = _bootclasspath_impl, | ||
attrs = { | ||
"java_runtime_alias": attr.label( | ||
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, | ||
), | ||
"_allowlist_function_transition": attr.label( | ||
default = "@bazel_tools//tools/allowlists/function_transition_allowlist", | ||
), | ||
"_utf8_environment": attr.label( | ||
default = ":utf8_environment", | ||
cfg = "exec", | ||
), | ||
}, | ||
toolchains = [_JAVA_BOOTSTRAP_RUNTIME_TOOLCHAIN_TYPE], | ||
) | ||
|
||
def bootclasspath(name, **kwargs): | ||
_bootclasspath( | ||
name = name, | ||
output_jar = name + ".jar", | ||
**kwargs | ||
) |
Oops, something went wrong.