diff options
author | 2024-10-02 16:07:43 -0700 | |
---|---|---|
committer | 2024-10-02 16:13:35 -0700 | |
commit | b8083bb94ea6761d6f56b7c2edfe8e03e78f98c8 (patch) | |
tree | 2e16e789b80219a36e0952e9ad95a963cb811406 | |
parent | 8bce3818334988d4ac7da979c7a8a529613c455b (diff) |
Delete more unused bazel code
Remove more bazel code that is not used by queryview.
Test: builds
Flag: EXEMPT refactor
Change-Id: I838bcada9b9ccfaf5a61bfd5ec35fe1d8192c2b2
-rw-r--r-- | bazel/Android.bp | 22 | ||||
-rw-r--r-- | bazel/configurability.go | 391 | ||||
-rw-r--r-- | bazel/properties.go | 1467 | ||||
-rw-r--r-- | bazel/properties_test.go | 836 | ||||
-rw-r--r-- | bazel/testing.go | 105 | ||||
-rw-r--r-- | bp2build/Android.bp | 2 | ||||
-rw-r--r-- | bp2build/build_conversion.go | 42 | ||||
-rw-r--r-- | bp2build/configurability.go | 328 | ||||
-rw-r--r-- | bp2build/constants.go | 5 |
9 files changed, 10 insertions, 3188 deletions
diff --git a/bazel/Android.bp b/bazel/Android.bp deleted file mode 100644 index f8273a847..000000000 --- a/bazel/Android.bp +++ /dev/null @@ -1,22 +0,0 @@ -package { - default_applicable_licenses: ["Android-Apache-2.0"], -} - -bootstrap_go_package { - name: "soong-bazel", - pkgPath: "android/soong/bazel", - srcs: [ - "configurability.go", - "properties.go", - "testing.go", - ], - testSrcs: [ - "properties_test.go", - ], - pluginFor: [ - "soong_build", - ], - deps: [ - "blueprint", - ], -} diff --git a/bazel/configurability.go b/bazel/configurability.go deleted file mode 100644 index 3a65614da..000000000 --- a/bazel/configurability.go +++ /dev/null @@ -1,391 +0,0 @@ -// Copyright 2021 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" - "math" - "sort" - "strings" -) - -const ( - // ArchType names in arch.go - archArm = "arm" - archArm64 = "arm64" - archRiscv64 = "riscv64" - archX86 = "x86" - archX86_64 = "x86_64" - - // OsType names in arch.go - OsAndroid = "android" - OsDarwin = "darwin" - OsLinux = "linux_glibc" - osLinuxMusl = "linux_musl" - osLinuxBionic = "linux_bionic" - OsWindows = "windows" - - // Targets in arch.go - osArchAndroidArm = "android_arm" - OsArchAndroidArm64 = "android_arm64" - osArchAndroidRiscv64 = "android_riscv64" - osArchAndroidX86 = "android_x86" - osArchAndroidX86_64 = "android_x86_64" - osArchDarwinArm64 = "darwin_arm64" - osArchDarwinX86_64 = "darwin_x86_64" - osArchLinuxX86 = "linux_glibc_x86" - osArchLinuxX86_64 = "linux_glibc_x86_64" - osArchLinuxMuslArm = "linux_musl_arm" - osArchLinuxMuslArm64 = "linux_musl_arm64" - osArchLinuxMuslX86 = "linux_musl_x86" - osArchLinuxMuslX86_64 = "linux_musl_x86_64" - osArchLinuxBionicArm64 = "linux_bionic_arm64" - osArchLinuxBionicX86_64 = "linux_bionic_x86_64" - osArchWindowsX86 = "windows_x86" - osArchWindowsX86_64 = "windows_x86_64" - - // This is the string representation of the default condition wherever a - // configurable attribute is used in a select statement, i.e. - // //conditions:default for Bazel. - // - // This is consistently named "conditions_default" to mirror the Soong - // config variable default key in an Android.bp file, although there's no - // integration with Soong config variables (yet). - ConditionsDefaultConfigKey = "conditions_default" - - ConditionsDefaultSelectKey = "//conditions:default" - - productVariableBazelPackage = "//build/bazel/product_config/config_settings" - - AndroidAndInApex = "android-in_apex" - AndroidPlatform = "system" - Unbundled_app = "unbundled_app" - - InApex = "in_apex" - NonApex = "non_apex" - - ErrorproneDisabled = "errorprone_disabled" - // TODO: b/294868620 - Remove when completing the bug - SanitizersEnabled = "sanitizers_enabled" -) - -func PowerSetWithoutEmptySet[T any](items []T) [][]T { - resultSize := int(math.Pow(2, float64(len(items)))) - powerSet := make([][]T, 0, resultSize-1) - for i := 1; i < resultSize; i++ { - combination := make([]T, 0) - for j := 0; j < len(items); j++ { - if (i>>j)%2 == 1 { - combination = append(combination, items[j]) - } - } - powerSet = append(powerSet, combination) - } - return powerSet -} - -func createPlatformArchMap() map[string]string { - // Copy of archFeatures from android/arch_list.go because the bazel - // package can't access the android package - archFeatures := map[string][]string{ - "arm": {}, - "arm64": { - "dotprod", - }, - "riscv64": {}, - "x86": { - "ssse3", - "sse4", - "sse4_1", - "sse4_2", - "aes_ni", - "avx", - "avx2", - "avx512", - "popcnt", - "movbe", - }, - "x86_64": { - "ssse3", - "sse4", - "sse4_1", - "sse4_2", - "aes_ni", - "avx", - "avx2", - "avx512", - "popcnt", - }, - } - result := make(map[string]string) - for arch, allFeatures := range archFeatures { - result[arch] = "//build/bazel_common_rules/platforms/arch:" + arch - // Sometimes we want to select on multiple features being active, so - // add the power set of all possible features to the map. More details - // in android.ModuleBase.GetArchVariantProperties - for _, features := range PowerSetWithoutEmptySet(allFeatures) { - sort.Strings(features) - archFeaturesName := arch + "-" + strings.Join(features, "-") - result[archFeaturesName] = "//build/bazel/platforms/arch/variants:" + archFeaturesName - } - } - result[ConditionsDefaultConfigKey] = ConditionsDefaultSelectKey - return result -} - -var ( - // These are the list of OSes and architectures with a Bazel config_setting - // and constraint value equivalent. These exist in arch.go, but the android - // package depends on the bazel package, so a cyclic dependency prevents - // using those variables here. - - // A map of architectures to the Bazel label of the constraint_value - // for the @platforms//cpu:cpu constraint_setting - platformArchMap = createPlatformArchMap() - - // A map of target operating systems to the Bazel label of the - // constraint_value for the @platforms//os:os constraint_setting - platformOsMap = map[string]string{ - OsAndroid: "//build/bazel_common_rules/platforms/os:android", - OsDarwin: "//build/bazel_common_rules/platforms/os:darwin", - OsLinux: "//build/bazel_common_rules/platforms/os:linux_glibc", - osLinuxMusl: "//build/bazel_common_rules/platforms/os:linux_musl", - osLinuxBionic: "//build/bazel_common_rules/platforms/os:linux_bionic", - OsWindows: "//build/bazel_common_rules/platforms/os:windows", - ConditionsDefaultConfigKey: ConditionsDefaultSelectKey, // The default condition of an os select map. - } - - platformOsArchMap = map[string]string{ - osArchAndroidArm: "//build/bazel_common_rules/platforms/os_arch:android_arm", - OsArchAndroidArm64: "//build/bazel_common_rules/platforms/os_arch:android_arm64", - osArchAndroidRiscv64: "//build/bazel_common_rules/platforms/os_arch:android_riscv64", - osArchAndroidX86: "//build/bazel_common_rules/platforms/os_arch:android_x86", - osArchAndroidX86_64: "//build/bazel_common_rules/platforms/os_arch:android_x86_64", - osArchDarwinArm64: "//build/bazel_common_rules/platforms/os_arch:darwin_arm64", - osArchDarwinX86_64: "//build/bazel_common_rules/platforms/os_arch:darwin_x86_64", - osArchLinuxX86: "//build/bazel_common_rules/platforms/os_arch:linux_glibc_x86", - osArchLinuxX86_64: "//build/bazel_common_rules/platforms/os_arch:linux_glibc_x86_64", - osArchLinuxMuslArm: "//build/bazel_common_rules/platforms/os_arch:linux_musl_arm", - osArchLinuxMuslArm64: "//build/bazel_common_rules/platforms/os_arch:linux_musl_arm64", - osArchLinuxMuslX86: "//build/bazel_common_rules/platforms/os_arch:linux_musl_x86", - osArchLinuxMuslX86_64: "//build/bazel_common_rules/platforms/os_arch:linux_musl_x86_64", - osArchLinuxBionicArm64: "//build/bazel_common_rules/platforms/os_arch:linux_bionic_arm64", - osArchLinuxBionicX86_64: "//build/bazel_common_rules/platforms/os_arch:linux_bionic_x86_64", - osArchWindowsX86: "//build/bazel_common_rules/platforms/os_arch:windows_x86", - osArchWindowsX86_64: "//build/bazel_common_rules/platforms/os_arch:windows_x86_64", - ConditionsDefaultConfigKey: ConditionsDefaultSelectKey, // The default condition of an os select map. - } - - // Map where keys are OsType names, and values are slices containing the archs - // that that OS supports. - // These definitions copied from arch.go. - // TODO(cparsons): Source from arch.go; this task is nontrivial, as it currently results - // in a cyclic dependency. - osToArchMap = map[string][]string{ - OsAndroid: {archArm, archArm64, archRiscv64, archX86, archX86_64}, - OsLinux: {archX86, archX86_64}, - osLinuxMusl: {archX86, archX86_64}, - OsDarwin: {archArm64, archX86_64}, - osLinuxBionic: {archArm64, archX86_64}, - // TODO(cparsons): According to arch.go, this should contain archArm, archArm64, as well. - OsWindows: {archX86, archX86_64}, - } - - osAndInApexMap = map[string]string{ - AndroidAndInApex: "//build/bazel/rules/apex:android-in_apex", - AndroidPlatform: "//build/bazel/rules/apex:system", - Unbundled_app: "//build/bazel/rules/apex:unbundled_app", - OsDarwin: "//build/bazel_common_rules/platforms/os:darwin", - OsLinux: "//build/bazel_common_rules/platforms/os:linux_glibc", - osLinuxMusl: "//build/bazel_common_rules/platforms/os:linux_musl", - osLinuxBionic: "//build/bazel_common_rules/platforms/os:linux_bionic", - OsWindows: "//build/bazel_common_rules/platforms/os:windows", - ConditionsDefaultConfigKey: ConditionsDefaultSelectKey, - } - - inApexMap = map[string]string{ - InApex: "//build/bazel/rules/apex:in_apex", - NonApex: "//build/bazel/rules/apex:non_apex", - ConditionsDefaultConfigKey: ConditionsDefaultSelectKey, - } - - errorProneMap = map[string]string{ - ErrorproneDisabled: "//build/bazel/rules/java/errorprone:errorprone_globally_disabled", - ConditionsDefaultConfigKey: ConditionsDefaultSelectKey, - } - - // TODO: b/294868620 - Remove when completing the bug - sanitizersEnabledMap = map[string]string{ - SanitizersEnabled: "//build/bazel/rules/cc:sanitizers_enabled", - ConditionsDefaultConfigKey: ConditionsDefaultSelectKey, - } -) - -// basic configuration types -type configurationType int - -const ( - noConfig configurationType = iota - arch - os - osArch - productVariables - osAndInApex - inApex - errorProneDisabled - // TODO: b/294868620 - Remove when completing the bug - sanitizersEnabled -) - -func osArchString(os string, arch string) string { - return fmt.Sprintf("%s_%s", os, arch) -} - -func (ct configurationType) String() string { - return map[configurationType]string{ - noConfig: "no_config", - arch: "arch", - os: "os", - osArch: "arch_os", - productVariables: "product_variables", - osAndInApex: "os_in_apex", - inApex: "in_apex", - errorProneDisabled: "errorprone_disabled", - // TODO: b/294868620 - Remove when completing the bug - sanitizersEnabled: "sanitizers_enabled", - }[ct] -} - -func (ct configurationType) validateConfig(config string) { - switch ct { - case noConfig: - if config != "" { - panic(fmt.Errorf("Cannot specify config with %s, but got %s", ct, config)) - } - case arch: - if _, ok := platformArchMap[config]; !ok { - panic(fmt.Errorf("Unknown arch: %s", config)) - } - case os: - if _, ok := platformOsMap[config]; !ok { - panic(fmt.Errorf("Unknown os: %s", config)) - } - case osArch: - if _, ok := platformOsArchMap[config]; !ok { - panic(fmt.Errorf("Unknown os+arch: %s", config)) - } - case productVariables: - // do nothing - case osAndInApex: - // do nothing - // this axis can contain additional per-apex keys - case inApex: - if _, ok := inApexMap[config]; !ok { - panic(fmt.Errorf("Unknown in_apex config: %s", config)) - } - case errorProneDisabled: - if _, ok := errorProneMap[config]; !ok { - panic(fmt.Errorf("Unknown errorprone config: %s", config)) - } - // TODO: b/294868620 - Remove when completing the bug - case sanitizersEnabled: - if _, ok := sanitizersEnabledMap[config]; !ok { - panic(fmt.Errorf("Unknown sanitizers_enabled config: %s", config)) - } - default: - panic(fmt.Errorf("Unrecognized ConfigurationType %d", ct)) - } -} - -// SelectKey returns the Bazel select key for a given configurationType and config string. -func (ca ConfigurationAxis) SelectKey(config string) string { - ca.validateConfig(config) - switch ca.configurationType { - case noConfig: - panic(fmt.Errorf("SelectKey is unnecessary for noConfig ConfigurationType ")) - case arch: - return platformArchMap[config] - case os: - return platformOsMap[config] - case osArch: - return platformOsArchMap[config] - case productVariables: - if config == ConditionsDefaultConfigKey { - return ConditionsDefaultSelectKey - } - return fmt.Sprintf("%s:%s", productVariableBazelPackage, config) - case osAndInApex: - if ret, exists := osAndInApexMap[config]; exists { - return ret - } - return config - case inApex: - return inApexMap[config] - case errorProneDisabled: - return errorProneMap[config] - // TODO: b/294868620 - Remove when completing the bug - case sanitizersEnabled: - return sanitizersEnabledMap[config] - default: - panic(fmt.Errorf("Unrecognized ConfigurationType %d", ca.configurationType)) - } -} - -var ( - // Indicating there is no configuration axis - NoConfigAxis = ConfigurationAxis{configurationType: noConfig} - // An axis for architecture-specific configurations - ArchConfigurationAxis = ConfigurationAxis{configurationType: arch} - // An axis for os-specific configurations - OsConfigurationAxis = ConfigurationAxis{configurationType: os} - // An axis for arch+os-specific configurations - OsArchConfigurationAxis = ConfigurationAxis{configurationType: osArch} - // An axis for os+in_apex-specific configurations - OsAndInApexAxis = ConfigurationAxis{configurationType: osAndInApex} - // An axis for in_apex-specific configurations - InApexAxis = ConfigurationAxis{configurationType: inApex} - - ErrorProneAxis = ConfigurationAxis{configurationType: errorProneDisabled} - - // TODO: b/294868620 - Remove when completing the bug - SanitizersEnabledAxis = ConfigurationAxis{configurationType: sanitizersEnabled} -) - -// ProductVariableConfigurationAxis returns an axis for the given product variable -func ProductVariableConfigurationAxis(archVariant bool, variable string) ConfigurationAxis { - return ConfigurationAxis{ - configurationType: productVariables, - subType: variable, - archVariant: archVariant, - } -} - -// ConfigurationAxis is an independent axis for configuration, there should be no overlap between -// elements within an axis. -type ConfigurationAxis struct { - configurationType - // some configuration types (e.g. productVariables) have multiple independent axes, subType helps - // distinguish between them without needing to list all 17 product variables. - subType string - - archVariant bool -} - -func (ca *ConfigurationAxis) less(other ConfigurationAxis) bool { - if ca.configurationType == other.configurationType { - return ca.subType < other.subType - } - return ca.configurationType < other.configurationType -} diff --git a/bazel/properties.go b/bazel/properties.go deleted file mode 100644 index 9c63bc04b..000000000 --- a/bazel/properties.go +++ /dev/null @@ -1,1467 +0,0 @@ -// 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" - "reflect" - "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 SortedConfigurationAxes[T any](m map[ConfigurationAxis]T) []ConfigurationAxis { - keys := make([]ConfigurationAxis, 0, len(m)) - for k := range m { - keys = append(keys, k) - } - - sort.Slice(keys, func(i, j int) bool { return keys[i].less(keys[j]) }) - return keys -} - -// MakeLabelListFromTargetNames creates a LabelList from unqualified target names -// This is a utiltity function for bp2build converters of Soong modules that have 1:many generated targets -func MakeLabelListFromTargetNames(targetNames []string) LabelList { - labels := []Label{} - for _, name := range targetNames { - label := Label{Label: ":" + name} - labels = append(labels, label) - } - return MakeLabelList(labels) -} - -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(ll.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 { - uniqueLabels := FirstUniqueBazelLabels(originalLabels) - 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[string]bool, len(originalLabels)) - for _, l := range originalLabels { - if _, ok := found[l.Label]; ok { - continue - } - labels = append(labels, l) - found[l.Label] = 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 -} - -// FirstUniqueBazelLabelListAttribute takes a LabelListAttribute and makes the LabelList for -// each axis/configuration by keeping the first instance of a Label and omitting all subsequent -// repetitions. -func FirstUniqueBazelLabelListAttribute(attr LabelListAttribute) LabelListAttribute { - var result LabelListAttribute - result.Value = FirstUniqueBazelLabelList(attr.Value) - if attr.HasConfigurableValues() { - result.ConfigurableValues = make(configurableLabelLists) - } - for axis, configToLabels := range attr.ConfigurableValues { - for c, l := range configToLabels { - result.SetSelectValue(axis, c, FirstUniqueBazelLabelList(l)) - } - } - - return result -} - -// SubtractBazelLabelListAttribute subtract needle from haystack for LabelList in each -// axis/configuration. -func SubtractBazelLabelListAttribute(haystack LabelListAttribute, needle LabelListAttribute) LabelListAttribute { - var result LabelListAttribute - result.Value = SubtractBazelLabelList(haystack.Value, needle.Value) - if haystack.HasConfigurableValues() { - result.ConfigurableValues = make(configurableLabelLists) - } - for axis, configToLabels := range haystack.ConfigurableValues { - for haystackConfig, haystackLabels := range configToLabels { - result.SetSelectValue(axis, haystackConfig, SubtractBazelLabelList(haystackLabels, needle.SelectValue(axis, haystackConfig))) - } - } - - 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.archVariant { - 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, sanitizersEnabled: - 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, sanitizersEnabled: - 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 { - return SortedConfigurationAxes(la.ConfigurableValues) -} - -// 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, sanitizersEnabled: - 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 -} - -// ToStringListAttribute creates a StringListAttribute from this BoolAttribute, -// where each bool corresponds to a string list value generated by the provided -// function. -// TODO(b/271425661): Generalize this -func (ba *BoolAttribute) ToStringListAttribute(valueFunc func(boolPtr *bool, axis ConfigurationAxis, config string) []string) (StringListAttribute, error) { - mainVal := valueFunc(ba.Value, NoConfigAxis, "") - if !ba.HasConfigurableValues() { - return MakeStringListAttribute(mainVal), nil - } - - result := StringListAttribute{} - 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 := valueFunc(&boolPtr, axis, config) - if !reflect.DeepEqual(val, 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, sanitizersEnabled: - 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 { - return SortedConfigurationAxes(ba.ConfigurableValues) -} - -// 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 - - // If a property has struct tag "variant_prepend", this value should - // be set to True, so that when bp2build generates BUILD.bazel, variant - // properties(select ...) come before general properties. - Prepend 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, inApex, errorProneDisabled, sanitizersEnabled: - 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, inApex, errorProneDisabled, sanitizersEnabled: - 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 { - return SortedConfigurationAxes(lla.ConfigurableValues) -} - -// 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 -} - -// HasAxisSpecificValues returns true if the attribute contains axis specific label list values from a given axis -func (lla LabelListAttribute) HasAxisSpecificValues(axis ConfigurationAxis) bool { - for _, values := range lla.ConfigurableValues[axis] { - if !values.IsNil() { - 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() { - // If there are OsAndInApexAxis, we need to use - // * includes from the OS & in APEX Axis for non-Android configs for libraries that need to be - // included in non-Android OSes - // * excludes from the OS Axis for non-Android configs, to exclude libraries that should _not_ - // be included in the non-Android OSes - if _, ok := lla.ConfigurableValues[OsAndInApexAxis]; ok { - inApexLabels := lla.ConfigurableValues[OsAndInApexAxis][ConditionsDefaultConfigKey] - for config, labels := range lla.ConfigurableValues[OsConfigurationAxis] { - // OsAndroid has already handled its excludes. - // We only need to copy the excludes from other arches, so if there are none, skip it. - if config == OsAndroid || len(labels.Excludes) == 0 { - continue - } - lla.ConfigurableValues[OsAndInApexAxis][config] = LabelList{ - Includes: inApexLabels.Includes, - Excludes: labels.Excludes, - } - } - } - - 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: allLabels.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) - } - cs[axis][config] = str -} - -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 -} - -// SetValue sets the base, non-configured value for the Label -func (sa *StringAttribute) SetValue(value string) { - sa.SetSelectValue(NoConfigAxis, "", &value) -} - -// 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, sanitizersEnabled: - 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, sanitizersEnabled: - 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 { - return SortedConfigurationAxes(sa.ConfigurableValues) -} - -// 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("string 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)) - } - } else if containsProductVariables { - usedBaseValue := false - for a, configToProp := range sa.ConfigurableValues { - if a.configurationType == productVariables { - for c, p := range configToProp { - if p == nil { - sa.SetSelectValue(a, c, sa.Value) - usedBaseValue = true - } - } - } - } - if usedBaseValue { - sa.Value = nil - } - } - 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 - - // If a property has struct tag "variant_prepend", this value should - // be set to True, so that when bp2build generates BUILD.bazel, variant - // properties(select ...) come before general properties. - Prepend bool -} - -// IsEmpty returns true if the attribute has no values under any configuration. -func (sla StringListAttribute) IsEmpty() bool { - return len(sla.Value) == 0 && !sla.HasConfigurableValues() -} - -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, errorProneDisabled, sanitizersEnabled: - 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, errorProneDisabled, sanitizersEnabled: - 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 { - return SortedConfigurationAxes(sla.ConfigurableValues) -} - -// 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) { - if len(slice) == 0 { - return slice, false - } - 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 -} - -// StringMapAttribute is a map of strings. -// The use case for this is storing the flag_values in a config_setting object. -// Bazel rules do not support map attributes, and this should NOT be used in Bazel rules. -type StringMapAttribute map[string]string - -// ConfigSettingAttributes stores the keys of a config_setting object. -type ConfigSettingAttributes struct { - // Each key in Flag_values is a label to a custom string_setting - Flag_values StringMapAttribute - // Each element in Constraint_values is a label to a constraint_value - Constraint_values LabelListAttribute -} diff --git a/bazel/properties_test.go b/bazel/properties_test.go deleted file mode 100644 index 751cb8b30..000000000 --- a/bazel/properties_test.go +++ /dev/null @@ -1,836 +0,0 @@ -// Copyright 2021 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 ( - "reflect" - "strings" - "testing" - - "github.com/google/blueprint/proptools" -) - -func TestUniqueBazelLabels(t *testing.T) { - testCases := []struct { - originalLabels []Label - expectedUniqueLabels []Label - }{ - { - originalLabels: []Label{ - {Label: "a"}, - {Label: "b"}, - {Label: "a"}, - {Label: "c"}, - // namespaces - {Label: "//foo:bar", OriginalModuleName: "bar"}, // when referenced from foo namespace - {Label: "//foo:bar", OriginalModuleName: "//foo:bar"}, // when reference from root namespace - }, - expectedUniqueLabels: []Label{ - {Label: "//foo:bar", OriginalModuleName: "bar"}, - {Label: "a"}, - {Label: "b"}, - {Label: "c"}, - }, - }, - } - for _, tc := range testCases { - actualUniqueLabels := UniqueSortedBazelLabels(tc.originalLabels) - if !reflect.DeepEqual(tc.expectedUniqueLabels, actualUniqueLabels) { - t.Fatalf("Expected %v, got %v", tc.expectedUniqueLabels, actualUniqueLabels) - } - } -} - -func TestSubtractStrings(t *testing.T) { - testCases := []struct { - haystack []string - needle []string - expectedResult []string - }{ - { - haystack: []string{ - "a", - "b", - "c", - }, - needle: []string{ - "a", - }, - expectedResult: []string{ - "b", "c", - }, - }, - } - for _, tc := range testCases { - actualResult := SubtractStrings(tc.haystack, tc.needle) - if !reflect.DeepEqual(tc.expectedResult, actualResult) { - t.Fatalf("Expected %v, got %v", tc.expectedResult, actualResult) - } - } -} - -func TestSubtractBazelLabelList(t *testing.T) { - testCases := []struct { - haystack LabelList - needle LabelList - expectedResult LabelList - }{ - { - haystack: LabelList{ - Includes: []Label{ - {Label: "a"}, - {Label: "b"}, - {Label: "c"}, - }, - Excludes: []Label{ - {Label: "x"}, - {Label: "y"}, - {Label: "z"}, - }, - }, - needle: LabelList{ - Includes: []Label{ - {Label: "a"}, - }, - Excludes: []Label{ - {Label: "z"}, - }, - }, - // NOTE: Excludes are intentionally not subtracted - expectedResult: LabelList{ - Includes: []Label{ - {Label: "b"}, - {Label: "c"}, - }, - Excludes: []Label{ - {Label: "x"}, - {Label: "y"}, - {Label: "z"}, - }, - }, - }, - } - for _, tc := range testCases { - actualResult := SubtractBazelLabelList(tc.haystack, tc.needle) - if !reflect.DeepEqual(tc.expectedResult, actualResult) { - t.Fatalf("Expected %v, got %v", tc.expectedResult, actualResult) - } - } -} - -func TestSubtractBazelLabelListAttribute(t *testing.T) { - testCases := []struct { - haystack LabelListAttribute - needle LabelListAttribute - expected LabelListAttribute - }{ - { - haystack: LabelListAttribute{ - Value: makeLabelList( - []string{"a", "b", "a", "c"}, - []string{"x", "x", "y", "z"}, - ), - ConfigurableValues: configurableLabelLists{ - ArchConfigurationAxis: labelListSelectValues{ - "arm": makeLabelList([]string{"arm_1", "arm_2"}, []string{}), - "x86": makeLabelList([]string{"x86_3", "x86_4", "x86_5"}, []string{"x86_5"}), - }, - }, - }, - needle: LabelListAttribute{ - Value: makeLabelList( - []string{"d", "a"}, - []string{"x", "y2", "z2"}, - ), - ConfigurableValues: configurableLabelLists{ - ArchConfigurationAxis: labelListSelectValues{ - "arm": makeLabelList([]string{"arm_1", "arm_3"}, []string{}), - "x86": makeLabelList([]string{"x86_3", "x86_4"}, []string{"x86_6"}), - }, - }, - }, - expected: LabelListAttribute{ - Value: makeLabelList( - []string{"b", "c"}, - []string{"x", "x", "y", "z"}, - ), - ConfigurableValues: configurableLabelLists{ - ArchConfigurationAxis: labelListSelectValues{ - "arm": makeLabelList([]string{"arm_2"}, []string{}), - "x86": makeLabelList([]string{"x86_5"}, []string{"x86_5"}), - }, - }, - ForceSpecifyEmptyList: false, - EmitEmptyList: false, - Prepend: false, - }, - }, - } - for _, tc := range testCases { - got := SubtractBazelLabelListAttribute(tc.haystack, tc.needle) - if !reflect.DeepEqual(tc.expected, got) { - t.Fatalf("Expected\n%v, but got\n%v", tc.expected, got) - } - } -} - -func TestFirstUniqueBazelLabelList(t *testing.T) { - testCases := []struct { - originalLabelList LabelList - expectedUniqueLabelList LabelList - }{ - { - originalLabelList: LabelList{ - Includes: []Label{ - {Label: "a"}, - {Label: "b"}, - {Label: "a"}, - {Label: "c"}, - // namespaces - {Label: "//foo:bar", OriginalModuleName: "bar"}, // when referenced from foo namespace - {Label: "//foo:bar", OriginalModuleName: "//foo:bar"}, // when referenced from root namespace - }, - Excludes: []Label{ - {Label: "x"}, - {Label: "x"}, - {Label: "y"}, - {Label: "z"}, - }, - }, - expectedUniqueLabelList: LabelList{ - Includes: []Label{ - {Label: "a"}, - {Label: "b"}, - {Label: "c"}, - {Label: "//foo:bar", OriginalModuleName: "bar"}, - }, - Excludes: []Label{ - {Label: "x"}, - {Label: "y"}, - {Label: "z"}, - }, - }, - }, - } - for _, tc := range testCases { - actualUniqueLabelList := FirstUniqueBazelLabelList(tc.originalLabelList) - if !reflect.DeepEqual(tc.expectedUniqueLabelList, actualUniqueLabelList) { - t.Fatalf("Expected %v, got %v", tc.expectedUniqueLabelList, actualUniqueLabelList) - } - } -} - -func TestFirstUniqueBazelLabelListAttribute(t *testing.T) { - testCases := []struct { - originalLabelList LabelListAttribute - expectedUniqueLabelList LabelListAttribute - }{ - { - originalLabelList: LabelListAttribute{ - Value: makeLabelList( - []string{"a", "b", "a", "c"}, - []string{"x", "x", "y", "z"}, - ), - ConfigurableValues: configurableLabelLists{ - ArchConfigurationAxis: labelListSelectValues{ - "arm": makeLabelList([]string{"1", "2", "1"}, []string{}), - "x86": makeLabelList([]string{"3", "4", "4"}, []string{"5", "5"}), - }, - }, - }, - expectedUniqueLabelList: LabelListAttribute{ - Value: makeLabelList( - []string{"a", "b", "c"}, - []string{"x", "y", "z"}, - ), - ConfigurableValues: configurableLabelLists{ - ArchConfigurationAxis: labelListSelectValues{ - "arm": makeLabelList([]string{"1", "2"}, []string{}), - "x86": makeLabelList([]string{"3", "4"}, []string{"5"}), - }, - }, - }, - }, - } - for _, tc := range testCases { - actualUniqueLabelList := FirstUniqueBazelLabelListAttribute(tc.originalLabelList) - if !reflect.DeepEqual(tc.expectedUniqueLabelList, actualUniqueLabelList) { - t.Fatalf("Expected %v, got %v", tc.expectedUniqueLabelList, actualUniqueLabelList) - } - } -} - -func TestUniqueSortedBazelLabelList(t *testing.T) { - testCases := []struct { - originalLabelList LabelList - expectedUniqueLabelList LabelList - }{ - { - originalLabelList: LabelList{ - Includes: []Label{ - {Label: "c"}, - {Label: "a"}, - {Label: "a"}, - {Label: "b"}, - }, - Excludes: []Label{ - {Label: "y"}, - {Label: "z"}, - {Label: "x"}, - {Label: "x"}, - }, - }, - expectedUniqueLabelList: LabelList{ - Includes: []Label{ - {Label: "a"}, - {Label: "b"}, - {Label: "c"}, - }, - Excludes: []Label{ - {Label: "x"}, - {Label: "y"}, - {Label: "z"}, - }, - }, - }, - } - for _, tc := range testCases { - actualUniqueLabelList := UniqueSortedBazelLabelList(tc.originalLabelList) - if !reflect.DeepEqual(tc.expectedUniqueLabelList, actualUniqueLabelList) { - t.Fatalf("Expected %v, got %v", tc.expectedUniqueLabelList, actualUniqueLabelList) - } - } -} - -func makeLabels(labels ...string) []Label { - var ret []Label - for _, l := range labels { - ret = append(ret, Label{Label: l}) - } - return ret -} - -func makeLabelList(includes, excludes []string) LabelList { - return LabelList{ - Includes: makeLabels(includes...), - Excludes: makeLabels(excludes...), - } -} - -func TestResolveExcludes(t *testing.T) { - attr := LabelListAttribute{ - Value: makeLabelList( - []string{ - "all_include", - "arm_exclude", - "android_exclude", - "product_config_exclude", - }, - []string{"all_exclude"}, - ), - ConfigurableValues: configurableLabelLists{ - ArchConfigurationAxis: labelListSelectValues{ - "arm": makeLabelList([]string{}, []string{"arm_exclude"}), - "x86": makeLabelList([]string{"x86_include"}, []string{}), - ConditionsDefaultConfigKey: makeLabelList([]string{"default_include"}, []string{}), - }, - OsConfigurationAxis: labelListSelectValues{ - "android": makeLabelList([]string{}, []string{"android_exclude"}), - "linux": makeLabelList([]string{"linux_include"}, []string{}), - }, - OsArchConfigurationAxis: labelListSelectValues{ - "linux_x86": makeLabelList([]string{"linux_x86_include"}, []string{}), - }, - ProductVariableConfigurationAxis(false, "product_with_defaults"): labelListSelectValues{ - "a": makeLabelList([]string{}, []string{"not_in_value"}), - "b": makeLabelList([]string{"b_val"}, []string{}), - "c": makeLabelList([]string{"c_val"}, []string{}), - ConditionsDefaultConfigKey: makeLabelList([]string{"c_val", "default", "default2", "all_exclude"}, []string{}), - }, - ProductVariableConfigurationAxis(false, "product_only_with_excludes"): labelListSelectValues{ - "a": makeLabelList([]string{}, []string{"product_config_exclude"}), - }, - }, - } - - attr.ResolveExcludes() - - expectedBaseIncludes := []Label{{Label: "all_include"}} - if !reflect.DeepEqual(expectedBaseIncludes, attr.Value.Includes) { - t.Errorf("Expected Value includes %q, got %q", attr.Value.Includes, expectedBaseIncludes) - } - var nilLabels []Label - expectedConfiguredIncludes := map[ConfigurationAxis]map[string][]Label{ - ArchConfigurationAxis: { - "arm": nilLabels, - "x86": makeLabels("arm_exclude", "x86_include"), - ConditionsDefaultConfigKey: makeLabels("arm_exclude", "default_include"), - }, - OsConfigurationAxis: { - "android": nilLabels, - "linux": makeLabels("android_exclude", "linux_include"), - ConditionsDefaultConfigKey: makeLabels("android_exclude"), - }, - OsArchConfigurationAxis: { - "linux_x86": makeLabels("linux_x86_include"), - ConditionsDefaultConfigKey: nilLabels, - }, - ProductVariableConfigurationAxis(false, "product_with_defaults"): { - "a": nilLabels, - "b": makeLabels("b_val"), - "c": makeLabels("c_val"), - ConditionsDefaultConfigKey: makeLabels("c_val", "default", "default2"), - }, - ProductVariableConfigurationAxis(false, "product_only_with_excludes"): { - "a": nilLabels, - ConditionsDefaultConfigKey: makeLabels("product_config_exclude"), - }, - } - for _, axis := range attr.SortedConfigurationAxes() { - if _, ok := expectedConfiguredIncludes[axis]; !ok { - t.Errorf("Found unexpected axis %s", axis) - continue - } - expectedForAxis := expectedConfiguredIncludes[axis] - gotForAxis := attr.ConfigurableValues[axis] - if len(expectedForAxis) != len(gotForAxis) { - t.Errorf("Expected %d configs for %s, got %d: %s", len(expectedForAxis), axis, len(gotForAxis), gotForAxis) - } - for config, value := range gotForAxis { - if expected, ok := expectedForAxis[config]; ok { - if !reflect.DeepEqual(expected, value.Includes) { - t.Errorf("For %s,\nexpected: %#v\ngot %#v", axis, expected, value.Includes) - } - } else { - t.Errorf("Got unexpected config %q for %s", config, axis) - } - } - } -} - -func TestLabelListAttributePartition(t *testing.T) { - testCases := []struct { - name string - input LabelListAttribute - predicated LabelListAttribute - unpredicated LabelListAttribute - predicate func(label Label) bool - }{ - { - name: "move all to predicated partition", - input: MakeLabelListAttribute(makeLabelList( - []string{"keep1", "throw1", "keep2", "throw2"}, - []string{"keep1", "throw1", "keep2", "throw2"}, - )), - predicated: MakeLabelListAttribute(makeLabelList( - []string{"keep1", "throw1", "keep2", "throw2"}, - []string{"keep1", "throw1", "keep2", "throw2"}, - )), - unpredicated: LabelListAttribute{}, - predicate: func(label Label) bool { - return true - }, - }, - { - name: "move all to unpredicated partition", - input: MakeLabelListAttribute(makeLabelList( - []string{"keep1", "throw1", "keep2", "throw2"}, - []string{"keep1", "throw1", "keep2", "throw2"}, - )), - predicated: LabelListAttribute{}, - unpredicated: MakeLabelListAttribute(makeLabelList( - []string{"keep1", "throw1", "keep2", "throw2"}, - []string{"keep1", "throw1", "keep2", "throw2"}, - )), - predicate: func(label Label) bool { - return false - }, - }, - { - name: "partition includes and excludes", - input: MakeLabelListAttribute(makeLabelList( - []string{"keep1", "throw1", "keep2", "throw2"}, - []string{"keep1", "throw1", "keep2", "throw2"}, - )), - predicated: MakeLabelListAttribute(makeLabelList( - []string{"keep1", "keep2"}, - []string{"keep1", "keep2"}, - )), - unpredicated: MakeLabelListAttribute(makeLabelList( - []string{"throw1", "throw2"}, - []string{"throw1", "throw2"}, - )), - predicate: func(label Label) bool { - return strings.HasPrefix(label.Label, "keep") - }, - }, - { - name: "partition excludes only", - input: MakeLabelListAttribute(makeLabelList( - []string{}, - []string{"keep1", "throw1", "keep2", "throw2"}, - )), - predicated: MakeLabelListAttribute(makeLabelList( - []string{}, - []string{"keep1", "keep2"}, - )), - unpredicated: MakeLabelListAttribute(makeLabelList( - []string{}, - []string{"throw1", "throw2"}, - )), - predicate: func(label Label) bool { - return strings.HasPrefix(label.Label, "keep") - }, - }, - { - name: "partition includes only", - input: MakeLabelListAttribute(makeLabelList( - []string{"keep1", "throw1", "keep2", "throw2"}, - []string{}, - )), - predicated: MakeLabelListAttribute(makeLabelList( - []string{"keep1", "keep2"}, - []string{}, - )), - unpredicated: MakeLabelListAttribute(makeLabelList( - []string{"throw1", "throw2"}, - []string{}, - )), - predicate: func(label Label) bool { - return strings.HasPrefix(label.Label, "keep") - }, - }, - { - name: "empty partition", - input: MakeLabelListAttribute(makeLabelList([]string{}, []string{})), - predicated: LabelListAttribute{}, - unpredicated: LabelListAttribute{}, - predicate: func(label Label) bool { - return true - }, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - predicated, unpredicated := tc.input.Partition(tc.predicate) - if !predicated.Value.Equals(tc.predicated.Value) { - t.Errorf("expected predicated labels to be %v; got %v", tc.predicated, predicated) - } - for axis, configs := range predicated.ConfigurableValues { - tcConfigs, ok := tc.predicated.ConfigurableValues[axis] - if !ok || !reflect.DeepEqual(configs, tcConfigs) { - t.Errorf("expected predicated labels to be %v; got %v", tc.predicated, predicated) - } - } - if !unpredicated.Value.Equals(tc.unpredicated.Value) { - t.Errorf("expected unpredicated labels to be %v; got %v", tc.unpredicated, unpredicated) - } - for axis, configs := range unpredicated.ConfigurableValues { - tcConfigs, ok := tc.unpredicated.ConfigurableValues[axis] - if !ok || !reflect.DeepEqual(configs, tcConfigs) { - t.Errorf("expected unpredicated labels to be %v; got %v", tc.unpredicated, unpredicated) - } - } - }) - } -} - -// labelAddSuffixForTypeMapper returns a LabelMapper that adds suffix to label name for modules of -// typ -func labelAddSuffixForTypeMapper(suffix, typ string) LabelMapper { - return func(omc OtherModuleContext, label Label) (string, bool) { - m, ok := omc.ModuleFromName(label.Label) - if !ok { - return label.Label, false - } - mTyp := omc.OtherModuleType(m) - if typ == mTyp { - return label.Label + suffix, true - } - return label.Label, false - } -} - -func TestPartitionLabelListAttribute(t *testing.T) { - testCases := []struct { - name string - ctx *OtherModuleTestContext - labelList LabelListAttribute - filters LabelPartitions - expected PartitionToLabelListAttribute - expectedErrMsg *string - }{ - { - name: "no configurable values", - ctx: &OtherModuleTestContext{}, - labelList: LabelListAttribute{ - Value: makeLabelList([]string{"a.a", "b.b", "c.c", "d.d", "e.e"}, []string{}), - }, - filters: LabelPartitions{ - "A": LabelPartition{Extensions: []string{".a"}}, - "B": LabelPartition{Extensions: []string{".b"}}, - "C": LabelPartition{Extensions: []string{".c"}}, - }, - expected: PartitionToLabelListAttribute{ - "A": LabelListAttribute{Value: makeLabelList([]string{"a.a"}, []string{})}, - "B": LabelListAttribute{Value: makeLabelList([]string{"b.b"}, []string{})}, - "C": LabelListAttribute{Value: makeLabelList([]string{"c.c"}, []string{})}, - }, - }, - { - name: "no configurable values, remainder partition", - ctx: &OtherModuleTestContext{}, - labelList: LabelListAttribute{ - Value: makeLabelList([]string{"a.a", "b.b", "c.c", "d.d", "e.e"}, []string{}), - }, - filters: LabelPartitions{ - "A": LabelPartition{Extensions: []string{".a"}, Keep_remainder: true}, - "B": LabelPartition{Extensions: []string{".b"}}, - "C": LabelPartition{Extensions: []string{".c"}}, - }, - expected: PartitionToLabelListAttribute{ - "A": LabelListAttribute{Value: makeLabelList([]string{"a.a", "d.d", "e.e"}, []string{})}, - "B": LabelListAttribute{Value: makeLabelList([]string{"b.b"}, []string{})}, - "C": LabelListAttribute{Value: makeLabelList([]string{"c.c"}, []string{})}, - }, - }, - { - name: "no configurable values, empty partition", - ctx: &OtherModuleTestContext{}, - labelList: LabelListAttribute{ - Value: makeLabelList([]string{"a.a", "c.c"}, []string{}), - }, - filters: LabelPartitions{ - "A": LabelPartition{Extensions: []string{".a"}}, - "B": LabelPartition{Extensions: []string{".b"}}, - "C": LabelPartition{Extensions: []string{".c"}}, - }, - expected: PartitionToLabelListAttribute{ - "A": LabelListAttribute{Value: makeLabelList([]string{"a.a"}, []string{})}, - "C": LabelListAttribute{Value: makeLabelList([]string{"c.c"}, []string{})}, - }, - }, - { - name: "no configurable values, has map", - ctx: &OtherModuleTestContext{ - Modules: []TestModuleInfo{{ModuleName: "srcs", Typ: "fg", Dir: "dir"}}, - }, - labelList: LabelListAttribute{ - Value: makeLabelList([]string{"a.a", "srcs", "b.b", "c.c"}, []string{}), - }, - filters: LabelPartitions{ - "A": LabelPartition{Extensions: []string{".a"}, LabelMapper: labelAddSuffixForTypeMapper("_a", "fg")}, - "B": LabelPartition{Extensions: []string{".b"}}, - "C": LabelPartition{Extensions: []string{".c"}}, - }, - expected: PartitionToLabelListAttribute{ - "A": LabelListAttribute{Value: makeLabelList([]string{"a.a", "srcs_a"}, []string{})}, - "B": LabelListAttribute{Value: makeLabelList([]string{"b.b"}, []string{})}, - "C": LabelListAttribute{Value: makeLabelList([]string{"c.c"}, []string{})}, - }, - }, - { - name: "configurable values, keeps empty if excludes", - ctx: &OtherModuleTestContext{}, - labelList: LabelListAttribute{ - ConfigurableValues: configurableLabelLists{ - ArchConfigurationAxis: labelListSelectValues{ - "x86": makeLabelList([]string{"a.a", "c.c"}, []string{}), - "arm": makeLabelList([]string{"b.b"}, []string{}), - "x86_64": makeLabelList([]string{"b.b"}, []string{"d.d"}), - }, - }, - }, - filters: LabelPartitions{ - "A": LabelPartition{Extensions: []string{".a"}}, - "B": LabelPartition{Extensions: []string{".b"}}, - "C": LabelPartition{Extensions: []string{".c"}}, - }, - expected: PartitionToLabelListAttribute{ - "A": LabelListAttribute{ - ConfigurableValues: configurableLabelLists{ - ArchConfigurationAxis: labelListSelectValues{ - "x86": makeLabelList([]string{"a.a"}, []string{}), - "x86_64": makeLabelList([]string{}, []string{"c.c"}), - }, - }, - }, - "B": LabelListAttribute{ - ConfigurableValues: configurableLabelLists{ - ArchConfigurationAxis: labelListSelectValues{ - "arm": makeLabelList([]string{"b.b"}, []string{}), - "x86_64": makeLabelList([]string{"b.b"}, []string{"c.c"}), - }, - }, - }, - "C": LabelListAttribute{ - ConfigurableValues: configurableLabelLists{ - ArchConfigurationAxis: labelListSelectValues{ - "x86": makeLabelList([]string{"c.c"}, []string{}), - "x86_64": makeLabelList([]string{}, []string{"c.c"}), - }, - }, - }, - }, - }, - { - name: "error for multiple partitions same value", - ctx: &OtherModuleTestContext{}, - labelList: LabelListAttribute{ - Value: makeLabelList([]string{"a.a", "b.b", "c.c", "d.d", "e.e"}, []string{}), - }, - filters: LabelPartitions{ - "A": LabelPartition{Extensions: []string{".a"}}, - "other A": LabelPartition{Extensions: []string{".a"}}, - }, - expected: PartitionToLabelListAttribute{}, - expectedErrMsg: proptools.StringPtr(`"a.a" was found in multiple partitions:`), - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - got := PartitionLabelListAttribute(tc.ctx, &tc.labelList, tc.filters) - - if hasErrors, expectsErr := len(tc.ctx.errors) > 0, tc.expectedErrMsg != nil; hasErrors != expectsErr { - t.Errorf("Unexpected error(s): %q, expected: %q", tc.ctx.errors, *tc.expectedErrMsg) - } else if tc.expectedErrMsg != nil { - found := false - for _, err := range tc.ctx.errors { - if strings.Contains(err, *tc.expectedErrMsg) { - found = true - break - } - } - - if !found { - t.Errorf("Expected error message: %q, got %q", *tc.expectedErrMsg, tc.ctx.errors) - } - return - } - - if len(tc.expected) != len(got) { - t.Errorf("Expected %d partitions, got %d partitions", len(tc.expected), len(got)) - } - for partition, expectedLla := range tc.expected { - gotLla, ok := got[partition] - if !ok { - t.Errorf("Expected partition %q, but it was not found %v", partition, got) - continue - } - expectedLabelList := expectedLla.Value - gotLabelList := gotLla.Value - if !reflect.DeepEqual(expectedLabelList.Includes, gotLabelList.Includes) { - t.Errorf("Expected no config includes %v, got %v", expectedLabelList.Includes, gotLabelList.Includes) - } - expectedAxes := expectedLla.SortedConfigurationAxes() - gotAxes := gotLla.SortedConfigurationAxes() - if !reflect.DeepEqual(expectedAxes, gotAxes) { - t.Errorf("Expected axes %v, got %v (%#v)", expectedAxes, gotAxes, gotLla) - } - for _, axis := range expectedLla.SortedConfigurationAxes() { - if _, exists := gotLla.ConfigurableValues[axis]; !exists { - t.Errorf("Expected %s to be a supported axis, but it was not found", axis) - } - if expected, got := expectedLla.ConfigurableValues[axis], gotLla.ConfigurableValues[axis]; len(expected) != len(got) { - t.Errorf("For axis %q: expected configs %v, got %v", axis, expected, got) - } - for config, expectedLabelList := range expectedLla.ConfigurableValues[axis] { - gotLabelList, exists := gotLla.ConfigurableValues[axis][config] - if !exists { - t.Errorf("Expected %s to be a supported config, but config was not found", config) - continue - } - if !reflect.DeepEqual(expectedLabelList.Includes, gotLabelList.Includes) { - t.Errorf("Expected %s %s includes %v, got %v", axis, config, expectedLabelList.Includes, gotLabelList.Includes) - } - } - } - } - }) - } -} - -func TestDeduplicateAxesFromBase(t *testing.T) { - attr := StringListAttribute{ - Value: []string{ - "all_include", - "arm_include", - "android_include", - "linux_x86_include", - }, - ConfigurableValues: configurableStringLists{ - ArchConfigurationAxis: stringListSelectValues{ - "arm": []string{"arm_include"}, - "x86": []string{"x86_include"}, - }, - OsConfigurationAxis: stringListSelectValues{ - "android": []string{"android_include"}, - "linux": []string{"linux_include"}, - }, - OsArchConfigurationAxis: stringListSelectValues{ - "linux_x86": {"linux_x86_include"}, - }, - ProductVariableConfigurationAxis(false, "a"): stringListSelectValues{ - "a": []string{"not_in_value"}, - }, - }, - } - - attr.DeduplicateAxesFromBase() - - expectedBaseIncludes := []string{ - "all_include", - "arm_include", - "android_include", - "linux_x86_include", - } - if !reflect.DeepEqual(expectedBaseIncludes, attr.Value) { - t.Errorf("Expected Value includes %q, got %q", attr.Value, expectedBaseIncludes) - } - expectedConfiguredIncludes := configurableStringLists{ - ArchConfigurationAxis: stringListSelectValues{ - "x86": []string{"x86_include"}, - }, - OsConfigurationAxis: stringListSelectValues{ - "linux": []string{"linux_include"}, - }, - OsArchConfigurationAxis: stringListSelectValues{}, - ProductVariableConfigurationAxis(false, "a"): stringListSelectValues{ - "a": []string{"not_in_value"}, - }, - } - for _, axis := range attr.SortedConfigurationAxes() { - if _, ok := expectedConfiguredIncludes[axis]; !ok { - t.Errorf("Found unexpected axis %s", axis) - continue - } - expectedForAxis := expectedConfiguredIncludes[axis] - gotForAxis := attr.ConfigurableValues[axis] - if len(expectedForAxis) != len(gotForAxis) { - t.Errorf("Expected %d configs for %s, got %d: %s", len(expectedForAxis), axis, len(gotForAxis), gotForAxis) - } - for config, value := range gotForAxis { - if expected, ok := expectedForAxis[config]; ok { - if !reflect.DeepEqual(expected, value) { - t.Errorf("For %s, expected: %#v, got %#v", axis, expected, value) - } - } else { - t.Errorf("Got unexpected config %q for %s", config, axis) - } - } - } -} diff --git a/bazel/testing.go b/bazel/testing.go deleted file mode 100644 index 9a43b61d7..000000000 --- a/bazel/testing.go +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 2021 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" - - "github.com/google/blueprint" -) - -// TestModuleInfo implements blueprint.Module interface with sufficient information to mock a subset of -// a blueprint ModuleContext -type TestModuleInfo struct { - ModuleName string - Typ string - Dir string -} - -// Name returns name for testModuleInfo -- required to implement blueprint.Module -func (mi TestModuleInfo) Name() string { - return mi.ModuleName -} - -// GenerateBuildActions unused, but required to implmeent blueprint.Module -func (mi TestModuleInfo) GenerateBuildActions(blueprint.ModuleContext) {} - -func (mi TestModuleInfo) equals(other TestModuleInfo) bool { - return mi.ModuleName == other.ModuleName && mi.Typ == other.Typ && mi.Dir == other.Dir -} - -// ensure testModuleInfo implements blueprint.Module -var _ blueprint.Module = TestModuleInfo{} - -// OtherModuleTestContext is a mock context that implements OtherModuleContext -type OtherModuleTestContext struct { - Modules []TestModuleInfo - errors []string -} - -// ModuleFromName retrieves the testModuleInfo corresponding to name, if it exists -func (omc *OtherModuleTestContext) ModuleFromName(name string) (blueprint.Module, bool) { - for _, m := range omc.Modules { - if m.ModuleName == name { - return m, true - } - } - return TestModuleInfo{}, false -} - -// testModuleInfo returns the testModuleInfo corresponding to a blueprint.Module if it exists in omc -func (omc *OtherModuleTestContext) testModuleInfo(m blueprint.Module) (TestModuleInfo, bool) { - mi, ok := m.(TestModuleInfo) - if !ok { - return TestModuleInfo{}, false - } - for _, other := range omc.Modules { - if other.equals(mi) { - return mi, true - } - } - return TestModuleInfo{}, false -} - -// OtherModuleType returns type of m if it exists in omc -func (omc *OtherModuleTestContext) OtherModuleType(m blueprint.Module) string { - if mi, ok := omc.testModuleInfo(m); ok { - return mi.Typ - } - return "" -} - -// OtherModuleName returns name of m if it exists in omc -func (omc *OtherModuleTestContext) OtherModuleName(m blueprint.Module) string { - if mi, ok := omc.testModuleInfo(m); ok { - return mi.ModuleName - } - return "" -} - -// OtherModuleDir returns dir of m if it exists in omc -func (omc *OtherModuleTestContext) OtherModuleDir(m blueprint.Module) string { - if mi, ok := omc.testModuleInfo(m); ok { - return mi.Dir - } - return "" -} - -func (omc *OtherModuleTestContext) ModuleErrorf(format string, args ...interface{}) { - omc.errors = append(omc.errors, fmt.Sprintf(format, args...)) -} - -// Ensure otherModuleTestContext implements OtherModuleContext -var _ OtherModuleContext = &OtherModuleTestContext{} diff --git a/bp2build/Android.bp b/bp2build/Android.bp index ba1268214..28c026857 100644 --- a/bp2build/Android.bp +++ b/bp2build/Android.bp @@ -9,7 +9,6 @@ bootstrap_go_package { "androidbp_to_build_templates.go", "build_conversion.go", "bzl_conversion.go", - "configurability.go", "constants.go", "conversion.go", ], @@ -21,7 +20,6 @@ bootstrap_go_package { "soong-android-allowlists", "soong-android-soongconfig", "soong-apex", - "soong-bazel", "soong-cc", "soong-cc-config", "soong-etc", diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go index bd5676815..18213a880 100644 --- a/bp2build/build_conversion.go +++ b/bp2build/build_conversion.go @@ -26,7 +26,6 @@ import ( "strings" "android/soong/android" - "android/soong/bazel" "android/soong/starlark_fmt" "github.com/google/blueprint" "github.com/google/blueprint/proptools" @@ -182,12 +181,11 @@ type bpToBuildContext interface { } type CodegenContext struct { - config android.Config - context *android.Context - mode CodegenMode - additionalDeps []string - unconvertedDepMode unconvertedDepsMode - topDir string + config android.Config + context *android.Context + mode CodegenMode + additionalDeps []string + topDir string } func (ctx *CodegenContext) Mode() CodegenMode { @@ -207,16 +205,6 @@ const ( QueryView CodegenMode = iota ) -type unconvertedDepsMode int - -const ( - // Include a warning in conversion metrics about converted modules with unconverted direct deps - warnUnconvertedDeps unconvertedDepsMode = iota - // Error and fail conversion if encountering a module with unconverted direct deps - // Enabled by setting environment variable `BP2BUILD_ERROR_UNCONVERTED` - errorModulesUnconvertedDeps -) - func (mode CodegenMode) String() string { switch mode { case QueryView: @@ -245,13 +233,11 @@ func (ctx *CodegenContext) Context() *android.Context { return ctx.context } // NewCodegenContext creates a wrapper context that conforms to PathContext for // writing BUILD files in the output directory. func NewCodegenContext(config android.Config, context *android.Context, mode CodegenMode, topDir string) *CodegenContext { - var unconvertedDeps unconvertedDepsMode return &CodegenContext{ - context: context, - config: config, - mode: mode, - unconvertedDepMode: unconvertedDeps, - topDir: topDir, + context: context, + config: config, + mode: mode, + topDir: topDir, } } @@ -482,14 +468,6 @@ func prettyPrint(propertyValue reflect.Value, indent int, emitZeroValues bool) ( }), nil case reflect.Struct: - // Special cases where the bp2build sends additional information to the codegenerator - // by wrapping the attributes in a custom struct type. - if attr, ok := propertyValue.Interface().(bazel.Attribute); ok { - return prettyPrintAttribute(attr, indent) - } else if label, ok := propertyValue.Interface().(bazel.Label); ok { - return fmt.Sprintf("%q", label.Label), nil - } - // Sort and print the struct props by the key. structProps, err := extractStructProperties(propertyValue, indent) @@ -506,7 +484,7 @@ func prettyPrint(propertyValue reflect.Value, indent int, emitZeroValues bool) ( // Interfaces are used for for arch, multilib and target properties. return "", nil case reflect.Map: - if v, ok := propertyValue.Interface().(bazel.StringMapAttribute); ok { + if v, ok := propertyValue.Interface().(map[string]string); ok { return starlark_fmt.PrintStringStringDict(v, indent), nil } return "", fmt.Errorf("bp2build expects map of type map[string]string for field: %s", propertyValue) diff --git a/bp2build/configurability.go b/bp2build/configurability.go deleted file mode 100644 index 3d9f0a274..000000000 --- a/bp2build/configurability.go +++ /dev/null @@ -1,328 +0,0 @@ -package bp2build - -import ( - "fmt" - "reflect" - - "android/soong/android" - "android/soong/bazel" - "android/soong/starlark_fmt" -) - -// Configurability support for bp2build. - -type selects map[string]reflect.Value - -func getStringValue(str bazel.StringAttribute) (reflect.Value, []selects) { - value := reflect.ValueOf(str.Value) - - if !str.HasConfigurableValues() { - return value, []selects{} - } - - ret := selects{} - for _, axis := range str.SortedConfigurationAxes() { - configToStrs := str.ConfigurableValues[axis] - for config, strs := range configToStrs { - selectKey := axis.SelectKey(config) - ret[selectKey] = reflect.ValueOf(strs) - } - } - - // if there is a select, use the base value as the conditions default value - if len(ret) > 0 { - if _, ok := ret[bazel.ConditionsDefaultSelectKey]; !ok { - ret[bazel.ConditionsDefaultSelectKey] = value - value = reflect.Zero(value.Type()) - } - } - - return value, []selects{ret} -} - -func getStringListValues(list bazel.StringListAttribute) (reflect.Value, []selects, bool) { - value := reflect.ValueOf(list.Value) - prepend := list.Prepend - if !list.HasConfigurableValues() { - return value, []selects{}, prepend - } - - var ret []selects - for _, axis := range list.SortedConfigurationAxes() { - configToLists := list.ConfigurableValues[axis] - archSelects := map[string]reflect.Value{} - for config, labels := range configToLists { - selectKey := axis.SelectKey(config) - archSelects[selectKey] = reflect.ValueOf(labels) - } - if len(archSelects) > 0 { - ret = append(ret, archSelects) - } - } - - return value, ret, prepend -} - -func getLabelValue(label bazel.LabelAttribute) (reflect.Value, []selects) { - value := reflect.ValueOf(label.Value) - if !label.HasConfigurableValues() { - return value, []selects{} - } - - ret := selects{} - for _, axis := range label.SortedConfigurationAxes() { - configToLabels := label.ConfigurableValues[axis] - for config, labels := range configToLabels { - selectKey := axis.SelectKey(config) - ret[selectKey] = reflect.ValueOf(labels) - } - } - - // if there is a select, use the base value as the conditions default value - if len(ret) > 0 { - ret[bazel.ConditionsDefaultSelectKey] = value - value = reflect.Zero(value.Type()) - } - - return value, []selects{ret} -} - -func getBoolValue(boolAttr bazel.BoolAttribute) (reflect.Value, []selects) { - value := reflect.ValueOf(boolAttr.Value) - if !boolAttr.HasConfigurableValues() { - return value, []selects{} - } - - ret := selects{} - for _, axis := range boolAttr.SortedConfigurationAxes() { - configToBools := boolAttr.ConfigurableValues[axis] - for config, bools := range configToBools { - selectKey := axis.SelectKey(config) - ret[selectKey] = reflect.ValueOf(bools) - } - } - // if there is a select, use the base value as the conditions default value - if len(ret) > 0 { - ret[bazel.ConditionsDefaultSelectKey] = value - value = reflect.Zero(value.Type()) - } - - return value, []selects{ret} -} -func getLabelListValues(list bazel.LabelListAttribute) (reflect.Value, []selects, bool) { - value := reflect.ValueOf(list.Value.Includes) - prepend := list.Prepend - var ret []selects - for _, axis := range list.SortedConfigurationAxes() { - configToLabels := list.ConfigurableValues[axis] - if !configToLabels.HasConfigurableValues() { - continue - } - archSelects := map[string]reflect.Value{} - defaultVal := configToLabels[bazel.ConditionsDefaultConfigKey] - // Skip empty list values unless ether EmitEmptyList is true, or these values differ from the default. - emitEmptyList := list.EmitEmptyList || len(defaultVal.Includes) > 0 - for config, labels := range configToLabels { - // Omit any entries in the map which match the default value, for brevity. - if config != bazel.ConditionsDefaultConfigKey && labels.Equals(defaultVal) { - continue - } - selectKey := axis.SelectKey(config) - if use, value := labelListSelectValue(selectKey, labels, emitEmptyList); use { - archSelects[selectKey] = value - } - } - if len(archSelects) > 0 { - ret = append(ret, archSelects) - } - } - - return value, ret, prepend -} - -func labelListSelectValue(selectKey string, list bazel.LabelList, emitEmptyList bool) (bool, reflect.Value) { - if selectKey == bazel.ConditionsDefaultSelectKey || emitEmptyList || len(list.Includes) > 0 { - return true, reflect.ValueOf(list.Includes) - } else if len(list.Excludes) > 0 { - // if there is still an excludes -- we need to have an empty list for this select & use the - // value in conditions default Includes - return true, reflect.ValueOf([]string{}) - } - return false, reflect.Zero(reflect.TypeOf([]string{})) -} - -var ( - emptyBazelList = "[]" - bazelNone = "None" -) - -// prettyPrintAttribute converts an Attribute to its Bazel syntax. May contain -// select statements. -func prettyPrintAttribute(v bazel.Attribute, indent int) (string, error) { - var value reflect.Value - // configurableAttrs is the list of individual select statements to be - // concatenated together. These select statements should be along different - // axes. For example, one element may be - // `select({"//color:red": "one", "//color:green": "two"})`, and the second - // element may be `select({"//animal:cat": "three", "//animal:dog": "four"}). - // These selects should be sorted by axis identifier. - var configurableAttrs []selects - var prepend bool - var defaultSelectValue *string - var emitZeroValues bool - // If true, print the default attribute value, even if the attribute is zero. - shouldPrintDefault := false - switch list := v.(type) { - case bazel.StringAttribute: - if err := list.Collapse(); err != nil { - return "", err - } - value, configurableAttrs = getStringValue(list) - defaultSelectValue = &bazelNone - case bazel.StringListAttribute: - value, configurableAttrs, prepend = getStringListValues(list) - defaultSelectValue = &emptyBazelList - case bazel.LabelListAttribute: - value, configurableAttrs, prepend = getLabelListValues(list) - emitZeroValues = list.EmitEmptyList - defaultSelectValue = &emptyBazelList - if list.ForceSpecifyEmptyList && (!value.IsNil() || list.HasConfigurableValues()) { - shouldPrintDefault = true - } - case bazel.LabelAttribute: - if err := list.Collapse(); err != nil { - return "", err - } - value, configurableAttrs = getLabelValue(list) - defaultSelectValue = &bazelNone - case bazel.BoolAttribute: - if err := list.Collapse(); err != nil { - return "", err - } - value, configurableAttrs = getBoolValue(list) - defaultSelectValue = &bazelNone - default: - return "", fmt.Errorf("Not a supported Bazel attribute type: %s", v) - } - - var err error - ret := "" - if value.Kind() != reflect.Invalid { - s, err := prettyPrint(value, indent, false) // never emit zero values for the base value - if err != nil { - return ret, err - } - - ret += s - } - // Convenience function to prepend/append selects components to an attribute value. - concatenateSelects := func(selectsData selects, defaultValue *string, s string, prepend bool) (string, error) { - selectMap, err := prettyPrintSelectMap(selectsData, defaultValue, indent, emitZeroValues) - if err != nil { - return "", err - } - var left, right string - if prepend { - left, right = selectMap, s - } else { - left, right = s, selectMap - } - if left != "" && right != "" { - left += " + " - } - left += right - - return left, nil - } - - for _, configurableAttr := range configurableAttrs { - ret, err = concatenateSelects(configurableAttr, defaultSelectValue, ret, prepend) - if err != nil { - return "", err - } - } - - if ret == "" && shouldPrintDefault { - return *defaultSelectValue, nil - } - return ret, nil -} - -// prettyPrintSelectMap converts a map of select keys to reflected Values as a generic way -// to construct a select map for any kind of attribute type. -func prettyPrintSelectMap(selectMap map[string]reflect.Value, defaultValue *string, indent int, emitZeroValues bool) (string, error) { - if selectMap == nil { - return "", nil - } - - var selects string - for _, selectKey := range android.SortedKeys(selectMap) { - if selectKey == bazel.ConditionsDefaultSelectKey { - // Handle default condition later. - continue - } - value := selectMap[selectKey] - if isZero(value) && !emitZeroValues && isZero(selectMap[bazel.ConditionsDefaultSelectKey]) { - // Ignore zero values to not generate empty lists. However, always note zero values if - // the default value is non-zero. - continue - } - s, err := prettyPrintSelectEntry(value, selectKey, indent, true) - if err != nil { - return "", err - } - // s could still be an empty string, e.g. unset slices of structs with - // length of 0. - if s != "" { - selects += s + ",\n" - } - } - - if len(selects) == 0 { - // If there is a default value, and there are no selects for this axis, print that without any selects. - if val, exists := selectMap[bazel.ConditionsDefaultSelectKey]; exists { - return prettyPrint(val, indent, emitZeroValues) - } - // No conditions (or all values are empty lists), so no need for a map. - return "", nil - } - - // Create the map. - ret := "select({\n" - ret += selects - - // Handle the default condition - s, err := prettyPrintSelectEntry(selectMap[bazel.ConditionsDefaultSelectKey], bazel.ConditionsDefaultSelectKey, indent, emitZeroValues) - if err != nil { - return "", err - } - if s != "" { - // Print the custom default value. - ret += s - ret += ",\n" - } else if defaultValue != nil { - // Print an explicit empty list (the default value) even if the value is - // empty, to avoid errors about not finding a configuration that matches. - ret += fmt.Sprintf("%s\"%s\": %s,\n", starlark_fmt.Indention(indent+1), bazel.ConditionsDefaultSelectKey, *defaultValue) - } - - ret += starlark_fmt.Indention(indent) - ret += "})" - - return ret, nil -} - -// prettyPrintSelectEntry converts a reflect.Value into an entry in a select map -// with a provided key. -func prettyPrintSelectEntry(value reflect.Value, key string, indent int, emitZeroValues bool) (string, error) { - s := starlark_fmt.Indention(indent + 1) - v, err := prettyPrint(value, indent+1, emitZeroValues) - if err != nil { - return "", err - } - if v == "" { - return "", nil - } - s += fmt.Sprintf("\"%s\": %s", key, v) - return s, nil -} diff --git a/bp2build/constants.go b/bp2build/constants.go index 4870dffff..76ba106c4 100644 --- a/bp2build/constants.go +++ b/bp2build/constants.go @@ -20,9 +20,4 @@ var ( // The file name used for automatically generated files. GeneratedBuildFileName = "BUILD.bazel" - - // The file name used for hand-crafted build targets. - // NOTE: It is okay that this matches GeneratedBuildFileName, since we generate BUILD files in a different directory to source files - // FIXME: Because there are hundreds of existing BUILD.bazel files in the AOSP tree, we should pick another name here, like BUILD.android - HandcraftedBuildFileName = "BUILD.bazel" ) |