1# Copyright (C) 2023 The Android Open Source Project 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15load("@soong_injection//product_config_platforms:product_labels.bzl", _product_labels = "product_labels") 16load("//build/bazel/platforms/arch/variants:constants.bzl", _arch_constants = "constants") 17load( 18 "//build/bazel/toolchains/clang/host/linux-x86:cc_toolchain_constants.bzl", 19 "arch_to_variants", 20 "variant_constraints", 21 "variant_name", 22) 23load("@env//:env.bzl", "env") 24 25# This dict denotes the suffixes for host platforms (keys) and the constraints 26# associated with them (values). Used in transitions and tests, in addition to 27# here. 28host_platforms = { 29 "linux_x86": [ 30 "@//build/bazel_common_rules/platforms/arch:x86", 31 "@//build/bazel_common_rules/platforms/os:linux", 32 ], 33 "linux_x86_64": [ 34 "@//build/bazel_common_rules/platforms/arch:x86_64", 35 "@//build/bazel_common_rules/platforms/os:linux", 36 ], 37 "linux_musl_x86": [ 38 "@//build/bazel_common_rules/platforms/arch:x86", 39 "@//build/bazel_common_rules/platforms/os:linux_musl", 40 ], 41 "linux_musl_x86_64": [ 42 "@//build/bazel_common_rules/platforms/arch:x86_64", 43 "@//build/bazel_common_rules/platforms/os:linux_musl", 44 ], 45 # linux_bionic is the OS for the Linux kernel plus the Bionic libc runtime, 46 # but without the rest of Android. 47 "linux_bionic_arm64": [ 48 "@//build/bazel_common_rules/platforms/arch:arm64", 49 "@//build/bazel_common_rules/platforms/os:linux_bionic", 50 ], 51 "linux_bionic_x86_64": [ 52 "@//build/bazel_common_rules/platforms/arch:x86_64", 53 "@//build/bazel_common_rules/platforms/os:linux_bionic", 54 ], 55 "darwin_arm64": [ 56 "@//build/bazel_common_rules/platforms/arch:arm64", 57 "@//build/bazel_common_rules/platforms/os:darwin", 58 ], 59 "darwin_x86_64": [ 60 "@//build/bazel_common_rules/platforms/arch:x86_64", 61 "@//build/bazel_common_rules/platforms/os:darwin", 62 ], 63 "windows_x86": [ 64 "@//build/bazel_common_rules/platforms/arch:x86", 65 "@//build/bazel_common_rules/platforms/os:windows", 66 ], 67 "windows_x86_64": [ 68 "@//build/bazel_common_rules/platforms/arch:x86_64", 69 "@//build/bazel_common_rules/platforms/os:windows", 70 ], 71} 72 73def _is_variant_default(arch, variant): 74 return variant == None or variant in (arch, "generic") 75 76def _soong_arch_config_to_struct(soong_arch_config): 77 return struct( 78 arch = soong_arch_config["arch"], 79 arch_variant = soong_arch_config["arch_variant"], 80 cpu_variant = soong_arch_config["cpu_variant"], 81 ) 82 83def _determine_target_arches_from_config(config): 84 arches = [] 85 86 # ndk_abis and aml_abis explicitly get handled first as they override any setting 87 # for DeviceArch, DeviceSecondaryArch in Soong: 88 # https://cs.android.com/android/platform/superproject/+/master:build/soong/android/config.go;l=455-468;drc=b45a2ea782074944f79fc388df20b06e01f265f7 89 if config.get("Ndk_abis"): 90 for arch_config in _arch_constants.ndk_arches: 91 arches.append(_soong_arch_config_to_struct(arch_config)) 92 return arches 93 elif config.get("Aml_abis"): 94 for arch_config in _arch_constants.aml_arches: 95 arches.append(_soong_arch_config_to_struct(arch_config)) 96 return arches 97 98 arch = config.get("DeviceArch") 99 arch_variant = config.get("DeviceArchVariant") 100 cpu_variant = config.get("DeviceCpuVariant") 101 102 if _is_variant_default(arch, arch_variant): 103 arch_variant = "" 104 if _is_variant_default(arch, cpu_variant): 105 cpu_variant = "" 106 107 if not arch: 108 # TODO(b/258839711): determine how to better id whether a config is actually host only or we're just missing the target config 109 if "DeviceArch" in config: 110 fail("No architecture was specified in the product config, expected one of Ndk_abis, Aml_abis, or DeviceArch to be set:\n%s" % config) 111 else: 112 return arches 113 114 arches.append(struct( 115 arch = arch, 116 arch_variant = arch_variant, 117 cpu_variant = cpu_variant, 118 )) 119 120 arch = config.get("DeviceSecondaryArch") 121 arch_variant = config.get("DeviceSecondaryArchVariant") 122 cpu_variant = config.get("DeviceSecondaryCpuVariant") 123 124 if _is_variant_default(arch, arch_variant): 125 arch_variant = "" 126 if _is_variant_default(arch, cpu_variant): 127 cpu_variant = "" 128 129 if arch: 130 arches.append(struct( 131 arch = arch, 132 arch_variant = arch_variant, 133 cpu_variant = cpu_variant, 134 )) 135 return arches 136 137def _define_platform_for_arch(name, common_constraints, arch, secondary_arch = None): 138 if secondary_arch == None: 139 # When there is no secondary arch, we'll pretend it exists but is the same as the primary arch 140 secondary_arch = arch 141 native.platform( 142 name = name, 143 constraint_values = common_constraints + [ 144 "@//build/bazel_common_rules/platforms/arch:" + arch.arch, 145 "@//build/bazel_common_rules/platforms/arch:secondary_" + secondary_arch.arch, 146 "@//build/bazel_common_rules/platforms/os:android", 147 ] + ["@" + v for v in variant_constraints( 148 arch, 149 _arch_constants.AndroidArchToVariantToFeatures[arch.arch], 150 )], 151 ) 152 153def _define_platform_for_arch_with_secondary(name, common_constraints, arch, secondary_arch = None): 154 if secondary_arch != None: 155 _define_platform_for_arch(name, common_constraints, arch, secondary_arch) 156 _define_platform_for_arch(name + "_secondary", common_constraints, secondary_arch) 157 else: 158 _define_platform_for_arch(name, common_constraints, arch) 159 native.alias( 160 name = name + "_secondary", 161 actual = ":" + name, 162 ) 163 164def _verify_product_is_registered(name): 165 """ 166 Verifies that this android_product() is listed in _product_labels. 167 168 _product_labels is used to build a platform_mappings file entry from each product to its 169 build settings. This is because we store most product configuration in build settings, and 170 currently the only way to set build settings based on a certain platform is with a 171 platform_mappings file. 172 """ 173 my_label = native.repository_name() + "//" + native.package_name() + ":" + name 174 for label in _product_labels: 175 if my_label == label: 176 return 177 fail("All android_product() instances must have an entry in the platform_mappings file " + 178 "generated by bp2build. By default the products generated from legacy android product " + 179 "configurations and products listed in //build/bazel/tests/products:product_labels.bzl " + 180 "are included.") 181 182def android_product(*, name, soong_variables, extra_constraints = []): 183 """ 184 android_product integrates product variables into Bazel platforms. 185 186 This uses soong.variables to create constraints and platforms used by the 187 bazel build. The soong.variables file itself contains a post-processed list of 188 variables derived from Make variables, through soong_config.mk, generated 189 during the product config step. 190 191 Some constraints used here are handcrafted in 192 //build/bazel_common_rules/platforms/{arch,os}. The rest are dynamically generated. 193 194 If you're looking for what --config=android, --config=linux_x86_64 or most 195 select statements in the BUILD files (ultimately) refer to, they're all 196 created here. 197 """ 198 _verify_product_is_registered(name) 199 200 arch_configs = _determine_target_arches_from_config(soong_variables) 201 202 common_constraints = extra_constraints 203 204 # TODO(b/258802089): figure out how to deal with multiple arches for target 205 if len(arch_configs) > 0: 206 arch = arch_configs[0] 207 secondary_arch = None 208 if len(arch_configs) > 1: 209 secondary_arch = arch_configs[1] 210 211 _define_platform_for_arch_with_secondary(name, common_constraints, arch, secondary_arch) 212 213 # These variants are mostly for mixed builds, which may request a 214 # module with a certain arch 215 for arch, variants in arch_to_variants.items(): 216 for variant in variants: 217 native.platform( 218 name = name + "_android_" + arch + variant_name(variant), 219 constraint_values = common_constraints + [ 220 "@//build/bazel_common_rules/platforms/arch:" + arch, 221 "@//build/bazel_common_rules/platforms/arch:secondary_" + arch, 222 "@//build/bazel_common_rules/platforms/os:android", 223 ] + ["@" + v for v in variant_constraints( 224 variant, 225 _arch_constants.AndroidArchToVariantToFeatures[arch], 226 )], 227 ) 228 229 arch_transitions = [ 230 struct( 231 name = "arm", 232 arch = struct( 233 arch = "arm", 234 arch_variant = "armv7-a-neon", 235 cpu_variant = "", 236 ), 237 secondary_arch = None, 238 ), 239 struct( 240 name = "arm64", 241 arch = struct( 242 arch = "arm64", 243 arch_variant = "armv8-a", 244 cpu_variant = "", 245 ), 246 secondary_arch = struct( 247 arch = "arm", 248 arch_variant = "armv7-a-neon", 249 cpu_variant = "", 250 ), 251 ), 252 struct( 253 name = "arm64only", 254 arch = struct( 255 arch = "arm64", 256 arch_variant = "armv8-a", 257 cpu_variant = "", 258 ), 259 secondary_arch = None, 260 ), 261 struct( 262 name = "x86", 263 arch = struct( 264 arch = "x86", 265 arch_variant = "", 266 cpu_variant = "", 267 ), 268 secondary_arch = None, 269 ), 270 struct( 271 name = "x86_64", 272 arch = struct( 273 arch = "x86_64", 274 arch_variant = "", 275 cpu_variant = "", 276 ), 277 secondary_arch = struct( 278 arch = "x86", 279 arch_variant = "", 280 cpu_variant = "", 281 ), 282 ), 283 struct( 284 name = "x86_64only", 285 arch = struct( 286 arch = "x86_64", 287 arch_variant = "", 288 cpu_variant = "", 289 ), 290 secondary_arch = None, 291 ), 292 ] 293 294 # TODO(b/249685973): Remove this, this is currently just for aabs 295 # to build each architecture 296 for arch in arch_transitions: 297 _define_platform_for_arch_with_secondary(name + "__internal_" + arch.name, common_constraints, arch.arch, arch.secondary_arch) 298 299 # Now define the host platforms. We need a host platform per product because 300 # the host platforms still use the product variables. 301 # TODO(b/262753134): Investigate making the host platforms product-independant 302 for suffix, constraints in host_platforms.items(): 303 # Add RBE properties if the host platform support it. 304 exec_properties = {} 305 if "linux" in suffix and env.get("DEVICE_TEST_RBE_DOCKER_IMAGE_LINK"): 306 exec_properties = { 307 "container-image": env.get("DEVICE_TEST_RBE_DOCKER_IMAGE_LINK").replace("_atChar_", "@").replace("_colonChar_", ":"), 308 "dockerNetwork": "standard", 309 "dockerPrivileged": "true", 310 "dockerRunAsRoot": "true", 311 "OSFamily": "Linux", 312 } 313 native.platform( 314 name = name + "_" + suffix, 315 constraint_values = common_constraints + constraints, 316 exec_properties = exec_properties, 317 ) 318