product_variables srcs in prebuilt_etc

bp2build conversion handles product_variable srcs

bug: 228353067
Test: prebuilt_etc_conversion_test.go
Change-Id: I82d3a384ee14d4e981d502dd9eb824c87d5ae2c7
This commit is contained in:
Alix 2022-06-09 18:52:05 +00:00
parent 94e2603ab7
commit bbfd538326
6 changed files with 144 additions and 20 deletions

View file

@ -592,6 +592,9 @@ type ProductConfigProperty struct {
// "acme__board__soc_a", "acme__board__soc_b", and // "acme__board__soc_a", "acme__board__soc_b", and
// "acme__board__conditions_default" // "acme__board__conditions_default"
FullConfig string FullConfig string
// keeps track of whether this product variable is nested under an arch variant
OuterAxis bazel.ConfigurationAxis
} }
func (p *ProductConfigProperty) AlwaysEmit() bool { func (p *ProductConfigProperty) AlwaysEmit() bool {
@ -600,11 +603,11 @@ func (p *ProductConfigProperty) AlwaysEmit() bool {
func (p *ProductConfigProperty) ConfigurationAxis() bazel.ConfigurationAxis { func (p *ProductConfigProperty) ConfigurationAxis() bazel.ConfigurationAxis {
if p.Namespace == "" { if p.Namespace == "" {
return bazel.ProductVariableConfigurationAxis(p.FullConfig) return bazel.ProductVariableConfigurationAxis(p.FullConfig, p.OuterAxis)
} else { } else {
// Soong config variables can be uniquely identified by the namespace // Soong config variables can be uniquely identified by the namespace
// (e.g. acme, android) and the product variable name (e.g. board, size) // (e.g. acme, android) and the product variable name (e.g. board, size)
return bazel.ProductVariableConfigurationAxis(p.Namespace + "__" + p.Name) return bazel.ProductVariableConfigurationAxis(p.Namespace+"__"+p.Name, bazel.NoConfigAxis)
} }
} }
@ -663,9 +666,11 @@ func ProductVariableProperties(ctx BazelConversionPathContext) ProductConfigProp
moduleBase.variableProperties, moduleBase.variableProperties,
"", "",
"", "",
&productConfigProperties) &productConfigProperties,
bazel.ConfigurationAxis{},
)
for _, configToProps := range moduleBase.GetArchVariantProperties(ctx, moduleBase.variableProperties) { for axis, configToProps := range moduleBase.GetArchVariantProperties(ctx, moduleBase.variableProperties) {
for config, props := range configToProps { for config, props := range configToProps {
// GetArchVariantProperties is creating an instance of the requested type // GetArchVariantProperties is creating an instance of the requested type
// and productVariablesValues expects an interface, so no need to cast // and productVariablesValues expects an interface, so no need to cast
@ -674,7 +679,8 @@ func ProductVariableProperties(ctx BazelConversionPathContext) ProductConfigProp
props, props,
"", "",
config, config,
&productConfigProperties) &productConfigProperties,
axis)
} }
} }
} }
@ -687,7 +693,8 @@ func ProductVariableProperties(ctx BazelConversionPathContext) ProductConfigProp
namespacedVariableProp, namespacedVariableProp,
namespace, namespace,
"", "",
&productConfigProperties) &productConfigProperties,
bazel.NoConfigAxis)
} }
} }
} }
@ -803,6 +810,7 @@ func (props *ProductConfigProperties) zeroValuesForNamespacedVariables() {
p.Name, p.Name,
p.FullConfig, p.FullConfig,
zeroValue, zeroValue,
bazel.NoConfigAxis,
) )
} }
} }
@ -810,7 +818,7 @@ func (props *ProductConfigProperties) zeroValuesForNamespacedVariables() {
} }
func (p *ProductConfigProperties) AddProductConfigProperty( func (p *ProductConfigProperties) AddProductConfigProperty(
propertyName, namespace, productVariableName, config string, property interface{}) { propertyName, namespace, productVariableName, config string, property interface{}, outerAxis bazel.ConfigurationAxis) {
if (*p)[propertyName] == nil { if (*p)[propertyName] == nil {
(*p)[propertyName] = make(map[ProductConfigProperty]interface{}) (*p)[propertyName] = make(map[ProductConfigProperty]interface{})
} }
@ -819,6 +827,7 @@ func (p *ProductConfigProperties) AddProductConfigProperty(
Namespace: namespace, // e.g. acme, android Namespace: namespace, // e.g. acme, android
Name: productVariableName, // e.g. size, feature1, feature2, FEATURE3, board Name: productVariableName, // e.g. size, feature1, feature2, FEATURE3, board
FullConfig: config, // e.g. size, feature1-x86, size__conditions_default FullConfig: config, // e.g. size, feature1-x86, size__conditions_default
OuterAxis: outerAxis,
} }
if existing, ok := (*p)[propertyName][productConfigProp]; ok && namespace != "" { if existing, ok := (*p)[propertyName][productConfigProp]; ok && namespace != "" {
@ -869,7 +878,7 @@ func maybeExtractConfigVarProp(v reflect.Value) (reflect.Value, bool) {
return v, true return v, true
} }
func (productConfigProperties *ProductConfigProperties) AddProductConfigProperties(namespace, suffix string, variableValues reflect.Value) { func (productConfigProperties *ProductConfigProperties) AddProductConfigProperties(namespace, suffix string, variableValues reflect.Value, outerAxis bazel.ConfigurationAxis) {
// variableValues can either be a product_variables or // variableValues can either be a product_variables or
// soong_config_variables struct. // soong_config_variables struct.
// //
@ -974,7 +983,8 @@ func (productConfigProperties *ProductConfigProperties) AddProductConfigProperti
namespace, // e.g. acme, android namespace, // e.g. acme, android
productVariableName, // e.g. size, feature1, FEATURE2, board productVariableName, // e.g. size, feature1, FEATURE2, board
config, config,
field.Field(k).Interface(), // e.g. ["-DDEFAULT"], ["foo", "bar"] field.Field(k).Interface(), // e.g. ["-DDEFAULT"], ["foo", "bar"],
outerAxis,
) )
} }
} else if property.Kind() != reflect.Interface { } else if property.Kind() != reflect.Interface {
@ -988,6 +998,7 @@ func (productConfigProperties *ProductConfigProperties) AddProductConfigProperti
productVariableName, productVariableName,
config, config,
property.Interface(), property.Interface(),
outerAxis,
) )
} }
} }
@ -998,14 +1009,14 @@ func (productConfigProperties *ProductConfigProperties) AddProductConfigProperti
// product_variables and soong_config_variables to structs that can be generated // product_variables and soong_config_variables to structs that can be generated
// as select statements. // as select statements.
func productVariableValues( func productVariableValues(
fieldName string, variableProps interface{}, namespace, suffix string, productConfigProperties *ProductConfigProperties) { fieldName string, variableProps interface{}, namespace, suffix string, productConfigProperties *ProductConfigProperties, outerAxis bazel.ConfigurationAxis) {
if suffix != "" { if suffix != "" {
suffix = "-" + suffix suffix = "-" + suffix
} }
// variableValues represent the product_variables or soong_config_variables struct. // variableValues represent the product_variables or soong_config_variables struct.
variableValues := reflect.ValueOf(variableProps).Elem().FieldByName(fieldName) variableValues := reflect.ValueOf(variableProps).Elem().FieldByName(fieldName)
productConfigProperties.AddProductConfigProperties(namespace, suffix, variableValues) productConfigProperties.AddProductConfigProperties(namespace, suffix, variableValues, outerAxis)
} }
func VariableMutator(mctx BottomUpMutatorContext) { func VariableMutator(mctx BottomUpMutatorContext) {

View file

@ -295,10 +295,11 @@ var (
) )
// ProductVariableConfigurationAxis returns an axis for the given product variable // ProductVariableConfigurationAxis returns an axis for the given product variable
func ProductVariableConfigurationAxis(variable string) ConfigurationAxis { func ProductVariableConfigurationAxis(variable string, outerAxis ConfigurationAxis) ConfigurationAxis {
return ConfigurationAxis{ return ConfigurationAxis{
configurationType: productVariables, configurationType: productVariables,
subType: variable, subType: variable,
outerAxisType: outerAxis.configurationType,
} }
} }
@ -309,6 +310,8 @@ type ConfigurationAxis struct {
// some configuration types (e.g. productVariables) have multiple independent axes, subType helps // some configuration types (e.g. productVariables) have multiple independent axes, subType helps
// distinguish between them without needing to list all 17 product variables. // distinguish between them without needing to list all 17 product variables.
subType string subType string
// used to keep track of which product variables are arch variant
outerAxisType configurationType
} }
func (ca *ConfigurationAxis) less(other ConfigurationAxis) bool { func (ca *ConfigurationAxis) less(other ConfigurationAxis) bool {

View file

@ -309,8 +309,20 @@ func (la *LabelAttribute) Collapse() error {
_, containsProductVariables := axisTypes[productVariables] _, containsProductVariables := axisTypes[productVariables]
if containsProductVariables { if containsProductVariables {
if containsOs || containsArch || containsOsArch { if containsOs || containsArch || containsOsArch {
if containsArch {
allProductVariablesAreArchVariant := true
for k := range la.ConfigurableValues {
if k.configurationType == productVariables && k.outerAxisType != arch {
allProductVariablesAreArchVariant = false
}
}
if !allProductVariablesAreArchVariant {
return fmt.Errorf("label attribute could not be collapsed as it has two or more unrelated axes") 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 (containsOs && containsArch) || (containsOsArch && (containsOs || containsArch)) {
// If a bool attribute has both os and arch configuration axes, the only // If a bool attribute has both os and arch configuration axes, the only

View file

@ -247,13 +247,13 @@ func TestResolveExcludes(t *testing.T) {
OsArchConfigurationAxis: labelListSelectValues{ OsArchConfigurationAxis: labelListSelectValues{
"linux_x86": makeLabelList([]string{"linux_x86_include"}, []string{}), "linux_x86": makeLabelList([]string{"linux_x86_include"}, []string{}),
}, },
ProductVariableConfigurationAxis("product_with_defaults"): labelListSelectValues{ ProductVariableConfigurationAxis("product_with_defaults", NoConfigAxis): labelListSelectValues{
"a": makeLabelList([]string{}, []string{"not_in_value"}), "a": makeLabelList([]string{}, []string{"not_in_value"}),
"b": makeLabelList([]string{"b_val"}, []string{}), "b": makeLabelList([]string{"b_val"}, []string{}),
"c": makeLabelList([]string{"c_val"}, []string{}), "c": makeLabelList([]string{"c_val"}, []string{}),
ConditionsDefaultConfigKey: makeLabelList([]string{"c_val", "default", "default2"}, []string{}), ConditionsDefaultConfigKey: makeLabelList([]string{"c_val", "default", "default2"}, []string{}),
}, },
ProductVariableConfigurationAxis("product_only_with_excludes"): labelListSelectValues{ ProductVariableConfigurationAxis("product_only_with_excludes", NoConfigAxis): labelListSelectValues{
"a": makeLabelList([]string{}, []string{"not_in_value"}), "a": makeLabelList([]string{}, []string{"not_in_value"}),
}, },
}, },
@ -281,7 +281,7 @@ func TestResolveExcludes(t *testing.T) {
"linux_x86": makeLabels("linux_x86_include"), "linux_x86": makeLabels("linux_x86_include"),
ConditionsDefaultConfigKey: nilLabels, ConditionsDefaultConfigKey: nilLabels,
}, },
ProductVariableConfigurationAxis("product_with_defaults"): { ProductVariableConfigurationAxis("product_with_defaults", NoConfigAxis): {
"a": nilLabels, "a": nilLabels,
"b": makeLabels("b_val"), "b": makeLabels("b_val"),
"c": makeLabels("c_val"), "c": makeLabels("c_val"),
@ -674,7 +674,7 @@ func TestDeduplicateAxesFromBase(t *testing.T) {
OsArchConfigurationAxis: stringListSelectValues{ OsArchConfigurationAxis: stringListSelectValues{
"linux_x86": {"linux_x86_include"}, "linux_x86": {"linux_x86_include"},
}, },
ProductVariableConfigurationAxis("a"): stringListSelectValues{ ProductVariableConfigurationAxis("a", NoConfigAxis): stringListSelectValues{
"a": []string{"not_in_value"}, "a": []string{"not_in_value"},
}, },
}, },
@ -699,7 +699,7 @@ func TestDeduplicateAxesFromBase(t *testing.T) {
"linux": []string{"linux_include"}, "linux": []string{"linux_include"},
}, },
OsArchConfigurationAxis: stringListSelectValues{}, OsArchConfigurationAxis: stringListSelectValues{},
ProductVariableConfigurationAxis("a"): stringListSelectValues{ ProductVariableConfigurationAxis("a", NoConfigAxis): stringListSelectValues{
"a": []string{"not_in_value"}, "a": []string{"not_in_value"},
}, },
} }

View file

@ -15,10 +15,11 @@
package bp2build package bp2build
import ( import (
"fmt"
"testing"
"android/soong/android" "android/soong/android"
"android/soong/etc" "android/soong/etc"
"testing"
) )
func runPrebuiltEtcTestCase(t *testing.T, tc Bp2buildTestCase) { func runPrebuiltEtcTestCase(t *testing.T, tc Bp2buildTestCase) {
@ -128,6 +129,32 @@ prebuilt_etc {
"dir": `"etc/tz"`, "dir": `"etc/tz"`,
})}}) })}})
} }
func TestPrebuiltEtcProductVariables(t *testing.T) {
runPrebuiltEtcTestCase(t, Bp2buildTestCase{
Description: "prebuilt etc - product variables",
Filesystem: map[string]string{},
Blueprint: `
prebuilt_etc {
name: "apex_tz_version",
src: "version/tz_version",
filename: "tz_version",
product_variables: {
native_coverage: {
src: "src1",
},
},
}
`,
ExpectedBazelTargets: []string{
MakeBazelTarget("prebuilt_file", "apex_tz_version", AttrNameToString{
"filename": `"tz_version"`,
"src": `select({
"//build/bazel/product_variables:native_coverage": "src1",
"//conditions:default": "version/tz_version",
})`,
"dir": `"etc"`,
})}})
}
func runPrebuiltUsrShareTestCase(t *testing.T, tc Bp2buildTestCase) { func runPrebuiltUsrShareTestCase(t *testing.T, tc Bp2buildTestCase) {
t.Helper() t.Helper()
@ -265,3 +292,57 @@ prebuilt_etc {
"dir": `"etc"`, "dir": `"etc"`,
})}}) })}})
} }
func TestPrebuiltEtcProductVariableArchSrcs(t *testing.T) {
runPrebuiltEtcTestCase(t, Bp2buildTestCase{
Description: "prebuilt etc- SRcs from arch variant product variables",
Filesystem: map[string]string{},
Blueprint: `
prebuilt_etc {
name: "foo",
filename: "fooFilename",
arch: {
arm: {
src: "armSrc",
product_variables: {
native_coverage: {
src: "nativeCoverageArmSrc",
},
},
},
},
}`,
ExpectedBazelTargets: []string{
MakeBazelTarget("prebuilt_file", "foo", AttrNameToString{
"filename": `"fooFilename"`,
"dir": `"etc"`,
"src": `select({
"//build/bazel/platforms/arch:arm": "armSrc",
"//build/bazel/product_variables:native_coverage-arm": "nativeCoverageArmSrc",
"//conditions:default": None,
})`,
})}})
}
func TestPrebuiltEtcProductVariableError(t *testing.T) {
runPrebuiltEtcTestCase(t, Bp2buildTestCase{
Description: "",
Filesystem: map[string]string{},
Blueprint: `
prebuilt_etc {
name: "foo",
filename: "fooFilename",
arch: {
arm: {
src: "armSrc",
},
},
product_variables: {
native_coverage: {
src: "nativeCoverageArmSrc",
},
},
}`,
ExpectedErr: fmt.Errorf("label attribute could not be collapsed"),
})
}

View file

@ -31,6 +31,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"path/filepath" "path/filepath"
"reflect"
"strings" "strings"
"github.com/google/blueprint/proptools" "github.com/google/blueprint/proptools"
@ -692,6 +693,22 @@ func (module *PrebuiltEtc) ConvertWithBp2build(ctx android.TopDownMutatorContext
src.SetSelectValue(axis, config, label) src.SetSelectValue(axis, config, label)
} }
} }
for propName, productConfigProps := range android.ProductVariableProperties(ctx) {
for configProp, propVal := range productConfigProps {
if propName == "Src" {
props, ok := propVal.(*string)
if !ok {
ctx.PropertyErrorf(" Expected Property to have type string, but was %s\n", reflect.TypeOf(propVal).String())
continue
}
if props != nil {
label := android.BazelLabelForModuleSrcSingle(ctx, *props)
src.SetSelectValue(configProp.ConfigurationAxis(), configProp.SelectKey(), label)
}
}
}
}
} }
var filename string var filename string