blob: 4bb239101951a8f8ff99ceded56319b9b55cf6af [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"
Liz Kammera060c452021-03-24 10:14:47 -040020 "regexp"
Rupert Shuttleworth2e4219b2021-03-12 11:04:21 +000021 "sort"
22)
Jingwen Chen5d864492021-02-24 07:20:12 -050023
Jingwen Chen73850672020-12-14 08:25:34 -050024// BazelTargetModuleProperties contain properties and metadata used for
25// Blueprint to BUILD file conversion.
26type BazelTargetModuleProperties struct {
27 // The Bazel rule class for this target.
Liz Kammerfc46bc12021-02-19 11:06:17 -050028 Rule_class string `blueprint:"mutated"`
Jingwen Chen40067de2021-01-26 21:58:43 -050029
30 // The target label for the bzl file containing the definition of the rule class.
Liz Kammerfc46bc12021-02-19 11:06:17 -050031 Bzl_load_location string `blueprint:"mutated"`
Jingwen Chen73850672020-12-14 08:25:34 -050032}
Liz Kammer356f7d42021-01-26 09:18:53 -050033
Jingwen Chenfb4692a2021-02-07 10:05:16 -050034const BazelTargetModuleNamePrefix = "__bp2build__"
35
Liz Kammera060c452021-03-24 10:14:47 -040036var productVariableSubstitutionPattern = regexp.MustCompile("%(d|s)")
37
Liz Kammer356f7d42021-01-26 09:18:53 -050038// Label is used to represent a Bazel compatible Label. Also stores the original bp text to support
39// string replacement.
40type Label struct {
41 Bp_text string
42 Label string
43}
44
45// LabelList is used to represent a list of Bazel labels.
46type LabelList struct {
47 Includes []Label
48 Excludes []Label
49}
50
Jingwen Chen63930982021-03-24 10:04:33 -040051// GlobsInDir returns a list of glob expressions for a list of extensions
52// (optionally recursive) within a directory.
53func GlobsInDir(dir string, recursive bool, extensions []string) []string {
54 globs := []string{}
55
56 globInfix := ""
57 if dir == "." {
58 if recursive {
59 // e.g "**/*.h"
60 globInfix = "**/"
61 } // else e.g. "*.h"
62 for _, ext := range extensions {
63 globs = append(globs, globInfix+"*"+ext)
64 }
65 } else {
66 if recursive {
67 // e.g. "foo/bar/**/*.h"
68 dir += "/**"
69 } // else e.g. "foo/bar/*.h"
70 for _, ext := range extensions {
71 globs = append(globs, dir+"/*"+ext)
72 }
73 }
74 return globs
75}
76
77// LooseHdrsGlobs returns the list of non-recursive header globs for each parent directory of
78// each source file in this LabelList's Includes.
79func (ll *LabelList) LooseHdrsGlobs(exts []string) []string {
80 var globs []string
81 for _, parentDir := range ll.uniqueParentDirectories() {
82 globs = append(globs,
83 GlobsInDir(parentDir, false, exts)...)
84 }
85 return globs
86}
87
88// uniqueParentDirectories returns a list of the unique parent directories for
89// all files in ll.Includes.
90func (ll *LabelList) uniqueParentDirectories() []string {
91 dirMap := map[string]bool{}
92 for _, label := range ll.Includes {
93 dirMap[filepath.Dir(label.Label)] = true
94 }
95 dirs := []string{}
96 for dir := range dirMap {
97 dirs = append(dirs, dir)
98 }
99 return dirs
100}
101
Liz Kammer356f7d42021-01-26 09:18:53 -0500102// Append appends the fields of other labelList to the corresponding fields of ll.
103func (ll *LabelList) Append(other LabelList) {
104 if len(ll.Includes) > 0 || len(other.Includes) > 0 {
105 ll.Includes = append(ll.Includes, other.Includes...)
106 }
107 if len(ll.Excludes) > 0 || len(other.Excludes) > 0 {
108 ll.Excludes = append(other.Excludes, other.Excludes...)
109 }
110}
Jingwen Chen5d864492021-02-24 07:20:12 -0500111
Rupert Shuttleworth2e4219b2021-03-12 11:04:21 +0000112func UniqueBazelLabels(originalLabels []Label) []Label {
113 uniqueLabelsSet := make(map[Label]bool)
114 for _, l := range originalLabels {
115 uniqueLabelsSet[l] = true
116 }
117 var uniqueLabels []Label
118 for l, _ := range uniqueLabelsSet {
119 uniqueLabels = append(uniqueLabels, l)
120 }
121 sort.SliceStable(uniqueLabels, func(i, j int) bool {
122 return uniqueLabels[i].Label < uniqueLabels[j].Label
123 })
124 return uniqueLabels
125}
126
127func UniqueBazelLabelList(originalLabelList LabelList) LabelList {
128 var uniqueLabelList LabelList
129 uniqueLabelList.Includes = UniqueBazelLabels(originalLabelList.Includes)
130 uniqueLabelList.Excludes = UniqueBazelLabels(originalLabelList.Excludes)
131 return uniqueLabelList
132}
133
Rupert Shuttleworthb8151682021-04-06 20:06:21 +0000134// Subtract needle from haystack
135func SubtractStrings(haystack []string, needle []string) []string {
136 // This is really a set
137 remainder := make(map[string]bool)
138
139 for _, s := range haystack {
140 remainder[s] = true
141 }
142 for _, s := range needle {
143 delete(remainder, s)
144 }
145
146 var strings []string
147 for s, _ := range remainder {
148 strings = append(strings, s)
149 }
150
151 sort.SliceStable(strings, func(i, j int) bool {
152 return strings[i] < strings[j]
153 })
154
155 return strings
156}
157
158// Subtract needle from haystack
159func SubtractBazelLabels(haystack []Label, needle []Label) []Label {
160 // This is really a set
161 remainder := make(map[Label]bool)
162
163 for _, label := range haystack {
164 remainder[label] = true
165 }
166 for _, label := range needle {
167 delete(remainder, label)
168 }
169
170 var labels []Label
171 for label, _ := range remainder {
172 labels = append(labels, label)
173 }
174
175 sort.SliceStable(labels, func(i, j int) bool {
176 return labels[i].Label < labels[j].Label
177 })
178
179 return labels
180}
181
182// Subtract needle from haystack
183func SubtractBazelLabelList(haystack LabelList, needle LabelList) LabelList {
184 var result LabelList
185 result.Includes = SubtractBazelLabels(haystack.Includes, needle.Includes)
186 // NOTE: Excludes are intentionally not subtracted
187 result.Excludes = haystack.Excludes
188 return result
189}
190
Jingwen Chen07027912021-03-15 06:02:43 -0400191const (
Jingwen Chen91220d72021-03-24 02:18:33 -0400192 // ArchType names in arch.go
Jingwen Chen07027912021-03-15 06:02:43 -0400193 ARCH_ARM = "arm"
194 ARCH_ARM64 = "arm64"
Jingwen Chen91220d72021-03-24 02:18:33 -0400195 ARCH_X86 = "x86"
196 ARCH_X86_64 = "x86_64"
197
198 // OsType names in arch.go
199 OS_ANDROID = "android"
200 OS_DARWIN = "darwin"
201 OS_FUCHSIA = "fuchsia"
202 OS_LINUX = "linux_glibc"
203 OS_LINUX_BIONIC = "linux_bionic"
204 OS_WINDOWS = "windows"
Jingwen Chen07027912021-03-15 06:02:43 -0400205)
206
207var (
Jingwen Chenc1c26502021-04-05 10:35:13 +0000208 // These are the list of OSes and architectures with a Bazel config_setting
209 // and constraint value equivalent. These exist in arch.go, but the android
210 // package depends on the bazel package, so a cyclic dependency prevents
211 // using those variables here.
Jingwen Chen91220d72021-03-24 02:18:33 -0400212
213 // A map of architectures to the Bazel label of the constraint_value
214 // for the @platforms//cpu:cpu constraint_setting
215 PlatformArchMap = map[string]string{
216 ARCH_ARM: "//build/bazel/platforms/arch:arm",
217 ARCH_ARM64: "//build/bazel/platforms/arch:arm64",
218 ARCH_X86: "//build/bazel/platforms/arch:x86",
219 ARCH_X86_64: "//build/bazel/platforms/arch:x86_64",
220 }
221
222 // A map of target operating systems to the Bazel label of the
223 // constraint_value for the @platforms//os:os constraint_setting
224 PlatformOsMap = map[string]string{
225 OS_ANDROID: "//build/bazel/platforms/os:android",
226 OS_DARWIN: "//build/bazel/platforms/os:darwin",
227 OS_FUCHSIA: "//build/bazel/platforms/os:fuchsia",
228 OS_LINUX: "//build/bazel/platforms/os:linux",
229 OS_LINUX_BIONIC: "//build/bazel/platforms/os:linux_bionic",
230 OS_WINDOWS: "//build/bazel/platforms/os:windows",
231 }
Jingwen Chen07027912021-03-15 06:02:43 -0400232)
233
Jingwen Chenc1c26502021-04-05 10:35:13 +0000234type Attribute interface {
235 HasConfigurableValues() bool
236}
237
Jingwen Chen07027912021-03-15 06:02:43 -0400238// Arch-specific label_list typed Bazel attribute values. This should correspond
239// to the types of architectures supported for compilation in arch.go.
240type labelListArchValues struct {
241 X86 LabelList
242 X86_64 LabelList
243 Arm LabelList
244 Arm64 LabelList
Jingwen Chen91220d72021-03-24 02:18:33 -0400245 Common LabelList
246}
247
248type labelListOsValues struct {
249 Android LabelList
250 Darwin LabelList
251 Fuchsia LabelList
252 Linux LabelList
253 LinuxBionic LabelList
254 Windows LabelList
Jingwen Chen07027912021-03-15 06:02:43 -0400255}
256
257// LabelListAttribute is used to represent a list of Bazel labels as an
258// attribute.
259type LabelListAttribute struct {
260 // The non-arch specific attribute label list Value. Required.
261 Value LabelList
262
263 // The arch-specific attribute label list values. Optional. If used, these
264 // are generated in a select statement and appended to the non-arch specific
265 // label list Value.
266 ArchValues labelListArchValues
Jingwen Chen91220d72021-03-24 02:18:33 -0400267
268 // The os-specific attribute label list values. Optional. If used, these
269 // are generated in a select statement and appended to the non-os specific
270 // label list Value.
271 OsValues labelListOsValues
Jingwen Chen07027912021-03-15 06:02:43 -0400272}
273
274// MakeLabelListAttribute initializes a LabelListAttribute with the non-arch specific value.
275func MakeLabelListAttribute(value LabelList) LabelListAttribute {
276 return LabelListAttribute{Value: UniqueBazelLabelList(value)}
277}
278
Jingwen Chen63930982021-03-24 10:04:33 -0400279// Append appends all values, including os and arch specific ones, from another
280// LabelListAttribute to this LabelListAttribute.
281func (attrs *LabelListAttribute) Append(other LabelListAttribute) {
282 for arch := range PlatformArchMap {
283 this := attrs.GetValueForArch(arch)
284 that := other.GetValueForArch(arch)
285 this.Append(that)
286 attrs.SetValueForArch(arch, this)
287 }
288
289 for os := range PlatformOsMap {
290 this := attrs.GetValueForOS(os)
291 that := other.GetValueForOS(os)
292 this.Append(that)
293 attrs.SetValueForOS(os, this)
294 }
295
296 attrs.Value.Append(other.Value)
297}
298
Jingwen Chen07027912021-03-15 06:02:43 -0400299// HasArchSpecificValues returns true if the attribute contains
300// architecture-specific label_list values.
Jingwen Chenc1c26502021-04-05 10:35:13 +0000301func (attrs LabelListAttribute) HasConfigurableValues() bool {
302 for arch := range PlatformArchMap {
Jingwen Chen91220d72021-03-24 02:18:33 -0400303 if len(attrs.GetValueForArch(arch).Includes) > 0 {
304 return true
305 }
306 }
307
Jingwen Chenc1c26502021-04-05 10:35:13 +0000308 for os := range PlatformOsMap {
Jingwen Chen91220d72021-03-24 02:18:33 -0400309 if len(attrs.GetValueForOS(os).Includes) > 0 {
Jingwen Chen07027912021-03-15 06:02:43 -0400310 return true
311 }
312 }
313 return false
314}
315
Jingwen Chen91220d72021-03-24 02:18:33 -0400316func (attrs *LabelListAttribute) archValuePtrs() map[string]*LabelList {
317 return map[string]*LabelList{
318 ARCH_X86: &attrs.ArchValues.X86,
319 ARCH_X86_64: &attrs.ArchValues.X86_64,
320 ARCH_ARM: &attrs.ArchValues.Arm,
321 ARCH_ARM64: &attrs.ArchValues.Arm64,
322 }
323}
324
Jingwen Chen07027912021-03-15 06:02:43 -0400325// GetValueForArch returns the label_list attribute value for an architecture.
326func (attrs *LabelListAttribute) GetValueForArch(arch string) LabelList {
Jingwen Chen91220d72021-03-24 02:18:33 -0400327 var v *LabelList
328 if v = attrs.archValuePtrs()[arch]; v == nil {
Jingwen Chen07027912021-03-15 06:02:43 -0400329 panic(fmt.Errorf("Unknown arch: %s", arch))
330 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400331 return *v
Jingwen Chen07027912021-03-15 06:02:43 -0400332}
333
334// SetValueForArch sets the label_list attribute value for an architecture.
335func (attrs *LabelListAttribute) SetValueForArch(arch string, value LabelList) {
Jingwen Chen91220d72021-03-24 02:18:33 -0400336 var v *LabelList
337 if v = attrs.archValuePtrs()[arch]; v == nil {
Jingwen Chen07027912021-03-15 06:02:43 -0400338 panic(fmt.Errorf("Unknown arch: %s", arch))
339 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400340 *v = value
341}
342
343func (attrs *LabelListAttribute) osValuePtrs() map[string]*LabelList {
344 return map[string]*LabelList{
345 OS_ANDROID: &attrs.OsValues.Android,
346 OS_DARWIN: &attrs.OsValues.Darwin,
347 OS_FUCHSIA: &attrs.OsValues.Fuchsia,
348 OS_LINUX: &attrs.OsValues.Linux,
349 OS_LINUX_BIONIC: &attrs.OsValues.LinuxBionic,
350 OS_WINDOWS: &attrs.OsValues.Windows,
351 }
352}
353
354// GetValueForOS returns the label_list attribute value for an OS target.
355func (attrs *LabelListAttribute) GetValueForOS(os string) LabelList {
356 var v *LabelList
357 if v = attrs.osValuePtrs()[os]; v == nil {
358 panic(fmt.Errorf("Unknown os: %s", os))
359 }
360 return *v
361}
362
363// SetValueForArch sets the label_list attribute value for an OS target.
364func (attrs *LabelListAttribute) SetValueForOS(os string, value LabelList) {
365 var v *LabelList
366 if v = attrs.osValuePtrs()[os]; v == nil {
367 panic(fmt.Errorf("Unknown os: %s", os))
368 }
369 *v = value
Jingwen Chen07027912021-03-15 06:02:43 -0400370}
371
Jingwen Chen5d864492021-02-24 07:20:12 -0500372// StringListAttribute corresponds to the string_list Bazel attribute type with
373// support for additional metadata, like configurations.
374type StringListAttribute struct {
375 // The base value of the string list attribute.
376 Value []string
377
Jingwen Chenc1c26502021-04-05 10:35:13 +0000378 // The arch-specific attribute string list values. Optional. If used, these
379 // are generated in a select statement and appended to the non-arch specific
380 // label list Value.
Jingwen Chen5d864492021-02-24 07:20:12 -0500381 ArchValues stringListArchValues
Jingwen Chenc1c26502021-04-05 10:35:13 +0000382
383 // The os-specific attribute string list values. Optional. If used, these
384 // are generated in a select statement and appended to the non-os specific
385 // label list Value.
386 OsValues stringListOsValues
Jingwen Chen5d864492021-02-24 07:20:12 -0500387}
388
Rupert Shuttleworthb8151682021-04-06 20:06:21 +0000389// MakeStringListAttribute initializes a StringListAttribute with the non-arch specific value.
390func MakeStringListAttribute(value []string) StringListAttribute {
391 // NOTE: These strings are not necessarily unique or sorted.
392 return StringListAttribute{Value: value}
393}
394
Jingwen Chen5d864492021-02-24 07:20:12 -0500395// Arch-specific string_list typed Bazel attribute values. This should correspond
396// to the types of architectures supported for compilation in arch.go.
397type stringListArchValues struct {
Jingwen Chen07027912021-03-15 06:02:43 -0400398 X86 []string
399 X86_64 []string
400 Arm []string
401 Arm64 []string
Jingwen Chen91220d72021-03-24 02:18:33 -0400402 Common []string
Jingwen Chen5d864492021-02-24 07:20:12 -0500403}
404
Jingwen Chenc1c26502021-04-05 10:35:13 +0000405type stringListOsValues struct {
406 Android []string
407 Darwin []string
408 Fuchsia []string
409 Linux []string
410 LinuxBionic []string
411 Windows []string
412}
413
Jingwen Chen91220d72021-03-24 02:18:33 -0400414// HasConfigurableValues returns true if the attribute contains
Jingwen Chen5d864492021-02-24 07:20:12 -0500415// architecture-specific string_list values.
Jingwen Chenc1c26502021-04-05 10:35:13 +0000416func (attrs StringListAttribute) HasConfigurableValues() bool {
417 for arch := range PlatformArchMap {
Jingwen Chen5d864492021-02-24 07:20:12 -0500418 if len(attrs.GetValueForArch(arch)) > 0 {
419 return true
420 }
421 }
Jingwen Chenc1c26502021-04-05 10:35:13 +0000422
423 for os := range PlatformOsMap {
424 if len(attrs.GetValueForOS(os)) > 0 {
425 return true
426 }
427 }
Jingwen Chen5d864492021-02-24 07:20:12 -0500428 return false
429}
430
Jingwen Chen91220d72021-03-24 02:18:33 -0400431func (attrs *StringListAttribute) archValuePtrs() map[string]*[]string {
432 return map[string]*[]string{
433 ARCH_X86: &attrs.ArchValues.X86,
434 ARCH_X86_64: &attrs.ArchValues.X86_64,
435 ARCH_ARM: &attrs.ArchValues.Arm,
436 ARCH_ARM64: &attrs.ArchValues.Arm64,
437 }
438}
439
Jingwen Chen5d864492021-02-24 07:20:12 -0500440// GetValueForArch returns the string_list attribute value for an architecture.
441func (attrs *StringListAttribute) GetValueForArch(arch string) []string {
Jingwen Chen91220d72021-03-24 02:18:33 -0400442 var v *[]string
443 if v = attrs.archValuePtrs()[arch]; v == nil {
Jingwen Chen5d864492021-02-24 07:20:12 -0500444 panic(fmt.Errorf("Unknown arch: %s", arch))
445 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400446 return *v
Jingwen Chen5d864492021-02-24 07:20:12 -0500447}
448
449// SetValueForArch sets the string_list attribute value for an architecture.
450func (attrs *StringListAttribute) SetValueForArch(arch string, value []string) {
Jingwen Chen91220d72021-03-24 02:18:33 -0400451 var v *[]string
452 if v = attrs.archValuePtrs()[arch]; v == nil {
Jingwen Chen5d864492021-02-24 07:20:12 -0500453 panic(fmt.Errorf("Unknown arch: %s", arch))
454 }
Jingwen Chen91220d72021-03-24 02:18:33 -0400455 *v = value
Jingwen Chen5d864492021-02-24 07:20:12 -0500456}
Liz Kammera060c452021-03-24 10:14:47 -0400457
Jingwen Chenc1c26502021-04-05 10:35:13 +0000458func (attrs *StringListAttribute) osValuePtrs() map[string]*[]string {
459 return map[string]*[]string{
460 OS_ANDROID: &attrs.OsValues.Android,
461 OS_DARWIN: &attrs.OsValues.Darwin,
462 OS_FUCHSIA: &attrs.OsValues.Fuchsia,
463 OS_LINUX: &attrs.OsValues.Linux,
464 OS_LINUX_BIONIC: &attrs.OsValues.LinuxBionic,
465 OS_WINDOWS: &attrs.OsValues.Windows,
466 }
467}
468
469// GetValueForOS returns the string_list attribute value for an OS target.
470func (attrs *StringListAttribute) GetValueForOS(os string) []string {
471 var v *[]string
472 if v = attrs.osValuePtrs()[os]; v == nil {
473 panic(fmt.Errorf("Unknown os: %s", os))
474 }
475 return *v
476}
477
478// SetValueForArch sets the string_list attribute value for an OS target.
479func (attrs *StringListAttribute) SetValueForOS(os string, value []string) {
480 var v *[]string
481 if v = attrs.osValuePtrs()[os]; v == nil {
482 panic(fmt.Errorf("Unknown os: %s", os))
483 }
484 *v = value
485}
486
Liz Kammera060c452021-03-24 10:14:47 -0400487// TryVariableSubstitution, replace string substitution formatting within each string in slice with
488// Starlark string.format compatible tag for productVariable.
489func TryVariableSubstitutions(slice []string, productVariable string) ([]string, bool) {
490 ret := make([]string, 0, len(slice))
491 changesMade := false
492 for _, s := range slice {
493 newS, changed := TryVariableSubstitution(s, productVariable)
494 ret = append(ret, newS)
495 changesMade = changesMade || changed
496 }
497 return ret, changesMade
498}
499
500// TryVariableSubstitution, replace string substitution formatting within s with Starlark
501// string.format compatible tag for productVariable.
502func TryVariableSubstitution(s string, productVariable string) (string, bool) {
503 sub := productVariableSubstitutionPattern.ReplaceAllString(s, "{"+productVariable+"}")
504 return sub, s != sub
505}