blob: e1cdd4acf75ea2f5e3fb67b4f5ba65593f68f84a [file] [log] [blame]
Liz Kammer9abd62d2021-05-21 08:37:59 -04001// 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"
Cole Faustc843b992022-08-02 18:06:50 -070019 "math"
20 "sort"
Liz Kammer9abd62d2021-05-21 08:37:59 -040021 "strings"
22)
23
24const (
25 // ArchType names in arch.go
26 archArm = "arm"
27 archArm64 = "arm64"
28 archX86 = "x86"
29 archX86_64 = "x86_64"
30
31 // OsType names in arch.go
Wei Li81852ca2022-07-27 00:22:06 -070032 OsAndroid = "android"
Liz Kammer9abd62d2021-05-21 08:37:59 -040033 osDarwin = "darwin"
Liz Kammer9abd62d2021-05-21 08:37:59 -040034 osLinux = "linux_glibc"
Colin Cross528d67e2021-07-23 22:23:07 +000035 osLinuxMusl = "linux_musl"
Liz Kammer9abd62d2021-05-21 08:37:59 -040036 osLinuxBionic = "linux_bionic"
37 osWindows = "windows"
38
39 // Targets in arch.go
40 osArchAndroidArm = "android_arm"
41 osArchAndroidArm64 = "android_arm64"
42 osArchAndroidX86 = "android_x86"
43 osArchAndroidX86_64 = "android_x86_64"
Dan Willemsen8528f4e2021-10-19 00:22:06 -070044 osArchDarwinArm64 = "darwin_arm64"
Liz Kammer9abd62d2021-05-21 08:37:59 -040045 osArchDarwinX86_64 = "darwin_x86_64"
Liz Kammer9abd62d2021-05-21 08:37:59 -040046 osArchLinuxX86 = "linux_glibc_x86"
47 osArchLinuxX86_64 = "linux_glibc_x86_64"
Colin Crossa9b2aac2022-06-15 17:25:51 -070048 osArchLinuxMuslArm = "linux_musl_arm"
49 osArchLinuxMuslArm64 = "linux_musl_arm64"
Colin Cross528d67e2021-07-23 22:23:07 +000050 osArchLinuxMuslX86 = "linux_musl_x86"
51 osArchLinuxMuslX86_64 = "linux_musl_x86_64"
Liz Kammer9abd62d2021-05-21 08:37:59 -040052 osArchLinuxBionicArm64 = "linux_bionic_arm64"
53 osArchLinuxBionicX86_64 = "linux_bionic_x86_64"
54 osArchWindowsX86 = "windows_x86"
55 osArchWindowsX86_64 = "windows_x86_64"
56
57 // This is the string representation of the default condition wherever a
58 // configurable attribute is used in a select statement, i.e.
59 // //conditions:default for Bazel.
60 //
61 // This is consistently named "conditions_default" to mirror the Soong
62 // config variable default key in an Android.bp file, although there's no
63 // integration with Soong config variables (yet).
Chris Parsons51f8c392021-08-03 21:01:05 -040064 ConditionsDefaultConfigKey = "conditions_default"
Liz Kammer9abd62d2021-05-21 08:37:59 -040065
66 ConditionsDefaultSelectKey = "//conditions:default"
67
68 productVariableBazelPackage = "//build/bazel/product_variables"
Wei Li81852ca2022-07-27 00:22:06 -070069
70 AndroidAndInApex = "android-in_apex"
71 AndroidAndNonApex = "android-non_apex"
Liz Kammer9abd62d2021-05-21 08:37:59 -040072)
73
Cole Faustc843b992022-08-02 18:06:50 -070074func PowerSetWithoutEmptySet[T any](items []T) [][]T {
75 resultSize := int(math.Pow(2, float64(len(items))))
76 powerSet := make([][]T, 0, resultSize-1)
77 for i := 1; i < resultSize; i++ {
78 combination := make([]T, 0)
79 for j := 0; j < len(items); j++ {
80 if (i>>j)%2 == 1 {
81 combination = append(combination, items[j])
82 }
83 }
84 powerSet = append(powerSet, combination)
85 }
86 return powerSet
87}
88
89func createPlatformArchMap() map[string]string {
90 // Copy of archFeatures from android/arch_list.go because the bazel
91 // package can't access the android package
92 archFeatures := map[string][]string{
93 "arm": {
94 "neon",
95 },
96 "arm64": {
97 "dotprod",
98 },
99 "x86": {
100 "ssse3",
101 "sse4",
102 "sse4_1",
103 "sse4_2",
104 "aes_ni",
105 "avx",
106 "avx2",
107 "avx512",
108 "popcnt",
109 "movbe",
110 },
111 "x86_64": {
112 "ssse3",
113 "sse4",
114 "sse4_1",
115 "sse4_2",
116 "aes_ni",
117 "avx",
118 "avx2",
119 "avx512",
120 "popcnt",
121 },
122 }
123 result := make(map[string]string)
124 for arch, allFeatures := range archFeatures {
125 result[arch] = "//build/bazel/platforms/arch:" + arch
126 // Sometimes we want to select on multiple features being active, so
127 // add the power set of all possible features to the map. More details
128 // in android.ModuleBase.GetArchVariantProperties
129 for _, features := range PowerSetWithoutEmptySet(allFeatures) {
130 sort.Strings(features)
131 archFeaturesName := arch + "-" + strings.Join(features, "-")
132 result[archFeaturesName] = "//build/bazel/platforms/arch/variants:" + archFeaturesName
133 }
134 }
135 result[ConditionsDefaultConfigKey] = ConditionsDefaultSelectKey
136 return result
137}
138
Liz Kammer9abd62d2021-05-21 08:37:59 -0400139var (
140 // These are the list of OSes and architectures with a Bazel config_setting
141 // and constraint value equivalent. These exist in arch.go, but the android
142 // package depends on the bazel package, so a cyclic dependency prevents
143 // using those variables here.
144
145 // A map of architectures to the Bazel label of the constraint_value
146 // for the @platforms//cpu:cpu constraint_setting
Cole Faustc843b992022-08-02 18:06:50 -0700147 platformArchMap = createPlatformArchMap()
Liz Kammer9abd62d2021-05-21 08:37:59 -0400148
149 // A map of target operating systems to the Bazel label of the
150 // constraint_value for the @platforms//os:os constraint_setting
151 platformOsMap = map[string]string{
Wei Li81852ca2022-07-27 00:22:06 -0700152 OsAndroid: "//build/bazel/platforms/os:android",
Chris Parsons51f8c392021-08-03 21:01:05 -0400153 osDarwin: "//build/bazel/platforms/os:darwin",
154 osLinux: "//build/bazel/platforms/os:linux",
155 osLinuxMusl: "//build/bazel/platforms/os:linux_musl",
156 osLinuxBionic: "//build/bazel/platforms/os:linux_bionic",
157 osWindows: "//build/bazel/platforms/os:windows",
158 ConditionsDefaultConfigKey: ConditionsDefaultSelectKey, // The default condition of an os select map.
Liz Kammer9abd62d2021-05-21 08:37:59 -0400159 }
160
161 platformOsArchMap = map[string]string{
Chris Parsons51f8c392021-08-03 21:01:05 -0400162 osArchAndroidArm: "//build/bazel/platforms/os_arch:android_arm",
163 osArchAndroidArm64: "//build/bazel/platforms/os_arch:android_arm64",
164 osArchAndroidX86: "//build/bazel/platforms/os_arch:android_x86",
165 osArchAndroidX86_64: "//build/bazel/platforms/os_arch:android_x86_64",
Dan Willemsen8528f4e2021-10-19 00:22:06 -0700166 osArchDarwinArm64: "//build/bazel/platforms/os_arch:darwin_arm64",
Chris Parsons51f8c392021-08-03 21:01:05 -0400167 osArchDarwinX86_64: "//build/bazel/platforms/os_arch:darwin_x86_64",
168 osArchLinuxX86: "//build/bazel/platforms/os_arch:linux_glibc_x86",
169 osArchLinuxX86_64: "//build/bazel/platforms/os_arch:linux_glibc_x86_64",
Colin Crossa9b2aac2022-06-15 17:25:51 -0700170 osArchLinuxMuslArm: "//build/bazel/platforms/os_arch:linux_musl_arm",
171 osArchLinuxMuslArm64: "//build/bazel/platforms/os_arch:linux_musl_arm64",
Chris Parsons51f8c392021-08-03 21:01:05 -0400172 osArchLinuxMuslX86: "//build/bazel/platforms/os_arch:linux_musl_x86",
173 osArchLinuxMuslX86_64: "//build/bazel/platforms/os_arch:linux_musl_x86_64",
174 osArchLinuxBionicArm64: "//build/bazel/platforms/os_arch:linux_bionic_arm64",
175 osArchLinuxBionicX86_64: "//build/bazel/platforms/os_arch:linux_bionic_x86_64",
176 osArchWindowsX86: "//build/bazel/platforms/os_arch:windows_x86",
177 osArchWindowsX86_64: "//build/bazel/platforms/os_arch:windows_x86_64",
178 ConditionsDefaultConfigKey: ConditionsDefaultSelectKey, // The default condition of an os select map.
Liz Kammer9abd62d2021-05-21 08:37:59 -0400179 }
Chris Parsons58852a02021-12-09 18:10:18 -0500180
181 // Map where keys are OsType names, and values are slices containing the archs
182 // that that OS supports.
183 // These definitions copied from arch.go.
184 // TODO(cparsons): Source from arch.go; this task is nontrivial, as it currently results
185 // in a cyclic dependency.
186 osToArchMap = map[string][]string{
Wei Li81852ca2022-07-27 00:22:06 -0700187 OsAndroid: {archArm, archArm64, archX86, archX86_64},
Chris Parsons58852a02021-12-09 18:10:18 -0500188 osLinux: {archX86, archX86_64},
189 osLinuxMusl: {archX86, archX86_64},
190 osDarwin: {archArm64, archX86_64},
191 osLinuxBionic: {archArm64, archX86_64},
192 // TODO(cparsons): According to arch.go, this should contain archArm, archArm64, as well.
193 osWindows: {archX86, archX86_64},
194 }
Wei Li81852ca2022-07-27 00:22:06 -0700195
196 osAndInApexMap = map[string]string{
197 AndroidAndInApex: "//build/bazel/rules/apex:android-in_apex",
198 AndroidAndNonApex: "//build/bazel/rules/apex:android-non_apex",
199 ConditionsDefaultConfigKey: ConditionsDefaultSelectKey,
200 }
Liz Kammer9abd62d2021-05-21 08:37:59 -0400201)
202
203// basic configuration types
204type configurationType int
205
206const (
207 noConfig configurationType = iota
208 arch
209 os
210 osArch
211 productVariables
Wei Li81852ca2022-07-27 00:22:06 -0700212 osAndInApex
Liz Kammer9abd62d2021-05-21 08:37:59 -0400213)
214
Chris Parsons58852a02021-12-09 18:10:18 -0500215func osArchString(os string, arch string) string {
216 return fmt.Sprintf("%s_%s", os, arch)
217}
218
Liz Kammer9abd62d2021-05-21 08:37:59 -0400219func (ct configurationType) String() string {
220 return map[configurationType]string{
221 noConfig: "no_config",
222 arch: "arch",
223 os: "os",
224 osArch: "arch_os",
225 productVariables: "product_variables",
Wei Li81852ca2022-07-27 00:22:06 -0700226 osAndInApex: "os_in_apex",
Liz Kammer9abd62d2021-05-21 08:37:59 -0400227 }[ct]
228}
229
230func (ct configurationType) validateConfig(config string) {
231 switch ct {
232 case noConfig:
233 if config != "" {
234 panic(fmt.Errorf("Cannot specify config with %s, but got %s", ct, config))
235 }
236 case arch:
237 if _, ok := platformArchMap[config]; !ok {
238 panic(fmt.Errorf("Unknown arch: %s", config))
239 }
240 case os:
241 if _, ok := platformOsMap[config]; !ok {
242 panic(fmt.Errorf("Unknown os: %s", config))
243 }
244 case osArch:
245 if _, ok := platformOsArchMap[config]; !ok {
246 panic(fmt.Errorf("Unknown os+arch: %s", config))
247 }
248 case productVariables:
249 // do nothing
Wei Li81852ca2022-07-27 00:22:06 -0700250 case osAndInApex:
251 if _, ok := osAndInApexMap[config]; !ok {
252 panic(fmt.Errorf("Unknown os+in_apex config: %s", config))
253 }
Liz Kammer9abd62d2021-05-21 08:37:59 -0400254 default:
255 panic(fmt.Errorf("Unrecognized ConfigurationType %d", ct))
256 }
257}
258
259// SelectKey returns the Bazel select key for a given configurationType and config string.
Jingwen Chena47f28d2021-11-02 16:43:57 +0000260func (ca ConfigurationAxis) SelectKey(config string) string {
261 ca.validateConfig(config)
262 switch ca.configurationType {
Liz Kammer9abd62d2021-05-21 08:37:59 -0400263 case noConfig:
264 panic(fmt.Errorf("SelectKey is unnecessary for noConfig ConfigurationType "))
265 case arch:
266 return platformArchMap[config]
267 case os:
268 return platformOsMap[config]
269 case osArch:
270 return platformOsArchMap[config]
271 case productVariables:
Jingwen Chena47f28d2021-11-02 16:43:57 +0000272 if strings.HasSuffix(config, ConditionsDefaultConfigKey) {
273 // e.g. "acme__feature1__conditions_default" or "android__board__conditions_default"
Liz Kammer9abd62d2021-05-21 08:37:59 -0400274 return ConditionsDefaultSelectKey
275 }
Jingwen Chena47f28d2021-11-02 16:43:57 +0000276 return fmt.Sprintf("%s:%s", productVariableBazelPackage, config)
Wei Li81852ca2022-07-27 00:22:06 -0700277 case osAndInApex:
278 return osAndInApexMap[config]
Liz Kammer9abd62d2021-05-21 08:37:59 -0400279 default:
Jingwen Chena47f28d2021-11-02 16:43:57 +0000280 panic(fmt.Errorf("Unrecognized ConfigurationType %d", ca.configurationType))
Liz Kammer9abd62d2021-05-21 08:37:59 -0400281 }
282}
283
284var (
285 // Indicating there is no configuration axis
286 NoConfigAxis = ConfigurationAxis{configurationType: noConfig}
287 // An axis for architecture-specific configurations
288 ArchConfigurationAxis = ConfigurationAxis{configurationType: arch}
289 // An axis for os-specific configurations
290 OsConfigurationAxis = ConfigurationAxis{configurationType: os}
291 // An axis for arch+os-specific configurations
292 OsArchConfigurationAxis = ConfigurationAxis{configurationType: osArch}
Wei Li81852ca2022-07-27 00:22:06 -0700293 // An axis for os+in_apex-specific configurations
294 OsAndInApexAxis = ConfigurationAxis{configurationType: osAndInApex}
Liz Kammer9abd62d2021-05-21 08:37:59 -0400295)
296
297// ProductVariableConfigurationAxis returns an axis for the given product variable
298func ProductVariableConfigurationAxis(variable string) ConfigurationAxis {
299 return ConfigurationAxis{
300 configurationType: productVariables,
301 subType: variable,
302 }
303}
304
305// ConfigurationAxis is an independent axis for configuration, there should be no overlap between
306// elements within an axis.
307type ConfigurationAxis struct {
308 configurationType
309 // some configuration types (e.g. productVariables) have multiple independent axes, subType helps
310 // distinguish between them without needing to list all 17 product variables.
311 subType string
312}
313
314func (ca *ConfigurationAxis) less(other ConfigurationAxis) bool {
315 if ca.configurationType < other.configurationType {
316 return true
317 }
318 return ca.subType < other.subType
319}