blob: 4f8736c25accee9fd696a09cdd861c44d0ce4aca [file] [log] [blame]
# Copyright 2018 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.
"""Implementation."""
load("//providers:providers.bzl", "AndroidCcLinkParamsInfo", "AndroidIdlInfo", "AndroidLibraryAarInfo", "AndroidLintRulesInfo", "AndroidNativeLibsInfo", "BaselineProfileProvider", "DataBindingV2Info", "StarlarkAndroidResourcesInfo", "StarlarkApkInfo")
load("//rules:acls.bzl", "acls")
load("//rules:attrs.bzl", _attrs = "attrs")
load("//rules:common.bzl", _common = "common")
load("//rules:data_binding.bzl", _data_binding = "data_binding")
load("//rules:idl.bzl", _idl = "idl")
load("//rules:intellij.bzl", _intellij = "intellij")
load("//rules:java.bzl", _java = "java")
load(
"//rules:processing_pipeline.bzl",
"ProviderInfo",
"processing_pipeline",
)
load("//rules:proguard.bzl", _proguard = "proguard")
load("//rules:resources.bzl", _resources = "resources")
load("//rules:utils.bzl", "get_android_sdk", "get_android_toolchain", "log", "utils")
load("//rules:visibility.bzl", "PROJECT_VISIBILITY")
load("//rules/flags:flags.bzl", _flags = "flags")
load("@rules_cc//cc/common:cc_common.bzl", "cc_common")
load("@rules_cc//cc/common:cc_info.bzl", "CcInfo")
load("@rules_java//java/common:java_info.bzl", "JavaInfo")
load("@rules_java//java/common:java_plugin_info.bzl", "JavaPluginInfo")
load("@rules_java//java/common:proguard_spec_info.bzl", "ProguardSpecInfo")
visibility(PROJECT_VISIBILITY)
_USES_DEPRECATED_IMPLICIT_EXPORT_ERROR = (
"Setting `deps` without `srcs` or `resource_files` is not supported. Consider using " +
"`exports` to explicitly specify the exported targets of %s."
)
_SRCS_CONTAIN_RESOURCE_LABEL_ERROR = (
"The srcs attribute of an android_library rule should not contain label " +
"with resources %s"
)
_IDL_IMPORT_ROOT_SET_WITHOUT_SRCS_OR_PARCELABLES_ERROR = (
"The 'idl_import_root' attribute of the android_library rule was set, " +
"but neither 'idl_srcs' nor 'idl_parcelables' were specified."
)
_IDL_SRC_FROM_DIFFERENT_PACKAGE_ERROR = (
"Do not import '%s' directly. You should either move the file to this " +
"package or depend on an appropriate rule there."
)
_IDL_IDLOPTS_UNSUPPORTERD_ERROR = (
"`idlopts` is supported only if `idl_uses_aosp_compiler` is set to true."
)
# Android library AAR context attributes.
_PROVIDERS = "providers"
_VALIDATION_OUTPUTS = "validation_outputs"
_AARContextInfo = provider(
"Android library AAR context object",
fields = {
_PROVIDERS: "The list of all providers to propagate.",
_VALIDATION_OUTPUTS: "List of outputs given to OutputGroupInfo _validation group",
},
)
def _has_srcs(ctx):
return ctx.files.srcs or ctx.files.idl_srcs or getattr(ctx.files, "common_srcs", False)
def _uses_deprecated_implicit_export(ctx):
return (ctx.attr.deps and not (_has_srcs(ctx) or
ctx.attr._defined_assets or
ctx.files.resource_files or
ctx.attr.manifest or
ctx.attr.baseline_profiles))
def _uses_resources_and_deps_without_srcs(ctx):
return (ctx.attr.deps and
(ctx.attr._defined_assets or ctx.files.resource_files or ctx.attr.manifest) and
not _has_srcs(ctx))
def _check_deps_without_java_srcs(ctx):
if not ctx.attr.deps or _has_srcs(ctx):
return False
gfn = getattr(ctx.attr, "generator_function", "")
if _uses_deprecated_implicit_export(ctx):
log.error(_USES_DEPRECATED_IMPLICIT_EXPORT_ERROR % ctx.label)
if _uses_resources_and_deps_without_srcs(ctx):
if (acls.in_android_library_resources_without_srcs_generator_functions(gfn) or
acls.in_android_library_resources_without_srcs(str(ctx.label))):
return True
return False
def _validate_rule_context(ctx):
# Verify that idl_import_root is specified with idl_src or idl_parcelables.
if (ctx.attr._defined_idl_import_root and
not (ctx.attr._defined_idl_srcs or ctx.attr._defined_idl_parcelables)):
log.error(_IDL_IMPORT_ROOT_SET_WITHOUT_SRCS_OR_PARCELABLES_ERROR)
# Verify that idl_srcs are not from another package.
for idl_src in ctx.attr.idl_srcs:
if ctx.label.package != idl_src.label.package:
log.error(_IDL_SRC_FROM_DIFFERENT_PACKAGE_ERROR % idl_src.label)
# Check if idlopts is with idl_uses_aosp_compiler
if ctx.attr.idlopts and not ctx.attr.idl_uses_aosp_compiler:
log.error(_IDL_IDLOPTS_UNSUPPORTERD_ERROR)
return struct(
enable_deps_without_srcs = _check_deps_without_java_srcs(ctx),
)
def _exceptions_processor(ctx, **unused_ctxs):
return ProviderInfo(
name = "exceptions_ctx",
value = _validate_rule_context(ctx),
)
def _process_manifest(ctx, **unused_ctxs):
manifest_ctx = _resources.bump_min_sdk(
ctx,
manifest = ctx.file.manifest,
)
return ProviderInfo(
name = "manifest_ctx",
value = manifest_ctx,
)
def _process_localized_resources(ctx, **unused_ctxs):
return ProviderInfo(
name = "localized_ctx",
value = struct(
resource_files = ctx.files.resource_files,
providers = [],
),
)
def _process_resources(ctx, java_package, manifest_ctx, localized_ctx, **unused_ctxs):
# exports_manifest can be overridden by a bazel flag.
if ctx.attr.exports_manifest == _attrs.tristate.auto:
exports_manifest = ctx.fragments.android.get_exports_manifest_default
else:
exports_manifest = ctx.attr.exports_manifest == _attrs.tristate.yes
resource_apks = []
for apk in utils.collect_providers(StarlarkApkInfo, ctx.attr.resource_apks):
resource_apks.append(apk.signed_apk)
# Process Android Resources
resources_ctx = _resources.process(
ctx,
manifest = manifest_ctx.processed_manifest,
resource_files = localized_ctx.resource_files,
defined_assets = ctx.attr._defined_assets,
assets = ctx.files.assets,
defined_assets_dir = ctx.attr._defined_assets_dir,
assets_dir = ctx.attr.assets_dir,
exports_manifest = exports_manifest,
java_package = java_package,
custom_package = ctx.attr.custom_package,
neverlink = ctx.attr.neverlink,
enable_data_binding = ctx.attr.enable_data_binding,
deps = ctx.attr.deps,
resource_apks = resource_apks,
exports = ctx.attr.exports,
# Processing behavior changing flags.
enable_res_v3 = _flags.get(ctx).android_enable_res_v3,
# TODO(b/144163743): remove fix_resource_transitivity, which was only added to emulate
# misbehavior on the Java side.
fix_resource_transitivity = bool(ctx.attr.srcs),
# Tool and Processing related inputs
aapt = get_android_toolchain(ctx).aapt2.files_to_run,
android_jar = get_android_sdk(ctx).android_jar,
android_kit = get_android_toolchain(ctx).android_kit.files_to_run,
busybox = get_android_toolchain(ctx).android_resources_busybox.files_to_run,
java_toolchain = _common.get_java_toolchain(ctx),
host_javabase = _common.get_host_javabase(ctx),
instrument_xslt = utils.only(get_android_toolchain(ctx).add_g3itr_xslt.files.to_list()),
res_v3_dummy_manifest = utils.only(
get_android_toolchain(ctx).res_v3_dummy_manifest.files.to_list(),
),
res_v3_dummy_r_txt = utils.only(
get_android_toolchain(ctx).res_v3_dummy_r_txt.files.to_list(),
),
xsltproc = get_android_toolchain(ctx).xsltproc_tool.files_to_run,
zip_tool = get_android_toolchain(ctx).zip_tool.files_to_run,
)
# TODO(b/139305816): Remove the ability for android_library to be added in
# the srcs attribute of another android_library.
if resources_ctx.defines_resources:
# Verify that srcs do no contain labels.
for src in ctx.attr.srcs:
if StarlarkAndroidResourcesInfo in src:
log.error(_SRCS_CONTAIN_RESOURCE_LABEL_ERROR % src.label)
return ProviderInfo(
name = "resources_ctx",
value = resources_ctx,
)
def _process_idl(ctx, **unused_sub_ctxs):
return ProviderInfo(
name = "idl_ctx",
value = _idl.process(
ctx,
idl_srcs = ctx.files.idl_srcs,
idl_parcelables = ctx.files.idl_parcelables,
idl_import_root =
ctx.attr.idl_import_root if ctx.attr._defined_idl_import_root else None,
idl_preprocessed = ctx.files.idl_preprocessed,
deps = utils.collect_providers(AndroidIdlInfo, ctx.attr.deps),
exports = utils.collect_providers(AndroidIdlInfo, ctx.attr.exports),
aidl = get_android_sdk(ctx).aidl,
aidl_lib = ctx.attr._aidl_lib,
aidl_framework = get_android_sdk(ctx).framework_aidl,
uses_aosp_compiler = ctx.attr.idl_uses_aosp_compiler,
idlopts = ctx.attr.idlopts,
),
)
def _process_data_binding(ctx, java_package, resources_ctx, **unused_sub_ctxs):
if ctx.attr.enable_data_binding and not acls.in_databinding_allowed(str(ctx.label)):
fail("This target is not allowed to use databinding and enable_data_binding is True.")
return ProviderInfo(
name = "db_ctx",
value = _data_binding.process(
ctx,
defines_resources = resources_ctx.defines_resources,
enable_data_binding = ctx.attr.enable_data_binding,
java_package = java_package,
layout_info = resources_ctx.data_binding_layout_info,
deps = utils.collect_providers(DataBindingV2Info, ctx.attr.deps),
exports = utils.collect_providers(DataBindingV2Info, ctx.attr.exports),
data_binding_exec = get_android_toolchain(ctx).data_binding_exec.files_to_run,
data_binding_annotation_processor =
get_android_toolchain(ctx).data_binding_annotation_processor,
data_binding_annotation_template =
utils.only(get_android_toolchain(ctx).data_binding_annotation_template.files.to_list()),
),
)
def _process_proguard(ctx, idl_ctx, **unused_sub_ctxs):
return ProviderInfo(
name = "proguard_ctx",
value = _proguard.process_specs(
ctx,
proguard_configs = ctx.files.proguard_specs,
proguard_spec_providers = utils.collect_providers(
ProguardSpecInfo,
ctx.attr.deps,
ctx.attr.exports,
idl_ctx.idl_deps,
),
proguard_allowlister =
get_android_toolchain(ctx).proguard_allowlister.files_to_run,
),
)
def _process_jvm(ctx, exceptions_ctx, resources_ctx, idl_ctx, db_ctx, **unused_sub_ctxs):
java_info = _java.compile_android(
ctx,
ctx.outputs.lib_jar,
ctx.outputs.lib_src_jar,
srcs = ctx.files.srcs + idl_ctx.idl_java_srcs + db_ctx.java_srcs,
javac_opts = ctx.attr.javacopts + db_ctx.javac_opts,
r_java = resources_ctx.r_java,
deps =
utils.collect_providers(JavaInfo, ctx.attr.deps, idl_ctx.idl_deps),
exports = utils.collect_providers(JavaInfo, ctx.attr.exports),
plugins = utils.collect_providers(JavaPluginInfo, ctx.attr.plugins, db_ctx.java_plugins),
exported_plugins = utils.collect_providers(
JavaPluginInfo,
ctx.attr.exported_plugins,
),
annotation_processor_additional_outputs = (
db_ctx.java_annotation_processor_additional_outputs
),
annotation_processor_additional_inputs = (
db_ctx.java_annotation_processor_additional_inputs
),
enable_deps_without_srcs = exceptions_ctx.enable_deps_without_srcs,
neverlink = ctx.attr.neverlink,
strict_deps = "DEFAULT",
java_toolchain = _common.get_java_toolchain(ctx),
)
return ProviderInfo(
name = "jvm_ctx",
value = struct(
java_info = java_info,
providers = [java_info],
),
)
def _process_lint_rules(ctx, **unused_sub_ctxs):
providers = []
if acls.in_enable_exported_lint_checks(str(ctx.label)):
# Propagate Lint rule Jars from any exported AARs (b/229993446)
android_lint_rules = [info.lint_jars for info in utils.collect_providers(
AndroidLintRulesInfo,
ctx.attr.exports,
)]
if android_lint_rules:
providers.append(
AndroidLintRulesInfo(
lint_jars = depset(transitive = android_lint_rules),
),
)
return ProviderInfo(
name = "lint_rules_ctx",
value = struct(
providers = providers,
),
)
def _process_aar(ctx, java_package, resources_ctx, proguard_ctx, **unused_ctx):
aar_ctx = {
_PROVIDERS: [],
_VALIDATION_OUTPUTS: [],
}
starlark_aar = _resources.make_aar(
ctx,
manifest = resources_ctx.starlark_processed_manifest,
assets = ctx.files.assets,
assets_dir = ctx.attr.assets_dir,
resource_files = resources_ctx.starlark_processed_resources if not ctx.attr.neverlink else [],
class_jar = ctx.outputs.lib_jar,
r_txt = resources_ctx.starlark_r_txt,
aar_metadata = ctx.file.aar_metadata,
proguard_specs = proguard_ctx.proguard_configs,
busybox = get_android_toolchain(ctx).android_resources_busybox.files_to_run,
host_javabase = _common.get_host_javabase(ctx),
)
if not ctx.attr.neverlink:
aar_ctx[_PROVIDERS].append(AndroidLibraryAarInfo(
aar = starlark_aar if resources_ctx.defines_resources else None,
))
return ProviderInfo(
name = "aar_ctx",
value = _AARContextInfo(**aar_ctx),
)
def _get_cc_link_params_infos(ctx, idl_ctx):
infos = []
for info in utils.collect_providers(JavaInfo, ctx.attr.deps, ctx.attr.exports, idl_ctx.idl_deps):
if getattr(info, "cc_link_params_info", None):
infos.append(info.cc_link_params_info)
else:
# cc_link_params_info attr not available without --experimental_google_legacy_api
infos.append(
CcInfo(
compilation_context = None,
linking_context = cc_common.create_linking_context(
linker_inputs = depset([
cc_common.create_linker_input(
owner = ctx.label,
libraries = info.transitive_native_libraries,
),
]),
),
),
)
return infos
def _process_native(ctx, idl_ctx, **unused_ctx):
return ProviderInfo(
name = "native_ctx",
value = struct(
providers = [
AndroidNativeLibsInfo(
native_libs = depset(
transitive = [
p.native_libs
for p in utils.collect_providers(
AndroidNativeLibsInfo,
ctx.attr.deps,
ctx.attr.exports,
)
],
order = "preorder",
),
),
AndroidCcLinkParamsInfo(
link_params = cc_common.merge_cc_infos(
cc_infos = _get_cc_link_params_infos(ctx, idl_ctx) +
[
info.link_params
for info in utils.collect_providers(
AndroidCcLinkParamsInfo,
ctx.attr.deps,
ctx.attr.exports,
idl_ctx.idl_deps,
)
] +
utils.collect_providers(
CcInfo,
ctx.attr.deps,
ctx.attr.exports,
idl_ctx.idl_deps,
),
),
),
],
),
)
def _process_intellij(ctx, java_package, manifest_ctx, resources_ctx, idl_ctx, jvm_ctx, **unused_sub_ctxs):
android_ide_info = _intellij.make_android_ide_info(
ctx,
java_package = java_package,
manifest = manifest_ctx.processed_manifest,
defines_resources = resources_ctx.defines_resources,
merged_manifest = resources_ctx.merged_manifest,
resources_apk = resources_ctx.resources_apk,
r_jar = utils.only(resources_ctx.r_java.outputs.jars) if resources_ctx.r_java else None,
idl_import_root = idl_ctx.idl_import_root,
idl_srcs = idl_ctx.idl_srcs,
idl_java_srcs = idl_ctx.idl_java_srcs,
java_info = jvm_ctx.java_info,
signed_apk = None, # signed_apk, always empty for android_library.
aar = getattr(ctx.outputs, "aar", None), # Deprecate aar for android_library.
apks_under_test = [], # apks_under_test, always empty for android_library
native_libs = dict(), # nativelibs, always empty for android_library
idlclass = get_android_toolchain(ctx).idlclass.files_to_run,
host_javabase = _common.get_host_javabase(ctx),
)
return ProviderInfo(
name = "intellij_ctx",
value = struct(
android_ide_info = android_ide_info,
providers = [android_ide_info],
),
)
def _process_coverage(ctx, **unused_ctx):
return ProviderInfo(
name = "coverage_ctx",
value = struct(
providers = [
coverage_common.instrumented_files_info(
ctx,
source_attributes = ["srcs"],
# NOTE: Associates is only applicable for OSS rules_kotlin.
dependency_attributes = ["associates", "assets", "deps", "exports"],
),
],
),
)
def _process_baseline_profiles(ctx, **unused_ctx):
return ProviderInfo(
name = "bp_ctx",
value = struct(
providers = [
BaselineProfileProvider(files = depset(
ctx.files.baseline_profiles,
transitive = [bp.files for bp in utils.collect_providers(BaselineProfileProvider, ctx.attr.deps, ctx.attr.exports)],
)),
],
),
)
# Order dependent, as providers will not be available to downstream processors
# that may depend on the provider. Iteration order for a dictionary is based on
# insertion.
PROCESSORS = dict(
ExceptionsProcessor = _exceptions_processor,
LintRulesProcessor = _process_lint_rules,
ManifestProcessor = _process_manifest,
LocalizedResourcesProcessor = _process_localized_resources,
ResourceProcessor = _process_resources,
IdlProcessor = _process_idl,
DataBindingProcessor = _process_data_binding,
JvmProcessor = _process_jvm,
ProguardProcessor = _process_proguard,
AarProcessor = _process_aar,
NativeProcessor = _process_native,
IntelliJProcessor = _process_intellij,
CoverageProcessor = _process_coverage,
BaselineProfilesProcessor = _process_baseline_profiles,
)
def finalize(
ctx,
resources_ctx,
intellij_ctx,
jvm_ctx,
proguard_ctx,
providers,
validation_outputs,
**unused_ctxs):
"""Creates the DefaultInfo and OutputGroupInfo providers.
Args:
ctx: The context.
resources_ctx: ProviderInfo. The resources ctx.
intellij_ctx: ProviderInfo. The intellij ctx.
jvm_ctx: ProviderInfo. The jvm ctx.
proguard_ctx: ProviderInfo. The proguard ctx.
providers: sequence of providers. The providers to propagate.
validation_outputs: sequence of Files. The validation outputs.
**unused_ctxs: Unused ProviderInfo.
Returns:
A struct with Android and Java legacy providers and a list of providers.
"""
transitive_runfiles = []
if not ctx.attr.neverlink:
for p in utils.collect_providers(
DefaultInfo,
ctx.attr.deps,
ctx.attr.exports,
):
transitive_runfiles.append(p.data_runfiles.files)
transitive_runfiles.append(p.default_runfiles.files)
runfiles = ctx.runfiles(
files = (
(resources_ctx.r_java.runtime_output_jars if resources_ctx.r_java and not ctx.attr.neverlink else []) +
([ctx.outputs.lib_jar] if (ctx.attr.srcs or ctx.attr.idl_srcs) and not ctx.attr.neverlink else [])
),
transitive_files = depset(transitive = transitive_runfiles),
collect_default = True,
)
files = [ctx.outputs.lib_jar]
if getattr(ctx.outputs, "resources_src_jar", None):
files.append(ctx.outputs.resources_src_jar)
if getattr(ctx.outputs, "resources_jar", None):
files.append(ctx.outputs.resources_jar)
providers.extend([
DefaultInfo(
files = depset(files),
runfiles = runfiles,
),
OutputGroupInfo(
compilation_outputs = depset([ctx.outputs.lib_jar]),
_source_jars = depset(
[ctx.outputs.lib_src_jar],
transitive = [jvm_ctx.java_info.transitive_source_jars],
),
_direct_source_jars = depset([ctx.outputs.lib_src_jar]),
_hidden_top_level_INTERNAL_ = depset(
resources_ctx.validation_results,
transitive = [
info._hidden_top_level_INTERNAL_
for info in utils.collect_providers(
OutputGroupInfo,
ctx.attr.deps,
ctx.attr.exports,
)
] + [proguard_ctx.transitive_proguard_configs],
),
_validation = depset(validation_outputs),
),
])
return providers
_PROCESSING_PIPELINE = processing_pipeline.make_processing_pipeline(
processors = PROCESSORS,
finalize = finalize,
)
def impl(ctx):
"""The rule implementation.
Args:
ctx: The context.
Returns:
A legacy struct provider.
"""
java_package = _java.resolve_package_from_label(ctx.label, ctx.attr.custom_package)
return processing_pipeline.run(ctx, java_package, _PROCESSING_PIPELINE)