Merge "Add StringAttribute for bp2building"
This commit is contained in:
committed by
Gerrit Code Review
commit
1ad11e6fbf
@@ -960,6 +960,146 @@ func PartitionLabelListAttribute(ctx OtherModuleContext, lla *LabelListAttribute
|
|||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StringAttribute corresponds to the string Bazel attribute type with
|
||||||
|
// support for additional metadata, like configurations.
|
||||||
|
type StringAttribute struct {
|
||||||
|
// The base value of the string attribute.
|
||||||
|
Value *string
|
||||||
|
|
||||||
|
// The configured attribute label list Values. Optional
|
||||||
|
// a map of independent configurability axes
|
||||||
|
ConfigurableValues configurableStrings
|
||||||
|
}
|
||||||
|
|
||||||
|
type configurableStrings map[ConfigurationAxis]stringSelectValues
|
||||||
|
|
||||||
|
func (cs configurableStrings) setValueForAxis(axis ConfigurationAxis, config string, str *string) {
|
||||||
|
if cs[axis] == nil {
|
||||||
|
cs[axis] = make(stringSelectValues)
|
||||||
|
}
|
||||||
|
var v = ""
|
||||||
|
if str != nil {
|
||||||
|
v = *str
|
||||||
|
}
|
||||||
|
cs[axis][config] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
type stringSelectValues map[string]string
|
||||||
|
|
||||||
|
// HasConfigurableValues returns true if the attribute contains axis-specific string values.
|
||||||
|
func (sa StringAttribute) HasConfigurableValues() bool {
|
||||||
|
for _, selectValues := range sa.ConfigurableValues {
|
||||||
|
if len(selectValues) > 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetSelectValue set a value for a bazel select for the given axis, config and value.
|
||||||
|
func (sa *StringAttribute) SetSelectValue(axis ConfigurationAxis, config string, str *string) {
|
||||||
|
axis.validateConfig(config)
|
||||||
|
switch axis.configurationType {
|
||||||
|
case noConfig:
|
||||||
|
sa.Value = str
|
||||||
|
case arch, os, osArch, productVariables:
|
||||||
|
if sa.ConfigurableValues == nil {
|
||||||
|
sa.ConfigurableValues = make(configurableStrings)
|
||||||
|
}
|
||||||
|
sa.ConfigurableValues.setValueForAxis(axis, config, str)
|
||||||
|
default:
|
||||||
|
panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectValue gets a value for a bazel select for the given axis and config.
|
||||||
|
func (sa *StringAttribute) SelectValue(axis ConfigurationAxis, config string) *string {
|
||||||
|
axis.validateConfig(config)
|
||||||
|
switch axis.configurationType {
|
||||||
|
case noConfig:
|
||||||
|
return sa.Value
|
||||||
|
case arch, os, osArch, productVariables:
|
||||||
|
if v, ok := sa.ConfigurableValues[axis][config]; ok {
|
||||||
|
return &v
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SortedConfigurationAxes returns all the used ConfigurationAxis in sorted order.
|
||||||
|
func (sa *StringAttribute) SortedConfigurationAxes() []ConfigurationAxis {
|
||||||
|
keys := make([]ConfigurationAxis, 0, len(sa.ConfigurableValues))
|
||||||
|
for k := range sa.ConfigurableValues {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Slice(keys, func(i, j int) bool { return keys[i].less(keys[j]) })
|
||||||
|
return keys
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collapse reduces the configurable axes of the string attribute to a single axis.
|
||||||
|
// This is necessary for final writing to bp2build, as a configurable string
|
||||||
|
// attribute can only be comprised by a single select.
|
||||||
|
func (sa *StringAttribute) Collapse() error {
|
||||||
|
axisTypes := sa.axisTypes()
|
||||||
|
_, containsOs := axisTypes[os]
|
||||||
|
_, containsArch := axisTypes[arch]
|
||||||
|
_, containsOsArch := axisTypes[osArch]
|
||||||
|
_, containsProductVariables := axisTypes[productVariables]
|
||||||
|
if containsProductVariables {
|
||||||
|
if containsOs || containsArch || containsOsArch {
|
||||||
|
return fmt.Errorf("boolean attribute could not be collapsed as it has two or more unrelated axes")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (containsOs && containsArch) || (containsOsArch && (containsOs || containsArch)) {
|
||||||
|
// If a bool attribute has both os and arch configuration axes, the only
|
||||||
|
// way to successfully union their values is to increase the granularity
|
||||||
|
// of the configuration criteria to os_arch.
|
||||||
|
for osType, supportedArchs := range osToArchMap {
|
||||||
|
for _, supportedArch := range supportedArchs {
|
||||||
|
osArch := osArchString(osType, supportedArch)
|
||||||
|
if archOsVal := sa.SelectValue(OsArchConfigurationAxis, osArch); archOsVal != nil {
|
||||||
|
// Do nothing, as the arch_os is explicitly defined already.
|
||||||
|
} else {
|
||||||
|
archVal := sa.SelectValue(ArchConfigurationAxis, supportedArch)
|
||||||
|
osVal := sa.SelectValue(OsConfigurationAxis, osType)
|
||||||
|
if osVal != nil && archVal != nil {
|
||||||
|
// In this case, arch takes precedence. (This fits legacy Soong behavior, as arch mutator
|
||||||
|
// runs after os mutator.
|
||||||
|
sa.SetSelectValue(OsArchConfigurationAxis, osArch, archVal)
|
||||||
|
} else if osVal != nil && archVal == nil {
|
||||||
|
sa.SetSelectValue(OsArchConfigurationAxis, osArch, osVal)
|
||||||
|
} else if osVal == nil && archVal != nil {
|
||||||
|
sa.SetSelectValue(OsArchConfigurationAxis, osArch, archVal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// All os_arch values are now set. Clear os and arch axes.
|
||||||
|
delete(sa.ConfigurableValues, ArchConfigurationAxis)
|
||||||
|
delete(sa.ConfigurableValues, OsConfigurationAxis)
|
||||||
|
// Verify post-condition; this should never fail, provided no additional
|
||||||
|
// axes are introduced.
|
||||||
|
if len(sa.ConfigurableValues) > 1 {
|
||||||
|
panic(fmt.Errorf("error in collapsing attribute: %#v", sa))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sa *StringAttribute) axisTypes() map[configurationType]bool {
|
||||||
|
types := map[configurationType]bool{}
|
||||||
|
for k := range sa.ConfigurableValues {
|
||||||
|
if strs := sa.ConfigurableValues[k]; len(strs) > 0 {
|
||||||
|
types[k.configurationType] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return types
|
||||||
|
}
|
||||||
|
|
||||||
// StringListAttribute corresponds to the string_list Bazel attribute type with
|
// StringListAttribute corresponds to the string_list Bazel attribute type with
|
||||||
// support for additional metadata, like configurations.
|
// support for additional metadata, like configurations.
|
||||||
type StringListAttribute struct {
|
type StringListAttribute struct {
|
||||||
|
@@ -230,6 +230,52 @@ func TestGenerateSoongModuleTargets(t *testing.T) {
|
|||||||
|
|
||||||
func TestGenerateBazelTargetModules(t *testing.T) {
|
func TestGenerateBazelTargetModules(t *testing.T) {
|
||||||
testCases := []Bp2buildTestCase{
|
testCases := []Bp2buildTestCase{
|
||||||
|
{
|
||||||
|
Description: "string prop empty",
|
||||||
|
Blueprint: `custom {
|
||||||
|
name: "foo",
|
||||||
|
string_literal_prop: "",
|
||||||
|
bazel_module: { bp2build_available: true },
|
||||||
|
}`,
|
||||||
|
ExpectedBazelTargets: []string{
|
||||||
|
makeBazelTarget("custom", "foo", AttrNameToString{
|
||||||
|
"string_literal_prop": `""`,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Description: `string prop "PROP"`,
|
||||||
|
Blueprint: `custom {
|
||||||
|
name: "foo",
|
||||||
|
string_literal_prop: "PROP",
|
||||||
|
bazel_module: { bp2build_available: true },
|
||||||
|
}`,
|
||||||
|
ExpectedBazelTargets: []string{
|
||||||
|
makeBazelTarget("custom", "foo", AttrNameToString{
|
||||||
|
"string_literal_prop": `"PROP"`,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Description: `string prop arch variant`,
|
||||||
|
Blueprint: `custom {
|
||||||
|
name: "foo",
|
||||||
|
arch: {
|
||||||
|
arm: { string_literal_prop: "ARM" },
|
||||||
|
arm64: { string_literal_prop: "ARM64" },
|
||||||
|
},
|
||||||
|
bazel_module: { bp2build_available: true },
|
||||||
|
}`,
|
||||||
|
ExpectedBazelTargets: []string{
|
||||||
|
makeBazelTarget("custom", "foo", AttrNameToString{
|
||||||
|
"string_literal_prop": `select({
|
||||||
|
"//build/bazel/platforms/arch:arm": "ARM",
|
||||||
|
"//build/bazel/platforms/arch:arm64": "ARM64",
|
||||||
|
"//conditions:default": None,
|
||||||
|
})`,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Description: "string ptr props",
|
Description: "string ptr props",
|
||||||
Blueprint: `custom {
|
Blueprint: `custom {
|
||||||
@@ -244,7 +290,7 @@ func TestGenerateBazelTargetModules(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Description: "string props",
|
Description: "string list props",
|
||||||
Blueprint: `custom {
|
Blueprint: `custom {
|
||||||
name: "foo",
|
name: "foo",
|
||||||
string_list_prop: ["a", "b"],
|
string_list_prop: ["a", "b"],
|
||||||
|
@@ -15,11 +15,12 @@
|
|||||||
package bp2build
|
package bp2build
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"android/soong/android"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"android/soong/android"
|
||||||
)
|
)
|
||||||
|
|
||||||
func setUp() {
|
func setUp() {
|
||||||
@@ -103,6 +104,7 @@ custom = rule(
|
|||||||
"one_to_many_prop": attr.bool(),
|
"one_to_many_prop": attr.bool(),
|
||||||
"other_embedded_prop": attr.string(),
|
"other_embedded_prop": attr.string(),
|
||||||
"string_list_prop": attr.string_list(),
|
"string_list_prop": attr.string_list(),
|
||||||
|
"string_literal_prop": attr.string(),
|
||||||
"string_prop": attr.string(),
|
"string_prop": attr.string(),
|
||||||
"string_ptr_prop": attr.string(),
|
"string_ptr_prop": attr.string(),
|
||||||
},
|
},
|
||||||
@@ -132,6 +134,7 @@ custom_defaults = rule(
|
|||||||
"one_to_many_prop": attr.bool(),
|
"one_to_many_prop": attr.bool(),
|
||||||
"other_embedded_prop": attr.string(),
|
"other_embedded_prop": attr.string(),
|
||||||
"string_list_prop": attr.string_list(),
|
"string_list_prop": attr.string_list(),
|
||||||
|
"string_literal_prop": attr.string(),
|
||||||
"string_prop": attr.string(),
|
"string_prop": attr.string(),
|
||||||
"string_ptr_prop": attr.string(),
|
"string_ptr_prop": attr.string(),
|
||||||
},
|
},
|
||||||
@@ -161,6 +164,7 @@ custom_test_ = rule(
|
|||||||
"one_to_many_prop": attr.bool(),
|
"one_to_many_prop": attr.bool(),
|
||||||
"other_embedded_prop": attr.string(),
|
"other_embedded_prop": attr.string(),
|
||||||
"string_list_prop": attr.string_list(),
|
"string_list_prop": attr.string_list(),
|
||||||
|
"string_literal_prop": attr.string(),
|
||||||
"string_prop": attr.string(),
|
"string_prop": attr.string(),
|
||||||
"string_ptr_prop": attr.string(),
|
"string_ptr_prop": attr.string(),
|
||||||
# test_prop start
|
# test_prop start
|
||||||
|
@@ -13,6 +13,30 @@ import (
|
|||||||
|
|
||||||
type selects map[string]reflect.Value
|
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 {
|
||||||
|
ret[bazel.ConditionsDefaultSelectKey] = value
|
||||||
|
value = reflect.Zero(value.Type())
|
||||||
|
}
|
||||||
|
|
||||||
|
return value, []selects{ret}
|
||||||
|
}
|
||||||
|
|
||||||
func getStringListValues(list bazel.StringListAttribute) (reflect.Value, []selects) {
|
func getStringListValues(list bazel.StringListAttribute) (reflect.Value, []selects) {
|
||||||
value := reflect.ValueOf(list.Value)
|
value := reflect.ValueOf(list.Value)
|
||||||
if !list.HasConfigurableValues() {
|
if !list.HasConfigurableValues() {
|
||||||
@@ -137,6 +161,12 @@ func prettyPrintAttribute(v bazel.Attribute, indent int) (string, error) {
|
|||||||
// If true, print the default attribute value, even if the attribute is zero.
|
// If true, print the default attribute value, even if the attribute is zero.
|
||||||
shouldPrintDefault := false
|
shouldPrintDefault := false
|
||||||
switch list := v.(type) {
|
switch list := v.(type) {
|
||||||
|
case bazel.StringAttribute:
|
||||||
|
if err := list.Collapse(); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
value, configurableAttrs = getStringValue(list)
|
||||||
|
defaultSelectValue = &bazelNone
|
||||||
case bazel.StringListAttribute:
|
case bazel.StringListAttribute:
|
||||||
value, configurableAttrs = getStringListValues(list)
|
value, configurableAttrs = getStringListValues(list)
|
||||||
defaultSelectValue = &emptyBazelList
|
defaultSelectValue = &emptyBazelList
|
||||||
|
@@ -173,11 +173,12 @@ type customProps struct {
|
|||||||
Bool_prop bool
|
Bool_prop bool
|
||||||
Bool_ptr_prop *bool
|
Bool_ptr_prop *bool
|
||||||
// Ensure that properties tagged `blueprint:mutated` are omitted
|
// Ensure that properties tagged `blueprint:mutated` are omitted
|
||||||
Int_prop int `blueprint:"mutated"`
|
Int_prop int `blueprint:"mutated"`
|
||||||
Int64_ptr_prop *int64
|
Int64_ptr_prop *int64
|
||||||
String_prop string
|
String_prop string
|
||||||
String_ptr_prop *string
|
String_literal_prop *string `android:"arch_variant"`
|
||||||
String_list_prop []string
|
String_ptr_prop *string
|
||||||
|
String_list_prop []string
|
||||||
|
|
||||||
Nested_props nestedProps
|
Nested_props nestedProps
|
||||||
Nested_props_ptr *nestedProps
|
Nested_props_ptr *nestedProps
|
||||||
@@ -305,23 +306,29 @@ type OtherEmbeddedAttr struct {
|
|||||||
type customBazelModuleAttributes struct {
|
type customBazelModuleAttributes struct {
|
||||||
EmbeddedAttr
|
EmbeddedAttr
|
||||||
*OtherEmbeddedAttr
|
*OtherEmbeddedAttr
|
||||||
String_ptr_prop *string
|
String_literal_prop bazel.StringAttribute
|
||||||
String_list_prop []string
|
String_ptr_prop *string
|
||||||
Arch_paths bazel.LabelListAttribute
|
String_list_prop []string
|
||||||
|
Arch_paths bazel.LabelListAttribute
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *customModule) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
|
func (m *customModule) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
|
||||||
paths := bazel.LabelListAttribute{}
|
|
||||||
|
|
||||||
if p := m.props.One_to_many_prop; p != nil && *p {
|
if p := m.props.One_to_many_prop; p != nil && *p {
|
||||||
customBp2buildOneToMany(ctx, m)
|
customBp2buildOneToMany(ctx, m)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
paths := bazel.LabelListAttribute{}
|
||||||
|
strAttr := bazel.StringAttribute{}
|
||||||
for axis, configToProps := range m.GetArchVariantProperties(ctx, &customProps{}) {
|
for axis, configToProps := range m.GetArchVariantProperties(ctx, &customProps{}) {
|
||||||
for config, props := range configToProps {
|
for config, props := range configToProps {
|
||||||
if archProps, ok := props.(*customProps); ok && archProps.Arch_paths != nil {
|
if custProps, ok := props.(*customProps); ok {
|
||||||
paths.SetSelectValue(axis, config, android.BazelLabelForModuleSrcExcludes(ctx, archProps.Arch_paths, archProps.Arch_paths_exclude))
|
if custProps.Arch_paths != nil {
|
||||||
|
paths.SetSelectValue(axis, config, android.BazelLabelForModuleSrcExcludes(ctx, custProps.Arch_paths, custProps.Arch_paths_exclude))
|
||||||
|
}
|
||||||
|
if custProps.String_literal_prop != nil {
|
||||||
|
strAttr.SetSelectValue(axis, config, custProps.String_literal_prop)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -329,10 +336,12 @@ func (m *customModule) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
|
|||||||
paths.ResolveExcludes()
|
paths.ResolveExcludes()
|
||||||
|
|
||||||
attrs := &customBazelModuleAttributes{
|
attrs := &customBazelModuleAttributes{
|
||||||
String_ptr_prop: m.props.String_ptr_prop,
|
String_literal_prop: strAttr,
|
||||||
String_list_prop: m.props.String_list_prop,
|
String_ptr_prop: m.props.String_ptr_prop,
|
||||||
Arch_paths: paths,
|
String_list_prop: m.props.String_list_prop,
|
||||||
|
Arch_paths: paths,
|
||||||
}
|
}
|
||||||
|
|
||||||
attrs.Embedded_attr = m.props.Embedded_prop
|
attrs.Embedded_attr = m.props.Embedded_prop
|
||||||
if m.props.OtherEmbeddedProps != nil {
|
if m.props.OtherEmbeddedProps != nil {
|
||||||
attrs.OtherEmbeddedAttr = &OtherEmbeddedAttr{Other_embedded_attr: m.props.OtherEmbeddedProps.Other_embedded_prop}
|
attrs.OtherEmbeddedAttr = &OtherEmbeddedAttr{Other_embedded_attr: m.props.OtherEmbeddedProps.Other_embedded_prop}
|
||||||
|
Reference in New Issue
Block a user