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 "strings" 20) 21 22const ( 23 // ArchType names in arch.go 24 archArm = "arm" 25 archArm64 = "arm64" 26 archX86 = "x86" 27 archX86_64 = "x86_64" 28 29 // OsType names in arch.go 30 osAndroid = "android" 31 osDarwin = "darwin" 32 osLinux = "linux_glibc" 33 osLinuxMusl = "linux_musl" 34 osLinuxBionic = "linux_bionic" 35 osWindows = "windows" 36 37 // Targets in arch.go 38 osArchAndroidArm = "android_arm" 39 osArchAndroidArm64 = "android_arm64" 40 osArchAndroidX86 = "android_x86" 41 osArchAndroidX86_64 = "android_x86_64" 42 osArchDarwinArm64 = "darwin_arm64" 43 osArchDarwinX86_64 = "darwin_x86_64" 44 osArchLinuxX86 = "linux_glibc_x86" 45 osArchLinuxX86_64 = "linux_glibc_x86_64" 46 osArchLinuxMuslX86 = "linux_musl_x86" 47 osArchLinuxMuslX86_64 = "linux_musl_x86_64" 48 osArchLinuxBionicArm64 = "linux_bionic_arm64" 49 osArchLinuxBionicX86_64 = "linux_bionic_x86_64" 50 osArchWindowsX86 = "windows_x86" 51 osArchWindowsX86_64 = "windows_x86_64" 52 53 // This is the string representation of the default condition wherever a 54 // configurable attribute is used in a select statement, i.e. 55 // //conditions:default for Bazel. 56 // 57 // This is consistently named "conditions_default" to mirror the Soong 58 // config variable default key in an Android.bp file, although there's no 59 // integration with Soong config variables (yet). 60 ConditionsDefaultConfigKey = "conditions_default" 61 62 ConditionsDefaultSelectKey = "//conditions:default" 63 64 productVariableBazelPackage = "//build/bazel/product_variables" 65) 66 67var ( 68 // These are the list of OSes and architectures with a Bazel config_setting 69 // and constraint value equivalent. These exist in arch.go, but the android 70 // package depends on the bazel package, so a cyclic dependency prevents 71 // using those variables here. 72 73 // A map of architectures to the Bazel label of the constraint_value 74 // for the @platforms//cpu:cpu constraint_setting 75 platformArchMap = map[string]string{ 76 archArm: "//build/bazel/platforms/arch:arm", 77 archArm64: "//build/bazel/platforms/arch:arm64", 78 archX86: "//build/bazel/platforms/arch:x86", 79 archX86_64: "//build/bazel/platforms/arch:x86_64", 80 ConditionsDefaultConfigKey: ConditionsDefaultSelectKey, // The default condition of as arch select map. 81 } 82 83 // A map of target operating systems to the Bazel label of the 84 // constraint_value for the @platforms//os:os constraint_setting 85 platformOsMap = map[string]string{ 86 osAndroid: "//build/bazel/platforms/os:android", 87 osDarwin: "//build/bazel/platforms/os:darwin", 88 osLinux: "//build/bazel/platforms/os:linux", 89 osLinuxMusl: "//build/bazel/platforms/os:linux_musl", 90 osLinuxBionic: "//build/bazel/platforms/os:linux_bionic", 91 osWindows: "//build/bazel/platforms/os:windows", 92 ConditionsDefaultConfigKey: ConditionsDefaultSelectKey, // The default condition of an os select map. 93 } 94 95 platformOsArchMap = map[string]string{ 96 osArchAndroidArm: "//build/bazel/platforms/os_arch:android_arm", 97 osArchAndroidArm64: "//build/bazel/platforms/os_arch:android_arm64", 98 osArchAndroidX86: "//build/bazel/platforms/os_arch:android_x86", 99 osArchAndroidX86_64: "//build/bazel/platforms/os_arch:android_x86_64", 100 osArchDarwinArm64: "//build/bazel/platforms/os_arch:darwin_arm64", 101 osArchDarwinX86_64: "//build/bazel/platforms/os_arch:darwin_x86_64", 102 osArchLinuxX86: "//build/bazel/platforms/os_arch:linux_glibc_x86", 103 osArchLinuxX86_64: "//build/bazel/platforms/os_arch:linux_glibc_x86_64", 104 osArchLinuxMuslX86: "//build/bazel/platforms/os_arch:linux_musl_x86", 105 osArchLinuxMuslX86_64: "//build/bazel/platforms/os_arch:linux_musl_x86_64", 106 osArchLinuxBionicArm64: "//build/bazel/platforms/os_arch:linux_bionic_arm64", 107 osArchLinuxBionicX86_64: "//build/bazel/platforms/os_arch:linux_bionic_x86_64", 108 osArchWindowsX86: "//build/bazel/platforms/os_arch:windows_x86", 109 osArchWindowsX86_64: "//build/bazel/platforms/os_arch:windows_x86_64", 110 ConditionsDefaultConfigKey: ConditionsDefaultSelectKey, // The default condition of an os select map. 111 } 112 113 // Map where keys are OsType names, and values are slices containing the archs 114 // that that OS supports. 115 // These definitions copied from arch.go. 116 // TODO(cparsons): Source from arch.go; this task is nontrivial, as it currently results 117 // in a cyclic dependency. 118 osToArchMap = map[string][]string{ 119 osAndroid: {archArm, archArm64, archX86, archX86_64}, 120 osLinux: {archX86, archX86_64}, 121 osLinuxMusl: {archX86, archX86_64}, 122 osDarwin: {archArm64, archX86_64}, 123 osLinuxBionic: {archArm64, archX86_64}, 124 // TODO(cparsons): According to arch.go, this should contain archArm, archArm64, as well. 125 osWindows: {archX86, archX86_64}, 126 } 127) 128 129// basic configuration types 130type configurationType int 131 132const ( 133 noConfig configurationType = iota 134 arch 135 os 136 osArch 137 productVariables 138) 139 140func osArchString(os string, arch string) string { 141 return fmt.Sprintf("%s_%s", os, arch) 142} 143 144func (ct configurationType) String() string { 145 return map[configurationType]string{ 146 noConfig: "no_config", 147 arch: "arch", 148 os: "os", 149 osArch: "arch_os", 150 productVariables: "product_variables", 151 }[ct] 152} 153 154func (ct configurationType) validateConfig(config string) { 155 switch ct { 156 case noConfig: 157 if config != "" { 158 panic(fmt.Errorf("Cannot specify config with %s, but got %s", ct, config)) 159 } 160 case arch: 161 if _, ok := platformArchMap[config]; !ok { 162 panic(fmt.Errorf("Unknown arch: %s", config)) 163 } 164 case os: 165 if _, ok := platformOsMap[config]; !ok { 166 panic(fmt.Errorf("Unknown os: %s", config)) 167 } 168 case osArch: 169 if _, ok := platformOsArchMap[config]; !ok { 170 panic(fmt.Errorf("Unknown os+arch: %s", config)) 171 } 172 case productVariables: 173 // do nothing 174 default: 175 panic(fmt.Errorf("Unrecognized ConfigurationType %d", ct)) 176 } 177} 178 179// SelectKey returns the Bazel select key for a given configurationType and config string. 180func (ca ConfigurationAxis) SelectKey(config string) string { 181 ca.validateConfig(config) 182 switch ca.configurationType { 183 case noConfig: 184 panic(fmt.Errorf("SelectKey is unnecessary for noConfig ConfigurationType ")) 185 case arch: 186 return platformArchMap[config] 187 case os: 188 return platformOsMap[config] 189 case osArch: 190 return platformOsArchMap[config] 191 case productVariables: 192 if strings.HasSuffix(config, ConditionsDefaultConfigKey) { 193 // e.g. "acme__feature1__conditions_default" or "android__board__conditions_default" 194 return ConditionsDefaultSelectKey 195 } 196 return fmt.Sprintf("%s:%s", productVariableBazelPackage, config) 197 default: 198 panic(fmt.Errorf("Unrecognized ConfigurationType %d", ca.configurationType)) 199 } 200} 201 202var ( 203 // Indicating there is no configuration axis 204 NoConfigAxis = ConfigurationAxis{configurationType: noConfig} 205 // An axis for architecture-specific configurations 206 ArchConfigurationAxis = ConfigurationAxis{configurationType: arch} 207 // An axis for os-specific configurations 208 OsConfigurationAxis = ConfigurationAxis{configurationType: os} 209 // An axis for arch+os-specific configurations 210 OsArchConfigurationAxis = ConfigurationAxis{configurationType: osArch} 211) 212 213// ProductVariableConfigurationAxis returns an axis for the given product variable 214func ProductVariableConfigurationAxis(variable string) ConfigurationAxis { 215 return ConfigurationAxis{ 216 configurationType: productVariables, 217 subType: variable, 218 } 219} 220 221// ConfigurationAxis is an independent axis for configuration, there should be no overlap between 222// elements within an axis. 223type ConfigurationAxis struct { 224 configurationType 225 // some configuration types (e.g. productVariables) have multiple independent axes, subType helps 226 // distinguish between them without needing to list all 17 product variables. 227 subType string 228} 229 230func (ca *ConfigurationAxis) less(other ConfigurationAxis) bool { 231 if ca.configurationType < other.configurationType { 232 return true 233 } 234 return ca.subType < other.subType 235} 236