Handle product config vars in bp2build.

Test: bp2build ci  & mixed build libc
Bug: 183595873
Change-Id: I2d87434ff4df5a24efc5e3e38f087de035228934
This commit is contained in:
Liz Kammer
2021-05-06 13:54:29 -04:00
parent 32cf58a8fc
commit 6fd7b3fee9
6 changed files with 149 additions and 31 deletions

View File

@@ -19,6 +19,7 @@ import (
"path/filepath"
"regexp"
"sort"
"strings"
)
// BazelTargetModuleProperties contain properties and metadata used for
@@ -200,6 +201,10 @@ const (
// config variable default key in an Android.bp file, although there's no
// integration with Soong config variables (yet).
CONDITIONS_DEFAULT = "conditions_default"
ConditionsDefaultSelectKey = "//conditions:default"
productVariableBazelPackage = "//build/bazel/product_variables"
)
var (
@@ -215,7 +220,7 @@ var (
ARCH_ARM64: "//build/bazel/platforms/arch:arm64",
ARCH_X86: "//build/bazel/platforms/arch:x86",
ARCH_X86_64: "//build/bazel/platforms/arch:x86_64",
CONDITIONS_DEFAULT: "//conditions:default", // The default condition of as arch select map.
CONDITIONS_DEFAULT: ConditionsDefaultSelectKey, // The default condition of as arch select map.
}
// A map of target operating systems to the Bazel label of the
@@ -227,7 +232,7 @@ var (
OS_LINUX: "//build/bazel/platforms/os:linux",
OS_LINUX_BIONIC: "//build/bazel/platforms/os:linux_bionic",
OS_WINDOWS: "//build/bazel/platforms/os:windows",
CONDITIONS_DEFAULT: "//conditions:default", // The default condition of an os select map.
CONDITIONS_DEFAULT: ConditionsDefaultSelectKey, // The default condition of an os select map.
}
)
@@ -435,6 +440,10 @@ type StringListAttribute struct {
// are generated in a select statement and appended to the non-os specific
// label list Value.
OsValues stringListOsValues
// list of product-variable string list values. Optional. if used, each will generate a select
// statement appended to the label list Value.
ProductValues []ProductVariableValues
}
// MakeStringListAttribute initializes a StringListAttribute with the non-arch specific value.
@@ -466,6 +475,18 @@ type stringListOsValues struct {
ConditionsDefault []string
}
// Product Variable values for StringListAttribute
type ProductVariableValues struct {
ProductVariable string
Values []string
}
// SelectKey returns the appropriate select key for the receiving ProductVariableValues.
func (p ProductVariableValues) SelectKey() string {
return fmt.Sprintf("%s:%s", productVariableBazelPackage, strings.ToLower(p.ProductVariable))
}
// HasConfigurableValues returns true if the attribute contains
// architecture-specific string_list values.
func (attrs StringListAttribute) HasConfigurableValues() bool {
@@ -480,7 +501,8 @@ func (attrs StringListAttribute) HasConfigurableValues() bool {
return true
}
}
return false
return len(attrs.ProductValues) > 0
}
func (attrs *StringListAttribute) archValuePtrs() map[string]*[]string {
@@ -558,6 +580,21 @@ func (attrs *StringListAttribute) Append(other StringListAttribute) {
attrs.SetValueForOS(os, this)
}
productValues := make(map[string][]string, 0)
for _, pv := range attrs.ProductValues {
productValues[pv.ProductVariable] = pv.Values
}
for _, pv := range other.ProductValues {
productValues[pv.ProductVariable] = append(productValues[pv.ProductVariable], pv.Values...)
}
attrs.ProductValues = make([]ProductVariableValues, 0, len(productValues))
for pv, vals := range productValues {
attrs.ProductValues = append(attrs.ProductValues, ProductVariableValues{
ProductVariable: pv,
Values: vals,
})
}
attrs.Value = append(attrs.Value, other.Value...)
}

View File

