blob: a93aa000a23ab326df1be88c2248cb69c24fdc83 [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
Colin Crossf05b0d32022-07-14 18:10:34 -070026 archArm = "arm"
27 archArm64 = "arm64"
28 archRiscv64 = "riscv64"
29 archX86 = "x86"
30 archX86_64 = "x86_64"
Liz Kammer9abd62d2021-05-21 08:37:59 -040031
32 // OsType names in arch.go
Wei Li81852ca2022-07-27 00:22:06 -070033 OsAndroid = "android"
Liz Kammer9abd62d2021-05-21 08:37:59 -040034 osDarwin = "darwin"
Liz Kammer9abd62d2021-05-21 08:37:59 -040035 osLinux = "linux_glibc"
Colin Cross528d67e2021-07-23 22:23:07 +000036 osLinuxMusl = "linux_musl"
Liz Kammer9abd62d2021-05-21 08:37:59 -040037 osLinuxBionic = "linux_bionic"
38 osWindows = "windows"
39
40 // Targets in arch.go
41 osArchAndroidArm = "android_arm"
42 osArchAndroidArm64 = "android_arm64"
Colin Crossf05b0d32022-07-14 18:10:34 -070043 osArchAndroidRiscv64 = "android_riscv64"
Liz Kammer9abd62d2021-05-21 08:37:59 -040044 osArchAndroidX86 = "android_x86"
45 osArchAndroidX86_64 = "android_x86_64"
Dan Willemsen8528f4e2021-10-19 00:22:06 -070046 osArchDarwinArm64 = "darwin_arm64"
Liz Kammer9abd62d2021-05-21 08:37:59 -040047 osArchDarwinX86_64 = "darwin_x86_64"
Liz Kammer9abd62d2021-05-21 08:37:59 -040048 osArchLinuxX86 = "linux_glibc_x86"
49 osArchLinuxX86_64 = "linux_glibc_x86_64"
Colin Crossa9b2aac2022-06-15 17:25:51 -070050 osArchLinuxMuslArm = "linux_musl_arm"
51 osArchLinuxMuslArm64 = "linux_musl_arm64"
Colin Cross528d67e2021-07-23 22:23:07 +000052 osArchLinuxMuslX86 = "linux_musl_x86"
53 osArchLinuxMuslX86_64 = "linux_musl_x86_64"
Liz Kammer9abd62d2021-05-21 08:37:59 -040054 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).
Chris Parsons51f8c392021-08-03 21:01:05 -040066 ConditionsDefaultConfigKey = "conditions_default"
Liz Kammer9abd62d2021-05-21 08:37:59 -040067
68 ConditionsDefaultSelectKey = "//conditions:default"
69
70 productVariableBazelPackage = "//build/bazel/product_variables"
Wei Li81852ca2022-07-27 00:22:06 -070071
72 AndroidAndInApex = "android-in_apex"
73 AndroidAndNonApex = "android-non_apex"
Vinh Tran85fb07c2022-09-16 16:17:48 -040074
75 InApex = "in_apex"
76 NonApex = "non_apex"
Liz Kammer9abd62d2021-05-21 08:37:59 -040077)
78
Cole Faustc843b992022-08-02 18:06:50 -070079func PowerSetWithoutEmptySet[T any](items []T) [][]T {
80 resultSize := int(math.Pow(2, float64(len(items))))
81 powerSet := make([][]T, 0, resultSize-1)
82 for i := 1; i < resultSize; i++ {
83 combination := make([]T, 0)
84 for j := 0; j < len(items); j++ {
85 if (i>>j)%2 == 1 {
86 combination = append(combination, items[j])
87 }
88 }
89 powerSet = append(powerSet, combination)
90 }
91 return powerSet
92}
93
94func createPlatformArchMap() map[string]string {
95 // Copy of archFeatures from android/arch_list.go because the bazel
96 // package can't access the android package
97 archFeatures := map[string][]string{
98 "arm": {
99 "neon",
100 },
101 "arm64": {
102 "dotprod",
103 },
Colin Crossf05b0d32022-07-14 18:10:34 -0700104 "riscv64": {},
Cole Faustc843b992022-08-02 18:06:50 -0700105 "x86": {
106 "ssse3",
107 "sse4",
108 "sse4_1",
109 "sse4_2",
110 "aes_ni",
111 "avx",
112 "avx2",
113 "avx512",
114 "popcnt",
115 "movbe",
116 },
117 "x86_64": {
118 "ssse3",
119 "sse4",
120 "sse4_1",
121 "sse4_2",
122 "aes_ni",
123 "avx",
124 "avx2",
125 "avx512",
126 "popcnt",
127 },
128 }
129 result := make(map[string]string)
130 for arch, allFeatures := range archFeatures {
131 result[arch] = "//build/bazel/platforms/arch:" + arch
132 // Sometimes we want to select on multiple features being active, so
133 // add the power set of all possible features to the map. More details
134 // in android.ModuleBase.GetArchVariantProperties
135 for _, features := range PowerSetWithoutEmptySet(allFeatures) {
136 sort.Strings(features)
137 archFeaturesName := arch + "-" + strings.Join(features, "-")
138 result[archFeaturesName] = "//build/bazel/platforms/arch/variants:" + archFeaturesName
139 }
140 }
141 result[ConditionsDefaultConfigKey] = ConditionsDefaultSelectKey
142 return result
143}
144
Liz Kammer9abd62d2021-05-21 08:37:59 -0400145var (
146 // These are the list of OSes and architectures with a Bazel config_setting
147 // and constraint value equivalent. These exist in arch.go, but the android
148 // package depends on the bazel package, so a cyclic dependency prevents
149 // using those variables here.
150
151 // A map of architectures to the Bazel label of the constraint_value
152 // for the @platforms//cpu:cpu constraint_setting
Cole Faustc843b992022-08-02 18:06:50 -0700153 platformArchMap = createPlatformArchMap()
Liz Kammer9abd62d2021-05-21 08:37:59 -0400154
155 // A map of target operating systems to the Bazel label of the
156 // constraint_value for the @platforms//os:os constraint_setting
157 platformOsMap = map[string]string{
Wei Li81852ca2022-07-27 00:22:06 -0700158 OsAndroid: "//build/bazel/platforms/os:android",
Chris Parsons51f8c392021-08-03 21:01:05 -0400159 osDarwin: "//build/bazel/platforms/os:darwin",
160 osLinux: "//build/bazel/platforms/os:linux",
161 osLinuxMusl: "//build/bazel/platforms/os:linux_musl",
162 osLinuxBionic: "//build/bazel/platforms/os:linux_bionic",
163 osWindows: "//build/bazel/platforms/os:windows",
164 ConditionsDefaultConfigKey: ConditionsDefaultSelectKey, // The default condition of an os select map.
Liz Kammer9abd62d2021-05-21 08:37:59 -0400165 }
166
167 platformOsArchMap = map[string]string{
Chris Parsons51f8c392021-08-03 21:01:05 -0400168 osArchAndroidArm: "//build/bazel/platforms/os_arch:android_arm",
169 osArchAndroidArm64: "//build/bazel/platforms/os_arch:android_arm64",
Colin Crossf05b0d32022-07-14 18:10:34 -0700170 osArchAndroidRiscv64: "//build/bazel/platforms/os_arch:android_riscv64",
Chris Parsons51f8c392021-08-03 21:01:05 -0400171 osArchAndroidX86: "//build/bazel/platforms/os_arch:android_x86",
172 osArchAndroidX86_64: "//build/bazel/platforms/os_arch:android_x86_64",
Dan Willemsen8528f4e2021-10-19 00:22:06 -0700173 osArchDarwinArm64: "//build/bazel/platforms/os_arch:darwin_arm64",
Chris Parsons51f8c392021-08-03 21:01:05 -0400174 osArchDarwinX86_64: "//build/bazel/platforms/os_arch:darwin_x86_64",
175 osArchLinuxX86: "//build/bazel/platforms/os_arch:linux_glibc_x86",
176 osArchLinuxX86_64: "//build/bazel/platforms/os_arch:linux_glibc_x86_64",
Colin Crossa9b2aac2022-06-15 17:25:51 -0700177 osArchLinuxMuslArm: "//build/bazel/platforms/os_arch:linux_musl_arm",
178 osArchLinuxMuslArm64: "//build/bazel/platforms/os_arch:linux_musl_arm64",
Chris Parsons51f8c392021-08-03 21:01:05 -0400179 osArchLinuxMuslX86: "//build/bazel/platforms/os_arch:linux_musl_x86",
180 osArchLinuxMuslX86_64: "//build/bazel/platforms/os_arch:linux_musl_x86_64",
181 osArchLinuxBionicArm64: "//build/bazel/platforms/os_arch:linux_bionic_arm64",
182 osArchLinuxBionicX86_64: "//build/bazel/platforms/os_arch:linux_bionic_x86_64",
183 osArchWindowsX86: "//build/bazel/platforms/os_arch:windows_x86",
184 osArchWindowsX86_64: "//build/bazel/platforms/os_arch:windows_x86_64",
185 ConditionsDefaultConfigKey: ConditionsDefaultSelectKey, // The default condition of an os select map.
Liz Kammer9abd62d2021-05-21 08:37:59 -0400186 }
Chris Parsons58852a02021-12-09 18:10:18 -0500187
188 // Map where keys are OsType names, and values are slices containing the archs
189 // that that OS supports.
190 // These definitions copied from arch.go.
191 // TODO(cparsons): Source from arch.go; this task is nontrivial, as it currently results
192 // in a cyclic dependency.
193 osToArchMap = map[string][]string{
Colin Crossf05b0d32022-07-14 18:10:34 -0700194 OsAndroid: {archArm, archArm64, archRiscv64, archX86, archX86_64},
Chris Parsons58852a02021-12-09 18:10:18 -0500195 osLinux: {archX86, archX86_64},
196 osLinuxMusl: {archX86, archX86_64},
197 osDarwin: {archArm64, archX86_64},
198 osLinuxBionic: {archArm64, archX86_64},
199 // TODO(cparsons): According to arch.go, this should contain archArm, archArm64, as well.
200 osWindows: {archX86, archX86_64},
201 }
Wei Li81852ca2022-07-27 00:22:06 -0700202
203 osAndInApexMap = map[string]string{
204 AndroidAndInApex: "//build/bazel/rules/apex:android-in_apex",
205 AndroidAndNonApex: "//build/bazel/rules/apex:android-non_apex",
206 ConditionsDefaultConfigKey: ConditionsDefaultSelectKey,
207 }
Vinh Tran85fb07c2022-09-16 16:17:48 -0400208
209 inApexMap = map[string]string{
210 InApex: "//build/bazel/rules/apex:in_apex",
211 NonApex: "//build/bazel/rules/apex:non_apex",
212 ConditionsDefaultConfigKey: ConditionsDefaultSelectKey,
213 }
Liz Kammer9abd62d2021-05-21 08:37:59 -0400214)
215
216// basic configuration types
217type configurationType int
218
219const (
220 noConfig configurationType = iota
221 arch
222 os
223 osArch
224 productVariables
Wei Li81852ca2022-07-27 00:22:06 -0700225 osAndInApex
Vinh Tran85fb07c2022-09-16 16:17:48 -0400226 inApex
Liz Kammer9abd62d2021-05-21 08:37:59 -0400227)
228
Chris Parsons58852a02021-12-09 18:10:18 -0500229func osArchString(os string, arch string) string {
230 return fmt.Sprintf("%s_%s", os, arch)
231}
232
Liz Kammer9abd62d2021-05-21 08:37:59 -0400233func (ct configurationType) String() string {
234 return map[configurationType]string{
235 noConfig: "no_config",
236 arch: "arch",
237 os: "os",
238 osArch: "arch_os",
239 productVariables: "product_variables",
Wei Li81852ca2022-07-27 00:22:06 -0700240 osAndInApex: "os_in_apex",
Vinh Tran85fb07c2022-09-16 16:17:48 -0400241 inApex: "in_apex",
Liz Kammer9abd62d2021-05-21 08:37:59 -0400242 }[ct]
243}
244
245func (ct configurationType) validateConfig(config string) {
246 switch ct {
247 case noConfig:
248 if config != "" {
249 panic(fmt.Errorf("Cannot specify config with %s, but got %s", ct, config))
250 }
251 case arch:
252 if _, ok := platformArchMap[config]; !ok {
253 panic(fmt.Errorf("Unknown arch: %s", config))
254 }
255 case os:
256 if _, ok := platformOsMap[config]; !ok {
257 panic(fmt.Errorf("Unknown os: %s", config))
258 }
259 case osArch:
260 if _, ok := platformOsArchMap[config]; !ok {
261 panic(fmt.Errorf("Unknown os+arch: %s", config))
262 }
263 case productVariables:
264 // do nothing
Wei Li81852ca2022-07-27 00:22:06 -0700265 case osAndInApex:
266 if _, ok := osAndInApexMap[config]; !ok {
267 panic(fmt.Errorf("Unknown os+in_apex config: %s", config))
268 }
Vinh Tran85fb07c2022-09-16 16:17:48 -0400269 case inApex:
270 if _, ok := inApexMap[config]; !ok {
271 panic(fmt.Errorf("Unknown in_apex config: %s", config))
272 }
Liz Kammer9abd62d2021-05-21 08:37:59 -0400273 default:
274 panic(fmt.Errorf("Unrecognized ConfigurationType %d", ct))
275 }
276}
277
278// SelectKey returns the Bazel select key for a given configurationType and config string.
Jingwen Chena47f28d2021-11-02 16:43:57 +0000279func (ca ConfigurationAxis) SelectKey(config string) string {
280 ca.validateConfig(config)
281 switch ca.configurationType {
Liz Kammer9abd62d2021-05-21 08:37:59 -0400282 case noConfig:
283 panic(fmt.Errorf("SelectKey is unnecessary for noConfig ConfigurationType "))
284 case arch:
285 return platformArchMap[config]
286 case os:
287 return platformOsMap[config]
288 case osArch:
289 return platformOsArchMap[config]
290 case productVariables:
Jingwen Chena47f28d2021-11-02 16:43:57 +0000291 if strings.HasSuffix(config, ConditionsDefaultConfigKey) {
292 // e.g. "acme__feature1__conditions_default" or "android__board__conditions_default"
Liz Kammer9abd62d2021-05-21 08:37:59 -0400293 return ConditionsDefaultSelectKey
294 }
Jingwen Chena47f28d2021-11-02 16:43:57 +0000295 return fmt.Sprintf("%s:%s", productVariableBazelPackage, config)
Wei Li81852ca2022-07-27 00:22:06 -0700296 case osAndInApex:
297 return osAndInApexMap[config]
Vinh Tran85fb07c2022-09-16 16:17:48 -0400298 case inApex:
299 return inApexMap[config]
Liz Kammer9abd62d2021-05-21 08:37:59 -0400300 default:
Jingwen Chena47f28d2021-11-02 16:43:57 +0000301 panic(fmt.Errorf("Unrecognized ConfigurationType %d", ca.configurationType))
Liz Kammer9abd62d2021-05-21 08:37:59 -0400302 }
303}
304
305var (
306 // Indicating there is no configuration axis
307 NoConfigAxis = ConfigurationAxis{configurationType: noConfig}
308 // An axis for architecture-specific configurations
309 ArchConfigurationAxis = ConfigurationAxis{configurationType: arch}
310 // An axis for os-specific configurations
311 OsConfigurationAxis = ConfigurationAxis{configurationType: os}
312 // An axis for arch+os-specific configurations
313 OsArchConfigurationAxis = ConfigurationAxis{configurationType: osArch}
Wei Li81852ca2022-07-27 00:22:06 -0700314 // An axis for os+in_apex-specific configurations
315 OsAndInApexAxis = ConfigurationAxis{configurationType: osAndInApex}
Vinh Tran85fb07c2022-09-16 16:17:48 -0400316 // An axis for in_apex-specific configurations
317 InApexAxis = ConfigurationAxis{configurationType: inApex}
Liz Kammer9abd62d2021-05-21 08:37:59 -0400318)
319
320// ProductVariableConfigurationAxis returns an axis for the given product variable
Alixbbfd5382022-06-09 18:52:05 +0000321func ProductVariableConfigurationAxis(variable string, outerAxis ConfigurationAxis) ConfigurationAxis {
Liz Kammer9abd62d2021-05-21 08:37:59 -0400322 return ConfigurationAxis{
323 configurationType: productVariables,
324 subType: variable,
Alixbbfd5382022-06-09 18:52:05 +0000325 outerAxisType: outerAxis.configurationType,
Liz Kammer9abd62d2021-05-21 08:37:59 -0400326 }
327}
328
329// ConfigurationAxis is an independent axis for configuration, there should be no overlap between
330// elements within an axis.
331type ConfigurationAxis struct {
332 configurationType
333 // some configuration types (e.g. productVariables) have multiple independent axes, subType helps
334 // distinguish between them without needing to list all 17 product variables.
335 subType string
Alixbbfd5382022-06-09 18:52:05 +0000336 // used to keep track of which product variables are arch variant
337 outerAxisType configurationType
Liz Kammer9abd62d2021-05-21 08:37:59 -0400338}
339
340func (ca *ConfigurationAxis) less(other ConfigurationAxis) bool {
341 if ca.configurationType < other.configurationType {
342 return true
343 }
344 return ca.subType < other.subType
345}