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

Commit a17792e2 authored by Colin Cross's avatar Colin Cross Committed by Gerrit Code Review
Browse files

Merge "Remove more unused code" into main

parents 757e88a9 76d1b42c
Loading
Loading
Loading
Loading
+0 −425
Original line number Diff line number Diff line
@@ -16,16 +16,11 @@ package android

import (
	"encoding"
	"encoding/json"
	"fmt"
	"reflect"
	"runtime"
	"sort"
	"strings"

	"android/soong/bazel"
	"android/soong/starlark_fmt"

	"github.com/google/blueprint"
	"github.com/google/blueprint/bootstrap"
	"github.com/google/blueprint/proptools"
@@ -1899,428 +1894,8 @@ func decodeMultilibTargets(multilib string, targets []Target, prefer32 bool) ([]
	return buildTargets, nil
}

func (m *ModuleBase) getArchPropertySet(propertySet interface{}, archType ArchType) interface{} {
	archString := archType.Field
	for i := range m.archProperties {
		if m.archProperties[i] == nil {
			// Skip over nil properties
			continue
		}

		// Not archProperties are usable; this function looks for properties of a very specific
		// form, and ignores the rest.
		for _, archProperty := range m.archProperties[i] {
			// archPropValue is a property struct, we are looking for the form:
			// `arch: { arm: { key: value, ... }}`
			archPropValue := reflect.ValueOf(archProperty).Elem()

			// Unwrap src so that it should looks like a pointer to `arm: { key: value, ... }`
			src := archPropValue.FieldByName("Arch").Elem()

			// Step into non-nil pointers to structs in the src value.
			if src.Kind() == reflect.Ptr {
				if src.IsNil() {
					continue
				}
				src = src.Elem()
			}

			// Find the requested field (e.g. arm, x86) in the src struct.
			src = src.FieldByName(archString)

			// We only care about structs.
			if !src.IsValid() || 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.
			propertySetClone := reflect.New(reflect.ValueOf(propertySet).Elem().Type()).Interface()

			// Copy the located property struct into the cloned destination property struct.
			err := proptools.ExtendMatchingProperties([]interface{}{propertySetClone}, src.Interface(), nil, proptools.OrderReplace)
			if err != nil {
				// This is fine, it just means the src struct doesn't match the type of propertySet.
				continue
			}

			return propertySetClone
		}
	}
	// No property set was found specific to the given arch, so return an empty
	// property set.
	return reflect.New(reflect.ValueOf(propertySet).Elem().Type()).Interface()
}

// getMultilibPropertySet returns a property set struct matching the type of
// `propertySet`, containing multilib-specific module properties for the given architecture.
// If no multilib-specific properties exist for the given architecture, returns an empty property
// set matching `propertySet`'s type.
func (m *ModuleBase) getMultilibPropertySet(propertySet interface{}, archType ArchType) interface{} {
	// archType.Multilib is lowercase (for example, lib32) but property struct field is
	// capitalized, such as Lib32, so use strings.Title to capitalize it.
	multiLibString := strings.Title(archType.Multilib)

	for i := range m.archProperties {
		if m.archProperties[i] == nil {
			// Skip over nil properties
			continue
		}

		// Not archProperties are usable; this function looks for properties of a very specific
		// form, and ignores the rest.
		for _, archProperties := range m.archProperties[i] {
			// archPropValue is a property struct, we are looking for the form:
			// `multilib: { lib32: { key: value, ... }}`
			archPropValue := reflect.ValueOf(archProperties).Elem()

			// Unwrap src so that it should looks like a pointer to `lib32: { key: value, ... }`
			src := archPropValue.FieldByName("Multilib").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. lib32) in the src struct.
			src = src.FieldByName(multiLibString)

			// We only care about valid struct pointers.
			if !src.IsValid() || src.Kind() != reflect.Ptr || src.Elem().Kind() != reflect.Struct {
				continue
			}

			// Get the zero value for the requested property set.
			propertySetClone := reflect.New(reflect.ValueOf(propertySet).Elem().Type()).Interface()

			// Copy the located property struct into the "zero" property set struct.
			err := proptools.ExtendMatchingProperties([]interface{}{propertySetClone}, src.Interface(), nil, proptools.OrderReplace)

			if err != nil {
				// This is fine, it just means the src struct doesn't match.
				continue
			}

			return propertySetClone
		}
	}

	// There were no multilib properties specifically matching the given archtype.
	// Return zeroed value.
	return reflect.New(reflect.ValueOf(propertySet).Elem().Type()).Interface()
}

