Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 37bd24a1 authored by Jingwen Chen's avatar Jingwen Chen Committed by Gerrit Code Review
Browse files

Merge "bp2build: add configurable attribute (select) support."

parents 5e510d62 5d864499
Loading
Loading
Loading
Loading
+94 −0
Original line number Diff line number Diff line
@@ -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
}
+9 −2
Original line number Diff line number Diff line
@@ -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.
+71 −0
Original line number Diff line number Diff line
@@ -14,6 +14,8 @@

package bazel

import "fmt"

type bazelModuleProperties struct {
	// The label of the Bazel target replacing this Soong module.
	Label string
@@ -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))
	}
}
+1 −0
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@ bootstrap_go_package {
        "bp2build.go",
        "build_conversion.go",
        "bzl_conversion.go",
        "configurability.go",
        "conversion.go",
        "metrics.go",
    ],
+31 −0
Original line number Diff line number Diff line
@@ -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