@@ -1156,3 +1156,48 @@ cc_library_static {
)`},
})
}
func TestCcLibraryStaticProductVariableSelects(t *testing.T) {
runCcLibraryStaticTestCase(t, bp2buildTestCase{
description: "cc_library_static product variable selects",
moduleTypeUnderTest: "cc_library_static",
moduleTypeUnderTestFactory: cc.LibraryStaticFactory,
moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryStaticBp2Build,
depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
filesystem: map[string]string{},
blueprint: soongCcLibraryStaticPreamble + `
cc_library_static {
name: "foo_static",
srcs: ["common.c"],
product_variables: {
malloc_not_svelte: {
cflags: ["-Wmalloc_not_svelte"],
},
malloc_zero_contents: {
cflags: ["-Wmalloc_zero_contents"],
},
binder32bit: {
cflags: ["-Wbinder32bit"],
},
},
} `,
expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
copts = [
"-I.",
"-I$(BINDIR)/.",
] + select({
"//build/bazel/product_variables:malloc_not_svelte": ["-Wmalloc_not_svelte"],
"//conditions:default": [],
}) + select({
"//build/bazel/product_variables:malloc_zero_contents": ["-Wmalloc_zero_contents"],
"//conditions:default": [],
}) + select({
"//build/bazel/product_variables:binder32bit": ["-Wbinder32bit"],
"//conditions:default": [],
}),
linkstatic = True,
srcs = ["common.c"],
)`},
})
}

View File