// ArchVariantContext defines the limited context necessary to retrieve arch_variant properties.
type ArchVariantContext interface {
	ModuleErrorf(fmt string, args ...interface{})
	PropertyErrorf(property, fmt string, args ...interface{})
}

// ArchVariantProperties represents a map of arch-variant config strings to a property interface{}.
type ArchVariantProperties map[string]interface{}

// ConfigurationAxisToArchVariantProperties represents a map of bazel.ConfigurationAxis to
// ArchVariantProperties, such that each independent arch-variant axis maps to the
// configs/properties for that axis.
type ConfigurationAxisToArchVariantProperties map[bazel.ConfigurationAxis]ArchVariantProperties

// GetArchVariantProperties returns a ConfigurationAxisToArchVariantProperties where the
// arch-variant properties correspond to the values of the properties of the 'propertySet' struct
// that are specific to that axis/configuration. Each axis is independent, containing
// non-overlapping configs that correspond to the various "arch-variant" support, at this time:
//
//	arches (including multilib)
//	oses
//	arch+os combinations
//
// 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 config-specific property value specified
// by the module if defined.
//
// Arch-specific properties may come from an arch stanza or a multilib stanza; properties
// in these stanzas are combined.
// For example: `arch: { x86: { Foo: ["bar"] } }, multilib: { lib32: {` Foo: ["baz"] } }`
// will result in `Foo: ["bar", "baz"]` being returned for architecture x86, if the given
// propertyset contains `Foo []string`.
func (m *ModuleBase) GetArchVariantProperties(ctx ArchVariantContext, propertySet interface{}) ConfigurationAxisToArchVariantProperties {
	// Return value of the arch types to the prop values for that arch.
	axisToProps := ConfigurationAxisToArchVariantProperties{}

	// Nothing to do for non-arch-specific modules.
	if !m.ArchSpecific() {
		return axisToProps
	}

	dstType := reflect.ValueOf(propertySet).Type()
	var archProperties []interface{}

	// First find the property set in the module that corresponds to the requested
	// one. m.archProperties[i] corresponds to m.GetProperties()[i].
	for i, generalProp := range m.GetProperties() {
		srcType := reflect.ValueOf(generalProp).Type()
		if srcType == dstType {
			archProperties = m.archProperties[i]
			axisToProps[bazel.NoConfigAxis] = ArchVariantProperties{"": generalProp}
			break
		}
	}

	if archProperties == nil {
		// This module does not have the property set requested
		return axisToProps
	}

	archToProp := ArchVariantProperties{}
	// For each arch type (x86, arm64, etc.)
	for _, arch := range ArchTypeList() {
		// Arch properties are sometimes sharded (see createArchPropTypeDesc() ).
		// Iterate over every shard and extract a struct with the same type as the
		// input one that contains the data specific to that arch.
		propertyStructs := make([]reflect.Value, 0)
		archFeaturePropertyStructs := make(map[string][]reflect.Value, 0)
		for _, archProperty := range archProperties {
			archTypeStruct, ok := getArchTypeStruct(ctx, archProperty, arch)
			if ok {
				propertyStructs = append(propertyStructs, archTypeStruct)

				// For each feature this arch supports (arm: neon, x86: ssse3, sse4, ...)
				for _, feature := range archFeatures[arch] {
					prefix := "arch." + arch.Name + "." + feature
					if featureProperties, ok := getChildPropertyStruct(ctx, archTypeStruct, feature, prefix); ok {
						archFeaturePropertyStructs[feature] = append(archFeaturePropertyStructs[feature], featureProperties)
					}
				}
			}
			multilibStruct, ok := getMultilibStruct(ctx, archProperty, arch)
			if ok {
				propertyStructs = append(propertyStructs, multilibStruct)
			}
		}

		archToProp[arch.Name] = mergeStructs(ctx, propertyStructs, propertySet)

		// In soong, if multiple features match the current configuration, they're
		// all used. In bazel, we have to have unambiguous select() statements, so
		// we can't have two features that are both active in the same select().
		// One alternative is to split out each feature into a separate select(),
		// but then it's difficult to support exclude_srcs, which may need to
		// exclude things from the regular arch select() statement if a certain
		// feature is active. Instead, keep the features in the same select
		// statement as the arches, but emit the power set of all possible
		// combinations of features, so that bazel can match the most precise one.
		allFeatures := make([]string, 0, len(archFeaturePropertyStructs))
		for feature := range archFeaturePropertyStructs {
			allFeatures = append(allFeatures, feature)
		}
		for _, features := range bazel.PowerSetWithoutEmptySet(allFeatures) {
			sort.Strings(features)
			propsForCurrentFeatureSet := make([]reflect.Value, 0)
			propsForCurrentFeatureSet = append(propsForCurrentFeatureSet, propertyStructs...)
			for _, feature := range features {
				propsForCurrentFeatureSet = append(propsForCurrentFeatureSet, archFeaturePropertyStructs[feature]...)
			}
			archToProp[arch.Name+"-"+strings.Join(features, "-")] =
				mergeStructs(ctx, propsForCurrentFeatureSet, propertySet)
		}
	}
	axisToProps[bazel.ArchConfigurationAxis] = archToProp

	osToProp := ArchVariantProperties{}
	archOsToProp := ArchVariantProperties{}

	linuxStructs := getTargetStructs(ctx, archProperties, "Linux")
	bionicStructs := getTargetStructs(ctx, archProperties, "Bionic")
	hostStructs := getTargetStructs(ctx, archProperties, "Host")
	hostLinuxStructs := getTargetStructs(ctx, archProperties, "Host_linux")
	hostNotWindowsStructs := getTargetStructs(ctx, archProperties, "Not_windows")

	// For android, linux, ...
	for _, os := range osTypeList {
		if os == CommonOS {
			// It looks like this OS value is not used in Blueprint files
			continue
		}
		osStructs := make([]reflect.Value, 0)

		osSpecificStructs := getTargetStructs(ctx, archProperties, os.Field)
		if os.Class == Host {
			osStructs = append(osStructs, hostStructs...)
		}
		if os.Linux() {
			osStructs = append(osStructs, linuxStructs...)
		}
		if os.Bionic() {
			osStructs = append(osStructs, bionicStructs...)
		}
		if os.Linux() && os.Class == Host {
			osStructs = append(osStructs, hostLinuxStructs...)
		}

		if os == LinuxMusl {
			osStructs = append(osStructs, getTargetStructs(ctx, archProperties, "Musl")...)
		}
		if os == Linux {
			osStructs = append(osStructs, getTargetStructs(ctx, archProperties, "Glibc")...)
		}

		osStructs = append(osStructs, osSpecificStructs...)

		if os.Class == Host && os != Windows {
			osStructs = append(osStructs, hostNotWindowsStructs...)
		}
		osToProp[os.Name] = mergeStructs(ctx, osStructs, propertySet)

		// For arm, x86, ...
		for _, arch := range osArchTypeMap[os] {
			osArchStructs := make([]reflect.Value, 0)

			// Auto-combine with Linux_ and Bionic_ targets. This potentially results in
			// repetition and select() bloat, but use of Linux_* and Bionic_* targets is rare.
			// TODO(b/201423152): Look into cleanup.
			if os.Linux() {
				targetField := "Linux_" + arch.Name
				targetStructs := getTargetStructs(ctx, archProperties, targetField)
				osArchStructs = append(osArchStructs, targetStructs...)
			}
			if os.Bionic() {
				targetField := "Bionic_" + arch.Name
				targetStructs := getTargetStructs(ctx, archProperties, targetField)
				osArchStructs = append(osArchStructs, targetStructs...)
			}
			if os == LinuxMusl {
				targetField := "Musl_" + arch.Name
				targetStructs := getTargetStructs(ctx, archProperties, targetField)
				osArchStructs = append(osArchStructs, targetStructs...)
			}
			if os == Linux {
				targetField := "Glibc_" + arch.Name
				targetStructs := getTargetStructs(ctx, archProperties, targetField)
				osArchStructs = append(osArchStructs, targetStructs...)
			}

			targetField := GetCompoundTargetField(os, arch)
			targetName := fmt.Sprintf("%s_%s", os.Name, arch.Name)
			targetStructs := getTargetStructs(ctx, archProperties, targetField)
			osArchStructs = append(osArchStructs, targetStructs...)

			archOsToProp[targetName] = mergeStructs(ctx, osArchStructs, propertySet)
		}
	}

	axisToProps[bazel.OsConfigurationAxis] = osToProp
	axisToProps[bazel.OsArchConfigurationAxis] = archOsToProp
	return axisToProps
}

