1// 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 17import ( 18 "fmt" 19 "path/filepath" 20 "regexp" 21 "sort" 22) 23 24// BazelTargetModuleProperties contain properties and metadata used for 25// Blueprint to BUILD file conversion. 26type BazelTargetModuleProperties struct { 27 // The Bazel rule class for this target. 28 Rule_class string `blueprint:"mutated"` 29 30 // The target label for the bzl file containing the definition of the rule class. 31 Bzl_load_location string `blueprint:"mutated"` 32} 33 34const BazelTargetModuleNamePrefix = "__bp2build__" 35 36var productVariableSubstitutionPattern = regexp.MustCompile("%(d|s)") 37 38// Label is used to represent a Bazel compatible Label. Also stores the original 39// bp text to support string replacement. 40type Label struct { 41 // The string representation of a Bazel target label. This can be a relative 42 // or fully qualified label. These labels are used for generating BUILD 43 // files with bp2build. 44 Label string 45 46 // The original Soong/Blueprint module name that the label was derived from. 47 // This is used for replacing references to the original name with the new 48 // label, for example in genrule cmds. 49 // 50 // While there is a reversible 1:1 mapping from the module name to Bazel 51 // label with bp2build that could make computing the original module name 52 // from the label automatic, it is not the case for handcrafted targets, 53 // where modules can have a custom label mapping through the { bazel_module: 54 // { label: <label> } } property. 55 // 56 // With handcrafted labels, those modules don't go through bp2build 57 // conversion, but relies on handcrafted targets in the source tree. 58 OriginalModuleName string 59} 60 61// LabelList is used to represent a list of Bazel labels. 62type LabelList struct { 63 Includes []Label 64 Excludes []Label 65} 66 67// uniqueParentDirectories returns a list of the unique parent directories for 68// all files in ll.Includes. 69func (ll *LabelList) uniqueParentDirectories() []string { 70 dirMap := map[string]bool{} 71 for _, label := range ll.Includes { 72 dirMap[filepath.Dir(label.Label)] = true 73 } 74 dirs := []string{} 75 for dir := range dirMap { 76 dirs = append(dirs, dir) 77 } 78 return dirs 79} 80 81// Append appends the fields of other labelList to the corresponding fields of ll. 82func (ll *LabelList) Append(other LabelList) { 83 if len(ll.Includes) > 0 || len(other.Includes) > 0 { 84 ll.Includes = append(ll.Includes, other.Includes...) 85 } 86 if len(ll.Excludes) > 0 || len(other.Excludes) > 0 { 87 ll.Excludes = append(other.Excludes, other.Excludes...) 88 } 89} 90 91// UniqueSortedBazelLabels takes a []Label and deduplicates the labels, and returns 92// the slice in a sorted order. 93func UniqueSortedBazelLabels(originalLabels []Label) []Label { 94 uniqueLabelsSet := make(map[Label]bool) 95 for _, l := range originalLabels { 96 uniqueLabelsSet[l] = true 97 } 98 var uniqueLabels []Label 99 for l, _ := range uniqueLabelsSet { 100 uniqueLabels = append(uniqueLabels, l) 101 } 102 sort.SliceStable(uniqueLabels, func(i, j int) bool { 103 return uniqueLabels[i].Label < uniqueLabels[j].Label 104 }) 105 return uniqueLabels 106} 107 108func UniqueBazelLabelList(originalLabelList LabelList) LabelList { 109 var uniqueLabelList LabelList 110 uniqueLabelList.Includes = UniqueSortedBazelLabels(originalLabelList.Includes) 111 uniqueLabelList.Excludes = UniqueSortedBazelLabels(originalLabelList.Excludes) 112 return uniqueLabelList 113} 114 115// Subtract needle from haystack 116func SubtractStrings(haystack []string, needle []string) []string { 117 // This is really a set 118 remainder := make(map[string]bool) 119 120 for _, s := range haystack { 121 remainder[s] = true 122 } 123 for _, s := range needle { 124 delete(remainder, s) 125 } 126 127 var strings []string 128 for s, _ := range remainder { 129 strings = append(strings, s) 130 } 131 132 sort.SliceStable(strings, func(i, j int) bool { 133 return strings[i] < strings[j] 134 }) 135 136 return strings 137} 138 139// Subtract needle from haystack 140func SubtractBazelLabels(haystack []Label, needle []Label) []Label { 141 // This is really a set 142 remainder := make(map[Label]bool) 143 144 for _, label := range haystack { 145 remainder[label] = true 146 } 147 for _, label := range needle { 148 delete(remainder, label) 149 } 150 151 var labels []Label 152 for label, _ := range remainder { 153 labels = append(labels, label) 154 } 155 156 sort.SliceStable(labels, func(i, j int) bool { 157 return labels[i].Label < labels[j].Label 158 }) 159 160 return labels 161} 162 163// Subtract needle from haystack 164func SubtractBazelLabelList(haystack LabelList, needle LabelList) LabelList { 165 var result LabelList 166 result.Includes = SubtractBazelLabels(haystack.Includes, needle.Includes) 167 // NOTE: Excludes are intentionally not subtracted 168 result.Excludes = haystack.Excludes 169 return result 170} 171 172const ( 173 // ArchType names in arch.go 174 ARCH_ARM = "arm" 175 ARCH_ARM64 = "arm64" 176 ARCH_X86 = "x86" 177 ARCH_X86_64 = "x86_64" 178 179 // OsType names in arch.go 180 OS_ANDROID = "android" 181 OS_DARWIN = "darwin" 182 OS_FUCHSIA = "fuchsia" 183 OS_LINUX = "linux_glibc" 184 OS_LINUX_BIONIC = "linux_bionic" 185 OS_WINDOWS = "windows" 186 187 // This is the string representation of the default condition wherever a 188 // configurable attribute is used in a select statement, i.e. 189 // //conditions:default for Bazel. 190 // 191 // This is consistently named "conditions_default" to mirror the Soong 192 // config variable default key in an Android.bp file, although there's no 193 // integration with Soong config variables (yet). 194 CONDITIONS_DEFAULT = "conditions_default" 195) 196 197var ( 198 // These are the list of OSes and architectures with a Bazel config_setting 199 // and constraint value equivalent. These exist in arch.go, but the android 200 // package depends on the bazel package, so a cyclic dependency prevents 201 // using those variables here. 202 203 // A map of architectures to the Bazel label of the constraint_value 204 // for the @platforms//cpu:cpu constraint_setting 205 PlatformArchMap = map[string]string{ 206 ARCH_ARM: "//build/bazel/platforms/arch:arm", 207 ARCH_ARM64: "//build/bazel/platforms/arch:arm64", 208 ARCH_X86: "//build/bazel/platforms/arch:x86", 209 ARCH_X86_64: "//build/bazel/platforms/arch:x86_64", 210 CONDITIONS_DEFAULT: "//conditions:default", // The default condition of as arch select map. 211 } 212 213 // A map of target operating systems to the Bazel label of the 214 // constraint_value for the @platforms//os:os constraint_setting 215 PlatformOsMap = map[string]string{ 216 OS_ANDROID: "//build/bazel/platforms/os:android", 217 OS_DARWIN: "//build/bazel/platforms/os:darwin", 218 OS_FUCHSIA: "//build/bazel/platforms/os:fuchsia", 219 OS_LINUX: "//build/bazel/platforms/os:linux", 220 OS_LINUX_BIONIC: "//build/bazel/platforms/os:linux_bionic", 221 OS_WINDOWS: "//build/bazel/platforms/os:windows", 222 CONDITIONS_DEFAULT: "//conditions:default", // The default condition of an os select map. 223 } 224) 225 226type Attribute interface { 227 HasConfigurableValues() bool 228} 229 230// Represents an attribute whose value is a single label 231type LabelAttribute struct { 232 Value Label 233 X86 Label 234 X86_64 Label 235 Arm Label 236 Arm64 Label 237} 238 239func (attr *LabelAttribute) GetValueForArch(arch string) Label { 240 switch arch { 241 case ARCH_ARM: 242 return attr.Arm 243 case ARCH_ARM64: 244 return attr.Arm64 245 case ARCH_X86: 246 return attr.X86 247 case ARCH_X86_64: 248 return attr.X86_64 249 case CONDITIONS_DEFAULT: 250 return attr.Value 251 default: 252 panic("Invalid arch type") 253 } 254} 255 256func (attr *LabelAttribute) SetValueForArch(arch string, value Label) { 257 switch arch { 258 case ARCH_ARM: 259 attr.Arm = value 260 case ARCH_ARM64: 261 attr.Arm64 = value 262 case ARCH_X86: 263 attr.X86 = value 264 case ARCH_X86_64: 265 attr.X86_64 = value 266 default: 267 panic("Invalid arch type") 268 } 269} 270 271func (attr LabelAttribute) HasConfigurableValues() bool { 272 return attr.Arm.Label != "" || attr.Arm64.Label != "" || attr.X86.Label != "" || attr.X86_64.Label != "" 273} 274 275// Arch-specific label_list typed Bazel attribute values. This should correspond 276// to the types of architectures supported for compilation in arch.go. 277type labelListArchValues struct { 278 X86 LabelList 279 X86_64 LabelList 280 Arm LabelList 281 Arm64 LabelList 282 Common LabelList 283 284 ConditionsDefault LabelList 285} 286 287type labelListOsValues struct { 288 Android LabelList 289 Darwin LabelList 290 Fuchsia LabelList 291 Linux LabelList 292 LinuxBionic LabelList 293 Windows LabelList 294 295 ConditionsDefault LabelList 296} 297 298// LabelListAttribute is used to represent a list of Bazel labels as an 299// attribute. 300type LabelListAttribute struct { 301 // The non-arch specific attribute label list Value. Required. 302 Value LabelList 303 304 // The arch-specific attribute label list values. Optional. If used, these 305 // are generated in a select statement and appended to the non-arch specific 306 // label list Value. 307 ArchValues labelListArchValues 308 309 // The os-specific attribute label list values. Optional. If used, these 310 // are generated in a select statement and appended to the non-os specific 311 // label list Value. 312 OsValues labelListOsValues 313} 314 315// MakeLabelListAttribute initializes a LabelListAttribute with the non-arch specific value. 316func MakeLabelListAttribute(value LabelList) LabelListAttribute { 317 return LabelListAttribute{Value: UniqueBazelLabelList(value)} 318} 319 320// Append all values, including os and arch specific ones, from another 321// LabelListAttribute to this LabelListAttribute. 322func (attrs *LabelListAttribute) Append(other LabelListAttribute) { 323 for arch := range PlatformArchMap { 324 this := attrs.GetValueForArch(arch) 325 that := other.GetValueForArch(arch) 326 this.Append(that) 327 attrs.SetValueForArch(arch, this) 328 } 329 330 for os := range PlatformOsMap { 331 this := attrs.GetValueForOS(os) 332 that := other.GetValueForOS(os) 333 this.Append(that) 334 attrs.SetValueForOS(os, this) 335 } 336 337 attrs.Value.Append(other.Value) 338} 339 340// HasArchSpecificValues returns true if the attribute contains 341// architecture-specific label_list values. 342func (attrs LabelListAttribute) HasConfigurableValues() bool { 343 for arch := range PlatformArchMap { 344 if len(attrs.GetValueForArch(arch).Includes) > 0 { 345 return true 346 } 347 } 348 349 for os := range PlatformOsMap { 350 if len(attrs.GetValueForOS(os).Includes) > 0 { 351 return true 352 } 353 } 354 return false 355} 356 357func (attrs *LabelListAttribute) archValuePtrs() map[string]*LabelList { 358 return map[string]*LabelList{ 359 ARCH_X86: &attrs.ArchValues.X86, 360 ARCH_X86_64: &attrs.ArchValues.X86_64, 361 ARCH_ARM: &attrs.ArchValues.Arm, 362 ARCH_ARM64: &attrs.ArchValues.Arm64, 363 CONDITIONS_DEFAULT: &attrs.ArchValues.ConditionsDefault, 364 } 365} 366 367// GetValueForArch returns the label_list attribute value for an architecture. 368func (attrs *LabelListAttribute) GetValueForArch(arch string) LabelList { 369 var v *LabelList 370 if v = attrs.archValuePtrs()[arch]; v == nil { 371 panic(fmt.Errorf("Unknown arch: %s", arch)) 372 } 373 return *v 374} 375 376// SetValueForArch sets the label_list attribute value for an architecture. 377func (attrs *LabelListAttribute) SetValueForArch(arch string, value LabelList) { 378 var v *LabelList 379 if v = attrs.archValuePtrs()[arch]; v == nil { 380 panic(fmt.Errorf("Unknown arch: %s", arch)) 381 } 382 *v = value 383} 384 385func (attrs *LabelListAttribute) osValuePtrs() map[string]*LabelList { 386 return map[string]*LabelList{ 387 OS_ANDROID: &attrs.OsValues.Android, 388 OS_DARWIN: &attrs.OsValues.Darwin, 389 OS_FUCHSIA: &attrs.OsValues.Fuchsia, 390 OS_LINUX: &attrs.OsValues.Linux, 391 OS_LINUX_BIONIC: &attrs.OsValues.LinuxBionic, 392 OS_WINDOWS: &attrs.OsValues.Windows, 393 CONDITIONS_DEFAULT: &attrs.OsValues.ConditionsDefault, 394 } 395} 396 397// GetValueForOS returns the label_list attribute value for an OS target. 398func (attrs *LabelListAttribute) GetValueForOS(os string) LabelList { 399 var v *LabelList 400 if v = attrs.osValuePtrs()[os]; v == nil { 401 panic(fmt.Errorf("Unknown os: %s", os)) 402 } 403 return *v 404} 405 406// SetValueForArch sets the label_list attribute value for an OS target. 407func (attrs *LabelListAttribute) SetValueForOS(os string, value LabelList) { 408 var v *LabelList 409 if v = attrs.osValuePtrs()[os]; v == nil { 410 panic(fmt.Errorf("Unknown os: %s", os)) 411 } 412 *v = value 413} 414 415// StringListAttribute corresponds to the string_list Bazel attribute type with 416// support for additional metadata, like configurations. 417type StringListAttribute struct { 418 // The base value of the string list attribute. 419 Value []string 420 421 // The arch-specific attribute string list values. Optional. If used, these 422 // are generated in a select statement and appended to the non-arch specific 423 // label list Value. 424 ArchValues stringListArchValues 425 426 // The os-specific attribute string list values. Optional. If used, these 427 // are generated in a select statement and appended to the non-os specific 428 // label list Value. 429 OsValues stringListOsValues 430} 431 432// MakeStringListAttribute initializes a StringListAttribute with the non-arch specific value. 433func MakeStringListAttribute(value []string) StringListAttribute { 434 // NOTE: These strings are not necessarily unique or sorted. 435 return StringListAttribute{Value: value} 436} 437 438// Arch-specific string_list typed Bazel attribute values. This should correspond 439// to the types of architectures supported for compilation in arch.go. 440type stringListArchValues struct { 441 X86 []string 442 X86_64 []string 443 Arm []string 444 Arm64 []string 445 Common []string 446 447 ConditionsDefault []string 448} 449 450type stringListOsValues struct { 451 Android []string 452 Darwin []string 453 Fuchsia []string 454 Linux []string 455 LinuxBionic []string 456 Windows []string 457 458 ConditionsDefault []string 459} 460 461// HasConfigurableValues returns true if the attribute contains 462// architecture-specific string_list values. 463func (attrs StringListAttribute) HasConfigurableValues() bool { 464 for arch := range PlatformArchMap { 465 if len(attrs.GetValueForArch(arch)) > 0 { 466 return true 467 } 468 } 469 470 for os := range PlatformOsMap { 471 if len(attrs.GetValueForOS(os)) > 0 { 472 return true 473 } 474 } 475 return false 476} 477 478func (attrs *StringListAttribute) archValuePtrs() map[string]*[]string { 479 return map[string]*[]string{ 480 ARCH_X86: &attrs.ArchValues.X86, 481 ARCH_X86_64: &attrs.ArchValues.X86_64, 482 ARCH_ARM: &attrs.ArchValues.Arm, 483 ARCH_ARM64: &attrs.ArchValues.Arm64, 484 CONDITIONS_DEFAULT: &attrs.ArchValues.ConditionsDefault, 485 } 486} 487 488// GetValueForArch returns the string_list attribute value for an architecture. 489func (attrs *StringListAttribute) GetValueForArch(arch string) []string { 490 var v *[]string 491 if v = attrs.archValuePtrs()[arch]; v == nil { 492 panic(fmt.Errorf("Unknown arch: %s", arch)) 493 } 494 return *v 495} 496 497// SetValueForArch sets the string_list attribute value for an architecture. 498func (attrs *StringListAttribute) SetValueForArch(arch string, value []string) { 499 var v *[]string 500 if v = attrs.archValuePtrs()[arch]; v == nil { 501 panic(fmt.Errorf("Unknown arch: %s", arch)) 502 } 503 *v = value 504} 505 506func (attrs *StringListAttribute) osValuePtrs() map[string]*[]string { 507 return map[string]*[]string{ 508 OS_ANDROID: &attrs.OsValues.Android, 509 OS_DARWIN: &attrs.OsValues.Darwin, 510 OS_FUCHSIA: &attrs.OsValues.Fuchsia, 511 OS_LINUX: &attrs.OsValues.Linux, 512 OS_LINUX_BIONIC: &attrs.OsValues.LinuxBionic, 513 OS_WINDOWS: &attrs.OsValues.Windows, 514 CONDITIONS_DEFAULT: &attrs.OsValues.ConditionsDefault, 515 } 516} 517 518// GetValueForOS returns the string_list attribute value for an OS target. 519func (attrs *StringListAttribute) GetValueForOS(os string) []string { 520 var v *[]string 521 if v = attrs.osValuePtrs()[os]; v == nil { 522 panic(fmt.Errorf("Unknown os: %s", os)) 523 } 524 return *v 525} 526 527// SetValueForArch sets the string_list attribute value for an OS target. 528func (attrs *StringListAttribute) SetValueForOS(os string, value []string) { 529 var v *[]string 530 if v = attrs.osValuePtrs()[os]; v == nil { 531 panic(fmt.Errorf("Unknown os: %s", os)) 532 } 533 *v = value 534} 535 536// Append appends all values, including os and arch specific ones, from another 537// StringListAttribute to this StringListAttribute 538func (attrs *StringListAttribute) Append(other StringListAttribute) { 539 for arch := range PlatformArchMap { 540 this := attrs.GetValueForArch(arch) 541 that := other.GetValueForArch(arch) 542 this = append(this, that...) 543 attrs.SetValueForArch(arch, this) 544 } 545 546 for os := range PlatformOsMap { 547 this := attrs.GetValueForOS(os) 548 that := other.GetValueForOS(os) 549 this = append(this, that...) 550 attrs.SetValueForOS(os, this) 551 } 552 553 attrs.Value = append(attrs.Value, other.Value...) 554} 555 556// TryVariableSubstitution, replace string substitution formatting within each string in slice with 557// Starlark string.format compatible tag for productVariable. 558func TryVariableSubstitutions(slice []string, productVariable string) ([]string, bool) { 559 ret := make([]string, 0, len(slice)) 560 changesMade := false 561 for _, s := range slice { 562 newS, changed := TryVariableSubstitution(s, productVariable) 563 ret = append(ret, newS) 564 changesMade = changesMade || changed 565 } 566 return ret, changesMade 567} 568 569// TryVariableSubstitution, replace string substitution formatting within s with Starlark 570// string.format compatible tag for productVariable. 571func TryVariableSubstitution(s string, productVariable string) (string, bool) { 572 sub := productVariableSubstitutionPattern.ReplaceAllString(s, "{"+productVariable+"}") 573 return sub, s != sub 574} 575