# 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/rules:android_lint.bzl", "android_lint_subrule") load("//java/private:boot_class_path_info.bzl", "BootClassPathInfo") load("//java/private:java_common_internal.bzl", "target_kind") load("//java/private:java_info.bzl", "JavaInfo", "JavaPluginInfo") load(":compile_action.bzl", "compile_action") load(":proguard_validation.bzl", "validate_proguard_specs") # copybara: default multiline visibility 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 /. add_opens: (list[str]) Allow this library to reflectively access the given /. 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