// Returns a struct matching the propertySet interface, containing properties specific to the targetName
// For example, given these arguments:
//
//	propertySet = BaseCompilerProperties
//	targetName = "android_arm"
//
// And given this Android.bp fragment:
//
//	target:
//	   android_arm: {
//	      srcs: ["foo.c"],
//	   }
//	   android_arm64: {
//	      srcs: ["bar.c"],
//	  }
//	}
//
// This would return a BaseCompilerProperties with BaseCompilerProperties.Srcs = ["foo.c"]
func getTargetStructs(ctx ArchVariantContext, archProperties []interface{}, targetName string) []reflect.Value {
	var propertyStructs []reflect.Value
	for _, archProperty := range archProperties {
		archPropValues := reflect.ValueOf(archProperty).Elem()
		targetProp := archPropValues.FieldByName("Target").Elem()
		targetStruct, ok := getChildPropertyStruct(ctx, targetProp, targetName, targetName)
		if ok {
			propertyStructs = append(propertyStructs, targetStruct)
		} else {
			return []reflect.Value{}
		}
	}

	return propertyStructs
}

func mergeStructs(ctx ArchVariantContext, propertyStructs []reflect.Value, propertySet interface{}) interface{} {
	// Create a new instance of the requested property set
	value := reflect.New(reflect.ValueOf(propertySet).Elem().Type()).Interface()

	// Merge all the structs together
	for _, propertyStruct := range propertyStructs {
		mergePropertyStruct(ctx, value, propertyStruct)
	}

	return value
}

