434 lines
16 KiB
Python
434 lines
16 KiB
Python
# Copyright (C) 2023 The Android Open Source Project
|
|
#
|
|
# 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.
|
|
|
|
load("@//build/bazel/tests/products:product_labels.bzl", _test_product_labels = "product_labels")
|
|
load("@soong_injection//product_config_platforms:product_labels.bzl", _product_labels = "product_labels")
|
|
load("//build/bazel/platforms/arch/variants:constants.bzl", _arch_constants = "constants")
|
|
load("//build/bazel/product_variables:constants.bzl", "constants")
|
|
load(
|
|
"//prebuilts/clang/host/linux-x86:cc_toolchain_constants.bzl",
|
|
"arch_to_variants",
|
|
"variant_constraints",
|
|
"variant_name",
|
|
)
|
|
load(":product_variables_providing_rule.bzl", "product_variables_providing_rule")
|
|
|
|
all_android_product_labels = _product_labels + _test_product_labels
|
|
|
|
def _is_variant_default(arch, variant):
|
|
return variant == None or variant in (arch, "generic")
|
|
|
|
def _soong_arch_config_to_struct(soong_arch_config):
|
|
return struct(
|
|
arch = soong_arch_config["arch"],
|
|
arch_variant = soong_arch_config["arch_variant"],
|
|
cpu_variant = soong_arch_config["cpu_variant"],
|
|
)
|
|
|
|
def _determine_target_arches_from_config(config):
|
|
arches = []
|
|
|
|
# ndk_abis and aml_abis explicitly get handled first as they override any setting
|
|
# for DeviceArch, DeviceSecondaryArch in Soong:
|
|
# https://cs.android.com/android/platform/superproject/+/master:build/soong/android/config.go;l=455-468;drc=b45a2ea782074944f79fc388df20b06e01f265f7
|
|
if config.get("Ndk_abis"):
|
|
for arch_config in _arch_constants.ndk_arches:
|
|
arches.append(_soong_arch_config_to_struct(arch_config))
|
|
return arches
|
|
elif config.get("Aml_abis"):
|
|
for arch_config in _arch_constants.aml_arches:
|
|
arches.append(_soong_arch_config_to_struct(arch_config))
|
|
return arches
|
|
|
|
arch = config.get("DeviceArch")
|
|
arch_variant = config.get("DeviceArchVariant")
|
|
cpu_variant = config.get("DeviceCpuVariant")
|
|
|
|
if _is_variant_default(arch, arch_variant):
|
|
arch_variant = ""
|
|
if _is_variant_default(arch, cpu_variant):
|
|
cpu_variant = ""
|
|
|
|
if not arch:
|
|
# TODO(b/258839711): determine how to better id whether a config is actually host only or we're just missing the target config
|
|
if "DeviceArch" in config:
|
|
fail("No architecture was specified in the product config, expected one of Ndk_abis, Aml_abis, or DeviceArch to be set:\n%s" % config)
|
|
else:
|
|
return arches
|
|
|
|
arches.append(struct(
|
|
arch = arch,
|
|
arch_variant = arch_variant,
|
|
cpu_variant = cpu_variant,
|
|
))
|
|
|
|
arch = config.get("DeviceSecondaryArch")
|
|
arch_variant = config.get("DeviceSecondaryArchVariant")
|
|
cpu_variant = config.get("DeviceSecondaryCpuVariant")
|
|
|
|
if _is_variant_default(arch, arch_variant):
|
|
arch_variant = ""
|
|
if _is_variant_default(arch, cpu_variant):
|
|
cpu_variant = ""
|
|
|
|
if arch:
|
|
arches.append(struct(
|
|
arch = arch,
|
|
arch_variant = arch_variant,
|
|
cpu_variant = cpu_variant,
|
|
))
|
|
return arches
|
|
|
|
def _product_variable_constraint_settings(variables):
|
|
constraints = []
|
|
|
|
local_vars = dict(variables)
|
|
|
|
# Native_coverage is not set within soong.variables, but is hardcoded
|
|
# within config.go NewConfig
|
|
local_vars["Native_coverage"] = (
|
|
local_vars.get("ClangCoverage", False) or
|
|
local_vars.get("GcovCoverage", False)
|
|
)
|
|
|
|
# Some attributes on rules are able to access the values of product
|
|
# variables via make-style expansion (like $(foo)). We collect the values
|
|
# of the relevant product variables here so that it can be passed to
|
|
# product_variables_providing_rule, which exports a
|
|
# platform_common.TemplateVariableInfo provider to allow the substitution.
|
|
attribute_vars = {}
|
|
|
|
def add_attribute_var(typ, var, value):
|
|
if typ == "bool":
|
|
attribute_vars[var] = "1" if value else "0"
|
|
elif typ == "list":
|
|
attribute_vars[var] = ",".join(value)
|
|
elif typ == "int":
|
|
attribute_vars[var] = str(value)
|
|
elif typ == "string":
|
|
attribute_vars[var] = value
|
|
|
|
# Generate constraints for Soong config variables (bool, value, string typed).
|
|
vendor_vars = local_vars.pop("VendorVars", default = {})
|
|
for (namespace, variables) in vendor_vars.items():
|
|
for (var, value) in variables.items():
|
|
# All vendor vars are Starlark string-typed, even though they may be
|
|
# boxed bools/strings/arbitrary printf'd values, like numbers, so
|
|
# we'll need to do some translation work here by referring to
|
|
# soong_injection's generated data.
|
|
|
|
if value == "":
|
|
# Variable is not set so skip adding this as a constraint.
|
|
continue
|
|
|
|
# Create the identifier for the constraint var (or select key)
|
|
config_var = namespace + "__" + var
|
|
|
|
# List of all soong_config_module_type variables.
|
|
if not config_var in constants.SoongConfigVariables:
|
|
continue
|
|
|
|
# Normalize all constraint vars (i.e. select keys) to be lowercased.
|
|
constraint_var = config_var.lower()
|
|
|
|
if config_var in constants.SoongConfigBoolVariables:
|
|
constraints.append("@//build/bazel/product_variables:" + constraint_var)
|
|
elif config_var in constants.SoongConfigStringVariables:
|
|
# The string value is part of the the select key.
|
|
constraints.append("@//build/bazel/product_variables:" + constraint_var + "__" + value.lower())
|
|
elif config_var in constants.SoongConfigValueVariables:
|
|
# For value variables, providing_vars add support for substituting
|
|
# the value using TemplateVariableInfo.
|
|
constraints.append("@//build/bazel/product_variables:" + constraint_var)
|
|
add_attribute_var("string", constraint_var, value)
|
|
|
|
for (var, value) in local_vars.items():
|
|
# TODO(b/187323817): determine how to handle remaining product
|
|
# variables not used in product_variables
|
|
constraint_var = var.lower()
|
|
if not constants.ProductVariables.get(constraint_var):
|
|
continue
|
|
|
|
# variable.go excludes nil values
|
|
add_constraint = (value != None)
|
|
add_attribute_var(type(value), var, value)
|
|
if type(value) == "bool":
|
|
# variable.go special cases bools
|
|
add_constraint = value
|
|
|
|
if add_constraint:
|
|
constraints.append("@//build/bazel/product_variables:" + constraint_var)
|
|
|
|
return constraints, attribute_vars
|
|
|
|
def _define_platform_for_arch(name, common_constraints, arch, secondary_arch = None):
|
|
if secondary_arch == None:
|
|
# When there is no secondary arch, we'll pretend it exists but is the same as the primary arch
|
|
secondary_arch = arch
|
|
native.platform(
|
|
name = name,
|
|
constraint_values = common_constraints + [
|
|
"@//build/bazel/platforms/arch:" + arch.arch,
|
|
"@//build/bazel/platforms/arch:secondary_" + secondary_arch.arch,
|
|
"@//build/bazel/platforms/os:android",
|
|
] + ["@" + v for v in variant_constraints(
|
|
arch,
|
|
_arch_constants.AndroidArchToVariantToFeatures[arch.arch],
|
|
)],
|
|
)
|
|
|
|
def _define_platform_for_arch_with_secondary(name, common_constraints, arch, secondary_arch = None):
|
|
if secondary_arch != None:
|
|
_define_platform_for_arch(name, common_constraints, arch, secondary_arch)
|
|
_define_platform_for_arch(name + "_secondary", common_constraints, secondary_arch)
|
|
else:
|
|
_define_platform_for_arch(name, common_constraints, arch)
|
|
native.alias(
|
|
name = name + "_secondary",
|
|
actual = ":" + name,
|
|
)
|
|
|
|
def _verify_product_is_registered(name):
|
|
"""
|
|
Verifies that this android_product() is listed in all_android_product_labels.
|
|
|
|
all_android_product_labels is used to build a select statement from each product to its
|
|
_product_vars rule. This is because we store most product configuration in a rule instead of
|
|
constraint settings or build settings due to limitations in bazel. (constraint settings can't
|
|
be unbounded, typed, or have dependencies, build settings can't be set with --platforms)
|
|
"""
|
|
my_label = native.repository_name() + "//" + native.package_name() + ":" + name
|
|
for label in all_android_product_labels:
|
|
if my_label == label:
|
|
return
|
|
fail("All android_product() instances must be listed in all_android_product_labels in " +
|
|
"//build/bazel/product_config/android_product.bzl. By default the products generated " +
|
|
"from legacy android product configurations are included, additional platforms (like " +
|
|
"testing-specific platforms) must be manually listed in " +
|
|
"//build/bazel/tests/products/product_labels.bzl.")
|
|
|
|
def android_product(name, soong_variables):
|
|
"""
|
|
android_product integrates product variables into Bazel platforms.
|
|
|
|
This uses soong.variables to create constraints and platforms used by the
|
|
bazel build. The soong.variables file itself contains a post-processed list of
|
|
variables derived from Make variables, through soong_config.mk, generated
|
|
during the product config step.
|
|
|
|
Some constraints used here are handcrafted in
|
|
//build/bazel/platforms/{arch,os}. The rest are dynamically generated.
|
|
|
|
If you're looking for what --config=android, --config=linux_x86_64 or most
|
|
select statements in the BUILD files (ultimately) refer to, they're all
|
|
created here.
|
|
"""
|
|
_verify_product_is_registered(name)
|
|
|
|
product_var_constraints, attribute_vars = _product_variable_constraint_settings(soong_variables)
|
|
arch_configs = _determine_target_arches_from_config(soong_variables)
|
|
|
|
product_variables_providing_rule(
|
|
name = name + "_product_vars",
|
|
attribute_vars = attribute_vars,
|
|
product_vars = soong_variables,
|
|
)
|
|
|
|
native.constraint_value(
|
|
name = name + "_constraint_value",
|
|
constraint_setting = "@//build/bazel/product_config:current_product",
|
|
)
|
|
|
|
common_constraints = product_var_constraints + [name + "_constraint_value"]
|
|
|
|
# TODO(b/258802089): figure out how to deal with multiple arches for target
|
|
if len(arch_configs) > 0:
|
|
arch = arch_configs[0]
|
|
secondary_arch = None
|
|
if len(arch_configs) > 1:
|
|
secondary_arch = arch_configs[1]
|
|
|
|
_define_platform_for_arch_with_secondary(name, common_constraints, arch, secondary_arch)
|
|
|
|
# These variants are mostly for mixed builds, which may request a
|
|
# module with a certain arch
|
|
for arch, variants in arch_to_variants.items():
|
|
for variant in variants:
|
|
native.platform(
|
|
name = name + "_android_" + arch + variant_name(variant),
|
|
constraint_values = common_constraints + [
|
|
"@//build/bazel/platforms/arch:" + arch,
|
|
"@//build/bazel/platforms/arch:secondary_" + arch,
|
|
"@//build/bazel/platforms/os:android",
|
|
] + ["@" + v for v in variant_constraints(
|
|
variant,
|
|
_arch_constants.AndroidArchToVariantToFeatures[arch],
|
|
)],
|
|
)
|
|
|
|
arch_transitions = [
|
|
struct(
|
|
name = "arm",
|
|
arch = struct(
|
|
arch = "arm",
|
|
arch_variant = "armv7-a-neon",
|
|
cpu_variant = "",
|
|
),
|
|
secondary_arch = None,
|
|
),
|
|
struct(
|
|
name = "arm64",
|
|
arch = struct(
|
|
arch = "arm64",
|
|
arch_variant = "armv8-a",
|
|
cpu_variant = "",
|
|
),
|
|
secondary_arch = struct(
|
|
arch = "arm",
|
|
arch_variant = "armv7-a-neon",
|
|
cpu_variant = "",
|
|
),
|
|
),
|
|
struct(
|
|
name = "arm64only",
|
|
arch = struct(
|
|
arch = "arm64",
|
|
arch_variant = "armv8-a",
|
|
cpu_variant = "",
|
|
),
|
|
secondary_arch = None,
|
|
),
|
|
struct(
|
|
name = "x86",
|
|
arch = struct(
|
|
arch = "x86",
|
|
arch_variant = "",
|
|
cpu_variant = "",
|
|
),
|
|
secondary_arch = None,
|
|
),
|
|
struct(
|
|
name = "x86_64",
|
|
arch = struct(
|
|
arch = "x86_64",
|
|
arch_variant = "",
|
|
cpu_variant = "",
|
|
),
|
|
secondary_arch = struct(
|
|
arch = "x86",
|
|
arch_variant = "",
|
|
cpu_variant = "",
|
|
),
|
|
),
|
|
struct(
|
|
name = "x86_64only",
|
|
arch = struct(
|
|
arch = "x86_64",
|
|
arch_variant = "",
|
|
cpu_variant = "",
|
|
),
|
|
secondary_arch = None,
|
|
),
|
|
]
|
|
|
|
# TODO(b/249685973): Remove this, this is currently just for aabs
|
|
# to build each architecture
|
|
for arch in arch_transitions:
|
|
_define_platform_for_arch_with_secondary(name + "__internal_" + arch.name, common_constraints, arch.arch, arch.secondary_arch)
|
|
|
|
# Now define the host platforms. We need a host platform per product because
|
|
# the host platforms still use the product variables.
|
|
# TODO(b/262753134): Investigate making the host platforms product-independant
|
|
native.platform(
|
|
name = name + "_linux_x86",
|
|
constraint_values = common_constraints + [
|
|
"@//build/bazel/platforms/arch:x86",
|
|
"@//build/bazel/platforms/os:linux",
|
|
],
|
|
)
|
|
|
|
native.platform(
|
|
name = name + "_linux_x86_64",
|
|
constraint_values = common_constraints + [
|
|
"@//build/bazel/platforms/arch:x86_64",
|
|
"@//build/bazel/platforms/os:linux",
|
|
],
|
|
)
|
|
|
|
native.platform(
|
|
name = name + "_linux_musl_x86",
|
|
constraint_values = common_constraints + [
|
|
"@//build/bazel/platforms/arch:x86",
|
|
"@//build/bazel/platforms/os:linux_musl",
|
|
],
|
|
)
|
|
|
|
native.platform(
|
|
name = name + "_linux_musl_x86_64",
|
|
constraint_values = common_constraints + [
|
|
"@//build/bazel/platforms/arch:x86_64",
|
|
"@//build/bazel/platforms/os:linux_musl",
|
|
],
|
|
)
|
|
|
|
# linux_bionic is the OS for the Linux kernel plus the Bionic libc runtime, but
|
|
# without the rest of Android.
|
|
native.platform(
|
|
name = name + "_linux_bionic_arm64",
|
|
constraint_values = common_constraints + [
|
|
"@//build/bazel/platforms/arch:arm64",
|
|
"@//build/bazel/platforms/os:linux_bionic",
|
|
],
|
|
)
|
|
|
|
native.platform(
|
|
name = name + "_linux_bionic_x86_64",
|
|
constraint_values = common_constraints + [
|
|
"@//build/bazel/platforms/arch:x86_64",
|
|
"@//build/bazel/platforms/os:linux_bionic",
|
|
],
|
|
)
|
|
|
|
native.platform(
|
|
name = name + "_darwin_arm64",
|
|
constraint_values = common_constraints + [
|
|
"@//build/bazel/platforms/arch:arm64",
|
|
"@//build/bazel/platforms/os:darwin",
|
|
],
|
|
)
|
|
|
|
native.platform(
|
|
name = name + "_darwin_x86_64",
|
|
constraint_values = common_constraints + [
|
|
"@//build/bazel/platforms/arch:x86_64",
|
|
"@//build/bazel/platforms/os:darwin",
|
|
],
|
|
)
|
|
|
|
native.platform(
|
|
name = name + "_windows_x86",
|
|
constraint_values = common_constraints + [
|
|
"@//build/bazel/platforms/arch:x86",
|
|
"@//build/bazel/platforms/os:windows",
|
|
],
|
|
)
|
|
|
|
native.platform(
|
|
name = name + "_windows_x86_64",
|
|
constraint_values = common_constraints + [
|
|
"@//build/bazel/platforms/arch:x86_64",
|
|
"@//build/bazel/platforms/os:windows",
|
|
],
|
|
)
|