blob: b6bbd67c43220248a4de7f8e2878e5c250b3de6e [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"
Vinh Tran85fb07c2022-09-16 16:17:48 -040072
73 InApex = "in_apex"
74 NonApex = "non_apex"
Liz Kammer9abd62d2021-05-21 08:37:59 -040075)
76
Cole Faustc843b992022-08-02 18:06:50 -070077func PowerSetWithoutEmptySet[T any](items []T) [][]T {
78 resultSize := int(math.Pow(2, float64(len(items))))
79 powerSet := make([][]T, 0, resultSize-1)
80 for i := 1; i < resultSize; i++ {
81 combination := make([]T, 0)
82 for j := 0; j < len(items); j++ {
83 if (i>>j)%2 == 1 {
84 combination = append(combination, items[j])
85 }
86 }
87 powerSet = append(powerSet, combination)
88 }
89 return powerSet
90}
91
92func createPlatformArchMap() map[string]string {
93 // Copy of archFeatures from android/arch_list.go because the bazel
94 // package can't access the android package
95 archFeatures := map[string][]string{
96 "arm": {
97 "neon",
98 },
99 "arm64": {
100 "dotprod",
101 },
102 "x86": {
103 "ssse3",
104 "sse4",
105 "sse4_1",
106 "sse4_2",
107 "aes_ni",
108 "avx",
109 "avx2",
110 "avx512",
111 "popcnt",
112 "movbe",
113 },
114 "x86_64": {
115 "ssse3",
116 "sse4",
117 "sse4_1",
118 "sse4_2",
119 "aes_ni",
120 "avx",
121 "avx2",
122 "avx512",
123 "popcnt",
124 },
125 }
126 result := make(map[string]string)
127 for arch, allFeatures := range archFeatures {
128 result[arch] = "//build/bazel/platforms/arch:" + arch
129 // Sometimes we want to select on multiple features being active, so
130 // add the power set of all possible features to the map. More details
131 // in android.ModuleBase.GetArchVariantProperties
132 for _, features := range PowerSetWithoutEmptySet(allFeatures) {
133 sort.Strings(features)
134 archFeaturesName := arch + "-" + strings.Join(features, "-")
135 result[archFeaturesName] = "//build/bazel/platforms/arch/variants:" + archFeaturesName
136 }
137 }
138 result[ConditionsDefaultConfigKey] = ConditionsDefaultSelectKey
139 return result
140}
141
Liz Kammer9abd62d2021-05-21 08:37:59 -0400142var (
143 // These are the list of OSes and architectures with a Bazel config_setting
144 // and constraint value equivalent. These exist in arch.go, but the android
145 // package depends on the bazel package, so a cyclic dependency prevents
146 // using those variables here.
147
148 // A map of architectures to the Bazel label of the constraint_value
149 // for the @platforms//cpu:cpu constraint_setting
Cole Faustc843b992022-08-02 18:06:50 -0700150 platformArchMap = createPlatformArchMap()
Liz Kammer9abd62d2021-05-21 08:37:59 -0400151
152 // A map of target operating systems to the Bazel label of the
153 // constraint_value for the @platforms//os:os constraint_setting
154 platformOsMap = map[string]string{
Wei Li81852ca2022-07-27 00:22:06 -0700155 OsAndroid: "//build/bazel/platforms/os:android",
Chris Parsons51f8c392021-08-03 21:01:05 -0400156 osDarwin: "//build/bazel/platforms/os:darwin",
157 osLinux: "//build/bazel/platforms/os:linux",
158 osLinuxMusl: "//build/bazel/platforms/os:linux_musl",
159 osLinuxBionic: "//build/bazel/platforms/os:linux_bionic",
160 osWindows: "//build/bazel/platforms/os:windows",
161 ConditionsDefaultConfigKey: ConditionsDefaultSelectKey, // The default condition of an os select map.
Liz Kammer9abd62d2021-05-21 08:37:59 -0400162 }
163
164 platformOsArchMap = map[string]string{
Chris Parsons51f8c392021-08-03 21:01:05 -0400165 osArchAndroidArm: "//build/bazel/platforms/os_arch:android_arm",
166 osArchAndroidArm64: "//build/bazel/platforms/os_arch:android_arm64",
167 osArchAndroidX86: "//build/bazel/platforms/os_arch:android_x86",
168 osArchAndroidX86_64: "//build/bazel/platforms/os_arch:android_x86_64",
Dan Willemsen8528f4e2021-10-19 00:22:06 -0700169 osArchDarwinArm64: "//build/bazel/platforms/os_arch:darwin_arm64",
Chris Parsons51f8c392021-08-03 21:01:05 -0400170 osArchDarwinX86_64: "//build/bazel/platforms/os_arch:darwin_x86_64",
171 osArchLinuxX86: "//build/bazel/platforms/os_arch:linux_glibc_x86",
172 osArchLinuxX86_64: "//build/bazel/platforms/os_arch:linux_glibc_x86_64",
Colin Crossa9b2aac2022-06-15 17:25:51 -0700173 osArchLinuxMuslArm: "//build/bazel/platforms/os_arch:linux_musl_arm",
174 osArchLinuxMuslArm64: "//build/bazel/platforms/os_arch:linux_musl_arm64",
Chris Parsons51f8c392021-08-03 21:01:05 -0400175 osArchLinuxMuslX86: "//build/bazel/platforms/os_arch:linux_musl_x86",
176 osArchLinuxMuslX86_64: "//build/bazel/platforms/os_arch:linux_musl_x86_64",
177 osArchLinuxBionicArm64: "//build/bazel/platforms/os_arch:linux_bionic_arm64",
178 osArchLinuxBionicX86_64: "//build/bazel/platforms/os_arch:linux_bionic_x86_64",
179 osArchWindowsX86: "//build/bazel/platforms/os_arch:windows_x86",
180 osArchWindowsX86_64: "//build/bazel/platforms/os_arch:windows_x86_64",
181 ConditionsDefaultConfigKey: ConditionsDefaultSelectKey, // The default condition of an os select map.
Liz Kammer9abd62d2021-05-21 08:37:59 -0400182 }
Chris Parsons58852a02021-12-09 18:10:18 -0500183
184 // Map where keys are OsType names, and values are slices containing the archs
185 // that that OS supports.
186 // These definitions copied from arch.go.
187 // TODO(cparsons): Source from arch.go; this task is nontrivial, as it currently results
188 // in a cyclic dependency.
189 osToArchMap = map[string][]string{
Wei Li81852ca2022-07-27 00:22:06 -0700190 OsAndroid: {archArm, archArm64, archX86, archX86_64},
Chris Parsons58852a02021-12-09 18:10:18 -0500191 osLinux: {archX86, archX86_64},
192 osLinuxMusl: {archX86, archX86_64},
193 osDarwin: {archArm64, archX86_64},
194 osLinuxBionic: {archArm64, archX86_64},
195 // TODO(cparsons): According to arch.go, this should contain archArm, archArm64, as well.
196 osWindows: {archX86, archX86_64},
197 }
Wei Li81852ca2022-07-27 00:22:06 -0700198
199 osAndInApexMap = map[string]string{
200 AndroidAndInApex: "//build/bazel/rules/apex:android-in_apex",
201 AndroidAndNonApex: "//build/bazel/rules/apex:android-non_apex",
202 ConditionsDefaultConfigKey: ConditionsDefaultSelectKey,
203 }
Vinh Tran85fb07c2022-09-16 16:17:48 -0400204
205 inApexMap = map[string]string{
206 InApex: "//build/bazel/rules/apex:in_apex",
207 NonApex: "//build/bazel/rules/apex:non_apex",
208 ConditionsDefaultConfigKey: ConditionsDefaultSelectKey,
209 }
Liz Kammer9abd62d2021-05-21 08:37:59 -0400210)
211
212// basic configuration types
213type configurationType int
214
215const (
216 noConfig configurationType = iota
217 arch
218 os
219 osArch
220 productVariables
Wei Li81852ca2022-07-27 00:22:06 -0700221 osAndInApex
Vinh Tran85fb07c2022-09-16 16:17:48 -0400222 inApex
Liz Kammer9abd62d2021-05-21 08:37:59 -0400223)
224
Chris Parsons58852a02021-12-09 18:10:18 -0500225func osArchString(os string, arch string) string {
226 return fmt.Sprintf("%s_%s", os, arch)
227}
228
Liz Kammer9abd62d2021-05-21 08:37:59 -0400229func (ct configurationType) String() string {
230 return map[configurationType]string{
231 noConfig: "no_config",
232 arch: "arch",
233 os: "os",
234 osArch: "arch_os",
235 productVariables: "product_variables",
Wei Li81852ca2022-07-27 00:22:06 -0700236 osAndInApex: "os_in_apex",
Vinh Tran85fb07c2022-09-16 16:17:48 -0400237 inApex: "in_apex",
Liz Kammer9abd62d2021-05-21 08:37:59 -0400238 }[ct]
239}
240
241func (ct configurationType) validateConfig(config string) {
242 switch ct {
243 case noConfig:
244 if config != "" {
245 panic(fmt.Errorf("Cannot specify config with %s, but got %s", ct, config))
246 }
247 case arch:
248 if _, ok := platformArchMap[config]; !ok {
249 panic(fmt.Errorf("Unknown arch: %s", config))
250 }
251 case os:
252 if _, ok := platformOsMap[config]; !ok {
253 panic(fmt.Errorf("Unknown os: %s", config))
254 }
255 case osArch:
256 if _, ok := platformOsArchMap[config]; !ok {
257 panic(fmt.Errorf("Unknown os+arch: %s", config))
258 }
259 case productVariables:
260 // do nothing
Wei Li81852ca2022-07-27 00:22:06 -0700261 case osAndInApex:
262 if _, ok := osAndInApexMap[config]; !ok {
263 panic(fmt.Errorf("Unknown os+in_apex config: %s", config))
264 }
Vinh Tran85fb07c2022-09-16 16:17:48 -0400265 case inApex:
266 if _, ok := inApexMap[config]; !ok {
267 panic(fmt.Errorf("Unknown in_apex config: %s", config))
268 }
Liz Kammer9abd62d2021-05-21 08:37:59 -0400269 default:
270 panic(fmt.Errorf("Unrecognized ConfigurationType %d", ct))
271 }
272}
273
274// SelectKey returns the Bazel select key for a given configurationType and config string.
Jingwen Chena47f28d2021-11-02 16:43:57 +0000275func (ca ConfigurationAxis) SelectKey(config string) string {
276 ca.validateConfig(config)
277 switch ca.configurationType {
Liz Kammer9abd62d2021-05-21 08:37:59 -0400278 case noConfig:
279 panic(fmt.Errorf("SelectKey is unnecessary for noConfig ConfigurationType "))
280 case arch:
281 return platformArchMap[config]
282 case os:
283 return platformOsMap[config]
284 case osArch:
285 return platformOsArchMap[config]
286 case productVariables:
Jingwen Chena47f28d2021-11-02 16:43:57 +0000287 if strings.HasSuffix(config, ConditionsDefaultConfigKey) {
288 // e.g. "acme__feature1__conditions_default" or "android__board__conditions_default"
Liz Kammer9abd62d2021-05-21 08:37:59 -0400289 return ConditionsDefaultSelectKey
290 }
Jingwen Chena47f28d2021-11-02 16:43:57 +0000291 return fmt.Sprintf("%s:%s", productVariableBazelPackage, config)
Wei Li81852ca2022-07-27 00:22:06 -0700292 case osAndInApex:
293 return osAndInApexMap[config]
Vinh Tran85fb07c2022-09-16 16:17:48 -0400294 case inApex:
295 return inApexMap[config]
Liz Kammer9abd62d2021-05-21 08:37:59 -0400296 default:
Jingwen Chena47f28d2021-11-02 16:43:57 +0000297 panic(fmt.Errorf("Unrecognized ConfigurationType %d", ca.configurationType))
Liz Kammer9abd62d2021-05-21 08:37:59 -0400298 }
299}
300
301var (
302 // Indicating there is no configuration axis
303 NoConfigAxis = ConfigurationAxis{configurationType: noConfig}
304 // An axis for architecture-specific configurations
305 ArchConfigurationAxis = ConfigurationAxis{configurationType: arch}
306 // An axis for os-specific configurations
307 OsConfigurationAxis = ConfigurationAxis{configurationType: os}
308 // An axis for arch+os-specific configurations
309 OsArchConfigurationAxis = ConfigurationAxis{configurationType: osArch}
Wei Li81852ca2022-07-27 00:22:06 -0700310 // An axis for os+in_apex-specific configurations
311 OsAndInApexAxis = ConfigurationAxis{configurationType: osAndInApex}
Vinh Tran85fb07c2022-09-16 16:17:48 -0400312 // An axis for in_apex-specific configurations
313 InApexAxis = ConfigurationAxis{configurationType: inApex}
Liz Kammer9abd62d2021-05-21 08:37:59 -0400314)
315
316// ProductVariableConfigurationAxis returns an axis for the given product variable
Alixbbfd5382022-06-09 18:52:05 +0000317func ProductVariableConfigurationAxis(variable string, outerAxis ConfigurationAxis) ConfigurationAxis {
Liz Kammer9abd62d2021-05-21 08:37:59 -0400318 return ConfigurationAxis{
319 configurationType: productVariables,
320 subType: variable,
Alixbbfd5382022-06-09 18:52:05 +0000321 outerAxisType: outerAxis.configurationType,
Liz Kammer9abd62d2021-05-21 08:37:59 -0400322 }
323}
324
325// ConfigurationAxis is an independent axis for configuration, there should be no overlap between
326// elements within an axis.
327type ConfigurationAxis struct {
328 configurationType
329 // some configuration types (e.g. productVariables) have multiple independent axes, subType helps
330 // distinguish between them without needing to list all 17 product variables.
331 subType string
Alixbbfd5382022-06-09 18:52:05 +0000332 // used to keep track of which product variables are arch variant
333 outerAxisType configurationType
Liz Kammer9abd62d2021-05-21 08:37:59 -0400334}
335
336func (ca *ConfigurationAxis) less(other ConfigurationAxis) bool {
337 if ca.configurationType < other.configurationType {
338 return true
339 }
340 return ca.subType < other.subType
341}