blob: 3d80ad15483d087b0003e331a8bd424e0adef8ec [file] [log] [blame]
# Copyright 2023 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.
"""
Definition of java_toolchain rule and JavaToolchainInfo provider.
"""
load(":common/java/boot_class_path_info.bzl", "BootClassPathInfo")
load(":common/java/java_helper.bzl", "helper")
load(":common/java/java_info.bzl", "JavaPluginDataInfo")
load(":common/java/java_package_configuration.bzl", "JavaPackageConfigurationInfo")
load(":common/java/java_runtime.bzl", "JavaRuntimeInfo")
load(":common/java/java_semantics.bzl", "semantics")
_java_common_internal = _builtins.internal.java_common_internal_do_not_use
ToolchainInfo = _builtins.toplevel.platform_common.ToolchainInfo
PackageSpecificationInfo = _builtins.toplevel.PackageSpecificationInfo
def _java_toolchain_info_init(**_kwargs):
fail("JavaToolchainInfo instantiation is a private API")
_PRIVATE_API_DOC_STRING = "internal API, DO NOT USE!"
JavaToolchainInfo, _new_javatoolchaininfo = provider(
doc = "Information about the JDK used by the <code>java_*</code> rules.",
fields = {
"bootclasspath": "(depset[File]) The Java target bootclasspath entries. Corresponds to javac's -bootclasspath flag.",
"ijar": "(FilesToRunProvider) The ijar executable.",
"jacocorunner": "(FilesToRunProvider) The jacocorunner used by the toolchain.",
"java_runtime": "(JavaRuntimeInfo) The java runtime information.",
"jvm_opt": "(depset[str]) The default options for the JVM running the java compiler and associated tools.",
"label": "(label) The toolchain label.",
"proguard_allowlister": "(FilesToRunProvider) The binary to validate proguard configuration.",
"single_jar": "(FilesToRunProvider) The SingleJar deploy jar.",
"source_version": "(str) The java source version.",
"target_version": "(str) The java target version.",
"tools": "(depset[File]) The compilation tools.",
# private
"_android_linter": _PRIVATE_API_DOC_STRING,
"_bootclasspath_info": _PRIVATE_API_DOC_STRING,
"_bytecode_optimizer": _PRIVATE_API_DOC_STRING,
"_compatible_javacopts": _PRIVATE_API_DOC_STRING,
"_deps_checker": _PRIVATE_API_DOC_STRING,
"_forcibly_disable_header_compilation": _PRIVATE_API_DOC_STRING,
"_gen_class": _PRIVATE_API_DOC_STRING,
"_header_compiler": _PRIVATE_API_DOC_STRING,
"_header_compiler_builtin_processors": _PRIVATE_API_DOC_STRING,
"_header_compiler_direct": _PRIVATE_API_DOC_STRING,
"_javabuilder": _PRIVATE_API_DOC_STRING,
"_javacopts": _PRIVATE_API_DOC_STRING,
"_javacopts_list": _PRIVATE_API_DOC_STRING,
"_javac_supports_workers": _PRIVATE_API_DOC_STRING,
"_javac_supports_multiplex_workers": _PRIVATE_API_DOC_STRING,
"_javac_supports_worker_cancellation": _PRIVATE_API_DOC_STRING,
"_jspecify_info": _PRIVATE_API_DOC_STRING,
"_local_java_optimization_config": _PRIVATE_API_DOC_STRING,
"_one_version_tool": _PRIVATE_API_DOC_STRING,
"_one_version_allowlist": _PRIVATE_API_DOC_STRING,
"_one_version_allowlist_for_tests": _PRIVATE_API_DOC_STRING,
"_package_configuration": _PRIVATE_API_DOC_STRING,
"_reduced_classpath_incompatible_processors": _PRIVATE_API_DOC_STRING,
"_timezone_data": _PRIVATE_API_DOC_STRING,
},
init = _java_toolchain_info_init,
)
def _java_toolchain_impl(ctx):
javac_opts_list = _get_javac_opts(ctx)
bootclasspath_info = _get_bootclasspath_info(ctx)
java_runtime = _get_java_runtime(ctx)
if java_runtime and java_runtime.lib_ct_sym:
header_compiler_direct_data = [java_runtime.lib_ct_sym]
header_compiler_direct_jvm_opts = ["-Dturbine.ctSymPath=" + java_runtime.lib_ct_sym.path]
else:
header_compiler_direct_data = []
header_compiler_direct_jvm_opts = []
java_toolchain_info = _new_javatoolchaininfo(
bootclasspath = bootclasspath_info.bootclasspath,
ijar = ctx.attr.ijar.files_to_run if ctx.attr.ijar else None,
jacocorunner = ctx.attr.jacocorunner.files_to_run if ctx.attr.jacocorunner else None,
java_runtime = java_runtime,
jvm_opt = depset(_java_common_internal.expand_java_opts(ctx, "jvm_opts", tokenize = False, exec_paths = True)),
label = ctx.label,
proguard_allowlister = ctx.attr.proguard_allowlister.files_to_run if ctx.attr.proguard_allowlister else None,
single_jar = ctx.attr.singlejar.files_to_run,
source_version = ctx.attr.source_version,
target_version = ctx.attr.target_version,
tools = depset(ctx.files.tools),
# private
_android_linter = _get_android_lint_tool(ctx),
_bootclasspath_info = bootclasspath_info,
_bytecode_optimizer = _get_tool_from_executable(ctx, "_bytecode_optimizer"),
_compatible_javacopts = _get_compatible_javacopts(ctx),
_deps_checker = ctx.file.deps_checker,
_forcibly_disable_header_compilation = ctx.attr.forcibly_disable_header_compilation,
_gen_class = ctx.file.genclass,
_header_compiler = _get_tool_from_ctx(ctx, "header_compiler", "turbine_data", "turbine_jvm_opts"),
_header_compiler_builtin_processors = depset(ctx.attr.header_compiler_builtin_processors),
_header_compiler_direct = _get_tool_from_executable(
ctx,
"header_compiler_direct",
data = header_compiler_direct_data,
jvm_opts = header_compiler_direct_jvm_opts,
),
_javabuilder = _get_tool_from_ctx(ctx, "javabuilder", "javabuilder_data", "javabuilder_jvm_opts"),
_javacopts = helper.detokenize_javacopts(javac_opts_list),
_javacopts_list = javac_opts_list,
_javac_supports_workers = ctx.attr.javac_supports_workers,
_javac_supports_multiplex_workers = ctx.attr.javac_supports_multiplex_workers,
_javac_supports_worker_cancellation = ctx.attr.javac_supports_worker_cancellation,
_jspecify_info = _get_jspecify_info(ctx),
_local_java_optimization_config = ctx.files._local_java_optimization_configuration,
_one_version_tool = ctx.attr.oneversion.files_to_run if ctx.attr.oneversion else None,
_one_version_allowlist = ctx.file.oneversion_whitelist,
_one_version_allowlist_for_tests = ctx.file.oneversion_allowlist_for_tests,
_package_configuration = [dep[JavaPackageConfigurationInfo] for dep in ctx.attr.package_configuration],
_reduced_classpath_incompatible_processors = depset(ctx.attr.reduced_classpath_incompatible_processors, order = "preorder"),
_timezone_data = ctx.file.timezone_data,
)
toolchain_info = ToolchainInfo(java = java_toolchain_info)
return [java_toolchain_info, toolchain_info, DefaultInfo()]
def _get_bootclasspath_info(ctx):
bootclasspath_infos = [dep[BootClassPathInfo] for dep in ctx.attr.bootclasspath if BootClassPathInfo in dep]
if bootclasspath_infos:
if len(bootclasspath_infos) != 1:
fail("in attribute 'bootclasspath': expected exactly one entry with a BootClassPathInfo provider")
else:
return bootclasspath_infos[0]
else:
return BootClassPathInfo(bootclasspath = ctx.files.bootclasspath)
def _get_java_runtime(ctx):
if not ctx.attr.java_runtime:
return None
return ctx.attr.java_runtime[ToolchainInfo].java_runtime
def _get_javac_opts(ctx):
opts = []
if ctx.attr.source_version:
opts.extend(["-source", ctx.attr.source_version])
if ctx.attr.target_version:
opts.extend(["-target", ctx.attr.target_version])
if ctx.attr.xlint:
opts.append("-Xlint:" + ",".join(ctx.attr.xlint))
opts.extend(_java_common_internal.expand_java_opts(ctx, "misc", tokenize = True))
opts.extend(_java_common_internal.expand_java_opts(ctx, "javacopts", tokenize = True))
return opts
def _get_android_lint_tool(ctx):
if not ctx.attr.android_lint_runner:
return None
files_to_run = ctx.attr.android_lint_runner.files_to_run
if not files_to_run or not files_to_run.executable:
fail(ctx.attr.android_lint_runner.label, "does not refer to a valid executable target")
return struct(
tool = files_to_run,
data = depset(ctx.files.android_lint_data),
jvm_opts = depset([ctx.expand_location(opt, ctx.attr.android_lint_data) for opt in ctx.attr.android_lint_jvm_opts]),
lint_opts = [ctx.expand_location(opt, ctx.attr.android_lint_data) for opt in ctx.attr.android_lint_opts],
package_config = [dep[JavaPackageConfigurationInfo] for dep in ctx.attr.android_lint_package_configuration],
)
def _get_tool_from_ctx(ctx, tool_attr, data_attr, opts_attr):
dep = getattr(ctx.attr, tool_attr)
if not dep:
return None
files_to_run = dep.files_to_run
if not files_to_run or not files_to_run.executable:
fail(dep.label, "does not refer to a valid executable target")
data = getattr(ctx.attr, data_attr)
return struct(
tool = files_to_run,
data = depset(getattr(ctx.files, data_attr)),
jvm_opts = depset([ctx.expand_location(opt, data) for opt in getattr(ctx.attr, opts_attr)]),
)
def _get_tool_from_executable(ctx, attr_name, data = [], jvm_opts = []):
dep = getattr(ctx.attr, attr_name)
if not dep:
return None
files_to_run = dep.files_to_run
if not files_to_run or not files_to_run.executable:
fail(dep.label, "does not refer to a valid executable target")
return struct(tool = files_to_run, data = depset(data), jvm_opts = depset(jvm_opts))
def _get_compatible_javacopts(ctx):
result = {}
for key, opt_list in ctx.attr.compatible_javacopts.items():
result[key] = helper.detokenize_javacopts([token for opt in opt_list for token in ctx.tokenize(opt)])
return result
def _get_jspecify_info(ctx):
if not ctx.attr.jspecify_processor_class:
return None
stubs = ctx.files.jspecify_stubs
javacopts = []
javacopts.extend(ctx.attr.jspecify_javacopts)
if stubs:
javacopts.append("-Astubs=" + ":".join([file.path for file in stubs]))
return struct(
processor = JavaPluginDataInfo(
processor_classes = depset([ctx.attr.jspecify_processor_class]),
processor_jars = depset([ctx.file.jspecify_processor]),
processor_data = depset(stubs),
),
implicit_deps = depset([ctx.file.jspecify_implicit_deps]),
javacopts = javacopts,
packages = [target[PackageSpecificationInfo] for target in ctx.attr.jspecify_packages],
)
_java_toolchain = rule(
implementation = _java_toolchain_impl,
attrs = {
"android_lint_data": attr.label_list(cfg = "exec", allow_files = True),
"android_lint_opts": attr.string_list(default = []),
"android_lint_jvm_opts": attr.string_list(default = []),
"android_lint_package_configuration": attr.label_list(cfg = "exec", providers = [JavaPackageConfigurationInfo], allow_files = True),
"android_lint_runner": attr.label(cfg = "exec", executable = True, allow_single_file = True),
"bootclasspath": attr.label_list(default = [], allow_files = True),
"compatible_javacopts": attr.string_list_dict(),
"deps_checker": attr.label(allow_single_file = True, cfg = "exec", executable = True),
"forcibly_disable_header_compilation": attr.bool(default = False),
"genclass": attr.label(allow_single_file = True, cfg = "exec", executable = True),
"header_compiler": attr.label(allow_single_file = True, cfg = "exec", executable = True),
"header_compiler_direct": attr.label(allow_single_file = True, cfg = "exec", executable = True),
"header_compiler_builtin_processors": attr.string_list(),
"ijar": attr.label(cfg = "exec", allow_files = True, executable = True),
"jacocorunner": attr.label(cfg = "exec", allow_single_file = True, executable = True),
"javabuilder": attr.label(cfg = "exec", allow_single_file = True, executable = True),
"javabuilder_data": attr.label_list(cfg = "exec", allow_files = True),
"javabuilder_jvm_opts": attr.string_list(),
"java_runtime": attr.label(cfg = "exec", providers = [JavaRuntimeInfo]),
"javac_supports_workers": attr.bool(default = True),
"javac_supports_multiplex_workers": attr.bool(default = True),
"javac_supports_worker_cancellation": attr.bool(default = True),
"javacopts": attr.string_list(default = []),
"jspecify_implicit_deps": attr.label(cfg = "exec", allow_single_file = True, executable = True),
"jspecify_javacopts": attr.string_list(),
"jspecify_packages": attr.label_list(cfg = "exec", allow_files = True, providers = [PackageSpecificationInfo]),
"jspecify_processor": attr.label(cfg = "exec", allow_single_file = True, executable = True),
"jspecify_processor_class": attr.string(),
"jspecify_stubs": attr.label_list(cfg = "exec", allow_files = True),
"jvm_opts": attr.string_list(default = []),
"misc": attr.string_list(default = []),
"oneversion": attr.label(cfg = "exec", allow_files = True, executable = True),
"oneversion_whitelist": attr.label(allow_single_file = True),
"oneversion_allowlist_for_tests": attr.label(allow_single_file = True),
"package_configuration": attr.label_list(cfg = "exec", providers = [JavaPackageConfigurationInfo]),
"proguard_allowlister": attr.label(cfg = "exec", executable = True, allow_files = True, default = semantics.PROGUARD_ALLOWLISTER_LABEL),
"reduced_classpath_incompatible_processors": attr.string_list(),
"singlejar": attr.label(cfg = "exec", allow_files = True, executable = True),
"source_version": attr.string(),
"target_version": attr.string(),
"timezone_data": attr.label(cfg = "exec", allow_single_file = True),
"tools": attr.label_list(cfg = "exec", allow_files = True),
"turbine_data": attr.label_list(cfg = "exec", allow_files = True),
"turbine_jvm_opts": attr.string_list(),
"xlint": attr.string_list(default = []),
"licenses": attr.license() if hasattr(attr, "license") else attr.string_list(),
"_bytecode_optimizer": attr.label(
cfg = "exec",
executable = True,
default = configuration_field(fragment = "java", name = "java_toolchain_bytecode_optimizer"),
),
"_local_java_optimization_configuration": attr.label(
cfg = "exec",
default = configuration_field(fragment = "java", name = "local_java_optimization_configuration"),
allow_files = True,
),
},
fragments = ["java"],
)
def _extract_singleton_list_value(dict, key):
if key in dict and type(dict[key]) == type([]):
list = dict[key]
if len(list) > 1:
fail("expected a single value for:", key, "got: ", list)
elif len(list) == 1:
dict[key] = dict[key][0]
else:
dict[key] = None
def _java_toolchain_macro(**kwargs):
# these attributes are defined as executable `label_list`s in native but are
# expected to be singleton values. Since this is not supported in Starlark,
# we just inline the value from the list (if present) before invoking the
# rule.
_extract_singleton_list_value(kwargs, "genclass")
_extract_singleton_list_value(kwargs, "deps_checker")
_extract_singleton_list_value(kwargs, "header_compiler")
_extract_singleton_list_value(kwargs, "header_compiler_direct")
_extract_singleton_list_value(kwargs, "ijar")
_extract_singleton_list_value(kwargs, "javabuilder")
_extract_singleton_list_value(kwargs, "singlejar")
_java_toolchain(**kwargs)
java_toolchain = _java_toolchain_macro