Merge "Bp2build support for soong config variables + os"
diff --git a/android/variable.go b/android/variable.go
index aaf0606..bf66135 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -541,124 +541,102 @@
Module() Module
}
-// ProductConfigProperty contains the information for a single property (may be a struct) paired
-// with the appropriate ProductConfigVariable.
+// ProductConfigOrSoongConfigProperty represents either a soong config variable + its value
+// or a product config variable. You can get both a ConfigurationAxis and a SelectKey from it
+// for use in bazel attributes. ProductVariableProperties() will return a map from properties ->
+// this interface -> property structs for use in bp2build converters
+type ProductConfigOrSoongConfigProperty interface {
+ // Name of the product variable or soong config variable
+ Name() string
+ // AlwaysEmit returns true for soong config variables but false for product variables. This
+ // is intended to indicate if we need to always emit empty lists in the select statements.
+ AlwaysEmit() bool
+ // ConfigurationAxis returns the bazel.ConfigurationAxis that represents this variable. The
+ // configuration axis will change depending on the variable and whether it's arch/os variant
+ // as well.
+ ConfigurationAxis() bazel.ConfigurationAxis
+ // SelectKey returns a string that represents the key of a select branch, however, it is not
+ // actually the real label written out to the build file.
+ // this.ConfigurationAxis().SelectKey(this.SelectKey()) will give the actual label.
+ SelectKey() string
+}
+
+// ProductConfigProperty represents a product config variable, and if it is arch-variant or not.
type ProductConfigProperty struct {
// The name of the product variable, e.g. "safestack", "malloc_not_svelte",
// "board"
- Name string
+ name string
- // Namespace of the variable, if this is a soong_config_module_type variable
- // e.g. "acme", "ANDROID", "vendor_name"
- Namespace string
-
- // Unique configuration to identify this product config property (i.e. a
- // primary key), as just using the product variable name is not sufficient.
- //
- // For product variables, this is the product variable name + optional
- // archvariant information. e.g.
- //
- // product_variables: {
- // foo: {
- // cflags: ["-Dfoo"],
- // },
- // },
- //
- // FullConfig would be "foo".
- //
- // target: {
- // android: {
- // product_variables: {
- // foo: {
- // cflags: ["-Dfoo-android"],
- // },
- // },
- // },
- // },
- //
- // FullConfig would be "foo-android".
- //
- // For soong config variables, this is the namespace + product variable name
- // + value of the variable, if applicable. The value can also be
- // conditions_default.
- //
- // e.g.
- //
- // soong_config_variables: {
- // feature1: {
- // conditions_default: {
- // cflags: ["-DDEFAULT1"],
- // },
- // cflags: ["-DFEATURE1"],
- // },
- // }
- //
- // where feature1 is created in the "acme" namespace, so FullConfig would be
- // "acme__feature1" and "acme__feature1__conditions_default".
- //
- // e.g.
- //
- // soong_config_variables: {
- // board: {
- // soc_a: {
- // cflags: ["-DSOC_A"],
- // },
- // soc_b: {
- // cflags: ["-DSOC_B"],
- // },
- // soc_c: {},
- // conditions_default: {
- // cflags: ["-DSOC_DEFAULT"]
- // },
- // },
- // }
- //
- // where board is created in the "acme" namespace, so FullConfig would be
- // "acme__board__soc_a", "acme__board__soc_b", and
- // "acme__board__conditions_default"
- FullConfig string
-
- // keeps track of whether this product variable is nested under an arch variant
- OuterAxis bazel.ConfigurationAxis
+ arch string
}
-func (p *ProductConfigProperty) AlwaysEmit() bool {
- return p.Namespace != ""
+func (p ProductConfigProperty) Name() string {
+ return p.name
}
-func (p *ProductConfigProperty) ConfigurationAxis() bazel.ConfigurationAxis {
- if p.Namespace == "" {
- return bazel.ProductVariableConfigurationAxis(p.FullConfig, p.OuterAxis)
+func (p ProductConfigProperty) AlwaysEmit() bool {
+ return false
+}
+
+func (p ProductConfigProperty) ConfigurationAxis() bazel.ConfigurationAxis {
+ return bazel.ProductVariableConfigurationAxis(p.arch != "", p.name+"__"+p.arch)
+}
+
+func (p ProductConfigProperty) SelectKey() string {
+ if p.arch == "" {
+ return strings.ToLower(p.name)
} else {
- // Soong config variables can be uniquely identified by the namespace
- // (e.g. acme, android) and the product variable name (e.g. board, size)
- return bazel.ProductVariableConfigurationAxis(p.Namespace+"__"+p.Name, bazel.NoConfigAxis)
+ return strings.ToLower(p.name + "-" + p.arch)
}
}
+// SoongConfigProperty represents a soong config variable, its value if it's a string variable,
+// and if it's dependent on the OS or not
+type SoongConfigProperty struct {
+ name string
+ namespace string
+ // Can be an empty string for bool/value soong config variables
+ value string
+ // If there is a target: field inside a soong config property struct, the os that it selects
+ // on will be represented here.
+ os string
+}
+
+func (p SoongConfigProperty) Name() string {
+ return p.name
+}
+
+func (p SoongConfigProperty) AlwaysEmit() bool {
+ return true
+}
+
+func (p SoongConfigProperty) ConfigurationAxis() bazel.ConfigurationAxis {
+ return bazel.ProductVariableConfigurationAxis(false, p.namespace+"__"+p.name+"__"+p.os)
+}
+
// SelectKey returns the literal string that represents this variable in a BUILD
// select statement.
-func (p *ProductConfigProperty) SelectKey() string {
- if p.Namespace == "" {
- return strings.ToLower(p.FullConfig)
- }
-
- if p.FullConfig == bazel.ConditionsDefaultConfigKey {
+func (p SoongConfigProperty) SelectKey() string {
+ // p.value being conditions_default can happen with or without a desired os. When not using
+ // an os, we want to emit literally just //conditions:default in the select statement, but
+ // when using an os, we want to emit namespace__name__conditions_default__os, so that
+ // the branch is only taken if the variable is not set, and we're on the desired os.
+ // ConfigurationAxis#SelectKey will map the conditions_default result of this function to
+ // //conditions:default.
+ if p.value == bazel.ConditionsDefaultConfigKey && p.os == "" {
return bazel.ConditionsDefaultConfigKey
}
- value := p.FullConfig
- if value == p.Name {
- value = ""
+ parts := []string{p.namespace, p.name}
+ if p.value != "" && p.value != bazel.ConditionsDefaultSelectKey {
+ parts = append(parts, p.value)
+ }
+ if p.os != "" {
+ parts = append(parts, p.os)
}
- // e.g. acme__feature1, android__board__soc_a
- selectKey := strings.ToLower(strings.Join([]string{p.Namespace, p.Name}, "__"))
- if value != "" {
- selectKey = strings.ToLower(strings.Join([]string{selectKey, value}, "__"))
- }
-
- return selectKey
+ // e.g. acme__feature1, android__board__soc_a, my_namespace__my_variables__my_value__my_os
+ return strings.ToLower(strings.Join(parts, "__"))
}
// ProductConfigProperties is a map of maps to group property values according
@@ -674,7 +652,7 @@
//
// The value of the map is the interface{} representing the value of the
// property, like ["-DDEFINES"] for cflags.
-type ProductConfigProperties map[string]map[ProductConfigProperty]interface{}
+type ProductConfigProperties map[string]map[ProductConfigOrSoongConfigProperty]interface{}
// ProductVariableProperties returns a ProductConfigProperties containing only the properties which
// have been set for the given module.
@@ -685,26 +663,10 @@
if moduleBase.variableProperties != nil {
productVariablesProperty := proptools.FieldNameForProperty("product_variables")
- productVariableValues(
- productVariablesProperty,
- moduleBase.variableProperties,
- "",
- "",
- &productConfigProperties,
- bazel.ConfigurationAxis{},
- )
-
- for axis, configToProps := range moduleBase.GetArchVariantProperties(ctx, moduleBase.variableProperties) {
+ for /* axis */ _, configToProps := range moduleBase.GetArchVariantProperties(ctx, moduleBase.variableProperties) {
for config, props := range configToProps {
- // GetArchVariantProperties is creating an instance of the requested type
- // and productVariablesValues expects an interface, so no need to cast
- productVariableValues(
- productVariablesProperty,
- props,
- "",
- config,
- &productConfigProperties,
- axis)
+ variableValues := reflect.ValueOf(props).Elem().FieldByName(productVariablesProperty)
+ productConfigProperties.AddProductConfigProperties(variableValues, config)
}
}
}
@@ -712,13 +674,8 @@
if m, ok := module.(Bazelable); ok && m.namespacedVariableProps() != nil {
for namespace, namespacedVariableProps := range m.namespacedVariableProps() {
for _, namespacedVariableProp := range namespacedVariableProps {
- productVariableValues(
- soongconfig.SoongConfigProperty,
- namespacedVariableProp,
- namespace,
- "",
- &productConfigProperties,
- bazel.NoConfigAxis)
+ variableValues := reflect.ValueOf(namespacedVariableProp).Elem().FieldByName(soongconfig.SoongConfigProperty)
+ productConfigProperties.AddSoongConfigProperties(namespace, variableValues)
}
}
}
@@ -727,30 +684,49 @@
}
func (p *ProductConfigProperties) AddProductConfigProperty(
- propertyName, namespace, productVariableName, config string, property interface{}, outerAxis bazel.ConfigurationAxis) {
- if (*p)[propertyName] == nil {
- (*p)[propertyName] = make(map[ProductConfigProperty]interface{})
- }
+ propertyName, productVariableName, arch string, propertyValue interface{}) {
productConfigProp := ProductConfigProperty{
- Namespace: namespace, // e.g. acme, android
- Name: productVariableName, // e.g. size, feature1, feature2, FEATURE3, board
- FullConfig: config, // e.g. size, feature1-x86, size__conditions_default
- OuterAxis: outerAxis,
+ name: productVariableName, // e.g. size, feature1, feature2, FEATURE3, board
+ arch: arch, // e.g. "", x86, arm64
}
- if existing, ok := (*p)[propertyName][productConfigProp]; ok && namespace != "" {
+ p.AddEitherProperty(propertyName, productConfigProp, propertyValue)
+}
+
+func (p *ProductConfigProperties) AddSoongConfigProperty(
+ propertyName, namespace, variableName, value, os string, propertyValue interface{}) {
+
+ soongConfigProp := SoongConfigProperty{
+ namespace: namespace,
+ name: variableName, // e.g. size, feature1, feature2, FEATURE3, board
+ value: value,
+ os: os, // e.g. android, linux_x86
+ }
+
+ p.AddEitherProperty(propertyName, soongConfigProp, propertyValue)
+}
+
+func (p *ProductConfigProperties) AddEitherProperty(
+ propertyName string, key ProductConfigOrSoongConfigProperty, propertyValue interface{}) {
+ if (*p)[propertyName] == nil {
+ (*p)[propertyName] = make(map[ProductConfigOrSoongConfigProperty]interface{})
+ }
+
+ if existing, ok := (*p)[propertyName][key]; ok {
switch dst := existing.(type) {
case []string:
- if src, ok := property.([]string); ok {
- dst = append(dst, src...)
- (*p)[propertyName][productConfigProp] = dst
+ src, ok := propertyValue.([]string)
+ if !ok {
+ panic("Conflicting types")
}
+ dst = append(dst, src...)
+ (*p)[propertyName][key] = dst
default:
- panic(fmt.Errorf("TODO: handle merging value %s", existing))
+ panic(fmt.Errorf("TODO: handle merging value %#v", existing))
}
} else {
- (*p)[propertyName][productConfigProp] = property
+ (*p)[propertyName][key] = propertyValue
}
}
@@ -787,10 +763,7 @@
return v, true
}
-func (productConfigProperties *ProductConfigProperties) AddProductConfigProperties(namespace, suffix string, variableValues reflect.Value, outerAxis bazel.ConfigurationAxis) {
- // variableValues can either be a product_variables or
- // soong_config_variables struct.
- //
+func (productConfigProperties *ProductConfigProperties) AddProductConfigProperties(variableValues reflect.Value, arch string) {
// Example of product_variables:
//
// product_variables: {
@@ -803,35 +776,7 @@
// ],
// },
// },
- //
- // Example of soong_config_variables:
- //
- // soong_config_variables: {
- // feature1: {
- // conditions_default: {
- // ...
- // },
- // cflags: ...
- // },
- // feature2: {
- // cflags: ...
- // conditions_default: {
- // ...
- // },
- // },
- // board: {
- // soc_a: {
- // ...
- // },
- // soc_a: {
- // ...
- // },
- // soc_c: {},
- // conditions_default: {
- // ...
- // },
- // },
- // }
+
for i := 0; i < variableValues.NumField(); i++ {
// e.g. Platform_sdk_version, Unbundled_build, Malloc_not_svelte, etc.
productVariableName := variableValues.Type().Field(i).Name
@@ -843,25 +788,78 @@
continue
}
- // Unlike product variables, config variables require a few more
- // indirections to extract the struct from the reflect.Value.
- if v, ok := maybeExtractConfigVarProp(variableValue); ok {
- variableValue = v
- }
-
for j := 0; j < variableValue.NumField(); j++ {
property := variableValue.Field(j)
// e.g. Asflags, Cflags, Enabled, etc.
propertyName := variableValue.Type().Field(j).Name
- // config can also be "conditions_default".
- config := proptools.PropertyNameForField(propertyName)
+ if property.Kind() != reflect.Interface {
+ productConfigProperties.AddProductConfigProperty(propertyName, productVariableName, arch, property.Interface())
+ }
+ }
+ }
+
+}
+
+func (productConfigProperties *ProductConfigProperties) AddSoongConfigProperties(namespace string, soongConfigVariablesStruct reflect.Value) {
+ //
+ // Example of soong_config_variables:
+ //
+ // soong_config_variables: {
+ // feature1: {
+ // conditions_default: {
+ // ...
+ // },
+ // cflags: ...
+ // },
+ // feature2: {
+ // cflags: ...
+ // conditions_default: {
+ // ...
+ // },
+ // },
+ // board: {
+ // soc_a: {
+ // ...
+ // },
+ // soc_b: {
+ // ...
+ // },
+ // soc_c: {},
+ // conditions_default: {
+ // ...
+ // },
+ // },
+ // }
+ for i := 0; i < soongConfigVariablesStruct.NumField(); i++ {
+ // e.g. feature1, feature2, board
+ variableName := soongConfigVariablesStruct.Type().Field(i).Name
+ variableStruct := soongConfigVariablesStruct.Field(i)
+ // Check if any properties were set for the module
+ if variableStruct.IsZero() {
+ // e.g. feature1: {}
+ continue
+ }
+
+ // Unlike product variables, config variables require a few more
+ // indirections to extract the struct from the reflect.Value.
+ if v, ok := maybeExtractConfigVarProp(variableStruct); ok {
+ variableStruct = v
+ }
+
+ for j := 0; j < variableStruct.NumField(); j++ {
+ propertyOrStruct := variableStruct.Field(j)
+ // propertyOrValueName can either be:
+ // - A property, like: Asflags, Cflags, Enabled, etc.
+ // - A soong config string variable's value, like soc_a, soc_b, soc_c in the example above
+ // - "conditions_default"
+ propertyOrValueName := variableStruct.Type().Field(j).Name
// If the property wasn't set, no need to pass it along
- if property.IsZero() {
+ if propertyOrStruct.IsZero() {
continue
}
- if v, ok := maybeExtractConfigVarProp(property); ok {
+ if v, ok := maybeExtractConfigVarProp(propertyOrStruct); ok {
// The field is a struct, which is used by:
// 1) soong_config_string_variables
//
@@ -879,6 +877,9 @@
// cflags: ...,
// static_libs: ...
// }
+ //
+ // This means that propertyOrValueName is either conditions_default, or a soong
+ // config string variable's value.
field := v
// Iterate over fields of this struct prop.
for k := 0; k < field.NumField(); k++ {
@@ -888,47 +889,59 @@
if field.Field(k).IsZero() && namespace == "" {
continue
}
- actualPropertyName := field.Type().Field(k).Name
- productConfigProperties.AddProductConfigProperty(
- actualPropertyName, // e.g. cflags, static_libs
- namespace, // e.g. acme, android
- productVariableName, // e.g. size, feature1, FEATURE2, board
- config,
- field.Field(k).Interface(), // e.g. ["-DDEFAULT"], ["foo", "bar"],
- outerAxis,
- )
+ propertyName := field.Type().Field(k).Name
+ if propertyName == "Target" {
+ productConfigProperties.AddSoongConfigPropertiesFromTargetStruct(namespace, variableName, proptools.PropertyNameForField(propertyOrValueName), field.Field(k))
+ } else if propertyName == "Arch" || propertyName == "Multilib" {
+ panic("Arch/Multilib are not currently supported in soong config variable structs")
+ } else {
+ productConfigProperties.AddSoongConfigProperty(propertyName, namespace, variableName, proptools.PropertyNameForField(propertyOrValueName), "", field.Field(k).Interface())
+ }
}
- } else if property.Kind() != reflect.Interface {
+ } else if propertyOrStruct.Kind() != reflect.Interface {
// If not an interface, then this is not a conditions_default or
- // a struct prop. That is, this is a regular product variable,
- // or a bool/value config variable.
- config := productVariableName + suffix
- productConfigProperties.AddProductConfigProperty(
- propertyName,
- namespace,
- productVariableName,
- config,
- property.Interface(),
- outerAxis,
- )
+ // a struct prop. That is, this is a bool/value config variable.
+ if propertyOrValueName == "Target" {
+ productConfigProperties.AddSoongConfigPropertiesFromTargetStruct(namespace, variableName, "", propertyOrStruct)
+ } else if propertyOrValueName == "Arch" || propertyOrValueName == "Multilib" {
+ panic("Arch/Multilib are not currently supported in soong config variable structs")
+ } else {
+ productConfigProperties.AddSoongConfigProperty(propertyOrValueName, namespace, variableName, "", "", propertyOrStruct.Interface())
+ }
}
}
}
}
-// productVariableValues uses reflection to convert a property struct for
-// product_variables and soong_config_variables to structs that can be generated
-// as select statements.
-func productVariableValues(
- fieldName string, variableProps interface{}, namespace, suffix string, productConfigProperties *ProductConfigProperties, outerAxis bazel.ConfigurationAxis) {
- if suffix != "" {
- suffix = "-" + suffix
- }
+func (productConfigProperties *ProductConfigProperties) AddSoongConfigPropertiesFromTargetStruct(namespace, soongConfigVariableName string, soongConfigVariableValue string, targetStruct reflect.Value) {
+ // targetStruct will be a struct with fields like "android", "host", "arm", "x86",
+ // "android_arm", etc. The values of each of those fields will be a regular property struct.
+ for i := 0; i < targetStruct.NumField(); i++ {
+ targetFieldName := targetStruct.Type().Field(i).Name
+ archOrOsSpecificStruct := targetStruct.Field(i)
+ for j := 0; j < archOrOsSpecificStruct.NumField(); j++ {
+ property := archOrOsSpecificStruct.Field(j)
+ // e.g. Asflags, Cflags, Enabled, etc.
+ propertyName := archOrOsSpecificStruct.Type().Field(j).Name
- // variableValues represent the product_variables or soong_config_variables struct.
- variableValues := reflect.ValueOf(variableProps).Elem().FieldByName(fieldName)
- productConfigProperties.AddProductConfigProperties(namespace, suffix, variableValues, outerAxis)
+ if targetFieldName == "Android" {
+ productConfigProperties.AddSoongConfigProperty(propertyName, namespace, soongConfigVariableName, soongConfigVariableValue, "android", property.Interface())
+ } else if targetFieldName == "Host" {
+ for _, os := range osTypeList {
+ if os.Class == Host {
+ productConfigProperties.AddSoongConfigProperty(propertyName, namespace, soongConfigVariableName, soongConfigVariableValue, os.Name, property.Interface())
+ }
+ }
+ } else {
+ // One problem with supporting additional fields is that if multiple branches of
+ // "target" overlap, we don't want them to be in the same select statement (aka
+ // configuration axis). "android" and "host" are disjoint, so it's ok that we only
+ // have 2 axes right now. (soongConfigVariables and soongConfigVariablesPlusOs)
+ panic("TODO: support other target types in soong config variable structs: " + targetFieldName)
+ }
+ }
+ }
}
func VariableMutator(mctx BottomUpMutatorContext) {
diff --git a/bazel/configurability.go b/bazel/configurability.go
index d01877d..8f4f965 100644
--- a/bazel/configurability.go
+++ b/bazel/configurability.go
@@ -292,8 +292,7 @@
case osArch:
return platformOsArchMap[config]
case productVariables:
- if strings.HasSuffix(config, ConditionsDefaultConfigKey) {
- // e.g. "acme__feature1__conditions_default" or "android__board__conditions_default"
+ if config == ConditionsDefaultConfigKey {
return ConditionsDefaultSelectKey
}
return fmt.Sprintf("%s:%s", productVariableBazelPackage, config)
@@ -325,11 +324,11 @@
)
// ProductVariableConfigurationAxis returns an axis for the given product variable
-func ProductVariableConfigurationAxis(variable string, outerAxis ConfigurationAxis) ConfigurationAxis {
+func ProductVariableConfigurationAxis(archVariant bool, variable string) ConfigurationAxis {
return ConfigurationAxis{
configurationType: productVariables,
subType: variable,
- outerAxisType: outerAxis.configurationType,
+ archVariant: archVariant,
}
}
@@ -340,8 +339,8 @@
// 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
- // used to keep track of which product variables are arch variant
- outerAxisType configurationType
+
+ archVariant bool
}
func (ca *ConfigurationAxis) less(other ConfigurationAxis) bool {
diff --git a/bazel/properties.go b/bazel/properties.go
index 1757bad..77db1c4 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -334,7 +334,7 @@
if containsArch {
allProductVariablesAreArchVariant := true
for k := range la.ConfigurableValues {
- if k.configurationType == productVariables && k.outerAxisType != arch {
+ if k.configurationType == productVariables && !k.archVariant {
allProductVariablesAreArchVariant = false
}
}
diff --git a/bazel/properties_test.go b/bazel/properties_test.go
index cf03eb5..c56d11f 100644
--- a/bazel/properties_test.go
+++ b/bazel/properties_test.go
@@ -248,13 +248,13 @@
OsArchConfigurationAxis: labelListSelectValues{
"linux_x86": makeLabelList([]string{"linux_x86_include"}, []string{}),
},
- ProductVariableConfigurationAxis("product_with_defaults", NoConfigAxis): labelListSelectValues{
+ 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("product_only_with_excludes", NoConfigAxis): labelListSelectValues{
+ ProductVariableConfigurationAxis(false, "product_only_with_excludes"): labelListSelectValues{
"a": makeLabelList([]string{}, []string{"product_config_exclude"}),
},
},
@@ -282,13 +282,13 @@
"linux_x86": makeLabels("linux_x86_include"),
ConditionsDefaultConfigKey: nilLabels,
},
- ProductVariableConfigurationAxis("product_with_defaults", NoConfigAxis): {
+ ProductVariableConfigurationAxis(false, "product_with_defaults"): {
"a": nilLabels,
"b": makeLabels("b_val"),
"c": makeLabels("c_val"),
ConditionsDefaultConfigKey: makeLabels("c_val", "default", "default2"),
},
- ProductVariableConfigurationAxis("product_only_with_excludes", NoConfigAxis): {
+ ProductVariableConfigurationAxis(false, "product_only_with_excludes"): {
"a": nilLabels,
ConditionsDefaultConfigKey: makeLabels("product_config_exclude"),
},
@@ -679,7 +679,7 @@
OsArchConfigurationAxis: stringListSelectValues{
"linux_x86": {"linux_x86_include"},
},
- ProductVariableConfigurationAxis("a", NoConfigAxis): stringListSelectValues{
+ ProductVariableConfigurationAxis(false, "a"): stringListSelectValues{
"a": []string{"not_in_value"},
},
},
@@ -704,7 +704,7 @@
"linux": []string{"linux_include"},
},
OsArchConfigurationAxis: stringListSelectValues{},
- ProductVariableConfigurationAxis("a", NoConfigAxis): stringListSelectValues{
+ ProductVariableConfigurationAxis(false, "a"): stringListSelectValues{
"a": []string{"not_in_value"},
},
}
diff --git a/bp2build/soong_config_module_type_conversion_test.go b/bp2build/soong_config_module_type_conversion_test.go
index ba42f34..ad07f68 100644
--- a/bp2build/soong_config_module_type_conversion_test.go
+++ b/bp2build/soong_config_module_type_conversion_test.go
@@ -1251,3 +1251,111 @@
srcs = ["main.cc"],
)`}})
}
+
+func TestSoongConfigModuleType_CombinedWithArchVariantProperties(t *testing.T) {
+ bp := `
+soong_config_bool_variable {
+ name: "my_bool_variable",
+}
+
+soong_config_string_variable {
+ name: "my_string_variable",
+ values: [
+ "value1",
+ "value2",
+ ],
+}
+
+soong_config_module_type {
+ name: "special_build_cc_defaults",
+ module_type: "cc_defaults",
+ config_namespace: "my_namespace",
+ bool_variables: ["my_bool_variable"],
+ variables: ["my_string_variable"],
+ properties: ["target.android.cflags", "cflags"],
+}
+
+special_build_cc_defaults {
+ name: "sample_cc_defaults",
+ target: {
+ android: {
+ cflags: ["-DFOO"],
+ },
+ },
+ soong_config_variables: {
+ my_bool_variable: {
+ target: {
+ android: {
+ cflags: ["-DBAR"],
+ },
+ },
+ conditions_default: {
+ target: {
+ android: {
+ cflags: ["-DBAZ"],
+ },
+ },
+ },
+ },
+ my_string_variable: {
+ value1: {
+ cflags: ["-DVALUE1_NOT_ANDROID"],
+ target: {
+ android: {
+ cflags: ["-DVALUE1"],
+ },
+ },
+ },
+ value2: {
+ target: {
+ android: {
+ cflags: ["-DVALUE2"],
+ },
+ },
+ },
+ conditions_default: {
+ target: {
+ android: {
+ cflags: ["-DSTRING_VAR_CONDITIONS_DEFAULT"],
+ },
+ },
+ },
+ },
+ },
+}
+
+cc_binary {
+ name: "my_binary",
+ srcs: ["main.cc"],
+ defaults: ["sample_cc_defaults"],
+}`
+
+ runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
+ Description: "soong config variables - generates selects for library_linking_strategy",
+ ModuleTypeUnderTest: "cc_binary",
+ ModuleTypeUnderTestFactory: cc.BinaryFactory,
+ Blueprint: bp,
+ Filesystem: map[string]string{},
+ ExpectedBazelTargets: []string{`cc_binary(
+ name = "my_binary",
+ copts = select({
+ "//build/bazel/platforms/os:android": ["-DFOO"],
+ "//conditions:default": [],
+ }) + select({
+ "//build/bazel/product_variables:my_namespace__my_bool_variable__android": ["-DBAR"],
+ "//build/bazel/product_variables:my_namespace__my_bool_variable__conditions_default__android": ["-DBAZ"],
+ "//conditions:default": [],
+ }) + select({
+ "//build/bazel/product_variables:my_namespace__my_string_variable__value1": ["-DVALUE1_NOT_ANDROID"],
+ "//conditions:default": [],
+ }) + select({
+ "//build/bazel/product_variables:my_namespace__my_string_variable__conditions_default__android": ["-DSTRING_VAR_CONDITIONS_DEFAULT"],
+ "//build/bazel/product_variables:my_namespace__my_string_variable__value1__android": ["-DVALUE1"],
+ "//build/bazel/product_variables:my_namespace__my_string_variable__value2__android": ["-DVALUE2"],
+ "//conditions:default": [],
+ }),
+ local_includes = ["."],
+ srcs = ["main.cc"],
+ target_compatible_with = ["//build/bazel/platforms/os:android"],
+)`}})
+}
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 749fce5..3bb00ad 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -537,7 +537,7 @@
if !ok {
ctx.ModuleErrorf("Could not convert product variable %s property", proptools.PropertyNameForField(propName))
}
- newFlags, _ := bazel.TryVariableSubstitutions(flags, productConfigProp.Name)
+ newFlags, _ := bazel.TryVariableSubstitutions(flags, productConfigProp.Name())
attr.SetSelectValue(productConfigProp.ConfigurationAxis(), productConfigProp.SelectKey(), newFlags)
}
}
@@ -1350,7 +1350,7 @@
// Collect all the configurations that an include or exclude property exists for.
// We want to iterate all configurations rather than either the include or exclude because, for a
// particular configuration, we may have either only an include or an exclude to handle.
- productConfigProps := make(map[android.ProductConfigProperty]bool, len(props)+len(excludeProps))
+ productConfigProps := make(map[android.ProductConfigOrSoongConfigProperty]bool, len(props)+len(excludeProps))
for p := range props {
productConfigProps[p] = true
}