blob: d01877dd5b8270bbf34c57f6a036afebab1e9330 [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",
Colin Cross133782e2022-12-20 15:29:31 -0800160 osLinux: "//build/bazel/platforms/os:linux_glibc",
Chris Parsons51f8c392021-08-03 21:01:05 -0400161 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",
Liz Kammerffc17e42022-11-23 09:42:05 -0500206 osDarwin: "//build/bazel/platforms/os:darwin",
Colin Cross133782e2022-12-20 15:29:31 -0800207 osLinux: "//build/bazel/platforms/os:linux_glibc",
Liz Kammerffc17e42022-11-23 09:42:05 -0500208 osLinuxMusl: "//build/bazel/platforms/os:linux_musl",
209 osLinuxBionic: "//build/bazel/platforms/os:linux_bionic",
210 osWindows: "//build/bazel/platforms/os:windows",
Wei Li81852ca2022-07-27 00:22:06 -0700211 ConditionsDefaultConfigKey: ConditionsDefaultSelectKey,
212 }
Vinh Tran85fb07c2022-09-16 16:17:48 -0400213
214 inApexMap = map[string]string{
215 InApex: "//build/bazel/rules/apex:in_apex",
216 NonApex: "//build/bazel/rules/apex:non_apex",
217 ConditionsDefaultConfigKey: ConditionsDefaultSelectKey,
218 }
Liz Kammer9abd62d2021-05-21 08:37:59 -0400219)
220
221// basic configuration types
222type configurationType int
223
224const (
225 noConfig configurationType = iota
226 arch
227 os
228 osArch
229 productVariables
Wei Li81852ca2022-07-27 00:22:06 -0700230 osAndInApex
Vinh Tran85fb07c2022-09-16 16:17:48 -0400231 inApex
Liz Kammer9abd62d2021-05-21 08:37:59 -0400232)
233
Chris Parsons58852a02021-12-09 18:10:18 -0500234func osArchString(os string, arch string) string {
235 return fmt.Sprintf("%s_%s", os, arch)
236}
237
Liz Kammer9abd62d2021-05-21 08:37:59 -0400238func (ct configurationType) String() string {
239 return map[configurationType]string{
240 noConfig: "no_config",
241 arch: "arch",
242 os: "os",
243 osArch: "arch_os",
244 productVariables: "product_variables",
Wei Li81852ca2022-07-27 00:22:06 -0700245 osAndInApex: "os_in_apex",
Vinh Tran85fb07c2022-09-16 16:17:48 -0400246 inApex: "in_apex",
Liz Kammer9abd62d2021-05-21 08:37:59 -0400247 }[ct]
248}
249
250func (ct configurationType) validateConfig(config string) {
251 switch ct {
252 case noConfig:
253 if config != "" {
254 panic(fmt.Errorf("Cannot specify config with %s, but got %s", ct, config))
255 }
256 case arch:
257 if _, ok := platformArchMap[config]; !ok {
258 panic(fmt.Errorf("Unknown arch: %s", config))
259 }
260 case os:
261 if _, ok := platformOsMap[config]; !ok {
262 panic(fmt.Errorf("Unknown os: %s", config))
263 }
264 case osArch:
265 if _, ok := platformOsArchMap[config]; !ok {
266 panic(fmt.Errorf("Unknown os+arch: %s", config))
267 }
268 case productVariables:
269 // do nothing
Wei Li81852ca2022-07-27 00:22:06 -0700270 case osAndInApex:
Spandan Das4242f102023-04-19 22:31:54 +0000271 // do nothing
272 // this axis can contain additional per-apex keys
Vinh Tran85fb07c2022-09-16 16:17:48 -0400273 case inApex:
274 if _, ok := inApexMap[config]; !ok {
275 panic(fmt.Errorf("Unknown in_apex config: %s", config))
276 }
Liz Kammer9abd62d2021-05-21 08:37:59 -0400277 default:
278 panic(fmt.Errorf("Unrecognized ConfigurationType %d", ct))
279 }
280}
281
282// SelectKey returns the Bazel select key for a given configurationType and config string.
Jingwen Chena47f28d2021-11-02 16:43:57 +0000283func (ca ConfigurationAxis) SelectKey(config string) string {
284 ca.validateConfig(config)
285 switch ca.configurationType {
Liz Kammer9abd62d2021-05-21 08:37:59 -0400286 case noConfig:
287 panic(fmt.Errorf("SelectKey is unnecessary for noConfig ConfigurationType "))
288 case arch:
289 return platformArchMap[config]
290 case os:
291 return platformOsMap[config]
292 case osArch:
293 return platformOsArchMap[config]
294 case productVariables:
Jingwen Chena47f28d2021-11-02 16:43:57 +0000295 if strings.HasSuffix(config, ConditionsDefaultConfigKey) {
296 // e.g. "acme__feature1__conditions_default" or "android__board__conditions_default"
Liz Kammer9abd62d2021-05-21 08:37:59 -0400297 return ConditionsDefaultSelectKey
298 }
Jingwen Chena47f28d2021-11-02 16:43:57 +0000299 return fmt.Sprintf("%s:%s", productVariableBazelPackage, config)
Wei Li81852ca2022-07-27 00:22:06 -0700300 case osAndInApex:
Spandan Das4242f102023-04-19 22:31:54 +0000301 if ret, exists := osAndInApexMap[config]; exists {
302 return ret
303 }
304 return config
Vinh Tran85fb07c2022-09-16 16:17:48 -0400305 case inApex:
306 return inApexMap[config]
Liz Kammer9abd62d2021-05-21 08:37:59 -0400307 default:
Jingwen Chena47f28d2021-11-02 16:43:57 +0000308 panic(fmt.Errorf("Unrecognized ConfigurationType %d", ca.configurationType))
Liz Kammer9abd62d2021-05-21 08:37:59 -0400309 }
310}
311
312var (
313 // Indicating there is no configuration axis
314 NoConfigAxis = ConfigurationAxis{configurationType: noConfig}
315 // An axis for architecture-specific configurations
316 ArchConfigurationAxis = ConfigurationAxis{configurationType: arch}
317 // An axis for os-specific configurations
318 OsConfigurationAxis = ConfigurationAxis{configurationType: os}
319 // An axis for arch+os-specific configurations
320 OsArchConfigurationAxis = ConfigurationAxis{configurationType: osArch}
Wei Li81852ca2022-07-27 00:22:06 -0700321 // An axis for os+in_apex-specific configurations
322 OsAndInApexAxis = ConfigurationAxis{configurationType: osAndInApex}
Vinh Tran85fb07c2022-09-16 16:17:48 -0400323 // An axis for in_apex-specific configurations
324 InApexAxis = ConfigurationAxis{configurationType: inApex}
Liz Kammer9abd62d2021-05-21 08:37:59 -0400325)
326
327// ProductVariableConfigurationAxis returns an axis for the given product variable
Alixbbfd5382022-06-09 18:52:05 +0000328func ProductVariableConfigurationAxis(variable string, outerAxis ConfigurationAxis) ConfigurationAxis {
Liz Kammer9abd62d2021-05-21 08:37:59 -0400329 return ConfigurationAxis{
330 configurationType: productVariables,
331 subType: variable,
Alixbbfd5382022-06-09 18:52:05 +0000332 outerAxisType: outerAxis.configurationType,
Liz Kammer9abd62d2021-05-21 08:37:59 -0400333 }
334}
335
336// ConfigurationAxis is an independent axis for configuration, there should be no overlap between
337// elements within an axis.
338type ConfigurationAxis struct {
339 configurationType
340 // some configuration types (e.g. productVariables) have multiple independent axes, subType helps
341 // distinguish between them without needing to list all 17 product variables.
342 subType string
Alixbbfd5382022-06-09 18:52:05 +0000343 // used to keep track of which product variables are arch variant
344 outerAxisType configurationType
Liz Kammer9abd62d2021-05-21 08:37:59 -0400345}
346
347func (ca *ConfigurationAxis) less(other ConfigurationAxis) bool {
Chris Parsons7b3289b2023-01-26 17:30:44 -0500348 if ca.configurationType == other.configurationType {
349 return ca.subType < other.subType
Liz Kammer9abd62d2021-05-21 08:37:59 -0400350 }
Chris Parsons7b3289b2023-01-26 17:30:44 -0500351 return ca.configurationType < other.configurationType
Liz Kammer9abd62d2021-05-21 08:37:59 -0400352}