Loading android/arch.go +94 −0 Original line number Diff line number Diff line Loading @@ -1615,3 +1615,97 @@ func decodeMultilibTargets(multilib string, targets []Target, prefer32 bool) ([] return buildTargets, nil } // GetArchProperties returns a map of architectures to the values of the // properties of the 'dst' struct that are specific to that architecture. // // For example, passing a struct { Foo bool, Bar string } will return an // interface{} that can be type asserted back into the same struct, containing // the arch specific property value specified by the module if defined. func (m *ModuleBase) GetArchProperties(dst interface{}) map[ArchType]interface{} { // Return value of the arch types to the prop values for that arch. archToProp := map[ArchType]interface{}{} // Nothing to do for non-arch-specific modules. if !m.ArchSpecific() { return archToProp } // archProperties has the type of [][]interface{}. Looks complicated, so let's // explain this step by step. // // Loop over the outer index, which determines the property struct that // contains a matching set of properties in dst that we're interested in. // For example, BaseCompilerProperties or BaseLinkerProperties. for i := range m.archProperties { if m.archProperties[i] == nil { // Skip over nil arch props continue } // Non-nil arch prop, let's see if the props match up. for _, arch := range ArchTypeList() { // e.g X86, Arm field := arch.Field // If it's not nil, loop over the inner index, which determines the arch variant // of the prop type. In an Android.bp file, this is like looping over: // // arch: { arm: { key: value, ... }, x86: { key: value, ... } } for _, archProperties := range m.archProperties[i] { archPropValues := reflect.ValueOf(archProperties).Elem() // This is the archPropRoot struct. Traverse into the Arch nested struct. src := archPropValues.FieldByName("Arch").Elem() // Step into non-nil pointers to structs in the src value. if src.Kind() == reflect.Ptr { if src.IsNil() { // Ignore nil pointers. continue } src = src.Elem() } // Find the requested field (e.g. x86, x86_64) in the src struct. src = src.FieldByName(field) if !src.IsValid() { continue } // We only care about structs. These are not the droids you are looking for. if src.Kind() != reflect.Struct { continue } // If the value of the field is a struct then step into the // BlueprintEmbed field. The special "BlueprintEmbed" name is // used by createArchPropTypeDesc to embed the arch properties // in the parent struct, so the src arch prop should be in this // field. // // See createArchPropTypeDesc for more details on how Arch-specific // module properties are processed from the nested props and written // into the module's archProperties. src = src.FieldByName("BlueprintEmbed") // Clone the destination prop, since we want a unique prop struct per arch. dstClone := reflect.New(reflect.ValueOf(dst).Elem().Type()).Interface() // Copy the located property struct into the cloned destination property struct. err := proptools.ExtendMatchingProperties([]interface{}{dstClone}, src.Interface(), nil, proptools.OrderReplace) if err != nil { // This is fine, it just means the src struct doesn't match. continue } // Found the prop for the arch, you have. archToProp[arch] = dstClone // Go to the next prop. break } } } return archToProp } android/module.go +9 −2 Original line number Diff line number Diff line Loading @@ -1123,7 +1123,14 @@ type ModuleBase struct { variableProperties interface{} hostAndDeviceProperties hostAndDeviceProperties generalProperties []interface{} // Arch specific versions of structs in generalProperties. The outer index // has the same order as generalProperties as initialized in // InitAndroidArchModule, and the inner index chooses the props specific to // the architecture. The interface{} value is an archPropRoot that is // filled with arch specific values by the arch mutator. archProperties [][]interface{} customizableProperties []interface{} // Properties specific to the Blueprint to BUILD migration. Loading bazel/properties.go +71 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,8 @@ package bazel import "fmt" type bazelModuleProperties struct { // The label of the Bazel target replacing this Soong module. Label string Loading Loading @@ -63,3 +65,72 @@ func (ll *LabelList) Append(other LabelList) { ll.Excludes = append(other.Excludes, other.Excludes...) } } // 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 // Optional additive set of list values to the base value. ArchValues stringListArchValues } // Arch-specific string_list typed Bazel attribute values. This should correspond // to the types of architectures supported for compilation in arch.go. type stringListArchValues struct { X86 []string X86_64 []string Arm []string Arm64 []string Default []string // TODO(b/181299724): this is currently missing the "common" arch, which // doesn't have an equivalent platform() definition yet. } // HasArchSpecificValues returns true if the attribute contains // architecture-specific string_list values. func (attrs *StringListAttribute) HasArchSpecificValues() bool { for _, arch := range []string{"x86", "x86_64", "arm", "arm64", "default"} { if len(attrs.GetValueForArch(arch)) > 0 { return true } } return false } // GetValueForArch returns the string_list attribute value for an architecture. func (attrs *StringListAttribute) GetValueForArch(arch string) []string { switch arch { case "x86": return attrs.ArchValues.X86 case "x86_64": return attrs.ArchValues.X86_64 case "arm": return attrs.ArchValues.Arm case "arm64": return attrs.ArchValues.Arm64 case "default": return attrs.ArchValues.Default default: panic(fmt.Errorf("Unknown arch: %s", arch)) } } // SetValueForArch sets the string_list attribute value for an architecture. func (attrs *StringListAttribute) SetValueForArch(arch string, value []string) { switch arch { case "x86": attrs.ArchValues.X86 = value case "x86_64": attrs.ArchValues.X86_64 = value case "arm": attrs.ArchValues.Arm = value case "arm64": attrs.ArchValues.Arm64 = value case "default": attrs.ArchValues.Default = value default: panic(fmt.Errorf("Unknown arch: %s", arch)) } } bp2build/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -10,6 +10,7 @@ bootstrap_go_package { "bp2build.go", "build_conversion.go", "bzl_conversion.go", "configurability.go", "conversion.go", "metrics.go", ], Loading bp2build/build_conversion.go +31 −0 Original line number Diff line number Diff line Loading @@ -354,11 +354,42 @@ func prettyPrint(propertyValue reflect.Value, indent int) (string, error) { ret += makeIndent(indent) ret += "]" case reflect.Struct: // Special cases where the bp2build sends additional information to the codegenerator // by wrapping the attributes in a custom struct type. if labels, ok := propertyValue.Interface().(bazel.LabelList); ok { // TODO(b/165114590): convert glob syntax return prettyPrint(reflect.ValueOf(labels.Includes), indent) } else if label, ok := propertyValue.Interface().(bazel.Label); ok { return fmt.Sprintf("%q", label.Label), nil } else if stringList, ok := propertyValue.Interface().(bazel.StringListAttribute); ok { // A Bazel string_list attribute that may contain a select statement. ret, err := prettyPrint(reflect.ValueOf(stringList.Value), indent) if err != nil { return ret, err } if !stringList.HasArchSpecificValues() { // Select statement not needed. return ret, nil } ret += " + " + "select({\n" for _, arch := range android.ArchTypeList() { value := stringList.GetValueForArch(arch.Name) if len(value) > 0 { ret += makeIndent(indent + 1) list, _ := prettyPrint(reflect.ValueOf(value), indent+1) ret += fmt.Sprintf("\"%s\": %s,\n", platformArchMap[arch], list) } } ret += makeIndent(indent + 1) list, _ := prettyPrint(reflect.ValueOf(stringList.GetValueForArch("default")), indent+1) ret += fmt.Sprintf("\"%s\": %s,\n", "//conditions:default", list) ret += makeIndent(indent) ret += "})" return ret, err } ret = "{\n" Loading Loading
android/arch.go +94 −0 Original line number Diff line number Diff line Loading @@ -1615,3 +1615,97 @@ func decodeMultilibTargets(multilib string, targets []Target, prefer32 bool) ([] return buildTargets, nil } // GetArchProperties returns a map of architectures to the values of the // properties of the 'dst' struct that are specific to that architecture. // // For example, passing a struct { Foo bool, Bar string } will return an // interface{} that can be type asserted back into the same struct, containing // the arch specific property value specified by the module if defined. func (m *ModuleBase) GetArchProperties(dst interface{}) map[ArchType]interface{} { // Return value of the arch types to the prop values for that arch. archToProp := map[ArchType]interface{}{} // Nothing to do for non-arch-specific modules. if !m.ArchSpecific() { return archToProp } // archProperties has the type of [][]interface{}. Looks complicated, so let's // explain this step by step. // // Loop over the outer index, which determines the property struct that // contains a matching set of properties in dst that we're interested in. // For example, BaseCompilerProperties or BaseLinkerProperties. for i := range m.archProperties { if m.archProperties[i] == nil { // Skip over nil arch props continue } // Non-nil arch prop, let's see if the props match up. for _, arch := range ArchTypeList() { // e.g X86, Arm field := arch.Field // If it's not nil, loop over the inner index, which determines the arch variant // of the prop type. In an Android.bp file, this is like looping over: // // arch: { arm: { key: value, ... }, x86: { key: value, ... } } for _, archProperties := range m.archProperties[i] { archPropValues := reflect.ValueOf(archProperties).Elem() // This is the archPropRoot struct. Traverse into the Arch nested struct. src := archPropValues.FieldByName("Arch").Elem() // Step into non-nil pointers to structs in the src value. if src.Kind() == reflect.Ptr { if src.IsNil() { // Ignore nil pointers. continue } src = src.Elem() } // Find the requested field (e.g. x86, x86_64) in the src struct. src = src.FieldByName(field) if !src.IsValid() { continue } // We only care about structs. These are not the droids you are looking for. if src.Kind() != reflect.Struct { continue } // If the value of the field is a struct then step into the // BlueprintEmbed field. The special "BlueprintEmbed" name is // used by createArchPropTypeDesc to embed the arch properties // in the parent struct, so the src arch prop should be in this // field. // // See createArchPropTypeDesc for more details on how Arch-specific // module properties are processed from the nested props and written // into the module's archProperties. src = src.FieldByName("BlueprintEmbed") // Clone the destination prop, since we want a unique prop struct per arch. dstClone := reflect.New(reflect.ValueOf(dst).Elem().Type()).Interface() // Copy the located property struct into the cloned destination property struct. err := proptools.ExtendMatchingProperties([]interface{}{dstClone}, src.Interface(), nil, proptools.OrderReplace) if err != nil { // This is fine, it just means the src struct doesn't match. continue } // Found the prop for the arch, you have. archToProp[arch] = dstClone // Go to the next prop. break } } } return archToProp }
android/module.go +9 −2 Original line number Diff line number Diff line Loading @@ -1123,7 +1123,14 @@ type ModuleBase struct { variableProperties interface{} hostAndDeviceProperties hostAndDeviceProperties generalProperties []interface{} // Arch specific versions of structs in generalProperties. The outer index // has the same order as generalProperties as initialized in // InitAndroidArchModule, and the inner index chooses the props specific to // the architecture. The interface{} value is an archPropRoot that is // filled with arch specific values by the arch mutator. archProperties [][]interface{} customizableProperties []interface{} // Properties specific to the Blueprint to BUILD migration. Loading
bazel/properties.go +71 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,8 @@ package bazel import "fmt" type bazelModuleProperties struct { // The label of the Bazel target replacing this Soong module. Label string Loading Loading @@ -63,3 +65,72 @@ func (ll *LabelList) Append(other LabelList) { ll.Excludes = append(other.Excludes, other.Excludes...) } } // 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 // Optional additive set of list values to the base value. ArchValues stringListArchValues } // Arch-specific string_list typed Bazel attribute values. This should correspond // to the types of architectures supported for compilation in arch.go. type stringListArchValues struct { X86 []string X86_64 []string Arm []string Arm64 []string Default []string // TODO(b/181299724): this is currently missing the "common" arch, which // doesn't have an equivalent platform() definition yet. } // HasArchSpecificValues returns true if the attribute contains // architecture-specific string_list values. func (attrs *StringListAttribute) HasArchSpecificValues() bool { for _, arch := range []string{"x86", "x86_64", "arm", "arm64", "default"} { if len(attrs.GetValueForArch(arch)) > 0 { return true } } return false } // GetValueForArch returns the string_list attribute value for an architecture. func (attrs *StringListAttribute) GetValueForArch(arch string) []string { switch arch { case "x86": return attrs.ArchValues.X86 case "x86_64": return attrs.ArchValues.X86_64 case "arm": return attrs.ArchValues.Arm case "arm64": return attrs.ArchValues.Arm64 case "default": return attrs.ArchValues.Default default: panic(fmt.Errorf("Unknown arch: %s", arch)) } } // SetValueForArch sets the string_list attribute value for an architecture. func (attrs *StringListAttribute) SetValueForArch(arch string, value []string) { switch arch { case "x86": attrs.ArchValues.X86 = value case "x86_64": attrs.ArchValues.X86_64 = value case "arm": attrs.ArchValues.Arm = value case "arm64": attrs.ArchValues.Arm64 = value case "default": attrs.ArchValues.Default = value default: panic(fmt.Errorf("Unknown arch: %s", arch)) } }
bp2build/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -10,6 +10,7 @@ bootstrap_go_package { "bp2build.go", "build_conversion.go", "bzl_conversion.go", "configurability.go", "conversion.go", "metrics.go", ], Loading
bp2build/build_conversion.go +31 −0 Original line number Diff line number Diff line Loading @@ -354,11 +354,42 @@ func prettyPrint(propertyValue reflect.Value, indent int) (string, error) { ret += makeIndent(indent) ret += "]" case reflect.Struct: // Special cases where the bp2build sends additional information to the codegenerator // by wrapping the attributes in a custom struct type. if labels, ok := propertyValue.Interface().(bazel.LabelList); ok { // TODO(b/165114590): convert glob syntax return prettyPrint(reflect.ValueOf(labels.Includes), indent) } else if label, ok := propertyValue.Interface().(bazel.Label); ok { return fmt.Sprintf("%q", label.Label), nil } else if stringList, ok := propertyValue.Interface().(bazel.StringListAttribute); ok { // A Bazel string_list attribute that may contain a select statement. ret, err := prettyPrint(reflect.ValueOf(stringList.Value), indent) if err != nil { return ret, err } if !stringList.HasArchSpecificValues() { // Select statement not needed. return ret, nil } ret += " + " + "select({\n" for _, arch := range android.ArchTypeList() { value := stringList.GetValueForArch(arch.Name) if len(value) > 0 { ret += makeIndent(indent + 1) list, _ := prettyPrint(reflect.ValueOf(value), indent+1) ret += fmt.Sprintf("\"%s\": %s,\n", platformArchMap[arch], list) } } ret += makeIndent(indent + 1) list, _ := prettyPrint(reflect.ValueOf(stringList.GetValueForArch("default")), indent+1) ret += fmt.Sprintf("\"%s\": %s,\n", "//conditions:default", list) ret += makeIndent(indent) ret += "})" return ret, err } ret = "{\n" Loading