• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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