| # 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(":common/rule_util.bzl", "create_composite_dep") |
| load(":common/java/android_lint.bzl", "android_lint_action") |
| load(":common/java/compile_action.bzl", "COMPILE_ACTION") |
| |
| java_common = _builtins.toplevel.java_common |
| coverage_common = _builtins.toplevel.coverage_common |
| |
| JavaInfo = _builtins.toplevel.JavaInfo |
| JavaPluginInfo = _builtins.toplevel.JavaPluginInfo |
| ProtoInfo = _builtins.toplevel.ProtoInfo |
| CcInfo = _builtins.toplevel.CcInfo |
| |
| 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] |
| |
| def _get_attr_safe(ctx, attr, default): |
| return getattr(ctx.attr, attr) if hasattr(ctx.attr, attr) else default |
| |
| # 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 = java_common.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 = [], |
| classpath_resources = [], |
| javacopts = [], |
| neverlink = False, |
| enable_compile_jar_action = True, |
| coverage_config = 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. |
| |
| To prepare arguments for this call from rule's attributes use the provided |
| helpers: `collect_deps`, `collect_plugins`, and `collect_resources`. |
| |
| 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. |
| 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:Target, 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. |
| |
| Returns: |
| ({java_info: JavaInfo, |
| files_to_build: list[File], |
| has_sources_or_resources: bool, |
| instrumented_files_info: InstrumentedFilesInfo, |
| output_groups: dict[str,list[File]], |
| extra_providers: list[Provider]}) |
| """ |
| source_files = _filter_srcs(srcs, "java") |
| source_jars = _filter_srcs(srcs, "srcjar") |
| |
| java_info, compilation_info = COMPILE_ACTION.call( |
| ctx, |
| output_class_jar = ctx.outputs.classjar, |
| output_source_jar = ctx.outputs.sourcejar, |
| source_files = source_files, |
| source_jars = source_jars, |
| deps = _collect_deps(deps + ([coverage_config.runner] if coverage_config else [])), |
| runtime_deps = _collect_deps(runtime_deps), |
| plugins = _collect_plugins(plugins + [ctx.attr._java_plugins]), |
| exports = _collect_deps(exports), |
| exported_plugins = _collect_plugins(exported_plugins), |
| resources = resources + _filter_srcs(srcs, "properties"), |
| classpath_resources = classpath_resources, |
| native_libraries = _collect_native_libraries(deps, runtime_deps, exports), |
| javacopts = javacopts, |
| neverlink = neverlink, |
| strict_deps = ctx.fragments.java.strict_java_deps, |
| enable_compile_jar_action = enable_compile_jar_action, |
| ) |
| |
| output_groups = dict( |
| compilation_outputs = compilation_info.output_class_jars, |
| _source_jars = java_info.transitive_source_jars, |
| _direct_source_jars = java_info.source_jars, |
| ) |
| |
| # TODO(b/131760365): This is a hack, since the Starlark APIs don't have |
| # an explicit test for "host" or "tool" configuration. |
| if not (ctx.configuration == ctx.host_configuration or |
| ctx.bin_dir.path.find("-exec-") >= 0) and not neverlink: |
| lint_output = android_lint_action( |
| ctx, |
| source_files, |
| source_jars + [output.generated_source_jar for output in java_info.java_outputs if output.generated_source_jar != None], |
| compilation_info, |
| ) |
| if lint_output: |
| output_groups["_validation"] = [lint_output] |
| |
| instrumented_files_info = 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 {}, |
| ) |
| |
| return struct( |
| java_info = java_info, |
| files_to_build = compilation_info.output_class_jars, |
| has_sources_or_resources = source_files or source_jars or resources, |
| instrumented_files_info = instrumented_files_info, |
| output_groups = output_groups, |
| extra_providers = {}, |
| ) |
| |
| 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, neverlink, has_sources_or_resources, *extra_attrs): |
| """Constructs DefaultInfo for Java library like rule. |
| |
| Args: |
| ctx: (RuleContext) Used to construct the runfiles. |
| files: (list[File]) List of the files built by the rule. |
| neverlink: (bool) When true empty runfiles are constructed. |
| has_sources_or_resources: (bool) TODO(b/213551463): Check if this can be removed. |
| *extra_attrs: (list[Target]) Extra attributes to merge runfiles from. |
| |
| Returns: |
| (DefaultInfo) DefaultInfo provider. |
| """ |
| files_depset = depset(files) |
| if neverlink: |
| runfiles = None |
| else: |
| run_files = files_depset if has_sources_or_resources else None |
| runfiles = ctx.runfiles(transitive_files = run_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 = files_depset, |
| runfiles = runfiles, |
| ) |
| return default_info |
| |
| JAVA_COMMON_DEP = create_composite_dep( |
| basic_java_library, |
| COMPILE_ACTION, |
| ) |