1// Copyright 2021 Google Inc. All rights reserved. 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 15package bazel 16 17import ( 18 "fmt" 19 "math" 20 "sort" 21 "strings" 22) 23 24const ( 25 // ArchType names in arch.go 26 archArm = "arm" 27 archArm64 = "arm64" 28 archRiscv64 = "riscv64" 29 archX86 = "x86" 30 archX86_64 = "x86_64" 31 32 // OsType names in arch.go 33 OsAndroid = "android" 34 OsDarwin = "darwin" 35 OsLinux = "linux_glibc" 36 osLinuxMusl = "linux_musl" 37 osLinuxBionic = "linux_bionic" 38 OsWindows = "windows" 39 40 // Targets in arch.go 41 osArchAndroidArm = "android_arm" 42 OsArchAndroidArm64 = "android_arm64" 43 osArchAndroidRiscv64 = "android_riscv64" 44 osArchAndroidX86 = "android_x86" 45 osArchAndroidX86_64 = "android_x86_64" 46 osArchDarwinArm64 = "darwin_arm64" 47 osArchDarwinX86_64 = "darwin_x86_64" 48 osArchLinuxX86 = "linux_glibc_x86" 49 osArchLinuxX86_64 = "linux_glibc_x86_64" 50 osArchLinuxMuslArm = "linux_musl_arm" 51 osArchLinuxMuslArm64 = "linux_musl_arm64" 52 osArchLinuxMuslX86 = "linux_musl_x86" 53 osArchLinuxMuslX86_64 = "linux_musl_x86_64" 54 osArchLinuxBionicArm64 = "linux_bionic_arm64" 55 osArchLinuxBionicX86_64 = "linux_bionic_x86_64" 56 osArchWindowsX86 = "windows_x86" 57 osArchWindowsX86_64 = "windows_x86_64" 58 59 // This is the string representation of the default condition wherever a 60 // configurable attribute is used in a select statement, i.e. 61 // //conditions:default for Bazel. 62 // 63 // This is consistently named "conditions_default" to mirror the Soong 64 // config variable default key in an Android.bp file, although there's no 65 // integration with Soong config variables (yet). 66 ConditionsDefaultConfigKey = "conditions_default" 67 68 ConditionsDefaultSelectKey = "//conditions:default" 69 70 productVariableBazelPackage = "//build/bazel/product_config/config_settings" 71 72 AndroidAndInApex = "android-in_apex" 73 AndroidPlatform = "system" 74 Unbundled_app = "unbundled_app" 75 76 InApex = "in_apex" 77 NonApex = "non_apex" 78 79 ErrorproneDisabled = "errorprone_disabled" 80 // TODO: b/294868620 - Remove when completing the bug 81 SanitizersEnabled = "sanitizers_enabled" 82) 83 84func PowerSetWithoutEmptySet[T any](items []T) [][]T { 85 resultSize := int(math.Pow(2, float64(len(items)))) 86 powerSet := make([][]T, 0, resultSize-1) 87 for i := 1; i < resultSize; i++ { 88 combination := make([]T, 0) 89 for j := 0; j < len(items); j++ { 90 if (i>>j)%2 == 1 { 91 combination = append(combination, items[j]) 92 } 93 } 94 powerSet = append(powerSet, combination) 95 } 96 return powerSet 97} 98 99func createPlatformArchMap() map[string]string { 100 // Copy of archFeatures from android/arch_list.go because the bazel 101 // package can't access the android package 102 archFeatures := map[string][]string{ 103 "arm": { 104 "neon", 105 }, 106 "arm64": { 107 "dotprod", 108 }, 109 "riscv64": {}, 110 "x86": { 111 "ssse3", 112 "sse4", 113 "sse4_1", 114 "sse4_2", 115 "aes_ni", 116 "avx", 117 "avx2", 118 "avx512", 119 "popcnt", 120 "movbe", 121 }, 122 "x86_64": { 123 "ssse3", 124 "sse4", 125 "sse4_1", 126 "sse4_2", 127 "aes_ni", 128 "avx", 129 "avx2", 130 "avx512", 131 "popcnt", 132 }, 133 } 134 result := make(map[string]string) 135 for arch, allFeatures := range archFeatures { 136 result[arch] = "//build/bazel_common_rules/platforms/arch:" + arch 137 // Sometimes we want to select on multiple features being active, so 138 // add the power set of all possible features to the map. More details 139 // in android.ModuleBase.GetArchVariantProperties 140 for _, features := range PowerSetWithoutEmptySet(allFeatures) { 141 sort.Strings(features) 142 archFeaturesName := arch + "-" + strings.Join(features, "-") 143 result[archFeaturesName] = "//build/bazel/platforms/arch/variants:" + archFeaturesName 144 } 145 } 146 result[ConditionsDefaultConfigKey] = ConditionsDefaultSelectKey 147 return result 148} 149 150var ( 151 // These are the list of OSes and architectures with a Bazel config_setting 152 // and constraint value equivalent. These exist in arch.go, but the android 153 // package depends on the bazel package, so a cyclic dependency prevents 154 // using those variables here. 155 156 // A map of architectures to the Bazel label of the constraint_value 157 // for the @platforms//cpu:cpu constraint_setting 158 platformArchMap = createPlatformArchMap() 159 160 // A map of target operating systems to the Bazel label of the 161 // constraint_value for the @platforms//os:os constraint_setting 162 platformOsMap = map[string]string{ 163 OsAndroid: "//build/bazel_common_rules/platforms/os:android", 164 OsDarwin: "//build/bazel_common_rules/platforms/os:darwin", 165 OsLinux: "//build/bazel_common_rules/platforms/os:linux_glibc", 166 osLinuxMusl: "//build/bazel_common_rules/platforms/os:linux_musl", 167 osLinuxBionic: "//build/bazel_common_rules/platforms/os:linux_bionic", 168 OsWindows: "//build/bazel_common_rules/platforms/os:windows", 169 ConditionsDefaultConfigKey: ConditionsDefaultSelectKey, // The default condition of an os select map. 170 } 171 172 platformOsArchMap = map[string]string{ 173 osArchAndroidArm: "//build/bazel_common_rules/platforms/os_arch:android_arm", 174 OsArchAndroidArm64: "//build/bazel_common_rules/platforms/os_arch:android_arm64", 175 osArchAndroidRiscv64: "//build/bazel_common_rules/platforms/os_arch:android_riscv64", 176 osArchAndroidX86: "//build/bazel_common_rules/platforms/os_arch:android_x86", 177 osArchAndroidX86_64: "//build/bazel_common_rules/platforms/os_arch:android_x86_64", 178 osArchDarwinArm64: "//build/bazel_common_rules/platforms/os_arch:darwin_arm64", 179 osArchDarwinX86_64: "//build/bazel_common_rules/platforms/os_arch:darwin_x86_64", 180 osArchLinuxX86: "//build/bazel_common_rules/platforms/os_arch:linux_glibc_x86", 181 osArchLinuxX86_64: "//build/bazel_common_rules/platforms/os_arch:linux_glibc_x86_64", 182 osArchLinuxMuslArm: "//build/bazel_common_rules/platforms/os_arch:linux_musl_arm", 183 osArchLinuxMuslArm64: "//build/bazel_common_rules/platforms/os_arch:linux_musl_arm64", 184 osArchLinuxMuslX86: "//build/bazel_common_rules/platforms/os_arch:linux_musl_x86", 185 osArchLinuxMuslX86_64: "//build/bazel_common_rules/platforms/os_arch:linux_musl_x86_64", 186 osArchLinuxBionicArm64: "//build/bazel_common_rules/platforms/os_arch:linux_bionic_arm64", 187 osArchLinuxBionicX86_64: "//build/bazel_common_rules/platforms/os_arch:linux_bionic_x86_64", 188 osArchWindowsX86: "//build/bazel_common_rules/platforms/os_arch:windows_x86", 189 osArchWindowsX86_64: "//build/bazel_common_rules/platforms/os_arch:windows_x86_64", 190 ConditionsDefaultConfigKey: ConditionsDefaultSelectKey, // The default condition of an os select map. 191 } 192 193 // Map where keys are OsType names, and values are slices containing the archs 194 // that that OS supports. 195 // These definitions copied from arch.go. 196 // TODO(cparsons): Source from arch.go; this task is nontrivial, as it currently results 197 // in a cyclic dependency. 198 osToArchMap = map[string][]string{ 199 OsAndroid: {archArm, archArm64, archRiscv64, archX86, archX86_64}, 200 OsLinux: {archX86, archX86_64}, 201 osLinuxMusl: {archX86, archX86_64}, 202 OsDarwin: {archArm64, archX86_64}, 203 osLinuxBionic: {archArm64, archX86_64}, 204 // TODO(cparsons): According to arch.go, this should contain archArm, archArm64, as well. 205 OsWindows: {archX86, archX86_64}, 206 } 207 208 osAndInApexMap = map[string]string{ 209 AndroidAndInApex: "//build/bazel/rules/apex:android-in_apex", 210 AndroidPlatform: "//build/bazel/rules/apex:system", 211 Unbundled_app: "//build/bazel/rules/apex:unbundled_app", 212 OsDarwin: "//build/bazel_common_rules/platforms/os:darwin", 213 OsLinux: "//build/bazel_common_rules/platforms/os:linux_glibc", 214 osLinuxMusl: "//build/bazel_common_rules/platforms/os:linux_musl", 215 osLinuxBionic: "//build/bazel_common_rules/platforms/os:linux_bionic", 216 OsWindows: "//build/bazel_common_rules/platforms/os:windows", 217 ConditionsDefaultConfigKey: ConditionsDefaultSelectKey, 218 } 219 220 inApexMap = map[string]string{ 221 InApex: "//build/bazel/rules/apex:in_apex", 222 NonApex: "//build/bazel/rules/apex:non_apex", 223 ConditionsDefaultConfigKey: ConditionsDefaultSelectKey, 224 } 225 226 errorProneMap = map[string]string{ 227 ErrorproneDisabled: "//build/bazel/rules/java/errorprone:errorprone_globally_disabled", 228 ConditionsDefaultConfigKey: ConditionsDefaultSelectKey, 229 } 230 231 // TODO: b/294868620 - Remove when completing the bug 232 sanitizersEnabledMap = map[string]string{ 233 SanitizersEnabled: "//build/bazel/rules/cc:sanitizers_enabled", 234 ConditionsDefaultConfigKey: ConditionsDefaultSelectKey, 235 } 236) 237 238// basic configuration types 239type configurationType int 240 241const ( 242 noConfig configurationType = iota 243 arch 244 os 245 osArch 246 productVariables 247 osAndInApex 248 inApex 249 errorProneDisabled 250 // TODO: b/294868620 - Remove when completing the bug 251 sanitizersEnabled 252) 253 254func osArchString(os string, arch string) string { 255 return fmt.Sprintf("%s_%s", os, arch) 256} 257 258func (ct configurationType) String() string { 259 return map[configurationType]string{ 260 noConfig: "no_config", 261 arch: "arch", 262 os: "os", 263 osArch: "arch_os", 264 productVariables: "product_variables", 265 osAndInApex: "os_in_apex", 266 inApex: "in_apex", 267 errorProneDisabled: "errorprone_disabled", 268 // TODO: b/294868620 - Remove when completing the bug 269 sanitizersEnabled: "sanitizers_enabled", 270 }[ct] 271} 272 273func (ct configurationType) validateConfig(config string) { 274 switch ct { 275 case noConfig: 276 if config != "" { 277 panic(fmt.Errorf("Cannot specify config with %s, but got %s", ct, config)) 278 } 279 case arch: 280 if _, ok := platformArchMap[config]; !ok { 281 panic(fmt.Errorf("Unknown arch: %s", config)) 282 } 283 case os: 284 if _, ok := platformOsMap[config]; !ok { 285 panic(fmt.Errorf("Unknown os: %s", config)) 286 } 287 case osArch: 288 if _, ok := platformOsArchMap[config]; !ok { 289 panic(fmt.Errorf("Unknown os+arch: %s", config)) 290 } 291 case productVariables: 292 // do nothing 293 case osAndInApex: 294 // do nothing 295 // this axis can contain additional per-apex keys 296 case inApex: 297 if _, ok := inApexMap[config]; !ok { 298 panic(fmt.Errorf("Unknown in_apex config: %s", config)) 299 } 300 case errorProneDisabled: 301 if _, ok := errorProneMap[config]; !ok { 302 panic(fmt.Errorf("Unknown errorprone config: %s", config)) 303 } 304 // TODO: b/294868620 - Remove when completing the bug 305 case sanitizersEnabled: 306 if _, ok := sanitizersEnabledMap[config]; !ok { 307 panic(fmt.Errorf("Unknown sanitizers_enabled config: %s", config)) 308 } 309 default: 310 panic(fmt.Errorf("Unrecognized ConfigurationType %d", ct)) 311 } 312} 313 314// SelectKey returns the Bazel select key for a given configurationType and config string. 315func (ca ConfigurationAxis) SelectKey(config string) string { 316 ca.validateConfig(config) 317 switch ca.configurationType { 318 case noConfig: 319 panic(fmt.Errorf("SelectKey is unnecessary for noConfig ConfigurationType ")) 320 case arch: 321 return platformArchMap[config] 322 case os: 323 return platformOsMap[config] 324 case osArch: 325 return platformOsArchMap[config] 326 case productVariables: 327 if config == ConditionsDefaultConfigKey { 328 return ConditionsDefaultSelectKey 329 } 330 return fmt.Sprintf("%s:%s", productVariableBazelPackage, config) 331 case osAndInApex: 332 if ret, exists := osAndInApexMap[config]; exists { 333 return ret 334 } 335 return config 336 case inApex: 337 return inApexMap[config] 338 case errorProneDisabled: 339 return errorProneMap[config] 340 // TODO: b/294868620 - Remove when completing the bug 341 case sanitizersEnabled: 342 return sanitizersEnabledMap[config] 343 default: 344 panic(fmt.Errorf("Unrecognized ConfigurationType %d", ca.configurationType)) 345 } 346} 347 348var ( 349 // Indicating there is no configuration axis 350 NoConfigAxis = ConfigurationAxis{configurationType: noConfig} 351 // An axis for architecture-specific configurations 352 ArchConfigurationAxis = ConfigurationAxis{configurationType: arch} 353 // An axis for os-specific configurations 354 OsConfigurationAxis = ConfigurationAxis{configurationType: os} 355 // An axis for arch+os-specific configurations 356 OsArchConfigurationAxis = ConfigurationAxis{configurationType: osArch} 357 // An axis for os+in_apex-specific configurations 358 OsAndInApexAxis = ConfigurationAxis{configurationType: osAndInApex} 359 // An axis for in_apex-specific configurations 360 InApexAxis = ConfigurationAxis{configurationType: inApex} 361 362 ErrorProneAxis = ConfigurationAxis{configurationType: errorProneDisabled} 363 364 // TODO: b/294868620 - Remove when completing the bug 365 SanitizersEnabledAxis = ConfigurationAxis{configurationType: sanitizersEnabled} 366) 367 368// ProductVariableConfigurationAxis returns an axis for the given product variable 369func ProductVariableConfigurationAxis(archVariant bool, variable string) ConfigurationAxis { 370 return ConfigurationAxis{ 371 configurationType: productVariables, 372 subType: variable, 373 archVariant: archVariant, 374 } 375} 376 377// ConfigurationAxis is an independent axis for configuration, there should be no overlap between 378// elements within an axis. 379type ConfigurationAxis struct { 380 configurationType 381 // some configuration types (e.g. productVariables) have multiple independent axes, subType helps 382 // distinguish between them without needing to list all 17 product variables. 383 subType string 384 385 archVariant bool 386} 387 388func (ca *ConfigurationAxis) less(other ConfigurationAxis) bool { 389 if ca.configurationType == other.configurationType { 390 return ca.subType < other.subType 391 } 392 return ca.configurationType < other.configurationType 393} 394