blob: 5115b069e6d13a11fb48d12cf530ccbb28903bd5 [file] [log] [blame] [edit]
# 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.
"""Common attributes for Android rules."""
load("//providers:providers.bzl", "ApkInfo")
load("//rules:android_split_transition.bzl", "android_transition")
load("//rules:visibility.bzl", "PROJECT_VISIBILITY")
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(":utils.bzl", "ANDROID_SDK_TOOLCHAIN_TYPE", "log")
visibility(PROJECT_VISIBILITY)
def _add(attrs, *others):
new = {}
new.update(attrs)
for o in others:
for name in o.keys():
if name in new:
log.error("Attr '%s' is defined twice." % name)
new[name] = o[name]
return new
def _replace(attrs, **kwargs):
# Verify that new values are replacing existing ones, not adding.
for name in kwargs.keys():
if name not in attrs:
log.error("Attr '%s' is not defined, replacement failed." % name)
new = dict()
new.update(attrs)
new.update(kwargs)
return new
def _make_tristate_attr(default, doc = "", mandatory = False):
return attr.int(
default = default,
doc = doc,
mandatory = mandatory,
values = [-1, 0, 1],
)
def _normalize_tristate(attr_value):
"""Normalizes the tristate value going into a rule.
This is required because "tristate" is not officially supported as an
attribute type. An equivalent attribute type is an in with a constrained
set of values, namely [-1, 0, 1]. Unfortunately, tristate accepts
multiple types, integers, booleans and strings ("auto"). As a result, this
method normalizes the inputs to an integer.
This method needs to be applied to attributes that were formally tristate
to normalize the inputs.
"""
if type(attr_value) == "int":
return attr_value
if type(attr_value) == "string":
if attr_value.lower() == "auto":
return -1
if type(attr_value) == "bool":
return int(attr_value)
return attr_value # Return unknown type, let the rule fail.
_tristate = struct(
create = _make_tristate_attr,
normalize = _normalize_tristate,
yes = 1,
no = 0,
auto = -1,
)
_JAVA_RUNTIME = dict(
_host_javabase = attr.label(
cfg = "exec",
default = Label("//tools/jdk:current_java_runtime"),
),
)
# Android SDK attribute.
_ANDROID_SDK = dict(
_dummy_android_sdk = attr.label(
default = "//toolchains/android_sdk:dummy_sdk_tools",
),
)
# Compilation attributes for Android rules.
def _compilation_attributes(apply_android_transition = False):
return _add(
dict(
assets = attr.label_list(
allow_files = True,
cfg = "target",
doc = ("The list of assets to be packaged. This is typically a glob of " +
"all files under the assets directory. You can also reference " +
"other rules (any rule that produces files) or exported files in " +
"the other packages, as long as all those files are under the " +
"assets_dir directory in the corresponding package."),
),
assets_dir = attr.string(
doc = ("The string giving the path to the files in assets. " +
"The pair assets and assets_dir describe packaged assets and either both " +
"attributes should be provided or none of them."),
),
custom_package = attr.string(
doc = ("Java package for which java sources will be generated. " +
"By default the package is inferred from the directory where the BUILD file " +
"containing the rule is. You can specify a different package but this is " +
"highly discouraged since it can introduce classpath conflicts with other " +
"libraries that will only be detected at runtime."),
),
manifest = attr.label(
allow_single_file = [".xml"],
cfg = android_transition if apply_android_transition else "target",
doc = ("The name of the Android manifest file, normally " +
"AndroidManifest.xml. Must be defined if resource_files or assets are defined."),
),
resource_files = attr.label_list(
allow_files = True,
cfg = android_transition if apply_android_transition else "target",
doc = ("The list of resources to be packaged. This " +
"is typically a glob of all files under the res directory. Generated files " +
"(from genrules) can be referenced by Label here as well. The only " +
"restriction is that the generated outputs must be under the same \"res\" " +
"directory as any other resource files that are included."),
),
data = attr.label_list(
allow_files = True,
cfg = android_transition if apply_android_transition else "target",
doc = (
"Files needed by this rule at runtime. May list file or rule targets. Generally allows any target.\n\n" +
"The default outputs and runfiles of targets in the `data` attribute should appear in the `*.runfiles` area of" +
"any executable which is output by or has a runtime dependency on this target. " +
"This may include data files or binaries used when this target's " +
"[srcs](https://docs.bazel.build/versions/main/be/common-definitions.html#typical.srcs) are executed. " +
"See the [data dependencies](https://docs.bazel.build/versions/main/build-ref.html#data) section " +
"for more information about how to depend on and use data files.\n\n" +
"New rules should define a `data` attribute if they process inputs which might use other inputs at runtime. " +
"Rules' implementation functions must also " +
"[populate the target's runfiles](https://docs.bazel.build/versions/main/skylark/rules.html#runfiles) " +
"from the outputs and runfiles of any `data` attribute, as well as runfiles from any dependency attribute " +
"which provides either source code or runtime dependencies."
),
),
plugins = attr.label_list(
providers = [JavaPluginInfo],
cfg = "exec",
doc = (
"Java compiler plugins to run at compile-time. " +
"Every `java_plugin` specified in the plugins attribute will be run whenever this rule is built. " +
"A library may also inherit plugins from dependencies that use [exported_plugins](https://docs.bazel.build/versions/main/be/java.html#java_library.exported_plugins). " +
"Resources generated by the plugin will be included in the resulting jar of this rule."
),
),
javacopts = attr.string_list(
doc = (
"Extra compiler options for this library. " +
"Subject to \"[Make variable](https://docs.bazel.build/versions/main/be/make-variables.html)\" substitution and " +
"[Bourne shell tokenization](https://docs.bazel.build/versions/main/be/common-definitions.html#sh-tokenization).\n" +
"These compiler options are passed to javac after the global compiler options."
),
),
# TODO: Expose getPlugins() in JavaConfiguration.java
# com/google/devtools/build/lib/rules/java/JavaConfiguration.java
# com/google/devtools/build/lib/rules/java/JavaOptions.java
#
# _java_plugins = attr.label(
# allow_rules = ["java_plugin"],
# default = configuration_field(
# fragment = "java",
# name = "plugin",
# ),
# ),
),
_JAVA_RUNTIME,
)
# Attributes for rules that use the AndroidDataContext android_data.make_context
_DATA_CONTEXT = _add(
dict(
# Additional attrs needed for AndroidDataContext
_add_g3itr_xslt = attr.label(
cfg = "exec",
default = Label("//tools/android/xslt:add_g3itr.xslt"),
allow_single_file = True,
),
_android_manifest_merge_tool = attr.label(
cfg = "exec",
default = Label("//tools/android:merge_manifests"),
executable = True,
),
_xsltproc_tool = attr.label(
cfg = "exec",
default = Label("//tools/android/xslt:xslt"),
allow_files = True,
),
),
_ANDROID_SDK,
)
# Attributes for rules that produce an Android binary.
# NOTE: this is unused by the actual android_binary impl, and at this stage is only
# really used by a couple tests. We should clean it up at some point.
ANDROID_BINARY_ATTRS = _add(
dict(
crunch_png = attr.bool(
default = True,
),
debug_key = attr.label(
allow_files = True,
cfg = "exec",
default = Label("//tools/android:debug_keystore"),
),
debug_signing_keys = attr.label_list(),
deps = attr.label_list(
allow_files = True,
allow_rules = [
"aar_import",
"android_library",
"cc_library",
"java_import",
"java_library",
"java_lite_proto_library",
],
# aspects = [AndroidNeverlinkAspect, DexArchiveAspect], TODO(timpeut): enable this
# cfg = "android_split_transition", TODO(timpeut): enable this
providers = [JavaInfo, CcInfo],
),
densities = attr.string_list(),
dexopts = attr.string_list(),
dex_shards = attr.int(
default = 1,
),
enable_data_binding = attr.bool(),
feature_flags = attr.label_keyed_string_dict(
allow_files = True,
allow_rules = ["config_feature_flag"],
# TODO(timpeut): set nonconfigurable
providers = [config_common.FeatureFlagInfo],
),
incremental_dexing = _tristate.create(
default = _tristate.auto,
),
inline_constants = attr.bool(
default = False,
),
# TODO(timpeut): handle this line: .add(AndroidFeatureFlagSetProvider.getWhitelistAttribute(env))
instruments = attr.label(
allow_files = False,
allow_rules = ["android_binary"],
),
main_dex_list = attr.label(
allow_files = True,
),
main_dex_list_opts = attr.string_list(),
main_dex_proguard_specs = attr.label_list(
allow_files = True,
),
manifest_values = attr.string_dict(),
manifest_merger = attr.string(
default = "auto",
values = ["auto", "legacy", "android", "force_android"],
),
multidex = attr.string(
default = "native",
values = ["native", "legacy", "manual_main_dex"],
),
nocompress_extensions = attr.string_list(),
proguard_apply_dictionary = attr.label(
allow_files = True,
),
proguard_apply_mapping = attr.label(
allow_files = True,
),
proguard_generate_mapping = attr.bool(
default = False,
# TODO(timpeut): set nonconfigurable
),
proguard_generate_obfuscated_constant_string_mapping = attr.bool(
default = False,
),
proguard_optimization_passes = attr.int(),
proguard_specs = attr.label_list(
allow_files = True,
),
resource_configuration_filters = attr.string_list(),
shrink_resources = _tristate.create(
default = _tristate.auto,
),
srcs = attr.label_list(
# TODO(timpeut): Set PropertyFlag direct_compile_time_input
allow_files = [".java", ".srcjar"],
),
_build_java8_legacy_dex = attr.label(
cfg = "exec",
default = Label("//tools/android:build_java8_legacy_dex"),
executable = True,
),
_desugar = attr.label(
cfg = "exec",
default = Label("//tools/android:desugar_java8"),
executable = True,
),
_desugared_lib_config = attr.label(
allow_single_file = True,
default = Label("//tools/android:full_desugar_jdk_libs_config_json"),
),
_desugared_java8_legacy_apis = attr.label(
default = Label("//tools/android:desugared_java8_legacy_apis"),
),
_dexbuilder = attr.label(
cfg = "exec",
default = Label("//tools/android:dexbuilder"),
executable = True,
),
_dexbuilder_after_proguard = attr.label(
cfg = "exec",
default = Label("//tools/android:dexbuilder_after_proguard"),
executable = True,
),
_dexmerger = attr.label(
cfg = "exec",
default = Label("//tools/android:dexmerger"),
executable = True,
),
_dexsharder = attr.label(
cfg = "exec",
default = Label("//tools/android:dexsharder"),
executable = True,
),
_dex_list_obfuscator = attr.label(
cfg = "exec",
default = Label("//tools/android:dex_list_obfuscator"),
executable = True,
),
_java8_legacy_dex = attr.label(
default = Label("//tools/android:java8_legacy_dex"),
),
_merge_dexzips = attr.label(
cfg = "exec",
default = Label("//tools/android:merge_dexzips"),
executable = True,
),
_shuffle_jars = attr.label(
cfg = "exec",
default = Label("//tools/android:shuffle_jars"),
executable = True,
),
_zip_filter = attr.label(
cfg = "exec",
default = Label("//tools/android:zip_filter"),
executable = True,
),
# incremental_dexing = attrs.tristate.create() TODO(timpeut): enable once set to nonconfigurable
# TODO(timpeut): add instrumentation_test_check which is a ComputedDefault
# TODO(timpeut): expose the following in native and enable here
#_bytecode_optimizers = attr.label_list(
# default = configuration_field(
# fragment = "java",
# name = "bytecode_optimizers",
# ),
#),
#_cc_toolchain_split = attr.label(
# TODO(timpeut): set cfg android_split_transition
# default = configuration_field(
# fragment = "cpp",
# name = "toolchain_split",
# ),
#),
#_extra_proguard_specs = attr.label_list(
# default = configuration_field(
# fragment = "java",
# name = "extra_proguard_specs",
# ),
#),
),
_compilation_attributes(apply_android_transition = True),
_DATA_CONTEXT,
)
ANDROID_SDK_ATTRS = dict(
aapt = attr.label(
allow_files = True,
cfg = "exec",
executable = True,
mandatory = True,
),
aapt2 = attr.label(
allow_files = True,
cfg = "exec",
executable = True,
),
aidl = attr.label(
allow_files = True,
cfg = "exec",
executable = True,
mandatory = True,
),
aidl_lib = attr.label(
allow_files = [".jar"],
doc = "Deprecated, only used for the soon to be deleted forked compiler.",
),
android_jar = attr.label(
allow_single_file = [".jar"],
cfg = "exec",
mandatory = True,
),
annotations_jar = attr.label(
allow_single_file = [".jar"],
cfg = "exec",
),
apkbuilder = attr.label(
allow_files = True,
cfg = "exec",
executable = True,
),
apksigner = attr.label(
allow_files = True,
cfg = "exec",
executable = True,
mandatory = True,
),
adb = attr.label(
allow_single_file = True,
cfg = "exec",
executable = True,
mandatory = True,
),
build_tools_version = attr.string(),
dexdump = attr.label(
allow_files = True,
cfg = "exec",
executable = True,
mandatory = False,
),
dx = attr.label(
allow_files = True,
cfg = "exec",
executable = True,
mandatory = True,
),
framework_aidl = attr.label(
allow_single_file = True,
cfg = "exec",
mandatory = True,
),
legacy_main_dex_list_generator = attr.label(
allow_files = True,
cfg = "exec",
executable = True,
),
main_dex_classes = attr.label(
allow_single_file = True,
cfg = "exec",
mandatory = True,
),
main_dex_list_creator = attr.label(
allow_files = True,
cfg = "exec",
executable = True,
mandatory = True,
),
proguard = attr.label(
allow_files = True,
cfg = "exec",
executable = True,
mandatory = True,
),
source_properties = attr.label(
allow_single_file = True,
cfg = "exec",
),
zipalign = attr.label(
allow_files = True,
cfg = "exec",
executable = True,
mandatory = True,
),
_proguard = attr.label(
cfg = "exec",
default = configuration_field(
fragment = "java",
name = "proguard_top",
),
),
)
# Attributes for resolving platform-based toolchains. Only needed by the native
# DexArchiveAspect.
_ANDROID_TOOLCHAIN_ATTRS = dict(
_android_sdk_toolchain_type = attr.label(
allow_rules = ["toolchain_type"],
default = ANDROID_SDK_TOOLCHAIN_TYPE,
),
)
ANDROID_TOOLS_DEFAULTS_JAR_ATTRS = _add(_ANDROID_SDK)
_AUTOMATIC_EXEC_GROUPS_ENABLED = dict(
_use_auto_exec_groups = attr.bool(default = True),
)
attrs = struct(
ANDROID_SDK = _ANDROID_SDK,
compilation_attributes = _compilation_attributes,
DATA_CONTEXT = _DATA_CONTEXT,
JAVA_RUNTIME = _JAVA_RUNTIME,
ANDROID_TOOLCHAIN_ATTRS = _ANDROID_TOOLCHAIN_ATTRS,
tristate = _tristate,
add = _add,
replace = _replace,
AUTOMATIC_EXEC_GROUPS_ENABLED = _AUTOMATIC_EXEC_GROUPS_ENABLED,
)