| # 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. |
| |
| """ |
| Common code for reuse across java_* rules |
| """ |
| |
| load("@rules_cc//cc/common:cc_info.bzl", "CcInfo") |
| load("//java/common:java_common.bzl", "java_common") |
| load("//java/common:java_info.bzl", "JavaInfo") |
| load("//java/common:java_plugin_info.bzl", "JavaPluginInfo") |
| load("//java/common/rules:android_lint.bzl", "android_lint_subrule") |
| load(":compile_action.bzl", "compile_action") |
| load(":proguard_validation.bzl", "validate_proguard_specs") |
| |
| visibility([ |
| "//java/...", |
| ]) |
| |
| _java_common_internal = java_common.internal_DO_NOT_USE() |
| BootClassPathInfo = java_common.BootClassPathInfo |
| target_kind = _java_common_internal.target_kind |
| |
| def _filter_srcs(srcs, ext): |
| return [f for f in srcs if f.extension == ext] |
| |
| def _filter_provider(provider, *attrs): |
| return [dep[provider] for attr in attrs for dep in attr if provider in dep] |
| |
| # TODO(b/11285003): disallow jar files in deps, require java_import instead |
| def _filter_javainfo_and_legacy_jars(attr): |
| dep_list = [] |
| |
| # Native code collected data into a NestedSet, using add for legacy jars and |
| # addTransitive for JavaInfo. This resulted in legacy jars being first in the list. |
| for dep in attr: |
| kind = target_kind(dep) |
| if not JavaInfo in dep or kind == "java_binary" or kind == "java_test": |
| for file in dep[DefaultInfo].files.to_list(): |
| if file.extension == "jar": |
| # Native doesn't construct JavaInfo |
| java_info = JavaInfo(output_jar = file, compile_jar = file) |
| dep_list.append(java_info) |
| |
| for dep in attr: |
| if JavaInfo in dep: |
| dep_list.append(dep[JavaInfo]) |
| return dep_list |
| |
| def basic_java_library( |
| ctx, |
| srcs, |
| deps = [], |
| runtime_deps = [], |
| plugins = [], |
| exports = [], |
| exported_plugins = [], |
| resources = [], |
| resource_jars = [], |
| classpath_resources = [], |
| javacopts = [], |
| neverlink = False, |
| enable_compile_jar_action = True, |
| coverage_config = None, |
| proguard_specs = None, |
| add_exports = [], |
| add_opens = [], |
| bootclasspath = None, |
| javabuilder_jvm_flags = None): |
| """ |
| Creates actions that compile and lint Java sources, sets up coverage and returns JavaInfo, InstrumentedFilesInfo and output groups. |
| |
| The call creates actions and providers needed and shared by `java_library`, |
| `java_plugin`,`java_binary`, and `java_test` rules and it is primarily |
| intended to be used in those rules. |
| |
| Before compilation coverage.runner is added to the dependencies and if |
| present plugins are extended with the value of `--plugin` flag. |
| |
| Args: |
| ctx: (RuleContext) Used to register the actions. |
| srcs: (list[File]) The list of source files that are processed to create the target. |
| deps: (list[Target]) The list of other libraries to be linked in to the target. |
| runtime_deps: (list[Target]) Libraries to make available to the final binary or test at runtime only. |
| plugins: (list[Target]) Java compiler plugins to run at compile-time. |
| exports: (list[Target]) Exported libraries. |
| exported_plugins: (list[Target]) The list of `java_plugin`s (e.g. annotation |
| processors) to export to libraries that directly depend on this library. |
| resources: (list[File]) A list of data files to include in a Java jar. |
| resource_jars: (list[File]) A list of jar files to unpack and include in a |
| Java jar. |
| classpath_resources: (list[File]) |
| javacopts: (list[str]) |
| neverlink: (bool) Whether this library should only be used for compilation and not at runtime. |
| enable_compile_jar_action: (bool) Enables header compilation or ijar creation. |
| coverage_config: (struct{runner:JavaInfo, support_files:list[File]|depset[File], env:dict[str,str]}) |
| Coverage configuration. `runner` is added to dependencies during |
| compilation, `support_files` and `env` is returned in InstrumentedFilesInfo. |
| proguard_specs: (list[File]) Files to be used as Proguard specification. |
| Proguard validation is done only when the parameter is set. |
| 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>. |
| bootclasspath: (Target) The JDK APIs to compile this library against. |
| javabuilder_jvm_flags: (list[str]) Additional JVM flags to pass to JavaBuilder. |
| Returns: |
| (dict[str, Provider], |
| {files_to_build: list[File], |
| runfiles: list[File], |
| output_groups: dict[str,list[File]]}) |
| """ |
| source_files = _filter_srcs(srcs, "java") |
| source_jars = _filter_srcs(srcs, "srcjar") |
| |
| plugins_javaplugininfo = _collect_plugins(plugins) |
| plugins_javaplugininfo.append(ctx.attr._java_plugins[JavaPluginInfo]) |
| |
| properties = _filter_srcs(srcs, "properties") |
| if properties: |
| resources = list(resources) |
| resources.extend(properties) |
| |
| java_info, compilation_info = compile_action( |
| ctx, |
| ctx.outputs.classjar, |
| ctx.outputs.sourcejar, |
| source_files, |
| source_jars, |
| collect_deps(deps) + ([coverage_config.runner] if coverage_config and coverage_config.runner else []), |
| collect_deps(runtime_deps), |
| plugins_javaplugininfo, |
| collect_deps(exports), |
| _collect_plugins(exported_plugins), |
| resources, |
| resource_jars, |
| classpath_resources, |
| _collect_native_libraries(deps, runtime_deps, exports), |
| javacopts, |
| neverlink, |
| ctx.fragments.java.strict_java_deps, |
| enable_compile_jar_action, |
| add_exports = add_exports, |
| add_opens = add_opens, |
| bootclasspath = bootclasspath[BootClassPathInfo] if bootclasspath else None, |
| javabuilder_jvm_flags = javabuilder_jvm_flags, |
| ) |
| target = {"JavaInfo": java_info} |
| |
| output_groups = dict( |
| compilation_outputs = compilation_info.files_to_build, |
| _source_jars = java_info.transitive_source_jars, |
| _direct_source_jars = java_info.source_jars, |
| ) |
| |
| if ctx.fragments.java.run_android_lint: |
| generated_source_jars = [ |
| output.generated_source_jar |
| for output in java_info.java_outputs |
| if output.generated_source_jar != None |
| ] |
| lint_output = android_lint_subrule( |
| source_files, |
| source_jars + generated_source_jars, |
| compilation_info, |
| ) |
| if lint_output: |
| output_groups["_validation"] = [lint_output] |
| |
| target["InstrumentedFilesInfo"] = coverage_common.instrumented_files_info( |
| ctx, |
| source_attributes = ["srcs"], |
| dependency_attributes = ["deps", "data", "resources", "resource_jars", "exports", "runtime_deps", "jars"], |
| coverage_support_files = coverage_config.support_files if coverage_config else depset(), |
| coverage_environment = coverage_config.env if coverage_config else {}, |
| ) |
| |
| if proguard_specs != None: |
| target["ProguardSpecProvider"] = validate_proguard_specs( |
| ctx, |
| proguard_specs, |
| [deps, runtime_deps, exports], |
| ) |
| output_groups["_hidden_top_level_INTERNAL_"] = target["ProguardSpecProvider"].specs |
| |
| return target, struct( |
| files_to_build = compilation_info.files_to_build, |
| runfiles = compilation_info.runfiles, |
| output_groups = output_groups, |
| ) |
| |
| def _collect_plugins(plugins): |
| """Collects plugins from an attribute. |
| |
| Use this call to collect plugins from `plugins` or `exported_plugins` attribute. |
| |
| The call simply extracts JavaPluginInfo provider. |
| |
| Args: |
| plugins: (list[Target]) Attribute to collect plugins from. |
| Returns: |
| (list[JavaPluginInfo]) The plugins. |
| """ |
| return _filter_provider(JavaPluginInfo, plugins) |
| |
| def collect_deps(deps): |
| """Collects dependencies from an attribute. |
| |
| Use this call to collect plugins from `deps`, `runtime_deps`, or `exports` attribute. |
| |
| The call extracts JavaInfo and additionaly also "legacy jars". "legacy jars" |
| are wrapped into a JavaInfo. |
| |
| Args: |
| deps: (list[Target]) Attribute to collect dependencies from. |
| Returns: |
| (list[JavaInfo]) The dependencies. |
| """ |
| return _filter_javainfo_and_legacy_jars(deps) |
| |
| def _collect_native_libraries(*attrs): |
| """Collects native libraries from a list of attributes. |
| |
| Use this call to collect native libraries from `deps`, `runtime_deps`, or `exports` attributes. |
| |
| The call simply extracts CcInfo provider. |
| Args: |
| *attrs: (*list[Target]) Attribute to collect native libraries from. |
| Returns: |
| (list[CcInfo]) The native library dependencies. |
| """ |
| return _filter_provider(CcInfo, *attrs) |
| |
| def construct_defaultinfo(ctx, files_to_build, files, neverlink, *extra_attrs): |
| """Constructs DefaultInfo for Java library like rule. |
| |
| Args: |
| ctx: (RuleContext) Used to construct the runfiles. |
| files_to_build: (list[File]) List of the files built by the rule. |
| files: (list[File]) List of the files include in runfiles. |
| neverlink: (bool) When true empty runfiles are constructed. |
| *extra_attrs: (list[Target]) Extra attributes to merge runfiles from. |
| |
| Returns: |
| (DefaultInfo) DefaultInfo provider. |
| """ |
| if neverlink: |
| runfiles = None |
| else: |
| runfiles = ctx.runfiles(files = files, collect_default = True) |
| runfiles = runfiles.merge_all([dep[DefaultInfo].default_runfiles for attr in extra_attrs for dep in attr]) |
| default_info = DefaultInfo( |
| files = depset(files_to_build), |
| runfiles = runfiles, |
| ) |
| return default_info |