| # Copyright 2022 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. | |
| """ | |
| Defines the Android Split configuration transition for properly handling native | |
| dependencies | |
| The intended order of checks is: | |
| - If `--android_platforms` is set: | |
| - Split using the values of this flag as the target platform | |
| - If this is unset, use the first value from `--platforms`. | |
| - If this isn't a valid Android platform, an error will be thrown | |
| during the build. | |
| - Default | |
| - This will not update the output path to include "-android". | |
| - Don't split, using the same previously set `--cpu` value. | |
| """ | |
| load("//rules:visibility.bzl", "PROJECT_VISIBILITY") | |
| load(":utils.bzl", "utils") | |
| visibility(PROJECT_VISIBILITY) | |
| _ANDROID_PLATFORMS_SETTING = utils.ANDROID_PLATFORMS_SETTING | |
| def _android_split_transition_impl(settings, attrs): | |
| settings = dict(settings) | |
| # Propagate the bytecode_transformer setting. This is used for incremental bytecode injection, | |
| # and is read in the dex_desugar_aspect. | |
| if getattr(attrs, "bytecode_transformer", None): | |
| settings["//rules/flags:bytecode_transformer"] = getattr(attrs, "bytecode_transformer", None) | |
| # Always use `--android_platforms` when toolchain resolution is enabled. | |
| platforms_to_split = utils.get_android_platforms(settings) | |
| if not platforms_to_split: | |
| # If `--android_platforms` is unset, instead use only the first | |
| # value from `--platforms`. | |
| target_platform = utils.only(utils.get_cls(settings, "platforms")) | |
| platforms_to_split = [target_platform] | |
| return _handle_android_platforms(settings, platforms_to_split) | |
| # This transition exists so targets can be built in the same configuration as the deps of android_binary. | |
| # The goal is to avoid unnecessarily building a dependency in two different configurations which wastes resources. | |
| def _android_transition_impl(settings, attr): | |
| # There are cases where an android_binary depends on another android_binary via an attribute | |
| # we apply this transition to. In that case we end up applying this transition twice. | |
| # The second transition will fail. Since the transition clears out --android_platforms we can | |
| # use that as a signal to do nothing. | |
| if not utils.get_android_platforms(settings): | |
| return None | |
| configs = _android_split_transition_impl(settings, attr) | |
| # Always pick the config based on the first value in --android_platforms | |
| # This ensures the choice is consistent with the android_platforms_transition | |
| return configs[utils.get_android_platforms(settings)[0].name] | |
| def _handle_android_platforms(settings, platforms_to_split): | |
| """ | |
| Splits the configuration based on the values of --android_platforms. | |
| Each split will set the --platforms flag to one value from | |
| --android_platforms, as well as clean up a few other flags around native | |
| CC builds. | |
| """ | |
| result = dict() | |
| for platform in platforms_to_split: | |
| name = platform.name | |
| split_options = dict(settings) | |
| # Disable fat APKs for the child configurations. | |
| split_options[utils.add_cls_prefix("android_platforms")] = [] | |
| split_options[_ANDROID_PLATFORMS_SETTING] = [] | |
| # The cpu flag will be set by platform mapping if a mapping exists. | |
| split_options[utils.add_cls_prefix("platforms")] = [platform] | |
| _cc_flags_from_android(settings, split_options) | |
| result[name] = split_options | |
| return result | |
| def _cc_flags_from_android(settings, new_settings): | |
| new_settings[utils.add_cls_prefix("dynamic_mode")] = "off" | |
| _INPUTS = [ | |
| "//command_line_option:android_platforms", | |
| _ANDROID_PLATFORMS_SETTING, | |
| "//command_line_option:dynamic_mode", | |
| "//command_line_option:platforms", | |
| "//rules/flags:bytecode_transformer", | |
| ] | |
| _OUTPUTS = [ | |
| "//command_line_option:android_platforms", | |
| _ANDROID_PLATFORMS_SETTING, | |
| "//command_line_option:dynamic_mode", | |
| "//command_line_option:platforms", | |
| "//rules/flags:bytecode_transformer", | |
| ] | |
| android_split_transition = transition( | |
| implementation = _android_split_transition_impl, | |
| inputs = _INPUTS, | |
| outputs = _OUTPUTS, | |
| ) | |
| android_transition = transition( | |
| implementation = _android_transition_impl, | |
| inputs = _INPUTS, | |
| outputs = _OUTPUTS, | |
| ) |