1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339 |
- // Copyright 2020 Google Inc. All rights reserved.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package bazel
- import (
- "fmt"
- "path/filepath"
- "regexp"
- "sort"
- "strings"
- "github.com/google/blueprint"
- )
- // BazelTargetModuleProperties contain properties and metadata used for
- // Blueprint to BUILD file conversion.
- type BazelTargetModuleProperties struct {
- // The Bazel rule class for this target.
- Rule_class string `blueprint:"mutated"`
- // The target label for the bzl file containing the definition of the rule class.
- Bzl_load_location string `blueprint:"mutated"`
- }
- var productVariableSubstitutionPattern = regexp.MustCompile("%(d|s)")
- // Label is used to represent a Bazel compatible Label. Also stores the original
- // bp text to support string replacement.
- type Label struct {
- // The string representation of a Bazel target label. This can be a relative
- // or fully qualified label. These labels are used for generating BUILD
- // files with bp2build.
- Label string
- // The original Soong/Blueprint module name that the label was derived from.
- // This is used for replacing references to the original name with the new
- // label, for example in genrule cmds.
- //
- // While there is a reversible 1:1 mapping from the module name to Bazel
- // label with bp2build that could make computing the original module name
- // from the label automatic, it is not the case for handcrafted targets,
- // where modules can have a custom label mapping through the { bazel_module:
- // { label: <label> } } property.
- //
- // With handcrafted labels, those modules don't go through bp2build
- // conversion, but relies on handcrafted targets in the source tree.
- OriginalModuleName string
- }
- // LabelList is used to represent a list of Bazel labels.
- type LabelList struct {
- Includes []Label
- Excludes []Label
- }
- // MakeLabelList creates a LabelList from a list Label
- func MakeLabelList(labels []Label) LabelList {
- return LabelList{
- Includes: labels,
- Excludes: nil,
- }
- }
- func (ll *LabelList) Equals(other LabelList) bool {
- if len(ll.Includes) != len(other.Includes) || len(ll.Excludes) != len(other.Excludes) {
- return false
- }
- for i, _ := range ll.Includes {
- if ll.Includes[i] != other.Includes[i] {
- return false
- }
- }
- for i, _ := range ll.Excludes {
- if ll.Excludes[i] != other.Excludes[i] {
- return false
- }
- }
- return true
- }
- func (ll *LabelList) IsNil() bool {
- return ll.Includes == nil && ll.Excludes == nil
- }
- func (ll *LabelList) IsEmpty() bool {
- return len(ll.Includes) == 0 && len(ll.Excludes) == 0
- }
- func (ll *LabelList) deepCopy() LabelList {
- return LabelList{
- Includes: ll.Includes[:],
- Excludes: ll.Excludes[:],
- }
- }
- // uniqueParentDirectories returns a list of the unique parent directories for
- // all files in ll.Includes.
- func (ll *LabelList) uniqueParentDirectories() []string {
- dirMap := map[string]bool{}
- for _, label := range ll.Includes {
- dirMap[filepath.Dir(label.Label)] = true
- }
- dirs := []string{}
- for dir := range dirMap {
- dirs = append(dirs, dir)
- }
- return dirs
- }
- // Add inserts the label Label at the end of the LabelList.Includes.
- func (ll *LabelList) Add(label *Label) {
- if label == nil {
- return
- }
- ll.Includes = append(ll.Includes, *label)
- }
- // AddExclude inserts the label Label at the end of the LabelList.Excludes.
- func (ll *LabelList) AddExclude(label *Label) {
- if label == nil {
- return
- }
- ll.Excludes = append(ll.Excludes, *label)
- }
- // Append appends the fields of other labelList to the corresponding fields of ll.
- func (ll *LabelList) Append(other LabelList) {
- if len(ll.Includes) > 0 || len(other.Includes) > 0 {
- ll.Includes = append(ll.Includes, other.Includes...)
- }
- if len(ll.Excludes) > 0 || len(other.Excludes) > 0 {
- ll.Excludes = append(other.Excludes, other.Excludes...)
- }
- }
- // Partition splits a LabelList into two LabelLists depending on the return value
- // of the predicate.
- // This function preserves the Includes and Excludes, but it does not provide
- // that information to the partition function.
- func (ll *LabelList) Partition(predicate func(label Label) bool) (LabelList, LabelList) {
- predicated := LabelList{}
- unpredicated := LabelList{}
- for _, include := range ll.Includes {
- if predicate(include) {
- predicated.Add(&include)
- } else {
- unpredicated.Add(&include)
- }
- }
- for _, exclude := range ll.Excludes {
- if predicate(exclude) {
- predicated.AddExclude(&exclude)
- } else {
- unpredicated.AddExclude(&exclude)
- }
- }
- return predicated, unpredicated
- }
- // UniqueSortedBazelLabels takes a []Label and deduplicates the labels, and returns
- // the slice in a sorted order.
- func UniqueSortedBazelLabels(originalLabels []Label) []Label {
- uniqueLabelsSet := make(map[Label]bool)
- for _, l := range originalLabels {
- uniqueLabelsSet[l] = true
- }
- var uniqueLabels []Label
- for l, _ := range uniqueLabelsSet {
- uniqueLabels = append(uniqueLabels, l)
- }
- sort.SliceStable(uniqueLabels, func(i, j int) bool {
- return uniqueLabels[i].Label < uniqueLabels[j].Label
- })
- return uniqueLabels
- }
- func FirstUniqueBazelLabels(originalLabels []Label) []Label {
- var labels []Label
- found := make(map[Label]bool, len(originalLabels))
- for _, l := range originalLabels {
- if _, ok := found[l]; ok {
- continue
- }
- labels = append(labels, l)
- found[l] = true
- }
- return labels
- }
- func FirstUniqueBazelLabelList(originalLabelList LabelList) LabelList {
- var uniqueLabelList LabelList
- uniqueLabelList.Includes = FirstUniqueBazelLabels(originalLabelList.Includes)
- uniqueLabelList.Excludes = FirstUniqueBazelLabels(originalLabelList.Excludes)
- return uniqueLabelList
- }
- func UniqueSortedBazelLabelList(originalLabelList LabelList) LabelList {
- var uniqueLabelList LabelList
- uniqueLabelList.Includes = UniqueSortedBazelLabels(originalLabelList.Includes)
- uniqueLabelList.Excludes = UniqueSortedBazelLabels(originalLabelList.Excludes)
- return uniqueLabelList
- }
- // Subtract needle from haystack
- func SubtractStrings(haystack []string, needle []string) []string {
- // This is really a set
- needleMap := make(map[string]bool)
- for _, s := range needle {
- needleMap[s] = true
- }
- var strings []string
- for _, s := range haystack {
- if exclude := needleMap[s]; !exclude {
- strings = append(strings, s)
- }
- }
- return strings
- }
- // Subtract needle from haystack
- func SubtractBazelLabels(haystack []Label, needle []Label) []Label {
- // This is really a set
- needleMap := make(map[Label]bool)
- for _, s := range needle {
- needleMap[s] = true
- }
- var labels []Label
- for _, label := range haystack {
- if exclude := needleMap[label]; !exclude {
- labels = append(labels, label)
- }
- }
- return labels
- }
- // Appends two LabelLists, returning the combined list.
- func AppendBazelLabelLists(a LabelList, b LabelList) LabelList {
- var result LabelList
- result.Includes = append(a.Includes, b.Includes...)
- result.Excludes = append(a.Excludes, b.Excludes...)
- return result
- }
- // Subtract needle from haystack
- func SubtractBazelLabelList(haystack LabelList, needle LabelList) LabelList {
- var result LabelList
- result.Includes = SubtractBazelLabels(haystack.Includes, needle.Includes)
- // NOTE: Excludes are intentionally not subtracted
- result.Excludes = haystack.Excludes
- return result
- }
- type Attribute interface {
- HasConfigurableValues() bool
- }
- type labelSelectValues map[string]*Label
- type configurableLabels map[ConfigurationAxis]labelSelectValues
- func (cl configurableLabels) setValueForAxis(axis ConfigurationAxis, config string, value *Label) {
- if cl[axis] == nil {
- cl[axis] = make(labelSelectValues)
- }
- cl[axis][config] = value
- }
- // Represents an attribute whose value is a single label
- type LabelAttribute struct {
- Value *Label
- ConfigurableValues configurableLabels
- }
- func (la *LabelAttribute) axisTypes() map[configurationType]bool {
- types := map[configurationType]bool{}
- for k := range la.ConfigurableValues {
- if len(la.ConfigurableValues[k]) > 0 {
- types[k.configurationType] = true
- }
- }
- return types
- }
- // Collapse reduces the configurable axes of the label attribute to a single axis.
- // This is necessary for final writing to bp2build, as a configurable label
- // attribute can only be comprised by a single select.
- func (la *LabelAttribute) Collapse() error {
- axisTypes := la.axisTypes()
- _, containsOs := axisTypes[os]
- _, containsArch := axisTypes[arch]
- _, containsOsArch := axisTypes[osArch]
- _, containsProductVariables := axisTypes[productVariables]
- if containsProductVariables {
- if containsOs || containsArch || containsOsArch {
- if containsArch {
- allProductVariablesAreArchVariant := true
- for k := range la.ConfigurableValues {
- if k.configurationType == productVariables && k.outerAxisType != arch {
- allProductVariablesAreArchVariant = false
- }
- }
- if !allProductVariablesAreArchVariant {
- return fmt.Errorf("label attribute could not be collapsed as it has two or more unrelated axes")
- }
- } else {
- return fmt.Errorf("label attribute could not be collapsed as it has two or more unrelated axes")
- }
- }
- }
- if (containsOs && containsArch) || (containsOsArch && (containsOs || containsArch)) {
- // If a bool attribute has both os and arch configuration axes, the only
- // way to successfully union their values is to increase the granularity
- // of the configuration criteria to os_arch.
- for osType, supportedArchs := range osToArchMap {
- for _, supportedArch := range supportedArchs {
- osArch := osArchString(osType, supportedArch)
- if archOsVal := la.SelectValue(OsArchConfigurationAxis, osArch); archOsVal != nil {
- // Do nothing, as the arch_os is explicitly defined already.
- } else {
- archVal := la.SelectValue(ArchConfigurationAxis, supportedArch)
- osVal := la.SelectValue(OsConfigurationAxis, osType)
- if osVal != nil && archVal != nil {
- // In this case, arch takes precedence. (This fits legacy Soong behavior, as arch mutator
- // runs after os mutator.
- la.SetSelectValue(OsArchConfigurationAxis, osArch, *archVal)
- } else if osVal != nil && archVal == nil {
- la.SetSelectValue(OsArchConfigurationAxis, osArch, *osVal)
- } else if osVal == nil && archVal != nil {
- la.SetSelectValue(OsArchConfigurationAxis, osArch, *archVal)
- }
- }
- }
- }
- // All os_arch values are now set. Clear os and arch axes.
- delete(la.ConfigurableValues, ArchConfigurationAxis)
- delete(la.ConfigurableValues, OsConfigurationAxis)
- }
- return nil
- }
- // HasConfigurableValues returns whether there are configurable values set for this label.
- func (la LabelAttribute) HasConfigurableValues() bool {
- for _, selectValues := range la.ConfigurableValues {
- if len(selectValues) > 0 {
- return true
- }
- }
- return false
- }
- // SetValue sets the base, non-configured value for the Label
- func (la *LabelAttribute) SetValue(value Label) {
- la.SetSelectValue(NoConfigAxis, "", value)
- }
- // SetSelectValue set a value for a bazel select for the given axis, config and value.
- func (la *LabelAttribute) SetSelectValue(axis ConfigurationAxis, config string, value Label) {
- axis.validateConfig(config)
- switch axis.configurationType {
- case noConfig:
- la.Value = &value
- case arch, os, osArch, productVariables, osAndInApex:
- if la.ConfigurableValues == nil {
- la.ConfigurableValues = make(configurableLabels)
- }
- la.ConfigurableValues.setValueForAxis(axis, config, &value)
- default:
- panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
- }
- }
- // SelectValue gets a value for a bazel select for the given axis and config.
- func (la *LabelAttribute) SelectValue(axis ConfigurationAxis, config string) *Label {
- axis.validateConfig(config)
- switch axis.configurationType {
- case noConfig:
- return la.Value
- case arch, os, osArch, productVariables, osAndInApex:
- return la.ConfigurableValues[axis][config]
- default:
- panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
- }
- }
- // SortedConfigurationAxes returns all the used ConfigurationAxis in sorted order.
- func (la *LabelAttribute) SortedConfigurationAxes() []ConfigurationAxis {
- keys := make([]ConfigurationAxis, 0, len(la.ConfigurableValues))
- for k := range la.ConfigurableValues {
- keys = append(keys, k)
- }
- sort.Slice(keys, func(i, j int) bool { return keys[i].less(keys[j]) })
- return keys
- }
- // MakeLabelAttribute turns a string into a LabelAttribute
- func MakeLabelAttribute(label string) *LabelAttribute {
- return &LabelAttribute{
- Value: &Label{
- Label: label,
- },
- }
- }
- type configToBools map[string]bool
- func (ctb configToBools) setValue(config string, value *bool) {
- if value == nil {
- if _, ok := ctb[config]; ok {
- delete(ctb, config)
- }
- return
- }
- ctb[config] = *value
- }
- type configurableBools map[ConfigurationAxis]configToBools
- func (cb configurableBools) setValueForAxis(axis ConfigurationAxis, config string, value *bool) {
- if cb[axis] == nil {
- cb[axis] = make(configToBools)
- }
- cb[axis].setValue(config, value)
- }
- // BoolAttribute represents an attribute whose value is a single bool but may be configurable..
- type BoolAttribute struct {
- Value *bool
- ConfigurableValues configurableBools
- }
- // HasConfigurableValues returns whether there are configurable values for this attribute.
- func (ba BoolAttribute) HasConfigurableValues() bool {
- for _, cfgToBools := range ba.ConfigurableValues {
- if len(cfgToBools) > 0 {
- return true
- }
- }
- return false
- }
- // SetValue sets value for the no config axis
- func (ba *BoolAttribute) SetValue(value *bool) {
- ba.SetSelectValue(NoConfigAxis, "", value)
- }
- // SetSelectValue sets value for the given axis/config.
- func (ba *BoolAttribute) SetSelectValue(axis ConfigurationAxis, config string, value *bool) {
- axis.validateConfig(config)
- switch axis.configurationType {
- case noConfig:
- ba.Value = value
- case arch, os, osArch, productVariables, osAndInApex:
- if ba.ConfigurableValues == nil {
- ba.ConfigurableValues = make(configurableBools)
- }
- ba.ConfigurableValues.setValueForAxis(axis, config, value)
- default:
- panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
- }
- }
- // ToLabelListAttribute creates and returns a LabelListAttribute from this
- // bool attribute, where each bool in this attribute corresponds to a
- // label list value in the resultant attribute.
- func (ba *BoolAttribute) ToLabelListAttribute(falseVal LabelList, trueVal LabelList) (LabelListAttribute, error) {
- getLabelList := func(boolPtr *bool) LabelList {
- if boolPtr == nil {
- return LabelList{nil, nil}
- } else if *boolPtr {
- return trueVal
- } else {
- return falseVal
- }
- }
- mainVal := getLabelList(ba.Value)
- if !ba.HasConfigurableValues() {
- return MakeLabelListAttribute(mainVal), nil
- }
- result := LabelListAttribute{}
- if err := ba.Collapse(); err != nil {
- return result, err
- }
- for axis, configToBools := range ba.ConfigurableValues {
- if len(configToBools) < 1 {
- continue
- }
- for config, boolPtr := range configToBools {
- val := getLabelList(&boolPtr)
- if !val.Equals(mainVal) {
- result.SetSelectValue(axis, config, val)
- }
- }
- result.SetSelectValue(axis, ConditionsDefaultConfigKey, mainVal)
- }
- return result, nil
- }
- // Collapse reduces the configurable axes of the boolean attribute to a single axis.
- // This is necessary for final writing to bp2build, as a configurable boolean
- // attribute can only be comprised by a single select.
- func (ba *BoolAttribute) Collapse() error {
- axisTypes := ba.axisTypes()
- _, containsOs := axisTypes[os]
- _, containsArch := axisTypes[arch]
- _, containsOsArch := axisTypes[osArch]
- _, containsProductVariables := axisTypes[productVariables]
- if containsProductVariables {
- if containsOs || containsArch || containsOsArch {
- return fmt.Errorf("boolean attribute could not be collapsed as it has two or more unrelated axes")
- }
- }
- if (containsOs && containsArch) || (containsOsArch && (containsOs || containsArch)) {
- // If a bool attribute has both os and arch configuration axes, the only
- // way to successfully union their values is to increase the granularity
- // of the configuration criteria to os_arch.
- for osType, supportedArchs := range osToArchMap {
- for _, supportedArch := range supportedArchs {
- osArch := osArchString(osType, supportedArch)
- if archOsVal := ba.SelectValue(OsArchConfigurationAxis, osArch); archOsVal != nil {
- // Do nothing, as the arch_os is explicitly defined already.
- } else {
- archVal := ba.SelectValue(ArchConfigurationAxis, supportedArch)
- osVal := ba.SelectValue(OsConfigurationAxis, osType)
- if osVal != nil && archVal != nil {
- // In this case, arch takes precedence. (This fits legacy Soong behavior, as arch mutator
- // runs after os mutator.
- ba.SetSelectValue(OsArchConfigurationAxis, osArch, archVal)
- } else if osVal != nil && archVal == nil {
- ba.SetSelectValue(OsArchConfigurationAxis, osArch, osVal)
- } else if osVal == nil && archVal != nil {
- ba.SetSelectValue(OsArchConfigurationAxis, osArch, archVal)
- }
- }
- }
- }
- // All os_arch values are now set. Clear os and arch axes.
- delete(ba.ConfigurableValues, ArchConfigurationAxis)
- delete(ba.ConfigurableValues, OsConfigurationAxis)
- // Verify post-condition; this should never fail, provided no additional
- // axes are introduced.
- if len(ba.ConfigurableValues) > 1 {
- panic(fmt.Errorf("error in collapsing attribute: %#v", ba))
- }
- }
- return nil
- }
- func (ba *BoolAttribute) axisTypes() map[configurationType]bool {
- types := map[configurationType]bool{}
- for k := range ba.ConfigurableValues {
- if len(ba.ConfigurableValues[k]) > 0 {
- types[k.configurationType] = true
- }
- }
- return types
- }
- // SelectValue gets the value for the given axis/config.
- func (ba BoolAttribute) SelectValue(axis ConfigurationAxis, config string) *bool {
- axis.validateConfig(config)
- switch axis.configurationType {
- case noConfig:
- return ba.Value
- case arch, os, osArch, productVariables, osAndInApex:
- if v, ok := ba.ConfigurableValues[axis][config]; ok {
- return &v
- } else {
- return nil
- }
- default:
- panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
- }
- }
- // SortedConfigurationAxes returns all the used ConfigurationAxis in sorted order.
- func (ba *BoolAttribute) SortedConfigurationAxes() []ConfigurationAxis {
- keys := make([]ConfigurationAxis, 0, len(ba.ConfigurableValues))
- for k := range ba.ConfigurableValues {
- keys = append(keys, k)
- }
- sort.Slice(keys, func(i, j int) bool { return keys[i].less(keys[j]) })
- return keys
- }
- // labelListSelectValues supports config-specific label_list typed Bazel attribute values.
- type labelListSelectValues map[string]LabelList
- func (ll labelListSelectValues) addSelects(label labelSelectValues) {
- for k, v := range label {
- if label == nil {
- continue
- }
- l := ll[k]
- (&l).Add(v)
- ll[k] = l
- }
- }
- func (ll labelListSelectValues) appendSelects(other labelListSelectValues, forceSpecifyEmptyList bool) {
- for k, v := range other {
- l := ll[k]
- if forceSpecifyEmptyList && l.IsNil() && !v.IsNil() {
- l.Includes = []Label{}
- }
- (&l).Append(v)
- ll[k] = l
- }
- }
- // HasConfigurableValues returns whether there are configurable values within this set of selects.
- func (ll labelListSelectValues) HasConfigurableValues() bool {
- for _, v := range ll {
- if v.Includes != nil {
- return true
- }
- }
- return false
- }
- // LabelListAttribute is used to represent a list of Bazel labels as an
- // attribute.
- type LabelListAttribute struct {
- // The non-configured attribute label list Value. Required.
- Value LabelList
- // The configured attribute label list Values. Optional
- // a map of independent configurability axes
- ConfigurableValues configurableLabelLists
- // If true, differentiate between "nil" and "empty" list. nil means that
- // this attribute should not be specified at all, and "empty" means that
- // the attribute should be explicitly specified as an empty list.
- // This mode facilitates use of attribute defaults: an empty list should
- // override the default.
- ForceSpecifyEmptyList bool
- // If true, signal the intent to the code generator to emit all select keys,
- // even if the Includes list for that key is empty. This mode facilitates
- // specific select statements where an empty list for a non-default select
- // key has a meaning.
- EmitEmptyList bool
- }
- type configurableLabelLists map[ConfigurationAxis]labelListSelectValues
- func (cll configurableLabelLists) setValueForAxis(axis ConfigurationAxis, config string, list LabelList) {
- if list.IsNil() {
- if _, ok := cll[axis][config]; ok {
- delete(cll[axis], config)
- }
- return
- }
- if cll[axis] == nil {
- cll[axis] = make(labelListSelectValues)
- }
- cll[axis][config] = list
- }
- func (cll configurableLabelLists) Append(other configurableLabelLists, forceSpecifyEmptyList bool) {
- for axis, otherSelects := range other {
- selects := cll[axis]
- if selects == nil {
- selects = make(labelListSelectValues, len(otherSelects))
- }
- selects.appendSelects(otherSelects, forceSpecifyEmptyList)
- cll[axis] = selects
- }
- }
- func (lla *LabelListAttribute) Clone() *LabelListAttribute {
- result := &LabelListAttribute{ForceSpecifyEmptyList: lla.ForceSpecifyEmptyList}
- return result.Append(*lla)
- }
- // MakeLabelListAttribute initializes a LabelListAttribute with the non-arch specific value.
- func MakeLabelListAttribute(value LabelList) LabelListAttribute {
- return LabelListAttribute{
- Value: value,
- ConfigurableValues: make(configurableLabelLists),
- }
- }
- // MakeSingleLabelListAttribute initializes a LabelListAttribute as a non-arch specific list with 1 element, the given Label.
- func MakeSingleLabelListAttribute(value Label) LabelListAttribute {
- return MakeLabelListAttribute(MakeLabelList([]Label{value}))
- }
- func (lla *LabelListAttribute) SetValue(list LabelList) {
- lla.SetSelectValue(NoConfigAxis, "", list)
- }
- // SetSelectValue set a value for a bazel select for the given axis, config and value.
- func (lla *LabelListAttribute) SetSelectValue(axis ConfigurationAxis, config string, list LabelList) {
- axis.validateConfig(config)
- switch axis.configurationType {
- case noConfig:
- lla.Value = list
- case arch, os, osArch, productVariables, osAndInApex:
- if lla.ConfigurableValues == nil {
- lla.ConfigurableValues = make(configurableLabelLists)
- }
- lla.ConfigurableValues.setValueForAxis(axis, config, list)
- default:
- panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
- }
- }
- // SelectValue gets a value for a bazel select for the given axis and config.
- func (lla *LabelListAttribute) SelectValue(axis ConfigurationAxis, config string) LabelList {
- axis.validateConfig(config)
- switch axis.configurationType {
- case noConfig:
- return lla.Value
- case arch, os, osArch, productVariables, osAndInApex:
- return lla.ConfigurableValues[axis][config]
- default:
- panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
- }
- }
- // SortedConfigurationAxes returns all the used ConfigurationAxis in sorted order.
- func (lla *LabelListAttribute) SortedConfigurationAxes() []ConfigurationAxis {
- keys := make([]ConfigurationAxis, 0, len(lla.ConfigurableValues))
- for k := range lla.ConfigurableValues {
- keys = append(keys, k)
- }
- sort.Slice(keys, func(i, j int) bool { return keys[i].less(keys[j]) })
- return keys
- }
- // Append all values, including os and arch specific ones, from another
- // LabelListAttribute to this LabelListAttribute. Returns this LabelListAttribute.
- func (lla *LabelListAttribute) Append(other LabelListAttribute) *LabelListAttribute {
- forceSpecifyEmptyList := lla.ForceSpecifyEmptyList || other.ForceSpecifyEmptyList
- if forceSpecifyEmptyList && lla.Value.IsNil() && !other.Value.IsNil() {
- lla.Value.Includes = []Label{}
- }
- lla.Value.Append(other.Value)
- if lla.ConfigurableValues == nil {
- lla.ConfigurableValues = make(configurableLabelLists)
- }
- lla.ConfigurableValues.Append(other.ConfigurableValues, forceSpecifyEmptyList)
- return lla
- }
- // Add inserts the labels for each axis of LabelAttribute at the end of corresponding axis's
- // LabelList within the LabelListAttribute
- func (lla *LabelListAttribute) Add(label *LabelAttribute) {
- if label == nil {
- return
- }
- lla.Value.Add(label.Value)
- if lla.ConfigurableValues == nil && label.ConfigurableValues != nil {
- lla.ConfigurableValues = make(configurableLabelLists)
- }
- for axis, _ := range label.ConfigurableValues {
- if _, exists := lla.ConfigurableValues[axis]; !exists {
- lla.ConfigurableValues[axis] = make(labelListSelectValues)
- }
- lla.ConfigurableValues[axis].addSelects(label.ConfigurableValues[axis])
- }
- }
- // HasConfigurableValues returns true if the attribute contains axis-specific label list values.
- func (lla LabelListAttribute) HasConfigurableValues() bool {
- for _, selectValues := range lla.ConfigurableValues {
- if len(selectValues) > 0 {
- return true
- }
- }
- return false
- }
- // IsEmpty returns true if the attribute has no values under any configuration.
- func (lla LabelListAttribute) IsEmpty() bool {
- if len(lla.Value.Includes) > 0 {
- return false
- }
- for axis, _ := range lla.ConfigurableValues {
- if lla.ConfigurableValues[axis].HasConfigurableValues() {
- return false
- }
- }
- return true
- }
- // IsNil returns true if the attribute has not been set for any configuration.
- func (lla LabelListAttribute) IsNil() bool {
- if lla.Value.Includes != nil {
- return false
- }
- return !lla.HasConfigurableValues()
- }
- // Exclude for the given axis, config, removes Includes in labelList from Includes and appends them
- // to Excludes. This is to special case any excludes that are not specified in a bp file but need to
- // be removed, e.g. if they could cause duplicate element failures.
- func (lla *LabelListAttribute) Exclude(axis ConfigurationAxis, config string, labelList LabelList) {
- val := lla.SelectValue(axis, config)
- newList := SubtractBazelLabelList(val, labelList)
- newList.Excludes = append(newList.Excludes, labelList.Includes...)
- lla.SetSelectValue(axis, config, newList)
- }
- // ResolveExcludes handles excludes across the various axes, ensuring that items are removed from
- // the base value and included in default values as appropriate.
- func (lla *LabelListAttribute) ResolveExcludes() {
- for axis, configToLabels := range lla.ConfigurableValues {
- baseLabels := lla.Value.deepCopy()
- for config, val := range configToLabels {
- // Exclude config-specific excludes from base value
- lla.Value = SubtractBazelLabelList(lla.Value, LabelList{Includes: val.Excludes})
- // add base values to config specific to add labels excluded by others in this axis
- // then remove all config-specific excludes
- allLabels := baseLabels.deepCopy()
- allLabels.Append(val)
- lla.ConfigurableValues[axis][config] = SubtractBazelLabelList(allLabels, LabelList{Includes: val.Excludes})
- }
- // After going through all configs, delete the duplicates in the config
- // values that are already in the base Value.
- for config, val := range configToLabels {
- lla.ConfigurableValues[axis][config] = SubtractBazelLabelList(val, lla.Value)
- }
- // Now that the Value list is finalized for this axis, compare it with
- // the original list, and union the difference with the default
- // condition for the axis.
- difference := SubtractBazelLabelList(baseLabels, lla.Value)
- existingDefaults := lla.ConfigurableValues[axis][ConditionsDefaultConfigKey]
- existingDefaults.Append(difference)
- lla.ConfigurableValues[axis][ConditionsDefaultConfigKey] = FirstUniqueBazelLabelList(existingDefaults)
- // if everything ends up without includes, just delete the axis
- if !lla.ConfigurableValues[axis].HasConfigurableValues() {
- delete(lla.ConfigurableValues, axis)
- }
- }
- }
- // Partition splits a LabelListAttribute into two LabelListAttributes depending
- // on the return value of the predicate.
- // This function preserves the Includes and Excludes, but it does not provide
- // that information to the partition function.
- func (lla LabelListAttribute) Partition(predicate func(label Label) bool) (LabelListAttribute, LabelListAttribute) {
- predicated := LabelListAttribute{}
- unpredicated := LabelListAttribute{}
- valuePartitionTrue, valuePartitionFalse := lla.Value.Partition(predicate)
- predicated.SetValue(valuePartitionTrue)
- unpredicated.SetValue(valuePartitionFalse)
- for axis, selectValueLabelLists := range lla.ConfigurableValues {
- for config, labelList := range selectValueLabelLists {
- configPredicated, configUnpredicated := labelList.Partition(predicate)
- predicated.SetSelectValue(axis, config, configPredicated)
- unpredicated.SetSelectValue(axis, config, configUnpredicated)
- }
- }
- return predicated, unpredicated
- }
- // OtherModuleContext is a limited context that has methods with information about other modules.
- type OtherModuleContext interface {
- ModuleFromName(name string) (blueprint.Module, bool)
- OtherModuleType(m blueprint.Module) string
- OtherModuleName(m blueprint.Module) string
- OtherModuleDir(m blueprint.Module) string
- ModuleErrorf(fmt string, args ...interface{})
- }
- // LabelMapper is a function that takes a OtherModuleContext and returns a (potentially changed)
- // label and whether it was changed.
- type LabelMapper func(OtherModuleContext, Label) (string, bool)
- // LabelPartition contains descriptions of a partition for labels
- type LabelPartition struct {
- // Extensions to include in this partition
- Extensions []string
- // LabelMapper is a function that can map a label to a new label, and indicate whether to include
- // the mapped label in the partition
- LabelMapper LabelMapper
- // Whether to store files not included in any other partition in a group of LabelPartitions
- // Only one partition in a group of LabelPartitions can enabled Keep_remainder
- Keep_remainder bool
- }
- // LabelPartitions is a map of partition name to a LabelPartition describing the elements of the
- // partition
- type LabelPartitions map[string]LabelPartition
- // filter returns a pointer to a label if the label should be included in the partition or nil if
- // not.
- func (lf LabelPartition) filter(ctx OtherModuleContext, label Label) *Label {
- if lf.LabelMapper != nil {
- if newLabel, changed := lf.LabelMapper(ctx, label); changed {
- return &Label{newLabel, label.OriginalModuleName}
- }
- }
- for _, ext := range lf.Extensions {
- if strings.HasSuffix(label.Label, ext) {
- return &label
- }
- }
- return nil
- }
- // PartitionToLabelListAttribute is map of partition name to a LabelListAttribute
- type PartitionToLabelListAttribute map[string]LabelListAttribute
- type partitionToLabelList map[string]*LabelList
- func (p partitionToLabelList) appendIncludes(partition string, label Label) {
- if _, ok := p[partition]; !ok {
- p[partition] = &LabelList{}
- }
- p[partition].Includes = append(p[partition].Includes, label)
- }
- func (p partitionToLabelList) excludes(partition string, excludes []Label) {
- if _, ok := p[partition]; !ok {
- p[partition] = &LabelList{}
- }
- p[partition].Excludes = excludes
- }
- // PartitionLabelListAttribute partitions a LabelListAttribute into the requested partitions
- func PartitionLabelListAttribute(ctx OtherModuleContext, lla *LabelListAttribute, partitions LabelPartitions) PartitionToLabelListAttribute {
- ret := PartitionToLabelListAttribute{}
- var partitionNames []string
- // Stored as a pointer to distinguish nil (no remainder partition) from empty string partition
- var remainderPartition *string
- for p, f := range partitions {
- partitionNames = append(partitionNames, p)
- if f.Keep_remainder {
- if remainderPartition != nil {
- panic("only one partition can store the remainder")
- }
- // If we take the address of p in a loop, we'll end up with the last value of p in
- // remainderPartition, we want the requested partition
- capturePartition := p
- remainderPartition = &capturePartition
- }
- }
- partitionLabelList := func(axis ConfigurationAxis, config string) {
- value := lla.SelectValue(axis, config)
- partitionToLabels := partitionToLabelList{}
- for _, item := range value.Includes {
- wasFiltered := false
- var inPartition *string
- for partition, f := range partitions {
- filtered := f.filter(ctx, item)
- if filtered == nil {
- // did not match this filter, keep looking
- continue
- }
- wasFiltered = true
- partitionToLabels.appendIncludes(partition, *filtered)
- // don't need to check other partitions if this filter used the item,
- // continue checking if mapped to another name
- if *filtered == item {
- if inPartition != nil {
- ctx.ModuleErrorf("%q was found in multiple partitions: %q, %q", item.Label, *inPartition, partition)
- }
- capturePartition := partition
- inPartition = &capturePartition
- }
- }
- // if not specified in a partition, add to remainder partition if one exists
- if !wasFiltered && remainderPartition != nil {
- partitionToLabels.appendIncludes(*remainderPartition, item)
- }
- }
- // ensure empty lists are maintained
- if value.Excludes != nil {
- for _, partition := range partitionNames {
- partitionToLabels.excludes(partition, value.Excludes)
- }
- }
- for partition, list := range partitionToLabels {
- val := ret[partition]
- (&val).SetSelectValue(axis, config, *list)
- ret[partition] = val
- }
- }
- partitionLabelList(NoConfigAxis, "")
- for axis, configToList := range lla.ConfigurableValues {
- for config, _ := range configToList {
- partitionLabelList(axis, config)
- }
- }
- return ret
- }
- // StringAttribute corresponds to the string Bazel attribute type with
- // support for additional metadata, like configurations.
- type StringAttribute struct {
- // The base value of the string attribute.
- Value *string
- // The configured attribute label list Values. Optional
- // a map of independent configurability axes
- ConfigurableValues configurableStrings
- }
- type configurableStrings map[ConfigurationAxis]stringSelectValues
- func (cs configurableStrings) setValueForAxis(axis ConfigurationAxis, config string, str *string) {
- if cs[axis] == nil {
- cs[axis] = make(stringSelectValues)
- }
- var v = ""
- if str != nil {
- v = *str
- }
- cs[axis][config] = v
- }
- type stringSelectValues map[string]string
- // HasConfigurableValues returns true if the attribute contains axis-specific string values.
- func (sa StringAttribute) HasConfigurableValues() bool {
- for _, selectValues := range sa.ConfigurableValues {
- if len(selectValues) > 0 {
- return true
- }
- }
- return false
- }
- // SetSelectValue set a value for a bazel select for the given axis, config and value.
- func (sa *StringAttribute) SetSelectValue(axis ConfigurationAxis, config string, str *string) {
- axis.validateConfig(config)
- switch axis.configurationType {
- case noConfig:
- sa.Value = str
- case arch, os, osArch, productVariables:
- if sa.ConfigurableValues == nil {
- sa.ConfigurableValues = make(configurableStrings)
- }
- sa.ConfigurableValues.setValueForAxis(axis, config, str)
- default:
- panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
- }
- }
- // SelectValue gets a value for a bazel select for the given axis and config.
- func (sa *StringAttribute) SelectValue(axis ConfigurationAxis, config string) *string {
- axis.validateConfig(config)
- switch axis.configurationType {
- case noConfig:
- return sa.Value
- case arch, os, osArch, productVariables:
- if v, ok := sa.ConfigurableValues[axis][config]; ok {
- return &v
- } else {
- return nil
- }
- default:
- panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
- }
- }
- // SortedConfigurationAxes returns all the used ConfigurationAxis in sorted order.
- func (sa *StringAttribute) SortedConfigurationAxes() []ConfigurationAxis {
- keys := make([]ConfigurationAxis, 0, len(sa.ConfigurableValues))
- for k := range sa.ConfigurableValues {
- keys = append(keys, k)
- }
- sort.Slice(keys, func(i, j int) bool { return keys[i].less(keys[j]) })
- return keys
- }
- // Collapse reduces the configurable axes of the string attribute to a single axis.
- // This is necessary for final writing to bp2build, as a configurable string
- // attribute can only be comprised by a single select.
- func (sa *StringAttribute) Collapse() error {
- axisTypes := sa.axisTypes()
- _, containsOs := axisTypes[os]
- _, containsArch := axisTypes[arch]
- _, containsOsArch := axisTypes[osArch]
- _, containsProductVariables := axisTypes[productVariables]
- if containsProductVariables {
- if containsOs || containsArch || containsOsArch {
- return fmt.Errorf("boolean attribute could not be collapsed as it has two or more unrelated axes")
- }
- }
- if (containsOs && containsArch) || (containsOsArch && (containsOs || containsArch)) {
- // If a bool attribute has both os and arch configuration axes, the only
- // way to successfully union their values is to increase the granularity
- // of the configuration criteria to os_arch.
- for osType, supportedArchs := range osToArchMap {
- for _, supportedArch := range supportedArchs {
- osArch := osArchString(osType, supportedArch)
- if archOsVal := sa.SelectValue(OsArchConfigurationAxis, osArch); archOsVal != nil {
- // Do nothing, as the arch_os is explicitly defined already.
- } else {
- archVal := sa.SelectValue(ArchConfigurationAxis, supportedArch)
- osVal := sa.SelectValue(OsConfigurationAxis, osType)
- if osVal != nil && archVal != nil {
- // In this case, arch takes precedence. (This fits legacy Soong behavior, as arch mutator
- // runs after os mutator.
- sa.SetSelectValue(OsArchConfigurationAxis, osArch, archVal)
- } else if osVal != nil && archVal == nil {
- sa.SetSelectValue(OsArchConfigurationAxis, osArch, osVal)
- } else if osVal == nil && archVal != nil {
- sa.SetSelectValue(OsArchConfigurationAxis, osArch, archVal)
- }
- }
- }
- }
- // All os_arch values are now set. Clear os and arch axes.
- delete(sa.ConfigurableValues, ArchConfigurationAxis)
- delete(sa.ConfigurableValues, OsConfigurationAxis)
- // Verify post-condition; this should never fail, provided no additional
- // axes are introduced.
- if len(sa.ConfigurableValues) > 1 {
- panic(fmt.Errorf("error in collapsing attribute: %#v", sa))
- }
- }
- return nil
- }
- func (sa *StringAttribute) axisTypes() map[configurationType]bool {
- types := map[configurationType]bool{}
- for k := range sa.ConfigurableValues {
- if strs := sa.ConfigurableValues[k]; len(strs) > 0 {
- types[k.configurationType] = true
- }
- }
- return types
- }
- // StringListAttribute corresponds to the string_list Bazel attribute type with
- // support for additional metadata, like configurations.
- type StringListAttribute struct {
- // The base value of the string list attribute.
- Value []string
- // The configured attribute label list Values. Optional
- // a map of independent configurability axes
- ConfigurableValues configurableStringLists
- }
- type configurableStringLists map[ConfigurationAxis]stringListSelectValues
- func (csl configurableStringLists) Append(other configurableStringLists) {
- for axis, otherSelects := range other {
- selects := csl[axis]
- if selects == nil {
- selects = make(stringListSelectValues, len(otherSelects))
- }
- selects.appendSelects(otherSelects)
- csl[axis] = selects
- }
- }
- func (csl configurableStringLists) setValueForAxis(axis ConfigurationAxis, config string, list []string) {
- if csl[axis] == nil {
- csl[axis] = make(stringListSelectValues)
- }
- csl[axis][config] = list
- }
- type stringListSelectValues map[string][]string
- func (sl stringListSelectValues) appendSelects(other stringListSelectValues) {
- for k, v := range other {
- sl[k] = append(sl[k], v...)
- }
- }
- func (sl stringListSelectValues) hasConfigurableValues(other stringListSelectValues) bool {
- for _, val := range sl {
- if len(val) > 0 {
- return true
- }
- }
- return false
- }
- // MakeStringListAttribute initializes a StringListAttribute with the non-arch specific value.
- func MakeStringListAttribute(value []string) StringListAttribute {
- // NOTE: These strings are not necessarily unique or sorted.
- return StringListAttribute{
- Value: value,
- ConfigurableValues: make(configurableStringLists),
- }
- }
- // HasConfigurableValues returns true if the attribute contains axis-specific string_list values.
- func (sla StringListAttribute) HasConfigurableValues() bool {
- for _, selectValues := range sla.ConfigurableValues {
- if len(selectValues) > 0 {
- return true
- }
- }
- return false
- }
- // Append appends all values, including os and arch specific ones, from another
- // StringListAttribute to this StringListAttribute
- func (sla *StringListAttribute) Append(other StringListAttribute) *StringListAttribute {
- sla.Value = append(sla.Value, other.Value...)
- if sla.ConfigurableValues == nil {
- sla.ConfigurableValues = make(configurableStringLists)
- }
- sla.ConfigurableValues.Append(other.ConfigurableValues)
- return sla
- }
- func (sla *StringListAttribute) Clone() *StringListAttribute {
- result := &StringListAttribute{}
- return result.Append(*sla)
- }
- // SetSelectValue set a value for a bazel select for the given axis, config and value.
- func (sla *StringListAttribute) SetSelectValue(axis ConfigurationAxis, config string, list []string) {
- axis.validateConfig(config)
- switch axis.configurationType {
- case noConfig:
- sla.Value = list
- case arch, os, osArch, productVariables, osAndInApex:
- if sla.ConfigurableValues == nil {
- sla.ConfigurableValues = make(configurableStringLists)
- }
- sla.ConfigurableValues.setValueForAxis(axis, config, list)
- default:
- panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
- }
- }
- // SelectValue gets a value for a bazel select for the given axis and config.
- func (sla *StringListAttribute) SelectValue(axis ConfigurationAxis, config string) []string {
- axis.validateConfig(config)
- switch axis.configurationType {
- case noConfig:
- return sla.Value
- case arch, os, osArch, productVariables, osAndInApex:
- return sla.ConfigurableValues[axis][config]
- default:
- panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
- }
- }
- // SortedConfigurationAxes returns all the used ConfigurationAxis in sorted order.
- func (sla *StringListAttribute) SortedConfigurationAxes() []ConfigurationAxis {
- keys := make([]ConfigurationAxis, 0, len(sla.ConfigurableValues))
- for k := range sla.ConfigurableValues {
- keys = append(keys, k)
- }
- sort.Slice(keys, func(i, j int) bool { return keys[i].less(keys[j]) })
- return keys
- }
- // DeduplicateAxesFromBase ensures no duplication of items between the no-configuration value and
- // configuration-specific values. For example, if we would convert this StringListAttribute as:
- //
- // ["a", "b", "c"] + select({
- // "//condition:one": ["a", "d"],
- // "//conditions:default": [],
- // })
- //
- // after this function, we would convert this StringListAttribute as:
- //
- // ["a", "b", "c"] + select({
- // "//condition:one": ["d"],
- // "//conditions:default": [],
- // })
- func (sla *StringListAttribute) DeduplicateAxesFromBase() {
- base := sla.Value
- for axis, configToList := range sla.ConfigurableValues {
- for config, list := range configToList {
- remaining := SubtractStrings(list, base)
- if len(remaining) == 0 {
- delete(sla.ConfigurableValues[axis], config)
- } else {
- sla.ConfigurableValues[axis][config] = remaining
- }
- }
- }
- }
- // TryVariableSubstitution, replace string substitution formatting within each string in slice with
- // Starlark string.format compatible tag for productVariable.
- func TryVariableSubstitutions(slice []string, productVariable string) ([]string, bool) {
- ret := make([]string, 0, len(slice))
- changesMade := false
- for _, s := range slice {
- newS, changed := TryVariableSubstitution(s, productVariable)
- ret = append(ret, newS)
- changesMade = changesMade || changed
- }
- return ret, changesMade
- }
- // TryVariableSubstitution, replace string substitution formatting within s with Starlark
- // string.format compatible tag for productVariable.
- func TryVariableSubstitution(s string, productVariable string) (string, bool) {
- sub := productVariableSubstitutionPattern.ReplaceAllString(s, "$("+productVariable+")")
- return sub, s != sub
- }
|