blob: 702c31c4d868fc4176ab5e36df5e1af277c6a8d3 [file] [log] [blame]
Jingwen Chen30f5aaa2020-11-19 05:38:02 -05001// Copyright 2020 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
Rupert Shuttleworth2e4219b2021-03-12 11:04:21 +000017import (
18 "fmt"
Jingwen Chen63930982021-03-24 10:04:33 -040019 "path/filepath"
Trevor Radcliffe56b1a2b2023-02-06 21:58:30 +000020 "reflect"
Liz Kammera060c452021-03-24 10:14:47 -040021 "regexp"
Rupert Shuttleworth2e4219b2021-03-12 11:04:21 +000022 "sort"
Liz Kammer57e2e7a2021-09-20 12:55:02 -040023 "strings"
24
25 "github.com/google/blueprint"
Rupert Shuttleworth2e4219b2021-03-12 11:04:21 +000026)
Jingwen Chen5d864492021-02-24 07:20:12 -050027
Jingwen Chen73850672020-12-14 08:25:34 -050028// BazelTargetModuleProperties contain properties and metadata used for
29// Blueprint to BUILD file conversion.
30type BazelTargetModuleProperties struct {
31 // The Bazel rule class for this target.
Liz Kammerfc46bc12021-02-19 11:06:17 -050032 Rule_class string `blueprint:"mutated"`
Jingwen Chen40067de2021-01-26 21:58:43 -050033
34 // The target label for the bzl file containing the definition of the rule class.
Liz Kammerfc46bc12021-02-19 11:06:17 -050035 Bzl_load_location string `blueprint:"mutated"`
Jingwen Chen73850672020-12-14 08:25:34 -050036}
Liz Kammer356f7d42021-01-26 09:18:53 -050037
Liz Kammera060c452021-03-24 10:14:47 -040038var productVariableSubstitutionPattern = regexp.MustCompile("%(d|s)")
39
Jingwen Chen38e62642021-04-19 05:00:15 +000040// Label is used to represent a Bazel compatible Label. Also stores the original
41// bp text to support string replacement.
Liz Kammer356f7d42021-01-26 09:18:53 -050042type Label struct {
Jingwen Chen38e62642021-04-19 05:00:15 +000043 // The string representation of a Bazel target label. This can be a relative
44 // or fully qualified label. These labels are used for generating BUILD
45 // files with bp2build.
46 Label string
47
48 // The original Soong/Blueprint module name that the label was derived from.
49 // This is used for replacing references to the original name with the new
50 // label, for example in genrule cmds.
51 //
52 // While there is a reversible 1:1 mapping from the module name to Bazel
53 // label with bp2build that could make computing the original module name
54 // from the label automatic, it is not the case for handcrafted targets,
55 // where modules can have a custom label mapping through the { bazel_module:
56 // { label: <label> } } property.
57 //
58 // With handcrafted labels, those modules don't go through bp2build
59 // conversion, but relies on handcrafted targets in the source tree.
60 OriginalModuleName string
Liz Kammer356f7d42021-01-26 09:18:53 -050061}
62
63// LabelList is used to represent a list of Bazel labels.
64type LabelList struct {
65 Includes []Label
66 Excludes []Label
67}
68
Sam Delmericoc0161432022-02-25 21:34:51 +000069// MakeLabelList creates a LabelList from a list Label
70func MakeLabelList(labels []Label) LabelList {
71 return LabelList{
72 Includes: labels,
73 Excludes: nil,
74 }
75}
76
Chris Parsons7b3289b2023-01-26 17:30:44 -050077func SortedConfigurationAxes[T any](m map[ConfigurationAxis]T) []ConfigurationAxis {
78 keys := make([]ConfigurationAxis, 0, len(m))
79 for k := range m {
80 keys = append(keys, k)
81 }
82
83 sort.Slice(keys, func(i, j int) bool { return keys[i].less(keys[j]) })
84 return keys
85}
86
Spandan Das4238c652022-09-09 01:38:47 +000087// MakeLabelListFromTargetNames creates a LabelList from unqualified target names
88// This is a utiltity function for bp2build converters of Soong modules that have 1:many generated targets
89func MakeLabelListFromTargetNames(targetNames []string) LabelList {
90 labels := []Label{}
91 for _, name := range targetNames {
92 label := Label{Label: ":" + name}
93 labels = append(labels, label)
94 }
95 return MakeLabelList(labels)
96}
97
Chris Parsons51f8c392021-08-03 21:01:05 -040098func (ll *LabelList) Equals(other LabelList) bool {
99 if len(ll.Includes) != len(other.Includes) || len(ll.Excludes) != len(other.Excludes) {
100 return false
101 }
102 for i, _ := range ll.Includes {
103 if ll.Includes[i] != other.Includes[i] {
104 return false
105 }
106 }
107 for i, _ := range ll.Excludes {
108 if ll.Excludes[i] != other.Excludes[i] {
109 return false
110 }
111 }
112 return true
113}
114
Liz Kammer9abd62d2021-05-21 08:37:59 -0400115func (ll *LabelList) IsNil() bool {
116 return ll.Includes == nil && ll.Excludes == nil
117}
118
Sam Delmerico3177a6e2022-06-21 19:28:33 +0000119func (ll *LabelList) IsEmpty() bool {
120 return len(ll.Includes) == 0 && len(ll.Excludes) == 0
121}
122
Liz Kammer74deed42021-06-02 13:02:03 -0400123func (ll *LabelList) deepCopy() LabelList {
124 return LabelList{
125 Includes: ll.Includes[:],
126 Excludes: ll.Excludes[:],
127 }
128}
129
Jingwen Chen63930982021-03-24 10:04:33 -0400130// uniqueParentDirectories returns a list of the unique parent directories for
131// all files in ll.Includes.
132func (ll *LabelList) uniqueParentDirectories() []string {
133 dirMap := map[string]bool{}
134 for _, label := range ll.Includes {
135 dirMap[filepath.Dir(label.Label)] = true
136 }
137 dirs := []string{}
138 for dir := range dirMap {
139 dirs = append(dirs, dir)
140 }
141 return dirs
142}
143
Sam Delmericoc1130dc2022-08-25 14:43:54 -0400144// Add inserts the label Label at the end of the LabelList.Includes.
Liz Kammer12615db2021-09-28 09:19:17 -0400145func (ll *LabelList) Add(label *Label) {
146 if label == nil {
147 return
148 }
149 ll.Includes = append(ll.Includes, *label)
150}
151
Sam Delmericoc1130dc2022-08-25 14:43:54 -0400152// AddExclude inserts the label Label at the end of the LabelList.Excludes.
153func (ll *LabelList) AddExclude(label *Label) {
154 if label == nil {
155 return
156 }
157 ll.Excludes = append(ll.Excludes, *label)
158}
159
Liz Kammer356f7d42021-01-26 09:18:53 -0500160// Append appends the fields of other labelList to the corresponding fields of ll.
161func (ll *LabelList) Append(other LabelList) {
162 if len(ll.Includes) > 0 || len(other.Includes) > 0 {
163 ll.Includes = append(ll.Includes, other.Includes...)
164 }
165 if len(ll.Excludes) > 0 || len(other.Excludes) > 0 {
Liz Kammer748d7072023-01-25 12:07:43 -0500166 ll.Excludes = append(ll.Excludes, other.Excludes...)
Liz Kammer356f7d42021-01-26 09:18:53 -0500167 }
168}
Jingwen Chen5d864492021-02-24 07:20:12 -0500169
Sam Delmericoc1130dc2022-08-25 14:43:54 -0400170// Partition splits a LabelList into two LabelLists depending on the return value
171// of the predicate.
172// This function preserves the Includes and Excludes, but it does not provide
173// that information to the partition function.
174func (ll *LabelList) Partition(predicate func(label Label) bool) (LabelList, LabelList) {
175 predicated := LabelList{}
176 unpredicated := LabelList{}
177 for _, include := range ll.Includes {
178 if predicate(include) {
179 predicated.Add(&include)
180 } else {
181 unpredicated.Add(&include)
182 }
183 }
184 for _, exclude := range ll.Excludes {
185 if predicate(exclude) {
186 predicated.AddExclude(&exclude)
187 } else {
188 unpredicated.AddExclude(&exclude)
189 }
190 }
191 return predicated, unpredicated
192}
193
Jingwen Chened9c17d2021-04-13 07:14:55 +0000194// UniqueSortedBazelLabels takes a []Label and deduplicates the labels, and returns
195// the slice in a sorted order.
196func UniqueSortedBazelLabels(originalLabels []Label) []Label {
Rupert Shuttleworth2e4219b2021-03-12 11:04:21 +0000197 uniqueLabelsSet := make(map[Label]bool)
198 for _, l := range originalLabels {
199 uniqueLabelsSet[l] = true
200 }
201 var uniqueLabels []Label
202 for l, _ := range uniqueLabelsSet {
203 uniqueLabels = append(uniqueLabels, l)
204 }
205 sort.SliceStable(uniqueLabels, func(i, j int) bool {
206 return uniqueLabels[i].Label < uniqueLabels[j].Label
207 })
208 return uniqueLabels
209}
210
Liz Kammer9abd62d2021-05-21 08:37:59 -0400211func FirstUniqueBazelLabels(originalLabels []Label) []Label {
212 var labels []Label
213 found := make(map[Label]bool, len(originalLabels))
214 for _, l := range originalLabels {
215 if _, ok := found[l]; ok {
216 continue
217 }
218 labels = append(labels, l)
219 found[l] = true
220 }
221 return labels
222}
223
224func FirstUniqueBazelLabelList(originalLabelList LabelList) LabelList {
225 var uniqueLabelList LabelList
226 uniqueLabelList.Includes = FirstUniqueBazelLabels(originalLabelList.Includes)
227 uniqueLabelList.Excludes = FirstUniqueBazelLabels(originalLabelList.Excludes)
228 return uniqueLabelList
229}
230
231func UniqueSortedBazelLabelList(originalLabelList LabelList) LabelList {
Rupert Shuttleworth2e4219b2021-03-12 11:04:21 +0000232 var uniqueLabelList LabelList
Jingwen Chened9c17d2021-04-13 07:14:55 +0000233 uniqueLabelList.Includes = UniqueSortedBazelLabels(originalLabelList.Includes)
234 uniqueLabelList.Excludes = UniqueSortedBazelLabels(originalLabelList.Excludes)
Rupert Shuttleworth2e4219b2021-03-12 11:04:21 +0000235 return uniqueLabelList
236}
237
Rupert Shuttleworthb8151682021-04-06 20:06:21 +0000238// Subtract needle from haystack
239func SubtractStrings(haystack []string, needle []string) []string {
240 // This is really a set
Liz Kammer9bad9d62021-10-11 15:40:35 -0400241 needleMap := make(map[string]bool)
Rupert Shuttleworthb8151682021-04-06 20:06:21 +0000242 for _, s := range needle {
Liz Kammer9bad9d62021-10-11 15:40:35 -0400243 needleMap[s] = true
Rupert Shuttleworthb8151682021-04-06 20:06:21 +0000244 }
245
246 var strings []string
Liz Kammer9bad9d62021-10-11 15:40:35 -0400247 for _, s := range haystack {
248 if exclude := needleMap[s]; !exclude {
249 strings = append(strings, s)
250 }
Rupert Shuttleworthb8151682021-04-06 20:06:21 +0000251 }
252
Rupert Shuttleworthb8151682021-04-06 20:06:21 +0000253 return strings
254}
255
256// Subtract needle from haystack
257func SubtractBazelLabels(haystack []Label, needle []Label) []Label {
258 // This is really a set
Liz Kammer9bad9d62021-10-11 15:40:35 -0400259 needleMap := make(map[Label]bool)
260 for _, s := range needle {
261 needleMap[s] = true
Rupert Shuttleworthb8151682021-04-06 20:06:21 +0000262 }
263
264 var labels []Label
Liz Kammer9bad9d62021-10-11 15:40:35 -0400265 for _, label := range haystack {
266 if exclude := needleMap[label]; !exclude {
267 labels = append(labels, label)
268 }
Rupert Shuttleworthb8151682021-04-06 20:06:21 +0000269 }
270
Rupert Shuttleworthb8151682021-04-06 20:06:21 +0000271 return labels
272}
273
Chris Parsons484e50a2021-05-13 15:13:04 -0400274// Appends two LabelLists, returning the combined list.
275func AppendBazelLabelLists(a LabelList, b LabelList) LabelList {
276 var result LabelList
277 result.Includes = append(a.Includes, b.Includes...)
278 result.Excludes = append(a.Excludes, b.Excludes...)
279 return result
280}
281
Rupert Shuttleworthb8151682021-04-06 20:06:21 +0000282// Subtract needle from haystack
283func SubtractBazelLabelList(haystack LabelList, needle LabelList) LabelList {
284 var result LabelList
285 result.Includes = SubtractBazelLabels(haystack.Includes, needle.Includes)
286 // NOTE: Excludes are intentionally not subtracted
287 result.Excludes = haystack.Excludes
288 return result
289}
290
Liz Kammer5f5dbaa2023-07-17 17:44:08 -0400291// FirstUniqueBazelLabelListAttribute takes a LabelListAttribute and makes the LabelList for
292// each axis/configuration by keeping the first instance of a Label and omitting all subsequent
293// repetitions.
294func FirstUniqueBazelLabelListAttribute(attr LabelListAttribute) LabelListAttribute {
295 var result LabelListAttribute
296 result.Value = FirstUniqueBazelLabelList(attr.Value)
297 if attr.HasConfigurableValues() {
298 result.ConfigurableValues = make(configurableLabelLists)
299 }
300 for axis, configToLabels := range attr.ConfigurableValues {
301 for c, l := range configToLabels {
302 result.SetSelectValue(axis, c, FirstUniqueBazelLabelList(l))
303 }
304 }
305
306 return result
307}
308
309// SubtractBazelLabelListAttribute subtract needle from haystack for LabelList in each
310// axis/configuration.
311func SubtractBazelLabelListAttribute(haystack LabelListAttribute, needle LabelListAttribute) LabelListAttribute {
312 var result LabelListAttribute
313 result.Value = SubtractBazelLabelList(haystack.Value, needle.Value)
314 if haystack.HasConfigurableValues() {
315 result.ConfigurableValues = make(configurableLabelLists)
316 }
317 for axis, configToLabels := range haystack.ConfigurableValues {
318 for haystackConfig, haystackLabels := range configToLabels {
319 result.SetSelectValue(axis, haystackConfig, SubtractBazelLabelList(haystackLabels, needle.SelectValue(axis, haystackConfig)))
320 }
321 }
322
323 return result
324}
325
Jingwen Chenc1c26502021-04-05 10:35:13 +0000326type Attribute interface {
327 HasConfigurableValues() bool
328}
329
Liz Kammer9abd62d2021-05-21 08:37:59 -0400330type labelSelectValues map[string]*Label
Rupert Shuttleworth22cd2eb2021-05-27 02:15:54 -0400331
Liz Kammer9abd62d2021-05-21 08:37:59 -0400332type configurableLabels map[ConfigurationAxis]labelSelectValues
Rupert Shuttleworth22cd2eb2021-05-27 02:15:54 -0400333
Liz Kammer9abd62d2021-05-21 08:37:59 -0400334func (cl configurableLabels) setValueForAxis(axis ConfigurationAxis, config string, value *Label) {
335 if cl[axis] == nil {
336 cl[axis] = make(labelSelectValues)
337 }
338 cl[axis][config] = value
Rupert Shuttleworth22cd2eb2021-05-27 02:15:54 -0400339}
340
341// Represents an attribute whose value is a single label
342type LabelAttribute struct {
Liz Kammer9abd62d2021-05-21 08:37:59 -0400343 Value *Label
Rupert Shuttleworth22cd2eb2021-05-27 02:15:54 -0400344
Liz Kammer9abd62d2021-05-21 08:37:59 -0400345 ConfigurableValues configurableLabels
Lukacs T. Berki1353e592021-04-30 15:35:09 +0200346}
347
Chris Parsons58852a02021-12-09 18:10:18 -0500348func (la *LabelAttribute) axisTypes() map[configurationType]bool {
349 types := map[configurationType]bool{}
350 for k := range la.ConfigurableValues {
351 if len(la.ConfigurableValues[k]) > 0 {
352 types[k.configurationType] = true
353 }
354 }
355 return types
356}
357
358// Collapse reduces the configurable axes of the label attribute to a single axis.
359// This is necessary for final writing to bp2build, as a configurable label
360// attribute can only be comprised by a single select.
361func (la *LabelAttribute) Collapse() error {
362 axisTypes := la.axisTypes()
363 _, containsOs := axisTypes[os]
364 _, containsArch := axisTypes[arch]
365 _, containsOsArch := axisTypes[osArch]
366 _, containsProductVariables := axisTypes[productVariables]
367 if containsProductVariables {
368 if containsOs || containsArch || containsOsArch {
Alixbbfd5382022-06-09 18:52:05 +0000369 if containsArch {
370 allProductVariablesAreArchVariant := true
371 for k := range la.ConfigurableValues {
Cole Faust150f9a52023-04-26 10:52:24 -0700372 if k.configurationType == productVariables && !k.archVariant {
Alixbbfd5382022-06-09 18:52:05 +0000373 allProductVariablesAreArchVariant = false
374 }
375 }
376 if !allProductVariablesAreArchVariant {
377 return fmt.Errorf("label attribute could not be collapsed as it has two or more unrelated axes")
378 }
379 } else {
380 return fmt.Errorf("label attribute could not be collapsed as it has two or more unrelated axes")
381 }
Chris Parsons58852a02021-12-09 18:10:18 -0500382 }
383 }
384 if (containsOs && containsArch) || (containsOsArch && (containsOs || containsArch)) {
385 // If a bool attribute has both os and arch configuration axes, the only
386 // way to successfully union their values is to increase the granularity
387 // of the configuration criteria to os_arch.
388 for osType, supportedArchs := range osToArchMap {
389 for _, supportedArch := range supportedArchs {
390 osArch := osArchString(osType, supportedArch)
391 if archOsVal := la.SelectValue(OsArchConfigurationAxis, osArch); archOsVal != nil {
392 // Do nothing, as the arch_os is explicitly defined already.
393 } else {
394 archVal := la.SelectValue(ArchConfigurationAxis, supportedArch)
395 osVal := la.SelectValue(OsConfigurationAxis, osType)
396 if osVal != nil && archVal != nil {
397 // In this case, arch takes precedence. (This fits legacy Soong behavior, as arch mutator
398 // runs after os mutator.
399 la.SetSelectValue(OsArchConfigurationAxis, osArch, *archVal)
400 } else if osVal != nil && archVal == nil {
401 la.SetSelectValue(OsArchConfigurationAxis, osArch, *osVal)
402 } else if osVal == nil && archVal != nil {
403 la.SetSelectValue(OsArchConfigurationAxis, osArch, *archVal)
404 }
405 }
406 }
407 }
408 // All os_arch values are now set. Clear os and arch axes.
409 delete(la.ConfigurableValues, ArchConfigurationAxis)
410 delete(la.ConfigurableValues, OsConfigurationAxis)
411 }
412 return nil
413}
414
Liz Kammer9abd62d2021-05-21 08:37:59 -0400415// HasConfigurableValues returns whether there are configurable values set for this label.
416func (la LabelAttribute) HasConfigurableValues() bool {
Chris Parsons58852a02021-12-09 18:10:18 -0500417 for _, selectValues := range la.ConfigurableValues {
418 if len(selectValues) > 0 {
419 return true
420 }
421 }
422 return false
Lukacs T. Berki598dd002021-05-05 09:00:01 +0200423}
424
Liz Kammer9abd62d2021-05-21 08:37:59 -0400425// SetValue sets the base, non-configured value for the Label
426func (la *LabelAttribute) SetValue(value Label) {
427 la.SetSelectValue(NoConfigAxis, "", value)
Rupert Shuttleworth22cd2eb2021-05-27 02:15:54 -0400428}
429
Liz Kammer9abd62d2021-05-21 08:37:59 -0400430// SetSelectValue set a value for a bazel select for the given axis, config and value.
431func (la *LabelAttribute) SetSelectValue(axis ConfigurationAxis, config string, value Label) {
432 axis.validateConfig(config)
433 switch axis.configurationType {
434 case noConfig:
435 la.Value = &value
Wei Li81852ca2022-07-27 00:22:06 -0700436 case arch, os, osArch, productVariables, osAndInApex:
Liz Kammer9abd62d2021-05-21 08:37:59 -0400437 if la.ConfigurableValues == nil {
438 la.ConfigurableValues = make(configurableLabels)
Rupert Shuttleworth22cd2eb2021-05-27 02:15:54 -0400439 }
Liz Kammer9abd62d2021-05-21 08:37:59 -0400440 la.ConfigurableValues.setValueForAxis(axis, config, &value)
441 default:
442 panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
443 }
444}
445
446// SelectValue gets a value for a bazel select for the given axis and config.
Chris Parsons58852a02021-12-09 18:10:18 -0500447func (la *LabelAttribute) SelectValue(axis ConfigurationAxis, config string) *Label {
Liz Kammer9abd62d2021-05-21 08:37:59 -0400448 axis.validateConfig(config)
449 switch axis.configurationType {
450 case noConfig:
Chris Parsons58852a02021-12-09 18:10:18 -0500451 return la.Value
Wei Li81852ca2022-07-27 00:22:06 -0700452 case arch, os, osArch, productVariables, osAndInApex:
Chris Parsons58852a02021-12-09 18:10:18 -0500453 return la.ConfigurableValues[axis][config]
Liz Kammer9abd62d2021-05-21 08:37:59 -0400454 default:
455 panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
456 }
457}
458
459// SortedConfigurationAxes returns all the used ConfigurationAxis in sorted order.
460func (la *LabelAttribute) SortedConfigurationAxes() []ConfigurationAxis {
Chris Parsons7b3289b2023-01-26 17:30:44 -0500461 return SortedConfigurationAxes(la.ConfigurableValues)
Liz Kammer9abd62d2021-05-21 08:37:59 -0400462}
463
Sam Delmericoc0161432022-02-25 21:34:51 +0000464// MakeLabelAttribute turns a string into a LabelAttribute
465func MakeLabelAttribute(label string) *LabelAttribute {
466 return &LabelAttribute{
467 Value: &Label{
468 Label: label,
469 },
470 }
471}
472
Liz Kammerd366c902021-06-03 13:43:01 -0400473type configToBools map[string]bool
474
475func (ctb configToBools) setValue(config string, value *bool) {
476 if value == nil {
477 if _, ok := ctb[config]; ok {
478 delete(ctb, config)
479 }
480 return
481 }
482 ctb[config] = *value
483}
484
485type configurableBools map[ConfigurationAxis]configToBools
486
487func (cb configurableBools) setValueForAxis(axis ConfigurationAxis, config string, value *bool) {
488 if cb[axis] == nil {
489 cb[axis] = make(configToBools)
490 }
491 cb[axis].setValue(config, value)
492}
493
494// BoolAttribute represents an attribute whose value is a single bool but may be configurable..
495type BoolAttribute struct {
496 Value *bool
497
498 ConfigurableValues configurableBools
499}
500
501// HasConfigurableValues returns whether there are configurable values for this attribute.
502func (ba BoolAttribute) HasConfigurableValues() bool {
Chris Parsons58852a02021-12-09 18:10:18 -0500503 for _, cfgToBools := range ba.ConfigurableValues {
504 if len(cfgToBools) > 0 {
505 return true
506 }
507 }
508 return false
Liz Kammerd366c902021-06-03 13:43:01 -0400509}
510
Liz Kammerdfeb1202022-05-13 17:20:20 -0400511// SetValue sets value for the no config axis
512func (ba *BoolAttribute) SetValue(value *bool) {
513 ba.SetSelectValue(NoConfigAxis, "", value)
514}
515
Liz Kammerd366c902021-06-03 13:43:01 -0400516// SetSelectValue sets value for the given axis/config.
517func (ba *BoolAttribute) SetSelectValue(axis ConfigurationAxis, config string, value *bool) {
518 axis.validateConfig(config)
519 switch axis.configurationType {
520 case noConfig:
521 ba.Value = value
Wei Li81852ca2022-07-27 00:22:06 -0700522 case arch, os, osArch, productVariables, osAndInApex:
Liz Kammerd366c902021-06-03 13:43:01 -0400523 if ba.ConfigurableValues == nil {
524 ba.ConfigurableValues = make(configurableBools)
525 }
526 ba.ConfigurableValues.setValueForAxis(axis, config, value)
527 default:
528 panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
529 }
530}
531
Chris Parsons58852a02021-12-09 18:10:18 -0500532// ToLabelListAttribute creates and returns a LabelListAttribute from this
533// bool attribute, where each bool in this attribute corresponds to a
534// label list value in the resultant attribute.
535func (ba *BoolAttribute) ToLabelListAttribute(falseVal LabelList, trueVal LabelList) (LabelListAttribute, error) {
536 getLabelList := func(boolPtr *bool) LabelList {
537 if boolPtr == nil {
538 return LabelList{nil, nil}
539 } else if *boolPtr {
540 return trueVal
541 } else {
542 return falseVal
543 }
544 }
545
546 mainVal := getLabelList(ba.Value)
547 if !ba.HasConfigurableValues() {
548 return MakeLabelListAttribute(mainVal), nil
549 }
550
551 result := LabelListAttribute{}
552 if err := ba.Collapse(); err != nil {
553 return result, err
554 }
555
556 for axis, configToBools := range ba.ConfigurableValues {
557 if len(configToBools) < 1 {
558 continue
559 }
560 for config, boolPtr := range configToBools {
561 val := getLabelList(&boolPtr)
562 if !val.Equals(mainVal) {
563 result.SetSelectValue(axis, config, val)
564 }
565 }
566 result.SetSelectValue(axis, ConditionsDefaultConfigKey, mainVal)
567 }
568
569 return result, nil
570}
571
Trevor Radcliffe56b1a2b2023-02-06 21:58:30 +0000572// ToStringListAttribute creates a StringListAttribute from this BoolAttribute,
573// where each bool corresponds to a string list value generated by the provided
574// function.
575// TODO(b/271425661): Generalize this
576func (ba *BoolAttribute) ToStringListAttribute(valueFunc func(boolPtr *bool, axis ConfigurationAxis, config string) []string) (StringListAttribute, error) {
577 mainVal := valueFunc(ba.Value, NoConfigAxis, "")
578 if !ba.HasConfigurableValues() {
579 return MakeStringListAttribute(mainVal), nil
580 }
581
582 result := StringListAttribute{}
583 if err := ba.Collapse(); err != nil {
584 return result, err
585 }
586
587 for axis, configToBools := range ba.ConfigurableValues {
588 if len(configToBools) < 1 {
589 continue
590 }
591 for config, boolPtr := range configToBools {
592 val := valueFunc(&boolPtr, axis, config)
593 if !reflect.DeepEqual(val, mainVal) {
594 result.SetSelectValue(axis, config, val)
595 }
596 }
597 result.SetSelectValue(axis, ConditionsDefaultConfigKey, mainVal)
598 }
599
600 return result, nil
601}
602
Chris Parsons58852a02021-12-09 18:10:18 -0500603// Collapse reduces the configurable axes of the boolean attribute to a single axis.
604// This is necessary for final writing to bp2build, as a configurable boolean
605// attribute can only be comprised by a single select.
606func (ba *BoolAttribute) Collapse() error {
607 axisTypes := ba.axisTypes()
608 _, containsOs := axisTypes[os]
609 _, containsArch := axisTypes[arch]
610 _, containsOsArch := axisTypes[osArch]
611 _, containsProductVariables := axisTypes[productVariables]
612 if containsProductVariables {
613 if containsOs || containsArch || containsOsArch {
614 return fmt.Errorf("boolean attribute could not be collapsed as it has two or more unrelated axes")
615 }
616 }
617 if (containsOs && containsArch) || (containsOsArch && (containsOs || containsArch)) {
618 // If a bool attribute has both os and arch configuration axes, the only
619 // way to successfully union their values is to increase the granularity
620 // of the configuration criteria to os_arch.
621 for osType, supportedArchs := range osToArchMap {
622 for _, supportedArch := range supportedArchs {
623 osArch := osArchString(osType, supportedArch)
624 if archOsVal := ba.SelectValue(OsArchConfigurationAxis, osArch); archOsVal != nil {
625 // Do nothing, as the arch_os is explicitly defined already.
626 } else {
627 archVal := ba.SelectValue(ArchConfigurationAxis, supportedArch)
628 osVal := ba.SelectValue(OsConfigurationAxis, osType)
629 if osVal != nil && archVal != nil {
630 // In this case, arch takes precedence. (This fits legacy Soong behavior, as arch mutator
631 // runs after os mutator.
632 ba.SetSelectValue(OsArchConfigurationAxis, osArch, archVal)
633 } else if osVal != nil && archVal == nil {
634 ba.SetSelectValue(OsArchConfigurationAxis, osArch, osVal)
635 } else if osVal == nil && archVal != nil {
636 ba.SetSelectValue(OsArchConfigurationAxis, osArch, archVal)
637 }
638 }
639 }
640 }
641 // All os_arch values are now set. Clear os and arch axes.
642 delete(ba.ConfigurableValues, ArchConfigurationAxis)
643 delete(ba.ConfigurableValues, OsConfigurationAxis)
644 // Verify post-condition; this should never fail, provided no additional
645 // axes are introduced.
646 if len(ba.ConfigurableValues) > 1 {
Liz Kammer07e106f2022-01-13 17:00:10 -0500647 panic(fmt.Errorf("error in collapsing attribute: %#v", ba))
Chris Parsons58852a02021-12-09 18:10:18 -0500648 }
649 }
650 return nil
651}
652
653func (ba *BoolAttribute) axisTypes() map[configurationType]bool {
654 types := map[configurationType]bool{}
655 for k := range ba.ConfigurableValues {
656 if len(ba.ConfigurableValues[k]) > 0 {
657 types[k.configurationType] = true
658 }
659 }
660 return types
661}
662
Liz Kammerd366c902021-06-03 13:43:01 -0400663// SelectValue gets the value for the given axis/config.
664func (ba BoolAttribute) SelectValue(axis ConfigurationAxis, config string) *bool {
665 axis.validateConfig(config)
666 switch axis.configurationType {
667 case noConfig:
668 return ba.Value
Wei Li81852ca2022-07-27 00:22:06 -0700669 case arch, os, osArch, productVariables, osAndInApex:
Liz Kammerd366c902021-06-03 13:43:01 -0400670 if v, ok := ba.ConfigurableValues[axis][config]; ok {
671 return &v
672 } else {
673 return nil
674 }
675 default:
676 panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
677 }
678}
679
680// SortedConfigurationAxes returns all the used ConfigurationAxis in sorted order.
681func (ba *BoolAttribute) SortedConfigurationAxes() []ConfigurationAxis {
Chris Parsons7b3289b2023-01-26 17:30:44 -0500682 return SortedConfigurationAxes(ba.ConfigurableValues)
Liz Kammerd366c902021-06-03 13:43:01 -0400683}
684
Liz Kammer9abd62d2021-05-21 08:37:59 -0400685// labelListSelectValues supports config-specific label_list typed Bazel attribute values.
686type labelListSelectValues map[string]LabelList
687
Liz Kammer12615db2021-09-28 09:19:17 -0400688func (ll labelListSelectValues) addSelects(label labelSelectValues) {
689 for k, v := range label {
690 if label == nil {
691 continue
692 }
693 l := ll[k]
694 (&l).Add(v)
695 ll[k] = l
696 }
697}
698
Chris Parsons77acf2e2021-12-03 17:27:16 -0500699func (ll labelListSelectValues) appendSelects(other labelListSelectValues, forceSpecifyEmptyList bool) {
Liz Kammer9abd62d2021-05-21 08:37:59 -0400700 for k, v := range other {
701 l := ll[k]
Chris Parsons77acf2e2021-12-03 17:27:16 -0500702 if forceSpecifyEmptyList && l.IsNil() && !v.IsNil() {
703 l.Includes = []Label{}
704 }
Liz Kammer9abd62d2021-05-21 08:37:59 -0400705 (&l).Append(v)
706 ll[k] = l
707 }
708}
709
710// HasConfigurableValues returns whether there are configurable values within this set of selects.
711func (ll labelListSelectValues) HasConfigurableValues() bool {
712 for _, v := range ll {
Chris Parsons51f8c392021-08-03 21:01:05 -0400713 if v.Includes != nil {
Rupert Shuttleworth22cd2eb2021-05-27 02:15:54 -0400714 return true
715 }
Rupert Shuttleworth22cd2eb2021-05-27 02:15:54 -0400716 }
717 return false
718}
719
Jingwen Chen07027912021-03-15 06:02:43 -0400720// LabelListAttribute is used to represent a list of Bazel labels as an
721// attribute.
722type LabelListAttribute struct {
Liz Kammer9abd62d2021-05-21 08:37:59 -0400723 // The non-configured attribute label list Value. Required.
Jingwen Chen07027912021-03-15 06:02:43 -0400724 Value LabelList
725
Liz Kammer9abd62d2021-05-21 08:37:59 -0400726 // The configured attribute label list Values. Optional
727 // a map of independent configurability axes
728 ConfigurableValues configurableLabelLists
Chris Parsons51f8c392021-08-03 21:01:05 -0400729
730 // If true, differentiate between "nil" and "empty" list. nil means that
731 // this attribute should not be specified at all, and "empty" means that
732 // the attribute should be explicitly specified as an empty list.
733 // This mode facilitates use of attribute defaults: an empty list should
734 // override the default.
735 ForceSpecifyEmptyList bool
Jingwen Chen58ff6802021-11-17 12:14:41 +0000736
737 // If true, signal the intent to the code generator to emit all select keys,
738 // even if the Includes list for that key is empty. This mode facilitates
739 // specific select statements where an empty list for a non-default select
740 // key has a meaning.
741 EmitEmptyList bool
Zi Wang9f609db2023-01-04 11:06:54 -0800742
743 // If a property has struct tag "variant_prepend", this value should
744 // be set to True, so that when bp2build generates BUILD.bazel, variant
745 // properties(select ...) come before general properties.
746 Prepend bool
Liz Kammer9abd62d2021-05-21 08:37:59 -0400747}
Jingwen Chen91220d72021-03-24 02:18:33 -0400748
Liz Kammer9abd62d2021-05-21 08:37:59 -0400749type configurableLabelLists map[ConfigurationAxis]labelListSelectValues
750
751func (cll configurableLabelLists) setValueForAxis(axis ConfigurationAxis, config string, list LabelList) {
752 if list.IsNil() {
753 if _, ok := cll[axis][config]; ok {
754 delete(cll[axis], config)
755 }
756 return
757 }
758 if cll[axis] == nil {
759 cll[axis] = make(labelListSelectValues)
760 }
761
762 cll[axis][config] = list
763}
764
Chris Parsons77acf2e2021-12-03 17:27:16 -0500765func (cll configurableLabelLists) Append(other configurableLabelLists, forceSpecifyEmptyList bool) {
Liz Kammer9abd62d2021-05-21 08:37:59 -0400766 for axis, otherSelects := range other {
767 selects := cll[axis]
768 if selects == nil {
769 selects = make(labelListSelectValues, len(otherSelects))
770 }
Chris Parsons77acf2e2021-12-03 17:27:16 -0500771 selects.appendSelects(otherSelects, forceSpecifyEmptyList)
Liz Kammer9abd62d2021-05-21 08:37:59 -0400772 cll[axis] = selects
773 }
Jingwen Chen07027912021-03-15 06:02:43 -0400774}
775
Chris Parsons77acf2e2021-12-03 17:27:16 -0500776func (lla *LabelListAttribute) Clone() *LabelListAttribute {
777 result := &LabelListAttribute{ForceSpecifyEmptyList: lla.ForceSpecifyEmptyList}
778 return result.Append(*lla)
779}
780
Jingwen Chen07027912021-03-15 06:02:43 -0400781// MakeLabelListAttribute initializes a LabelListAttribute with the non-arch specific value.
782func MakeLabelListAttribute(value LabelList) LabelListAttribute {
Liz Kammer9abd62d2021-05-21 08:37:59 -0400783 return LabelListAttribute{
784 Value: value,
785 ConfigurableValues: make(configurableLabelLists),
786 }
787}
788
Cole Faust53b62092022-05-12 15:37:02 -0700789// MakeSingleLabelListAttribute initializes a LabelListAttribute as a non-arch specific list with 1 element, the given Label.
790func MakeSingleLabelListAttribute(value Label) LabelListAttribute {
791 return MakeLabelListAttribute(MakeLabelList([]Label{value}))
792}
793
Liz Kammer9abd62d2021-05-21 08:37:59 -0400794func (lla *LabelListAttribute) SetValue(list LabelList) {
795 lla.SetSelectValue(NoConfigAxis, "", list)
796}
797
798// SetSelectValue set a value for a bazel select for the given axis, config and value.
799func (lla *LabelListAttribute) SetSelectValue(axis ConfigurationAxis, config string, list LabelList) {
800 axis.validateConfig(config)
801 switch axis.configurationType {
802 case noConfig:
803 lla.Value = list
Alixc0dac522023-05-04 21:20:16 +0000804 case arch, os, osArch, productVariables, osAndInApex, inApex, errorProneDisabled:
Liz Kammer9abd62d2021-05-21 08:37:59 -0400805 if lla.ConfigurableValues == nil {
806 lla.ConfigurableValues = make(configurableLabelLists)
807 }
808 lla.ConfigurableValues.setValueForAxis(axis, config, list)
809 default:
810 panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
811 }
812}
813
814// SelectValue gets a value for a bazel select for the given axis and config.
815func (lla *LabelListAttribute) SelectValue(axis ConfigurationAxis, config string) LabelList {
816 axis.validateConfig(config)
817 switch axis.configurationType {
818 case noConfig:
819 return lla.Value
Alixc0dac522023-05-04 21:20:16 +0000820 case arch, os, osArch, productVariables, osAndInApex, inApex, errorProneDisabled:
Cole Faustc843b992022-08-02 18:06:50 -0700821 return lla.ConfigurableValues[axis][config]
Liz Kammer9abd62d2021-05-21 08:37:59 -0400822 default:
823 panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
824 }
825}
826
827// SortedConfigurationAxes returns all the used ConfigurationAxis in sorted order.
828func (lla *LabelListAttribute) SortedConfigurationAxes() []ConfigurationAxis {
Chris Parsons7b3289b2023-01-26 17:30:44 -0500829 return SortedConfigurationAxes(lla.ConfigurableValues)
Jingwen Chen07027912021-03-15 06:02:43 -0400830}
831
Jingwen Chened9c17d2021-04-13 07:14:55 +0000832// Append all values, including os and arch specific ones, from another
Chris Parsons77acf2e2021-12-03 17:27:16 -0500833// LabelListAttribute to this LabelListAttribute. Returns this LabelListAttribute.
834func (lla *LabelListAttribute) Append(other LabelListAttribute) *LabelListAttribute {
835 forceSpecifyEmptyList := lla.ForceSpecifyEmptyList || other.ForceSpecifyEmptyList
836 if forceSpecifyEmptyList && lla.Value.IsNil() && !other.Value.IsNil() {
Chris Parsons51f8c392021-08-03 21:01:05 -0400837 lla.Value.Includes = []Label{}
838 }
Liz Kammer9abd62d2021-05-21 08:37:59 -0400839 lla.Value.Append(other.Value)
840 if lla.ConfigurableValues == nil {
841 lla.ConfigurableValues = make(configurableLabelLists)
Jingwen Chen63930982021-03-24 10:04:33 -0400842 }
Chris Parsons77acf2e2021-12-03 17:27:16 -0500843 lla.ConfigurableValues.Append(other.ConfigurableValues, forceSpecifyEmptyList)
844 return lla
Jingwen Chen63930982021-03-24 10:04:33 -0400845}
846
Liz Kammer12615db2021-09-28 09:19:17 -0400847// Add inserts the labels for each axis of LabelAttribute at the end of corresponding axis's
848// LabelList within the LabelListAttribute
849func (lla *LabelListAttribute) Add(label *LabelAttribute) {
850 if label == nil {
851 return
852 }
853
854 lla.Value.Add(label.Value)
855 if lla.ConfigurableValues == nil && label.ConfigurableValues != nil {
856 lla.ConfigurableValues = make(configurableLabelLists)
857 }
858 for axis, _ := range label.ConfigurableValues {
859 if _, exists := lla.ConfigurableValues[axis]; !exists {
860 lla.ConfigurableValues[axis] = make(labelListSelectValues)
861 }
862 lla.ConfigurableValues[axis].addSelects(label.ConfigurableValues[axis])
863 }
864}
865
Liz Kammer9abd62d2021-05-21 08:37:59 -0400866// HasConfigurableValues returns true if the attribute contains axis-specific label list values.
867func (lla LabelListAttribute) HasConfigurableValues() bool {
Chris Parsons58852a02021-12-09 18:10:18 -0500868 for _, selectValues := range lla.ConfigurableValues {
869 if len(selectValues) > 0 {
870 return true
871 }
872 }
873 return false
Rupert Shuttleworthc194ffb2021-05-19 06:49:02 -0400874}
875
Trevor Radcliffe0d1b4022022-12-12 22:26:34 +0000876// HasAxisSpecificValues returns true if the attribute contains axis specific label list values from a given axis
877func (lla LabelListAttribute) HasAxisSpecificValues(axis ConfigurationAxis) bool {
878 for _, values := range lla.ConfigurableValues[axis] {
879 if !values.IsNil() {
880 return true
881 }
882 }
883 return false
884}
885
Chris Parsons69fa9f92021-07-13 11:47:44 -0400886// IsEmpty returns true if the attribute has no values under any configuration.
887func (lla LabelListAttribute) IsEmpty() bool {
888 if len(lla.Value.Includes) > 0 {
889 return false
890 }
891 for axis, _ := range lla.ConfigurableValues {
892 if lla.ConfigurableValues[axis].HasConfigurableValues() {
893 return false
894 }
895 }
896 return true
897}
898
Liz Kammer54309532021-12-14 12:21:22 -0500899// IsNil returns true if the attribute has not been set for any configuration.
900func (lla LabelListAttribute) IsNil() bool {
901 if lla.Value.Includes != nil {
902 return false
903 }
904 return !lla.HasConfigurableValues()
905}
906
907// Exclude for the given axis, config, removes Includes in labelList from Includes and appends them
908// to Excludes. This is to special case any excludes that are not specified in a bp file but need to
909// be removed, e.g. if they could cause duplicate element failures.
910func (lla *LabelListAttribute) Exclude(axis ConfigurationAxis, config string, labelList LabelList) {
911 val := lla.SelectValue(axis, config)
912 newList := SubtractBazelLabelList(val, labelList)
913 newList.Excludes = append(newList.Excludes, labelList.Includes...)
914 lla.SetSelectValue(axis, config, newList)
915}
916
Liz Kammer74deed42021-06-02 13:02:03 -0400917// ResolveExcludes handles excludes across the various axes, ensuring that items are removed from
918// the base value and included in default values as appropriate.
919func (lla *LabelListAttribute) ResolveExcludes() {
Liz Kammerffc17e42022-11-23 09:42:05 -0500920 // If there are OsAndInApexAxis, we need to use
921 // * includes from the OS & in APEX Axis for non-Android configs for libraries that need to be
922 // included in non-Android OSes
923 // * excludes from the OS Axis for non-Android configs, to exclude libraries that should _not_
924 // be included in the non-Android OSes
925 if _, ok := lla.ConfigurableValues[OsAndInApexAxis]; ok {
926 inApexLabels := lla.ConfigurableValues[OsAndInApexAxis][ConditionsDefaultConfigKey]
927 for config, labels := range lla.ConfigurableValues[OsConfigurationAxis] {
928 // OsAndroid has already handled its excludes.
929 // We only need to copy the excludes from other arches, so if there are none, skip it.
930 if config == OsAndroid || len(labels.Excludes) == 0 {
931 continue
932 }
933 lla.ConfigurableValues[OsAndInApexAxis][config] = LabelList{
934 Includes: inApexLabels.Includes,
935 Excludes: labels.Excludes,
936 }
937 }
938 }
939
Liz Kammer74deed42021-06-02 13:02:03 -0400940 for axis, configToLabels := range lla.ConfigurableValues {
941 baseLabels := lla.Value.deepCopy()
942 for config, val := range configToLabels {
943 // Exclude config-specific excludes from base value
944 lla.Value = SubtractBazelLabelList(lla.Value, LabelList{Includes: val.Excludes})
945
946 // add base values to config specific to add labels excluded by others in this axis
947 // then remove all config-specific excludes
948 allLabels := baseLabels.deepCopy()
949 allLabels.Append(val)
Liz Kammer748d7072023-01-25 12:07:43 -0500950 lla.ConfigurableValues[axis][config] = SubtractBazelLabelList(allLabels, LabelList{Includes: allLabels.Excludes})
Liz Kammer74deed42021-06-02 13:02:03 -0400951 }
952
953 // After going through all configs, delete the duplicates in the config
954 // values that are already in the base Value.
955 for config, val := range configToLabels {
956 lla.ConfigurableValues[axis][config] = SubtractBazelLabelList(val, lla.Value)
957 }
958
Jingwen Chen9af49a42021-11-02 10:27:17 +0000959 // Now that the Value list is finalized for this axis, compare it with
960 // the original list, and union the difference with the default
961 // condition for the axis.
962 difference := SubtractBazelLabelList(baseLabels, lla.Value)
963 existingDefaults := lla.ConfigurableValues[axis][ConditionsDefaultConfigKey]
964 existingDefaults.Append(difference)
965 lla.ConfigurableValues[axis][ConditionsDefaultConfigKey] = FirstUniqueBazelLabelList(existingDefaults)
Liz Kammer74deed42021-06-02 13:02:03 -0400966
967 // if everything ends up without includes, just delete the axis
968 if !lla.ConfigurableValues[axis].HasConfigurableValues() {
969 delete(lla.ConfigurableValues, axis)
970 }
971 }
972}
973
Sam Delmericoc1130dc2022-08-25 14:43:54 -0400974// Partition splits a LabelListAttribute into two LabelListAttributes depending
975// on the return value of the predicate.
976// This function preserves the Includes and Excludes, but it does not provide
977// that information to the partition function.
978func (lla LabelListAttribute) Partition(predicate func(label Label) bool) (LabelListAttribute, LabelListAttribute) {
979 predicated := LabelListAttribute{}
980 unpredicated := LabelListAttribute{}
981
982 valuePartitionTrue, valuePartitionFalse := lla.Value.Partition(predicate)
983 predicated.SetValue(valuePartitionTrue)
984 unpredicated.SetValue(valuePartitionFalse)
985
986 for axis, selectValueLabelLists := range lla.ConfigurableValues {
987 for config, labelList := range selectValueLabelLists {
988 configPredicated, configUnpredicated := labelList.Partition(predicate)
989 predicated.SetSelectValue(axis, config, configPredicated)
990 unpredicated.SetSelectValue(axis, config, configUnpredicated)
991 }
992 }
993
994 return predicated, unpredicated
995}
996
Liz Kammer57e2e7a2021-09-20 12:55:02 -0400997// OtherModuleContext is a limited context that has methods with information about other modules.
998type OtherModuleContext interface {
999 ModuleFromName(name string) (blueprint.Module, bool)
1000 OtherModuleType(m blueprint.Module) string
1001 OtherModuleName(m blueprint.Module) string
1002 OtherModuleDir(m blueprint.Module) string
1003 ModuleErrorf(fmt string, args ...interface{})
1004}
1005
1006// LabelMapper is a function that takes a OtherModuleContext and returns a (potentially changed)
1007// label and whether it was changed.
Liz Kammer12615db2021-09-28 09:19:17 -04001008type LabelMapper func(OtherModuleContext, Label) (string, bool)
Liz Kammer57e2e7a2021-09-20 12:55:02 -04001009
1010// LabelPartition contains descriptions of a partition for labels
1011type LabelPartition struct {
1012 // Extensions to include in this partition
1013 Extensions []string
1014 // LabelMapper is a function that can map a label to a new label, and indicate whether to include
1015 // the mapped label in the partition
1016 LabelMapper LabelMapper
1017 // Whether to store files not included in any other partition in a group of LabelPartitions
1018 // Only one partition in a group of LabelPartitions can enabled Keep_remainder
1019 Keep_remainder bool
1020}
1021
1022// LabelPartitions is a map of partition name to a LabelPartition describing the elements of the
1023// partition
1024type LabelPartitions map[string]LabelPartition
1025
1026// filter returns a pointer to a label if the label should be included in the partition or nil if
1027// not.
1028func (lf LabelPartition) filter(ctx OtherModuleContext, label Label) *Label {
1029 if lf.LabelMapper != nil {
Liz Kammer12615db2021-09-28 09:19:17 -04001030 if newLabel, changed := lf.LabelMapper(ctx, label); changed {
Liz Kammer57e2e7a2021-09-20 12:55:02 -04001031 return &Label{newLabel, label.OriginalModuleName}
1032 }
1033 }
1034 for _, ext := range lf.Extensions {
1035 if strings.HasSuffix(label.Label, ext) {
1036 return &label
1037 }
1038 }
1039
1040 return nil
1041}
1042
1043// PartitionToLabelListAttribute is map of partition name to a LabelListAttribute
1044type PartitionToLabelListAttribute map[string]LabelListAttribute
1045
1046type partitionToLabelList map[string]*LabelList
1047
1048func (p partitionToLabelList) appendIncludes(partition string, label Label) {
1049 if _, ok := p[partition]; !ok {
1050 p[partition] = &LabelList{}
1051 }
1052 p[partition].Includes = append(p[partition].Includes, label)
1053}
1054
1055func (p partitionToLabelList) excludes(partition string, excludes []Label) {
1056 if _, ok := p[partition]; !ok {
1057 p[partition] = &LabelList{}
1058 }
1059 p[partition].Excludes = excludes
1060}
1061
1062// PartitionLabelListAttribute partitions a LabelListAttribute into the requested partitions
1063func PartitionLabelListAttribute(ctx OtherModuleContext, lla *LabelListAttribute, partitions LabelPartitions) PartitionToLabelListAttribute {
1064 ret := PartitionToLabelListAttribute{}
1065 var partitionNames []string
1066 // Stored as a pointer to distinguish nil (no remainder partition) from empty string partition
1067 var remainderPartition *string
1068 for p, f := range partitions {
1069 partitionNames = append(partitionNames, p)
1070 if f.Keep_remainder {
1071 if remainderPartition != nil {
1072 panic("only one partition can store the remainder")
1073 }
1074 // If we take the address of p in a loop, we'll end up with the last value of p in
1075 // remainderPartition, we want the requested partition
1076 capturePartition := p
1077 remainderPartition = &capturePartition
1078 }
1079 }
1080
1081 partitionLabelList := func(axis ConfigurationAxis, config string) {
1082 value := lla.SelectValue(axis, config)
1083 partitionToLabels := partitionToLabelList{}
1084 for _, item := range value.Includes {
1085 wasFiltered := false
1086 var inPartition *string
1087 for partition, f := range partitions {
1088 filtered := f.filter(ctx, item)
1089 if filtered == nil {
1090 // did not match this filter, keep looking
1091 continue
1092 }
1093 wasFiltered = true
1094 partitionToLabels.appendIncludes(partition, *filtered)
1095 // don't need to check other partitions if this filter used the item,
1096 // continue checking if mapped to another name
1097 if *filtered == item {
1098 if inPartition != nil {
1099 ctx.ModuleErrorf("%q was found in multiple partitions: %q, %q", item.Label, *inPartition, partition)
1100 }
1101 capturePartition := partition
1102 inPartition = &capturePartition
1103 }
1104 }
1105
1106 // if not specified in a partition, add to remainder partition if one exists
1107 if !wasFiltered && remainderPartition != nil {
1108 partitionToLabels.appendIncludes(*remainderPartition, item)
1109 }
1110 }
1111
1112 // ensure empty lists are maintained
1113 if value.Excludes != nil {
1114 for _, partition := range partitionNames {
1115 partitionToLabels.excludes(partition, value.Excludes)
1116 }
1117 }
1118
1119 for partition, list := range partitionToLabels {
1120 val := ret[partition]
1121 (&val).SetSelectValue(axis, config, *list)
1122 ret[partition] = val
1123 }
1124 }
1125
1126 partitionLabelList(NoConfigAxis, "")
1127 for axis, configToList := range lla.ConfigurableValues {
1128 for config, _ := range configToList {
1129 partitionLabelList(axis, config)
1130 }
1131 }
1132 return ret
1133}
1134
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux3a019a62022-06-23 16:02:44 +00001135// StringAttribute corresponds to the string Bazel attribute type with
1136// support for additional metadata, like configurations.
1137type StringAttribute struct {
1138 // The base value of the string attribute.
1139 Value *string
1140
1141 // The configured attribute label list Values. Optional
1142 // a map of independent configurability axes
1143 ConfigurableValues configurableStrings
1144}
1145
1146type configurableStrings map[ConfigurationAxis]stringSelectValues
1147
1148func (cs configurableStrings) setValueForAxis(axis ConfigurationAxis, config string, str *string) {
1149 if cs[axis] == nil {
1150 cs[axis] = make(stringSelectValues)
1151 }
Liz Kammer9d2d4102022-12-21 14:51:37 -05001152 cs[axis][config] = str
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux3a019a62022-06-23 16:02:44 +00001153}
1154
Liz Kammer9d2d4102022-12-21 14:51:37 -05001155type stringSelectValues map[string]*string
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux3a019a62022-06-23 16:02:44 +00001156
1157// HasConfigurableValues returns true if the attribute contains axis-specific string values.
1158func (sa StringAttribute) HasConfigurableValues() bool {
1159 for _, selectValues := range sa.ConfigurableValues {
1160 if len(selectValues) > 0 {
1161 return true
1162 }
1163 }
1164 return false
1165}
1166
Liz Kammer9d2d4102022-12-21 14:51:37 -05001167// SetValue sets the base, non-configured value for the Label
1168func (sa *StringAttribute) SetValue(value string) {
1169 sa.SetSelectValue(NoConfigAxis, "", &value)
1170}
1171
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux3a019a62022-06-23 16:02:44 +00001172// SetSelectValue set a value for a bazel select for the given axis, config and value.
1173func (sa *StringAttribute) SetSelectValue(axis ConfigurationAxis, config string, str *string) {
1174 axis.validateConfig(config)
1175 switch axis.configurationType {
1176 case noConfig:
1177 sa.Value = str
1178 case arch, os, osArch, productVariables:
1179 if sa.ConfigurableValues == nil {
1180 sa.ConfigurableValues = make(configurableStrings)
1181 }
1182 sa.ConfigurableValues.setValueForAxis(axis, config, str)
1183 default:
1184 panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
1185 }
1186}
1187
1188// SelectValue gets a value for a bazel select for the given axis and config.
1189func (sa *StringAttribute) SelectValue(axis ConfigurationAxis, config string) *string {
1190 axis.validateConfig(config)
1191 switch axis.configurationType {
1192 case noConfig:
1193 return sa.Value
1194 case arch, os, osArch, productVariables:
1195 if v, ok := sa.ConfigurableValues[axis][config]; ok {
Liz Kammer9d2d4102022-12-21 14:51:37 -05001196 return v
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux3a019a62022-06-23 16:02:44 +00001197 } else {
1198 return nil
1199 }
1200 default:
1201 panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
1202 }
1203}
1204
1205// SortedConfigurationAxes returns all the used ConfigurationAxis in sorted order.
1206func (sa *StringAttribute) SortedConfigurationAxes() []ConfigurationAxis {
Chris Parsons7b3289b2023-01-26 17:30:44 -05001207 return SortedConfigurationAxes(sa.ConfigurableValues)
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux3a019a62022-06-23 16:02:44 +00001208}
1209
1210// Collapse reduces the configurable axes of the string attribute to a single axis.
1211// This is necessary for final writing to bp2build, as a configurable string
1212// attribute can only be comprised by a single select.
1213func (sa *StringAttribute) Collapse() error {
1214 axisTypes := sa.axisTypes()
1215 _, containsOs := axisTypes[os]
1216 _, containsArch := axisTypes[arch]
1217 _, containsOsArch := axisTypes[osArch]
1218 _, containsProductVariables := axisTypes[productVariables]
1219 if containsProductVariables {
1220 if containsOs || containsArch || containsOsArch {
Liz Kammer9d2d4102022-12-21 14:51:37 -05001221 return fmt.Errorf("string attribute could not be collapsed as it has two or more unrelated axes")
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux3a019a62022-06-23 16:02:44 +00001222 }
1223 }
1224 if (containsOs && containsArch) || (containsOsArch && (containsOs || containsArch)) {
1225 // If a bool attribute has both os and arch configuration axes, the only
1226 // way to successfully union their values is to increase the granularity
1227 // of the configuration criteria to os_arch.
1228 for osType, supportedArchs := range osToArchMap {
1229 for _, supportedArch := range supportedArchs {
1230 osArch := osArchString(osType, supportedArch)
1231 if archOsVal := sa.SelectValue(OsArchConfigurationAxis, osArch); archOsVal != nil {
1232 // Do nothing, as the arch_os is explicitly defined already.
1233 } else {
1234 archVal := sa.SelectValue(ArchConfigurationAxis, supportedArch)
1235 osVal := sa.SelectValue(OsConfigurationAxis, osType)
1236 if osVal != nil && archVal != nil {
1237 // In this case, arch takes precedence. (This fits legacy Soong behavior, as arch mutator
1238 // runs after os mutator.
1239 sa.SetSelectValue(OsArchConfigurationAxis, osArch, archVal)
1240 } else if osVal != nil && archVal == nil {
1241 sa.SetSelectValue(OsArchConfigurationAxis, osArch, osVal)
1242 } else if osVal == nil && archVal != nil {
1243 sa.SetSelectValue(OsArchConfigurationAxis, osArch, archVal)
1244 }
1245 }
1246 }
1247 }
Liz Kammer9d2d4102022-12-21 14:51:37 -05001248 /// All os_arch values are now set. Clear os and arch axes.
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux3a019a62022-06-23 16:02:44 +00001249 delete(sa.ConfigurableValues, ArchConfigurationAxis)
1250 delete(sa.ConfigurableValues, OsConfigurationAxis)
1251 // Verify post-condition; this should never fail, provided no additional
1252 // axes are introduced.
1253 if len(sa.ConfigurableValues) > 1 {
1254 panic(fmt.Errorf("error in collapsing attribute: %#v", sa))
1255 }
Liz Kammer9d2d4102022-12-21 14:51:37 -05001256 } else if containsProductVariables {
1257 usedBaseValue := false
1258 for a, configToProp := range sa.ConfigurableValues {
1259 if a.configurationType == productVariables {
1260 for c, p := range configToProp {
1261 if p == nil {
1262 sa.SetSelectValue(a, c, sa.Value)
1263 usedBaseValue = true
1264 }
1265 }
1266 }
1267 }
1268 if usedBaseValue {
1269 sa.Value = nil
1270 }
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux3a019a62022-06-23 16:02:44 +00001271 }
1272 return nil
1273}
1274
1275func (sa *StringAttribute) axisTypes() map[configurationType]bool {
1276 types := map[configurationType]bool{}
1277 for k := range sa.ConfigurableValues {
1278 if strs := sa.ConfigurableValues[k]; len(strs) > 0 {
1279 types[k.configurationType] = true
1280 }
1281 }
1282 return types
1283}
1284
Jingwen Chen5d864492021-02-24 07:20:12 -05001285// StringListAttribute corresponds to the string_list Bazel attribute type with
1286// support for additional metadata, like configurations.
1287type StringListAttribute struct {
1288 // The base value of the string list attribute.
1289 Value []string
1290
Liz Kammer9abd62d2021-05-21 08:37:59 -04001291 // The configured attribute label list Values. Optional
1292 // a map of independent configurability axes
1293 ConfigurableValues configurableStringLists
Zi Wang1cb11802022-12-09 16:08:54 -08001294
1295 // If a property has struct tag "variant_prepend", this value should
1296 // be set to True, so that when bp2build generates BUILD.bazel, variant
1297 // properties(select ...) come before general properties.
1298 Prepend bool
Liz Kammer9abd62d2021-05-21 08:37:59 -04001299}
Jingwen Chenc1c26502021-04-05 10:35:13 +00001300
Spandan Das4238c652022-09-09 01:38:47 +00001301// IsEmpty returns true if the attribute has no values under any configuration.
1302func (sla StringListAttribute) IsEmpty() bool {
1303 return len(sla.Value) == 0 && !sla.HasConfigurableValues()
1304}
1305
Liz Kammer9abd62d2021-05-21 08:37:59 -04001306type configurableStringLists map[ConfigurationAxis]stringListSelectValues
Liz Kammer6fd7b3f2021-05-06 13:54:29 -04001307
Liz Kammer9abd62d2021-05-21 08:37:59 -04001308func (csl configurableStringLists) Append(other configurableStringLists) {
1309 for axis, otherSelects := range other {
1310 selects := csl[axis]
1311 if selects == nil {
1312 selects = make(stringListSelectValues, len(otherSelects))
1313 }
1314 selects.appendSelects(otherSelects)
1315 csl[axis] = selects
1316 }
1317}
1318
1319func (csl configurableStringLists) setValueForAxis(axis ConfigurationAxis, config string, list []string) {
1320 if csl[axis] == nil {
1321 csl[axis] = make(stringListSelectValues)
1322 }
1323 csl[axis][config] = list
1324}
1325
1326type stringListSelectValues map[string][]string
1327
1328func (sl stringListSelectValues) appendSelects(other stringListSelectValues) {
1329 for k, v := range other {
1330 sl[k] = append(sl[k], v...)
1331 }
1332}
1333
1334func (sl stringListSelectValues) hasConfigurableValues(other stringListSelectValues) bool {
1335 for _, val := range sl {
1336 if len(val) > 0 {
1337 return true
1338 }
1339 }
1340 return false
Jingwen Chen5d864492021-02-24 07:20:12 -05001341}
1342
Rupert Shuttleworthb8151682021-04-06 20:06:21 +00001343// MakeStringListAttribute initializes a StringListAttribute with the non-arch specific value.
1344func MakeStringListAttribute(value []string) StringListAttribute {
1345 // NOTE: These strings are not necessarily unique or sorted.
Liz Kammer9abd62d2021-05-21 08:37:59 -04001346 return StringListAttribute{
1347 Value: value,
1348 ConfigurableValues: make(configurableStringLists),
Jingwen Chen91220d72021-03-24 02:18:33 -04001349 }
1350}
1351
Liz Kammer9abd62d2021-05-21 08:37:59 -04001352// HasConfigurableValues returns true if the attribute contains axis-specific string_list values.
1353func (sla StringListAttribute) HasConfigurableValues() bool {
Chris Parsons58852a02021-12-09 18:10:18 -05001354 for _, selectValues := range sla.ConfigurableValues {
1355 if len(selectValues) > 0 {
1356 return true
1357 }
1358 }
1359 return false
Rupert Shuttleworthc194ffb2021-05-19 06:49:02 -04001360}
1361
Jingwen Chened9c17d2021-04-13 07:14:55 +00001362// Append appends all values, including os and arch specific ones, from another
1363// StringListAttribute to this StringListAttribute
Chris Parsons77acf2e2021-12-03 17:27:16 -05001364func (sla *StringListAttribute) Append(other StringListAttribute) *StringListAttribute {
Liz Kammer9abd62d2021-05-21 08:37:59 -04001365 sla.Value = append(sla.Value, other.Value...)
1366 if sla.ConfigurableValues == nil {
1367 sla.ConfigurableValues = make(configurableStringLists)
1368 }
1369 sla.ConfigurableValues.Append(other.ConfigurableValues)
Chris Parsons77acf2e2021-12-03 17:27:16 -05001370 return sla
1371}
1372
1373func (sla *StringListAttribute) Clone() *StringListAttribute {
1374 result := &StringListAttribute{}
1375 return result.Append(*sla)
Liz Kammer9abd62d2021-05-21 08:37:59 -04001376}
1377
1378// SetSelectValue set a value for a bazel select for the given axis, config and value.
1379func (sla *StringListAttribute) SetSelectValue(axis ConfigurationAxis, config string, list []string) {
1380 axis.validateConfig(config)
1381 switch axis.configurationType {
1382 case noConfig:
1383 sla.Value = list
Alixc0dac522023-05-04 21:20:16 +00001384 case arch, os, osArch, productVariables, osAndInApex, errorProneDisabled:
Liz Kammer9abd62d2021-05-21 08:37:59 -04001385 if sla.ConfigurableValues == nil {
1386 sla.ConfigurableValues = make(configurableStringLists)
1387 }
1388 sla.ConfigurableValues.setValueForAxis(axis, config, list)
1389 default:
1390 panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
1391 }
1392}
1393
1394// SelectValue gets a value for a bazel select for the given axis and config.
1395func (sla *StringListAttribute) SelectValue(axis ConfigurationAxis, config string) []string {
1396 axis.validateConfig(config)
1397 switch axis.configurationType {
1398 case noConfig:
1399 return sla.Value
Alixc0dac522023-05-04 21:20:16 +00001400 case arch, os, osArch, productVariables, osAndInApex, errorProneDisabled:
Liz Kammer9abd62d2021-05-21 08:37:59 -04001401 return sla.ConfigurableValues[axis][config]
1402 default:
1403 panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
1404 }
1405}
1406
1407// SortedConfigurationAxes returns all the used ConfigurationAxis in sorted order.
1408func (sla *StringListAttribute) SortedConfigurationAxes() []ConfigurationAxis {
Chris Parsons7b3289b2023-01-26 17:30:44 -05001409 return SortedConfigurationAxes(sla.ConfigurableValues)
Jingwen Chened9c17d2021-04-13 07:14:55 +00001410}
1411
Liz Kammer5fad5012021-09-09 14:08:21 -04001412// DeduplicateAxesFromBase ensures no duplication of items between the no-configuration value and
1413// configuration-specific values. For example, if we would convert this StringListAttribute as:
Colin Crossd079e0b2022-08-16 10:27:33 -07001414//
1415// ["a", "b", "c"] + select({
1416// "//condition:one": ["a", "d"],
1417// "//conditions:default": [],
1418// })
1419//
Liz Kammer5fad5012021-09-09 14:08:21 -04001420// after this function, we would convert this StringListAttribute as:
Colin Crossd079e0b2022-08-16 10:27:33 -07001421//
1422// ["a", "b", "c"] + select({
1423// "//condition:one": ["d"],
1424// "//conditions:default": [],
1425// })
Liz Kammer5fad5012021-09-09 14:08:21 -04001426func (sla *StringListAttribute) DeduplicateAxesFromBase() {
1427 base := sla.Value
1428 for axis, configToList := range sla.ConfigurableValues {
1429 for config, list := range configToList {
1430 remaining := SubtractStrings(list, base)
1431 if len(remaining) == 0 {
1432 delete(sla.ConfigurableValues[axis], config)
1433 } else {
1434 sla.ConfigurableValues[axis][config] = remaining
1435 }
1436 }
1437 }
1438}
1439
Liz Kammera060c452021-03-24 10:14:47 -04001440// TryVariableSubstitution, replace string substitution formatting within each string in slice with
1441// Starlark string.format compatible tag for productVariable.
1442func TryVariableSubstitutions(slice []string, productVariable string) ([]string, bool) {
Liz Kammerf3963f82022-12-21 14:47:18 -05001443 if len(slice) == 0 {
1444 return slice, false
1445 }
Liz Kammera060c452021-03-24 10:14:47 -04001446 ret := make([]string, 0, len(slice))
1447 changesMade := false
1448 for _, s := range slice {
1449 newS, changed := TryVariableSubstitution(s, productVariable)
1450 ret = append(ret, newS)
1451 changesMade = changesMade || changed
1452 }
1453 return ret, changesMade
1454}
1455
1456// TryVariableSubstitution, replace string substitution formatting within s with Starlark
1457// string.format compatible tag for productVariable.
1458func TryVariableSubstitution(s string, productVariable string) (string, bool) {
Liz Kammerba7a9c52021-05-26 08:45:30 -04001459 sub := productVariableSubstitutionPattern.ReplaceAllString(s, "$("+productVariable+")")
Liz Kammera060c452021-03-24 10:14:47 -04001460 return sub, s != sub
1461}
Spandan Das6a448ec2023-04-19 17:36:12 +00001462
1463// StringMapAttribute is a map of strings.
1464// The use case for this is storing the flag_values in a config_setting object.
1465// Bazel rules do not support map attributes, and this should NOT be used in Bazel rules.
1466type StringMapAttribute map[string]string
1467
1468// ConfigSettingAttributes stores the keys of a config_setting object.
1469type ConfigSettingAttributes struct {
1470 // Each key in Flag_values is a label to a custom string_setting
1471 Flag_values StringMapAttribute
Spandan Das9cad90f2023-05-04 17:15:44 +00001472 // Each element in Constraint_values is a label to a constraint_value
1473 Constraint_values LabelListAttribute
Spandan Das6a448ec2023-04-19 17:36:12 +00001474}