@@ -208,7 +208,10 @@ func TestCcObjectProductVariable(t *testing.T) {
`,
expectedBazelTargets: []string{`cc_object(
name = "foo",
asflags = ["-DPLATFORM_SDK_VERSION={Platform_sdk_version}"],
asflags = select({
"//build/bazel/product_variables:platform_sdk_version": ["-DPLATFORM_SDK_VERSION={Platform_sdk_version}"],
"//conditions:default": [],
}),
copts = ["-fno-addrsig"],
)`,
},

View File

@@ -11,26 +11,42 @@ import (
type selects map[string]reflect.Value
func getStringListValues(list bazel.StringListAttribute) (reflect.Value, selects, selects) {
func getStringListValues(list bazel.StringListAttribute) (reflect.Value, []selects) {
value := reflect.ValueOf(list.Value)
if !list.HasConfigurableValues() {
return value, nil, nil
return value, []selects{}
}
selectValues := make([]selects, 0)
archSelects := map[string]reflect.Value{}
for arch, selectKey := range bazel.PlatformArchMap {
archSelects[selectKey] = reflect.ValueOf(list.GetValueForArch(arch))
}
if len(archSelects) > 0 {
selectValues = append(selectValues, archSelects)
}
osSelects := map[string]reflect.Value{}
for os, selectKey := range bazel.PlatformOsMap {
osSelects[selectKey] = reflect.ValueOf(list.GetValueForOS(os))
}
if len(osSelects) > 0 {
selectValues = append(selectValues, osSelects)
}
return value, archSelects, osSelects
for _, pv := range list.ProductValues {
s := make(selects)
if len(pv.Values) > 0 {
s[pv.SelectKey()] = reflect.ValueOf(pv.Values)
s[bazel.ConditionsDefaultSelectKey] = reflect.ValueOf([]string{})
selectValues = append(selectValues, s)
}
}
return value, selectValues
}
func getLabelValue(label bazel.LabelAttribute) (reflect.Value, selects, selects) {
func getLabelValue(label bazel.LabelAttribute) (reflect.Value, []selects) {
var value reflect.Value
var archSelects selects
@@ -43,13 +59,13 @@ func getLabelValue(label bazel.LabelAttribute) (reflect.Value, selects, selects)
value = reflect.ValueOf(label.Value)
}
return value, archSelects, nil
return value, []selects{archSelects}
}
func getLabelListValues(list bazel.LabelListAttribute) (reflect.Value, selects, selects) {
func getLabelListValues(list bazel.LabelListAttribute) (reflect.Value, []selects) {
value := reflect.ValueOf(list.Value.Includes)
if !list.HasConfigurableValues() {
return value, nil, nil
return value, []selects{}
}
archSelects := map[string]reflect.Value{}
@@ -62,29 +78,30 @@ func getLabelListValues(list bazel.LabelListAttribute) (reflect.Value, selects,
osSelects[selectKey] = reflect.ValueOf(list.GetValueForOS(os).Includes)
}
return value, archSelects, osSelects
return value, []selects{archSelects, osSelects}
}
// 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
var archSelects, osSelects selects
var configurableAttrs []selects
var defaultSelectValue string
switch list := v.(type) {
case bazel.StringListAttribute:
value, archSelects, osSelects = getStringListValues(list)
value, configurableAttrs = getStringListValues(list)
defaultSelectValue = "[]"
case bazel.LabelListAttribute:
value, archSelects, osSelects = getLabelListValues(list)
value, configurableAttrs = getLabelListValues(list)
defaultSelectValue = "[]"
case bazel.LabelAttribute:
value, archSelects, osSelects = getLabelValue(list)
value, configurableAttrs = getLabelValue(list)
defaultSelectValue = "None"
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)
@@ -108,13 +125,14 @@ func prettyPrintAttribute(v bazel.Attribute, indent int) (string, error) {
return s, nil
}
ret, err := appendSelects(archSelects, defaultSelectValue, ret)
if err != nil {
return "", err
for _, configurableAttr := range configurableAttrs {
ret, err = appendSelects(configurableAttr, defaultSelectValue, ret)
if err != nil {
return "", err
}
}
ret, err = appendSelects(osSelects, defaultSelectValue, ret)
return ret, err
return ret, nil
}
// prettyPrintSelectMap converts a map of select keys to reflected Values as a generic way
@@ -125,11 +143,10 @@ func prettyPrintSelectMap(selectMap map[string]reflect.Value, defaultValue strin
}
// addConditionsDefault := false
conditionsDefaultKey := bazel.PlatformArchMap[bazel.CONDITIONS_DEFAULT]
var selects string
for _, selectKey := range android.SortedStringKeys(selectMap) {
if selectKey == conditionsDefaultKey {
if selectKey == bazel.ConditionsDefaultSelectKey {
// Handle default condition later.
continue
}
@@ -159,14 +176,14 @@ func prettyPrintSelectMap(selectMap map[string]reflect.Value, defaultValue strin
ret += selects
// Handle the default condition
s, err := prettyPrintSelectEntry(selectMap[conditionsDefaultKey], conditionsDefaultKey, indent)
s, err := prettyPrintSelectEntry(selectMap[bazel.ConditionsDefaultSelectKey], bazel.ConditionsDefaultSelectKey, indent)
if err != nil {
return "", err
}
if s == "" {
// 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", makeIndent(indent+1), "//conditions:default", defaultValue)
ret += fmt.Sprintf("%s\"%s\": %s,\n", makeIndent(indent+1), bazel.ConditionsDefaultSelectKey, defaultValue)
} else {
// Print the custom default value.
ret += s

View File

@@ -318,6 +318,21 @@ func bp2BuildParseCompilerProps(ctx android.TopDownMutatorContext, module *Modul
}
}
productVariableProps := android.ProductVariableProperties(ctx)
if props, exists := productVariableProps["Cflags"]; exists {
for _, prop := range props {
flags, ok := prop.Property.([]string)
if !ok {
ctx.ModuleErrorf("Could not convert product variable cflag property")
}
newFlags, _ := bazel.TryVariableSubstitutions(flags, prop.ProductConfigVariable)
copts.ProductValues = append(copts.ProductValues, bazel.ProductVariableValues{
ProductVariable: prop.ProductConfigVariable,
Values: newFlags,
})
}
}
return compilerAttributes{
srcs: srcs,
copts: copts,

View File

@@ -116,7 +116,7 @@ type bazelObjectAttributes struct {
Hdrs bazel.LabelListAttribute
Deps bazel.LabelListAttribute
Copts bazel.StringListAttribute
Asflags []string
Asflags bazel.StringListAttribute
}
type bazelObject struct {
@@ -157,7 +157,7 @@ func ObjectBp2Build(ctx android.TopDownMutatorContext) {
// Set arch-specific configurable attributes
compilerAttrs := bp2BuildParseCompilerProps(ctx, m)
var asFlags []string
var asFlags bazel.StringListAttribute
var deps bazel.LabelListAttribute
for _, props := range m.linker.linkerProps() {
@@ -176,10 +176,11 @@ func ObjectBp2Build(ctx android.TopDownMutatorContext) {
ctx.ModuleErrorf("Could not convert product variable asflag property")
return
}
// TODO(b/183595873) handle other product variable usages -- as selects?
if newFlags, subbed := bazel.TryVariableSubstitutions(flags, prop.ProductConfigVariable); subbed {
asFlags = append(asFlags, newFlags...)
}
newFlags, _ := bazel.TryVariableSubstitutions(flags, prop.ProductConfigVariable)
asFlags.ProductValues = append(asFlags.ProductValues, bazel.ProductVariableValues{
ProductVariable: prop.ProductConfigVariable,
Values: newFlags,
})
}
}
// TODO(b/183595872) warn/error if we're not handling product variables