From 76d1b42c9f26115fcdd562328c6de3623170b589 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Fri, 12 Apr 2024 11:14:00 -0700 Subject: [PATCH] Remove more unused code Bug: 315353489 Test: builds Change-Id: I34cf772ba3c927bbbc141afb149cf0501ca6351f --- android/arch.go | 425 -------------------------------------------- android/variable.go | 387 ---------------------------------------- 2 files changed, 812 deletions(-) diff --git a/android/arch.go b/android/arch.go index 9e79e3175..f4303644a 100644 --- a/android/arch.go +++ b/android/arch.go @@ -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()), - ) -} diff --git a/android/variable.go b/android/variable.go index 9b630c01f..583c95014 100644 --- a/android/variable.go +++ b/android/variable.go @@ -20,8 +20,6 @@ import ( "runtime" "strings" - "android/soong/bazel" - "github.com/google/blueprint/proptools" ) @@ -492,10 +490,6 @@ type ProductVariables struct { CheckVendorSeappViolations *bool `json:",omitempty"` - // PartitionVarsForBazelMigrationOnlyDoNotUse are extra variables that are used to define the - // partition images. They should not be read from soong modules. - PartitionVarsForBazelMigrationOnlyDoNotUse PartitionVariables `json:",omitempty"` - BuildFlags map[string]string `json:",omitempty"` BuildFromSourceStub *bool `json:",omitempty"` @@ -645,387 +639,6 @@ func (this *ProductVariables) GetBuildFlagBool(flag string) bool { return val == "true" } -// ProductConfigContext requires the access to the Module to get product config properties. -type ProductConfigContext interface { - Module() Module -} - -// ProductConfigOrSoongConfigProperty represents either a soong config variable + its value -// or a product config variable. You can get both a ConfigurationAxis and a SelectKey from it -// for use in bazel attributes. ProductVariableProperties() will return a map from properties -> -// this interface -> property structs for use in bp2build converters -type ProductConfigOrSoongConfigProperty interface { - // Name of the product variable or soong config variable - Name() string - // AlwaysEmit returns true for soong config variables but false for product variables. This - // is intended to indicate if we need to always emit empty lists in the select statements. - AlwaysEmit() bool - // ConfigurationAxis returns the bazel.ConfigurationAxis that represents this variable. The - // configuration axis will change depending on the variable and whether it's arch/os variant - // as well. - ConfigurationAxis() bazel.ConfigurationAxis - // SelectKey returns a string that represents the key of a select branch, however, it is not - // actually the real label written out to the build file. - // this.ConfigurationAxis().SelectKey(this.SelectKey()) will give the actual label. - SelectKey() string -} - -// ProductConfigProperty represents a product config variable, and if it is arch-variant or not. -type ProductConfigProperty struct { - // The name of the product variable, e.g. "safestack", "malloc_not_svelte", - // "board" - name string - - arch string -} - -func (p ProductConfigProperty) Name() string { - return p.name -} - -func (p ProductConfigProperty) AlwaysEmit() bool { - return false -} - -func (p ProductConfigProperty) ConfigurationAxis() bazel.ConfigurationAxis { - return bazel.ProductVariableConfigurationAxis(p.arch != "", p.name+"__"+p.arch) -} - -func (p ProductConfigProperty) SelectKey() string { - if p.arch == "" { - return strings.ToLower(p.name) - } else { - return strings.ToLower(p.name + "-" + p.arch) - } -} - -// SoongConfigProperty represents a soong config variable, its value if it's a string variable, -// and if it's dependent on the OS or not -type SoongConfigProperty struct { - name string - namespace string - // Can be an empty string for bool/value soong config variables - value string - // If there is a target: field inside a soong config property struct, the os that it selects - // on will be represented here. - os string -} - -func (p SoongConfigProperty) Name() string { - return p.name -} - -func (p SoongConfigProperty) AlwaysEmit() bool { - return true -} - -func (p SoongConfigProperty) ConfigurationAxis() bazel.ConfigurationAxis { - return bazel.ProductVariableConfigurationAxis(false, p.namespace+"__"+p.name+"__"+p.os) -} - -// SelectKey returns the literal string that represents this variable in a BUILD -// select statement. -func (p SoongConfigProperty) SelectKey() string { - // p.value being conditions_default can happen with or without a desired os. When not using - // an os, we want to emit literally just //conditions:default in the select statement, but - // when using an os, we want to emit namespace__name__conditions_default__os, so that - // the branch is only taken if the variable is not set, and we're on the desired os. - // ConfigurationAxis#SelectKey will map the conditions_default result of this function to - // //conditions:default. - if p.value == bazel.ConditionsDefaultConfigKey && p.os == "" { - return bazel.ConditionsDefaultConfigKey - } - - parts := []string{p.namespace, p.name} - if p.value != "" && p.value != bazel.ConditionsDefaultSelectKey { - parts = append(parts, p.value) - } - if p.os != "" { - parts = append(parts, p.os) - } - - // e.g. acme__feature1, android__board__soc_a, my_namespace__my_variables__my_value__my_os - return strings.ToLower(strings.Join(parts, "__")) -} - -// ProductConfigProperties is a map of maps to group property values according -// their property name and the product config variable they're set under. -// -// The outer map key is the name of the property, like "cflags". -// -// The inner map key is a ProductConfigProperty, which is a struct of product -// variable name, namespace, and the "full configuration" of the product -// variable. -// -// e.g. product variable name: board, namespace: acme, full config: vendor_chip_foo -// -// The value of the map is the interface{} representing the value of the -// property, like ["-DDEFINES"] for cflags. -type ProductConfigProperties map[string]map[ProductConfigOrSoongConfigProperty]interface{} - -func (p *ProductConfigProperties) AddProductConfigProperty( - propertyName, productVariableName, arch string, propertyValue interface{}) { - - productConfigProp := ProductConfigProperty{ - name: productVariableName, // e.g. size, feature1, feature2, FEATURE3, board - arch: arch, // e.g. "", x86, arm64 - } - - p.AddEitherProperty(propertyName, productConfigProp, propertyValue) -} - -func (p *ProductConfigProperties) AddSoongConfigProperty( - propertyName, namespace, variableName, value, os string, propertyValue interface{}) { - - soongConfigProp := SoongConfigProperty{ - namespace: namespace, - name: variableName, // e.g. size, feature1, feature2, FEATURE3, board - value: value, - os: os, // e.g. android, linux_x86 - } - - p.AddEitherProperty(propertyName, soongConfigProp, propertyValue) -} - -func (p *ProductConfigProperties) AddEitherProperty( - propertyName string, key ProductConfigOrSoongConfigProperty, propertyValue interface{}) { - if (*p)[propertyName] == nil { - (*p)[propertyName] = make(map[ProductConfigOrSoongConfigProperty]interface{}) - } - - if existing, ok := (*p)[propertyName][key]; ok { - switch dst := existing.(type) { - case []string: - src, ok := propertyValue.([]string) - if !ok { - panic("Conflicting types") - } - dst = append(dst, src...) - (*p)[propertyName][key] = dst - default: - if existing != propertyValue { - panic(fmt.Errorf("TODO: handle merging value %#v", existing)) - } - } - } else { - (*p)[propertyName][key] = propertyValue - } -} - -// maybeExtractConfigVarProp attempts to read this value as a config var struct -// wrapped by interfaces and ptrs. If it's not the right type, the second return -// value is false. -func maybeExtractConfigVarProp(v reflect.Value) (reflect.Value, bool) { - if v.Kind() == reflect.Interface { - // The conditions_default value can be either - // 1) an ptr to an interface of a struct (bool config variables and product variables) - // 2) an interface of 1) (config variables with nested structs, like string vars) - v = v.Elem() - } - if v.Kind() != reflect.Ptr { - return v, false - } - v = reflect.Indirect(v) - if v.Kind() == reflect.Interface { - // Extract the struct from the interface - v = v.Elem() - } - - if !v.IsValid() { - return v, false - } - - if v.Kind() != reflect.Struct { - return v, false - } - return v, true -} - -func (productConfigProperties *ProductConfigProperties) AddProductConfigProperties(variableValues reflect.Value, arch string) { - // Example of product_variables: - // - // product_variables: { - // malloc_not_svelte: { - // shared_libs: ["malloc_not_svelte_shared_lib"], - // whole_static_libs: ["malloc_not_svelte_whole_static_lib"], - // exclude_static_libs: [ - // "malloc_not_svelte_static_lib_excludes", - // "malloc_not_svelte_whole_static_lib_excludes", - // ], - // }, - // }, - - for i := 0; i < variableValues.NumField(); i++ { - // e.g. Platform_sdk_version, Unbundled_build, Malloc_not_svelte, etc. - productVariableName := variableValues.Type().Field(i).Name - - variableValue := variableValues.Field(i) - // Check if any properties were set for the module - if variableValue.IsZero() { - // e.g. feature1: {}, malloc_not_svelte: {} - continue - } - - for j := 0; j < variableValue.NumField(); j++ { - property := variableValue.Field(j) - // e.g. Asflags, Cflags, Enabled, etc. - propertyName := variableValue.Type().Field(j).Name - if property.Kind() != reflect.Interface { - productConfigProperties.AddProductConfigProperty(propertyName, productVariableName, arch, property.Interface()) - } - } - } - -} - -func (productConfigProperties *ProductConfigProperties) AddSoongConfigProperties(namespace string, soongConfigVariablesStruct reflect.Value) error { - // - // Example of soong_config_variables: - // - // soong_config_variables: { - // feature1: { - // conditions_default: { - // ... - // }, - // cflags: ... - // }, - // feature2: { - // cflags: ... - // conditions_default: { - // ... - // }, - // }, - // board: { - // soc_a: { - // ... - // }, - // soc_b: { - // ... - // }, - // soc_c: {}, - // conditions_default: { - // ... - // }, - // }, - // } - for i := 0; i < soongConfigVariablesStruct.NumField(); i++ { - // e.g. feature1, feature2, board - variableName := soongConfigVariablesStruct.Type().Field(i).Name - variableStruct := soongConfigVariablesStruct.Field(i) - // Check if any properties were set for the module - if variableStruct.IsZero() { - // e.g. feature1: {} - continue - } - - // Unlike product variables, config variables require a few more - // indirections to extract the struct from the reflect.Value. - if v, ok := maybeExtractConfigVarProp(variableStruct); ok { - variableStruct = v - } else if !v.IsValid() { - // Skip invalid variables which may not used, else leads to panic - continue - } - - for j := 0; j < variableStruct.NumField(); j++ { - propertyOrStruct := variableStruct.Field(j) - // propertyOrValueName can either be: - // - A property, like: Asflags, Cflags, Enabled, etc. - // - A soong config string variable's value, like soc_a, soc_b, soc_c in the example above - // - "conditions_default" - propertyOrValueName := variableStruct.Type().Field(j).Name - - // If the property wasn't set, no need to pass it along - if propertyOrStruct.IsZero() { - continue - } - - if v, ok := maybeExtractConfigVarProp(propertyOrStruct); ok { - // The field is a struct, which is used by: - // 1) soong_config_string_variables - // - // soc_a: { - // cflags: ..., - // } - // - // soc_b: { - // cflags: ..., - // } - // - // 2) conditions_default structs for all soong config variable types. - // - // conditions_default: { - // cflags: ..., - // static_libs: ... - // } - // - // This means that propertyOrValueName is either conditions_default, or a soong - // config string variable's value. - field := v - // Iterate over fields of this struct prop. - for k := 0; k < field.NumField(); k++ { - // For product variables, zero values are irrelevant; however, for soong config variables, - // empty values are relevant because there can also be a conditions default which is not - // applied for empty variables. - if field.Field(k).IsZero() && namespace == "" { - continue - } - - propertyName := field.Type().Field(k).Name - if propertyName == "Target" { - productConfigProperties.AddSoongConfigPropertiesFromTargetStruct(namespace, variableName, proptools.PropertyNameForField(propertyOrValueName), field.Field(k)) - } else if propertyName == "Arch" || propertyName == "Multilib" { - return fmt.Errorf("Arch/Multilib are not currently supported in soong config variable structs") - } else { - productConfigProperties.AddSoongConfigProperty(propertyName, namespace, variableName, proptools.PropertyNameForField(propertyOrValueName), "", field.Field(k).Interface()) - } - } - } else if propertyOrStruct.Kind() != reflect.Interface { - // If not an interface, then this is not a conditions_default or - // a struct prop. That is, this is a bool/value config variable. - if propertyOrValueName == "Target" { - productConfigProperties.AddSoongConfigPropertiesFromTargetStruct(namespace, variableName, "", propertyOrStruct) - } else if propertyOrValueName == "Arch" || propertyOrValueName == "Multilib" { - return fmt.Errorf("Arch/Multilib are not currently supported in soong config variable structs") - } else { - productConfigProperties.AddSoongConfigProperty(propertyOrValueName, namespace, variableName, "", "", propertyOrStruct.Interface()) - } - } - } - } - return nil -} - -func (productConfigProperties *ProductConfigProperties) AddSoongConfigPropertiesFromTargetStruct(namespace, soongConfigVariableName string, soongConfigVariableValue string, targetStruct reflect.Value) { - // targetStruct will be a struct with fields like "android", "host", "arm", "x86", - // "android_arm", etc. The values of each of those fields will be a regular property struct. - for i := 0; i < targetStruct.NumField(); i++ { - targetFieldName := targetStruct.Type().Field(i).Name - archOrOsSpecificStruct := targetStruct.Field(i) - for j := 0; j < archOrOsSpecificStruct.NumField(); j++ { - property := archOrOsSpecificStruct.Field(j) - // e.g. Asflags, Cflags, Enabled, etc. - propertyName := archOrOsSpecificStruct.Type().Field(j).Name - - if targetFieldName == "Android" { - productConfigProperties.AddSoongConfigProperty(propertyName, namespace, soongConfigVariableName, soongConfigVariableValue, "android", property.Interface()) - } else if targetFieldName == "Host" { - for _, os := range osTypeList { - if os.Class == Host { - productConfigProperties.AddSoongConfigProperty(propertyName, namespace, soongConfigVariableName, soongConfigVariableValue, os.Name, property.Interface()) - } - } - } else if !archOrOsSpecificStruct.IsZero() { - // One problem with supporting additional fields is that if multiple branches of - // "target" overlap, we don't want them to be in the same select statement (aka - // configuration axis). "android" and "host" are disjoint, so it's ok that we only - // have 2 axes right now. (soongConfigVariables and soongConfigVariablesPlusOs) - panic("TODO: support other target types in soong config variable structs: " + targetFieldName) - } - } - } -} - func VariableMutator(mctx BottomUpMutatorContext) { var module Module var ok bool