| # Copyright 2021 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_import rule. | |
| """ | |
| load("@rules_cc//cc/common:cc_info.bzl", "CcInfo") | |
| load("//java/common:java_semantics.bzl", "semantics") | |
| load("//java/common/rules/impl:basic_java_library_impl.bzl", "construct_defaultinfo") | |
| load("//java/common/rules/impl:import_deps_check.bzl", "import_deps_check") | |
| load("//java/private:java_common.bzl", "java_common") | |
| load("//java/private:java_common_internal.bzl", _run_ijar_private_for_builtins = "run_ijar") | |
| load("//java/private:java_info.bzl", "JavaInfo") | |
| load(":proguard_validation.bzl", "validate_proguard_specs") | |
| # copybara: default visibility | |
| def _filter_provider(provider, *attrs): | |
| return [dep[provider] for attr in attrs for dep in attr if provider in dep] | |
| def _collect_jars(ctx, jars): | |
| jars_dict = {} | |
| for info in jars: | |
| if JavaInfo in info: | |
| fail("'jars' attribute cannot contain labels of Java targets") | |
| for jar in info[DefaultInfo].files.to_list(): | |
| jar_path = jar.dirname + jar.basename | |
| if jars_dict.get(jar_path) != None: | |
| fail("in jars attribute of java_import rule //" + ctx.label.package + ":" + ctx.attr.name + ": " + jar.basename + " is a duplicate") | |
| jars_dict[jar_path] = jar | |
| return [jar_tuple[1] for jar_tuple in jars_dict.items()] if len(jars_dict.items()) > 0 else [] | |
| def _process_with_ijars_if_needed(jars, ctx): | |
| file_dict = {} | |
| use_ijars = ctx.fragments.java.use_ijars() | |
| for jar in jars: | |
| interface_jar = jar | |
| if use_ijars: | |
| ijar_basename = jar.short_path.removeprefix("../").removesuffix("." + jar.extension) + "-ijar.jar" | |
| interface_jar_directory = "_ijar/" + ctx.label.name + "/" + ijar_basename | |
| interface_jar = ctx.actions.declare_file(interface_jar_directory) | |
| _run_ijar_private_for_builtins( | |
| ctx.actions, | |
| target_label = ctx.label, | |
| jar = jar, | |
| output = interface_jar, | |
| java_toolchain = semantics.find_java_toolchain(ctx), | |
| ) | |
| file_dict[jar] = interface_jar | |
| return file_dict | |
| def _check_export_error(ctx, exports, permit_exports): | |
| disallow_java_import_exports = ctx.fragments.java.disallow_java_import_exports() | |
| if len(exports) != 0 and (disallow_java_import_exports or not permit_exports): | |
| fail("java_import.exports is no longer supported; use java_import.deps instead") | |
| def _check_empty_jars_error(ctx, jars): | |
| if len(jars) == 0: | |
| fail("empty java_import.jars is not supported " + ctx.label.package) | |
| def bazel_java_import_rule( | |
| ctx, | |
| jars = [], | |
| srcjar = None, | |
| deps = [], | |
| runtime_deps = [], | |
| exports = [], | |
| neverlink = False, | |
| proguard_specs = [], | |
| add_exports = [], | |
| add_opens = [], | |
| permit_exports = True, | |
| skip_incomplete_deps_check = True): | |
| """Implements java_import. | |
| This rule allows the use of precompiled .jar files as libraries in other Java rules. | |
| Args: | |
| ctx: (RuleContext) Used to register the actions. | |
| jars: (list[Artifact]) List of output jars. | |
| srcjar: (Artifact) The jar containing the sources. | |
| deps: (list[Target]) The list of dependent libraries. | |
| runtime_deps: (list[Target]) Runtime dependencies to attach to the rule. | |
| exports: (list[Target]) The list of exported libraries. | |
| neverlink: (bool) Whether this rule should only be used for compilation and not at runtime. | |
| proguard_specs: (list[File]) Files to be used as Proguard specification. | |
| add_exports: (list[str]) Allow this library to access the given <module>/<package>. | |
| add_opens: (list[str]) Allow this library to reflectively access the given <module>/<package>. | |
| permit_exports: (bool) Allow using exports | |
| skip_incomplete_deps_check: (bool) If this target is allowed to have incomplete deps | |
| Returns: | |
| (list[provider]) A list containing DefaultInfo, JavaInfo, | |
| OutputGroupsInfo, ProguardSpecProvider providers. | |
| """ | |
| _check_empty_jars_error(ctx, jars) | |
| _check_export_error(ctx, exports, permit_exports) | |
| collected_jars = _collect_jars(ctx, jars) | |
| all_deps = _filter_provider(JavaInfo, deps, exports) | |
| merged_java_info = java_common.merge(all_deps) | |
| # import_deps_check is always run to generate the jdeps proto for downstream compile actions, | |
| # but may be silenced. | |
| has_incomplete_deps = "incomplete-deps" in ctx.attr.tags | |
| if skip_incomplete_deps_check or has_incomplete_deps: | |
| checking_mode = "silence" | |
| else: | |
| checking_mode = "error" | |
| jdeps_artifact = import_deps_check( | |
| ctx, | |
| collected_jars, | |
| merged_java_info.compile_jars, | |
| merged_java_info.transitive_compile_time_jars, | |
| "java_import", | |
| checking_mode = checking_mode, | |
| ) | |
| compilation_to_runtime_jar_map = _process_with_ijars_if_needed(collected_jars, ctx) | |
| runtime_deps_list = [runtime_dep[JavaInfo] for runtime_dep in runtime_deps if JavaInfo in runtime_dep] | |
| cc_info_list = [dep[CcInfo] for dep in deps if CcInfo in dep] | |
| java_infos = [] | |
| for jar in collected_jars: | |
| java_infos.append(JavaInfo( | |
| output_jar = jar, | |
| compile_jar = compilation_to_runtime_jar_map[jar], | |
| compile_jdeps = jdeps_artifact, | |
| deps = all_deps, | |
| runtime_deps = runtime_deps_list, | |
| neverlink = neverlink, | |
| source_jar = srcjar, | |
| exports = [export[JavaInfo] for export in exports if JavaInfo in export], # Watchout, maybe you need to add them there manually. | |
| native_libraries = cc_info_list, | |
| add_exports = add_exports, | |
| add_opens = add_opens, | |
| )) | |
| java_info = java_common.merge(java_infos) | |
| target = {"JavaInfo": java_info} | |
| target["ProguardSpecProvider"] = validate_proguard_specs( | |
| ctx, | |
| proguard_specs, | |
| [deps, runtime_deps, exports], | |
| ) | |
| # TODO(kotlaja): Revise if collected_runtimes can be added into construct_defaultinfo directly. | |
| collected_runtimes = [] | |
| for runtime_dep in ctx.attr.runtime_deps: | |
| collected_runtimes.extend(runtime_dep[DefaultInfo].files.to_list()) | |
| target["DefaultInfo"] = construct_defaultinfo( | |
| ctx, | |
| collected_jars, | |
| collected_jars + collected_runtimes, | |
| neverlink, | |
| exports, | |
| ) | |
| output_group_src_jars = depset() if srcjar == None else depset([srcjar]) | |
| validation_group = [] | |
| if jdeps_artifact != None and checking_mode != "silence": | |
| validation_group.append(jdeps_artifact) | |
| if srcjar != None: | |
| validation_group.append(srcjar) | |
| target["OutputGroupInfo"] = OutputGroupInfo( | |
| **{ | |
| "_source_jars": output_group_src_jars, | |
| "_direct_source_jars": output_group_src_jars, | |
| "_validation": depset(validation_group), | |
| "_hidden_top_level_INTERNAL_": target["ProguardSpecProvider"].specs, | |
| } | |
| ) | |
| return target |