func printArchTypeStarlarkDict(dict map[ArchType][]string) string {
	valDict := make(map[string]string, len(dict))
	for k, v := range dict {
		valDict[k.String()] = starlark_fmt.PrintStringList(v, 1)
	}
	return starlark_fmt.PrintDict(valDict, 0)
}

func printArchTypeNestedStarlarkDict(dict map[ArchType]map[string][]string) string {
	valDict := make(map[string]string, len(dict))
	for k, v := range dict {
		valDict[k.String()] = starlark_fmt.PrintStringListDict(v, 1)
	}
	return starlark_fmt.PrintDict(valDict, 0)
}

func printArchConfigList(arches []archConfig) string {
	jsonOut, err := json.MarshalIndent(arches, "", starlark_fmt.Indention(1))
	if err != nil {
		panic(fmt.Errorf("Error converting arch configs %#v to json: %q", arches, err))
	}
	return fmt.Sprintf("json.decode('''%s''')", string(jsonOut))
}

func StarlarkArchConfigurations() string {
	return fmt.Sprintf(`
_arch_to_variants = %s

_arch_to_cpu_variants = %s

_arch_to_features = %s

_android_arch_feature_for_arch_variant = %s

_aml_arches = %s

_ndk_arches = %s

arch_to_variants = _arch_to_variants
arch_to_cpu_variants = _arch_to_cpu_variants
arch_to_features = _arch_to_features
android_arch_feature_for_arch_variants = _android_arch_feature_for_arch_variant
aml_arches = _aml_arches
ndk_arches = _ndk_arches
`, printArchTypeStarlarkDict(archVariants),
		printArchTypeStarlarkDict(cpuVariants),
		printArchTypeStarlarkDict(archFeatures),
		printArchTypeNestedStarlarkDict(androidArchFeatureMap),
		printArchConfigList(getAmlAbisConfig()),
		printArchConfigList(getNdkAbisConfig()),
	)
}
+0 −387

File changed.

Preview size limit exceeded, changes collapsed.