diff options
Diffstat (limited to 'android/arch.go')
-rw-r--r-- | android/arch.go | 1061 |
1 files changed, 1061 insertions, 0 deletions
diff --git a/android/arch.go b/android/arch.go new file mode 100644 index 00000000..952b7207 --- /dev/null +++ b/android/arch.go @@ -0,0 +1,1061 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package android + +import ( + "fmt" + "reflect" + "runtime" + "strings" + + "github.com/google/blueprint" + "github.com/google/blueprint/proptools" +) + +func init() { + RegisterBottomUpMutator("defaults_deps", defaultsDepsMutator) + RegisterTopDownMutator("defaults", defaultsMutator) + + RegisterBottomUpMutator("host_or_device", HostOrDeviceMutator) + RegisterBottomUpMutator("host_type", HostTypeMutator) + RegisterBottomUpMutator("arch", ArchMutator) +} + +var ( + Arm = newArch("arm", "lib32") + Arm64 = newArch("arm64", "lib64") + Mips = newArch("mips", "lib32") + Mips64 = newArch("mips64", "lib64") + X86 = newArch("x86", "lib32") + X86_64 = newArch("x86_64", "lib64") + + Common = ArchType{ + Name: "common", + } +) + +var archTypeMap = map[string]ArchType{ + "arm": Arm, + "arm64": Arm64, + "mips": Mips, + "mips64": Mips64, + "x86": X86, + "x86_64": X86_64, +} + +/* +Example blueprints file containing all variant property groups, with comment listing what type +of variants get properties in that group: + +module { + arch: { + arm: { + // Host or device variants with arm architecture + }, + arm64: { + // Host or device variants with arm64 architecture + }, + mips: { + // Host or device variants with mips architecture + }, + mips64: { + // Host or device variants with mips64 architecture + }, + x86: { + // Host or device variants with x86 architecture + }, + x86_64: { + // Host or device variants with x86_64 architecture + }, + }, + multilib: { + lib32: { + // Host or device variants for 32-bit architectures + }, + lib64: { + // Host or device variants for 64-bit architectures + }, + }, + target: { + android: { + // Device variants + }, + host: { + // Host variants + }, + linux: { + // Linux host variants + }, + darwin: { + // Darwin host variants + }, + windows: { + // Windows host variants + }, + not_windows: { + // Non-windows host variants + }, + }, +} +*/ + +type Embed interface{} + +type archProperties struct { + // Properties to vary by target architecture + Arch struct { + // Properties for module variants being built to run on arm (host or device) + Arm struct { + Embed `blueprint:"filter(android:\"arch_variant\")"` + + // Arm arch variants + Armv5te interface{} `blueprint:"filter(android:\"arch_variant\")"` + Armv7_a interface{} `blueprint:"filter(android:\"arch_variant\")"` + Armv7_a_neon interface{} `blueprint:"filter(android:\"arch_variant\")"` + + // Arm cpu variants + Cortex_a7 interface{} `blueprint:"filter(android:\"arch_variant\")"` + Cortex_a8 interface{} `blueprint:"filter(android:\"arch_variant\")"` + Cortex_a9 interface{} `blueprint:"filter(android:\"arch_variant\")"` + Cortex_a15 interface{} `blueprint:"filter(android:\"arch_variant\")"` + Cortex_a53 interface{} `blueprint:"filter(android:\"arch_variant\")"` + Cortex_a53_a57 interface{} `blueprint:"filter(android:\"arch_variant\")"` + Krait interface{} `blueprint:"filter(android:\"arch_variant\")"` + Denver interface{} `blueprint:"filter(android:\"arch_variant\")"` + } + + // Properties for module variants being built to run on arm64 (host or device) + Arm64 struct { + Embed `blueprint:"filter(android:\"arch_variant\")"` + + // Arm64 arch variants + Armv8_a interface{} `blueprint:"filter(android:\"arch_variant\")"` + + // Arm64 cpu variants + Cortex_a53 interface{} `blueprint:"filter(android:\"arch_variant\")"` + Denver64 interface{} `blueprint:"filter(android:\"arch_variant\")"` + } + + // Properties for module variants being built to run on mips (host or device) + Mips struct { + Embed `blueprint:"filter(android:\"arch_variant\")"` + + // Mips arch variants + Mips32_fp interface{} `blueprint:"filter(android:\"arch_variant\")"` + Mips32r2_fp interface{} `blueprint:"filter(android:\"arch_variant\")"` + Mips32r2_fp_xburst interface{} `blueprint:"filter(android:\"arch_variant\")"` + Mips32r2dsp_fp interface{} `blueprint:"filter(android:\"arch_variant\")"` + Mips32r2dspr2_fp interface{} `blueprint:"filter(android:\"arch_variant\")"` + Mips32r6 interface{} `blueprint:"filter(android:\"arch_variant\")"` + + // Mips arch features + Rev6 interface{} `blueprint:"filter(android:\"arch_variant\")"` + } + + // Properties for module variants being built to run on mips64 (host or device) + Mips64 struct { + Embed `blueprint:"filter(android:\"arch_variant\")"` + + // Mips64 arch variants + Mips64r2 interface{} `blueprint:"filter(android:\"arch_variant\")"` + Mips64r6 interface{} `blueprint:"filter(android:\"arch_variant\")"` + + // Mips64 arch features + Rev6 interface{} `blueprint:"filter(android:\"arch_variant\")"` + } + + // Properties for module variants being built to run on x86 (host or device) + X86 struct { + Embed `blueprint:"filter(android:\"arch_variant\")"` + + // X86 arch variants + Atom interface{} `blueprint:"filter(android:\"arch_variant\")"` + Haswell interface{} `blueprint:"filter(android:\"arch_variant\")"` + Ivybridge interface{} `blueprint:"filter(android:\"arch_variant\")"` + Sandybridge interface{} `blueprint:"filter(android:\"arch_variant\")"` + Silvermont interface{} `blueprint:"filter(android:\"arch_variant\")"` + // Generic variant for X86 on X86_64 + X86_64 interface{} `blueprint:"filter(android:\"arch_variant\")"` + + // X86 arch features + Ssse3 interface{} `blueprint:"filter(android:\"arch_variant\")"` + Sse4 interface{} `blueprint:"filter(android:\"arch_variant\")"` + Sse4_1 interface{} `blueprint:"filter(android:\"arch_variant\")"` + Sse4_2 interface{} `blueprint:"filter(android:\"arch_variant\")"` + Aes_ni interface{} `blueprint:"filter(android:\"arch_variant\")"` + Avx interface{} `blueprint:"filter(android:\"arch_variant\")"` + Popcnt interface{} `blueprint:"filter(android:\"arch_variant\")"` + Movbe interface{} `blueprint:"filter(android:\"arch_variant\")"` + } + + // Properties for module variants being built to run on x86_64 (host or device) + X86_64 struct { + Embed `blueprint:"filter(android:\"arch_variant\")"` + + // X86 arch variants + Haswell interface{} `blueprint:"filter(android:\"arch_variant\")"` + Ivybridge interface{} `blueprint:"filter(android:\"arch_variant\")"` + Sandybridge interface{} `blueprint:"filter(android:\"arch_variant\")"` + Silvermont interface{} `blueprint:"filter(android:\"arch_variant\")"` + + // X86 arch features + Ssse3 interface{} `blueprint:"filter(android:\"arch_variant\")"` + Sse4 interface{} `blueprint:"filter(android:\"arch_variant\")"` + Sse4_1 interface{} `blueprint:"filter(android:\"arch_variant\")"` + Sse4_2 interface{} `blueprint:"filter(android:\"arch_variant\")"` + Aes_ni interface{} `blueprint:"filter(android:\"arch_variant\")"` + Avx interface{} `blueprint:"filter(android:\"arch_variant\")"` + Popcnt interface{} `blueprint:"filter(android:\"arch_variant\")"` + } + } + + // Properties to vary by 32-bit or 64-bit + Multilib struct { + // Properties for module variants being built to run on 32-bit devices + Lib32 interface{} `blueprint:"filter(android:\"arch_variant\")"` + // Properties for module variants being built to run on 64-bit devices + Lib64 interface{} `blueprint:"filter(android:\"arch_variant\")"` + } + // Properties to vary by build target (host or device, os, os+archictecture) + Target struct { + // Properties for module variants being built to run on the host + Host interface{} `blueprint:"filter(android:\"arch_variant\")"` + // Properties for module variants being built to run on the device + Android interface{} `blueprint:"filter(android:\"arch_variant\")"` + // Properties for module variants being built to run on arm devices + Android_arm interface{} `blueprint:"filter(android:\"arch_variant\")"` + // Properties for module variants being built to run on arm64 devices + Android_arm64 interface{} `blueprint:"filter(android:\"arch_variant\")"` + // Properties for module variants being built to run on mips devices + Android_mips interface{} `blueprint:"filter(android:\"arch_variant\")"` + // Properties for module variants being built to run on mips64 devices + Android_mips64 interface{} `blueprint:"filter(android:\"arch_variant\")"` + // Properties for module variants being built to run on x86 devices + Android_x86 interface{} `blueprint:"filter(android:\"arch_variant\")"` + // Properties for module variants being built to run on x86_64 devices + Android_x86_64 interface{} `blueprint:"filter(android:\"arch_variant\")"` + // Properties for module variants being built to run on devices that support 64-bit + Android64 interface{} `blueprint:"filter(android:\"arch_variant\")"` + // Properties for module variants being built to run on devices that do not support 64-bit + Android32 interface{} `blueprint:"filter(android:\"arch_variant\")"` + // Properties for module variants being built to run on linux hosts + Linux interface{} `blueprint:"filter(android:\"arch_variant\")"` + // Properties for module variants being built to run on linux x86 hosts + Linux_x86 interface{} `blueprint:"filter(android:\"arch_variant\")"` + // Properties for module variants being built to run on linux x86_64 hosts + Linux_x86_64 interface{} `blueprint:"filter(android:\"arch_variant\")"` + // Properties for module variants being built to run on darwin hosts + Darwin interface{} `blueprint:"filter(android:\"arch_variant\")"` + // Properties for module variants being built to run on darwin x86 hosts + Darwin_x86 interface{} `blueprint:"filter(android:\"arch_variant\")"` + // Properties for module variants being built to run on darwin x86_64 hosts + Darwin_x86_64 interface{} `blueprint:"filter(android:\"arch_variant\")"` + // Properties for module variants being built to run on windows hosts + Windows interface{} `blueprint:"filter(android:\"arch_variant\")"` + // Properties for module variants being built to run on windows x86 hosts + Windows_x86 interface{} `blueprint:"filter(android:\"arch_variant\")"` + // Properties for module variants being built to run on windows x86_64 hosts + Windows_x86_64 interface{} `blueprint:"filter(android:\"arch_variant\")"` + // Properties for module variants being built to run on linux or darwin hosts + Not_windows interface{} `blueprint:"filter(android:\"arch_variant\")"` + } +} + +var archFeatureMap = map[ArchType]map[string][]string{} + +func RegisterArchFeatures(arch ArchType, variant string, features ...string) { + archField := proptools.FieldNameForProperty(arch.Name) + variantField := proptools.FieldNameForProperty(variant) + archStruct := reflect.ValueOf(archProperties{}.Arch).FieldByName(archField) + if variant != "" { + if !archStruct.FieldByName(variantField).IsValid() { + panic(fmt.Errorf("Invalid variant %q for arch %q", variant, arch)) + } + } + for _, feature := range features { + field := proptools.FieldNameForProperty(feature) + if !archStruct.FieldByName(field).IsValid() { + panic(fmt.Errorf("Invalid feature %q for arch %q variant %q", feature, arch, variant)) + } + } + if archFeatureMap[arch] == nil { + archFeatureMap[arch] = make(map[string][]string) + } + archFeatureMap[arch][variant] = features +} + +// An Arch indicates a single CPU architecture. +type Arch struct { + ArchType ArchType + ArchVariant string + CpuVariant string + Abi []string + ArchFeatures []string +} + +func (a Arch) String() string { + s := a.ArchType.String() + if a.ArchVariant != "" { + s += "_" + a.ArchVariant + } + if a.CpuVariant != "" { + s += "_" + a.CpuVariant + } + return s +} + +type ArchType struct { + Name string + Multilib string +} + +func newArch(name, multilib string) ArchType { + return ArchType{ + Name: name, + Multilib: multilib, + } +} + +func (a ArchType) String() string { + return a.Name +} + +type HostOrDeviceSupported int + +const ( + _ HostOrDeviceSupported = iota + HostSupported + DeviceSupported + HostAndDeviceSupported + HostAndDeviceDefault +) + +type HostOrDevice int + +const ( + _ HostOrDevice = iota + Host + Device +) + +func (hod HostOrDevice) String() string { + switch hod { + case Device: + return "device" + case Host: + return "host" + default: + panic(fmt.Sprintf("unexpected HostOrDevice value %d", hod)) + } +} + +func (hod HostOrDevice) Property() string { + switch hod { + case Device: + return "android" + case Host: + return "host" + default: + panic(fmt.Sprintf("unexpected HostOrDevice value %d", hod)) + } +} + +func (hod HostOrDevice) Host() bool { + if hod == 0 { + panic("HostOrDevice unset") + } + return hod == Host +} + +func (hod HostOrDevice) Device() bool { + if hod == 0 { + panic("HostOrDevice unset") + } + return hod == Device +} + +var hostOrDeviceName = map[HostOrDevice]string{ + Device: "device", + Host: "host", +} + +type HostType int + +const ( + NoHostType HostType = iota + Linux + Darwin + Windows +) + +func CurrentHostType() HostType { + switch runtime.GOOS { + case "linux": + return Linux + case "darwin": + return Darwin + default: + panic(fmt.Sprintf("unsupported OS: %s", runtime.GOOS)) + } +} + +func (ht HostType) String() string { + switch ht { + case Linux: + return "linux" + case Darwin: + return "darwin" + case Windows: + return "windows" + default: + panic(fmt.Sprintf("unexpected HostType value %d", ht)) + } +} + +func (ht HostType) Field() string { + switch ht { + case Linux: + return "Linux" + case Darwin: + return "Darwin" + case Windows: + return "Windows" + default: + panic(fmt.Sprintf("unexpected HostType value %d", ht)) + } +} + +var ( + commonArch = Arch{ + ArchType: Common, + } +) + +func HostOrDeviceMutator(mctx BottomUpMutatorContext) { + var module Module + var ok bool + if module, ok = mctx.Module().(Module); !ok { + return + } + + hods := []HostOrDevice{} + + if module.base().HostSupported() { + hods = append(hods, Host) + } + + if module.base().DeviceSupported() { + hods = append(hods, Device) + } + + if len(hods) == 0 { + return + } + + hodNames := []string{} + for _, hod := range hods { + hodNames = append(hodNames, hod.String()) + } + + modules := mctx.CreateVariations(hodNames...) + for i, m := range modules { + m.(Module).base().SetHostOrDevice(hods[i]) + } +} + +func HostTypeMutator(mctx BottomUpMutatorContext) { + var module Module + var ok bool + if module, ok = mctx.Module().(Module); !ok { + return + } + + if !module.base().HostSupported() || !module.base().HostOrDevice().Host() { + return + } + + buildTypes, err := decodeHostTypesProductVariables(mctx.Config().(Config).ProductVariables) + if err != nil { + mctx.ModuleErrorf("%s", err.Error()) + return + } + + typeNames := []string{} + for _, ht := range buildTypes { + typeNames = append(typeNames, ht.String()) + } + + modules := mctx.CreateVariations(typeNames...) + for i, m := range modules { + m.(Module).base().SetHostType(buildTypes[i]) + } +} + +func ArchMutator(mctx BottomUpMutatorContext) { + var module Module + var ok bool + if module, ok = mctx.Module().(Module); !ok { + return + } + + moduleArches := []Arch{} + multilib := module.base().commonProperties.Compile_multilib + + if module.base().HostSupported() && module.base().HostOrDevice().Host() { + hostModuleArches, err := decodeMultilib(multilib, mctx.Config().(Config).HostArches[module.base().HostType()]) + if err != nil { + mctx.ModuleErrorf("%s", err.Error()) + } + + moduleArches = append(moduleArches, hostModuleArches...) + } + + if module.base().DeviceSupported() && module.base().HostOrDevice().Device() { + deviceModuleArches, err := decodeMultilib(multilib, mctx.Config().(Config).DeviceArches) + if err != nil { + mctx.ModuleErrorf("%s", err.Error()) + } + + moduleArches = append(moduleArches, deviceModuleArches...) + } + + if len(moduleArches) == 0 { + return + } + + archNames := []string{} + for _, arch := range moduleArches { + archNames = append(archNames, arch.String()) + } + + modules := mctx.CreateVariations(archNames...) + + for i, m := range modules { + m.(Module).base().SetArch(moduleArches[i]) + m.(Module).base().setArchProperties(mctx) + } +} + +func InitArchModule(m Module, + propertyStructs ...interface{}) (blueprint.Module, []interface{}) { + + base := m.base() + + base.generalProperties = append(base.generalProperties, + propertyStructs...) + + for _, properties := range base.generalProperties { + propertiesValue := reflect.ValueOf(properties) + if propertiesValue.Kind() != reflect.Ptr { + panic(fmt.Errorf("properties must be a pointer to a struct, got %T", + propertiesValue.Interface())) + } + + propertiesValue = propertiesValue.Elem() + if propertiesValue.Kind() != reflect.Struct { + panic(fmt.Errorf("properties must be a pointer to a struct, got %T", + propertiesValue.Interface())) + } + + archProperties := &archProperties{} + forEachInterface(reflect.ValueOf(archProperties), func(v reflect.Value) { + newValue := proptools.CloneEmptyProperties(propertiesValue) + v.Set(newValue) + }) + + base.archProperties = append(base.archProperties, archProperties) + } + + var allProperties []interface{} + allProperties = append(allProperties, base.generalProperties...) + for _, asp := range base.archProperties { + allProperties = append(allProperties, asp) + } + + return m, allProperties +} + +var variantReplacer = strings.NewReplacer("-", "_", ".", "_") + +func (a *ModuleBase) appendProperties(ctx BottomUpMutatorContext, + dst, src interface{}, field, srcPrefix string) interface{} { + + srcField := reflect.ValueOf(src).FieldByName(field) + if !srcField.IsValid() { + ctx.ModuleErrorf("field %q does not exist", srcPrefix) + return nil + } + + ret := srcField + + if srcField.Kind() == reflect.Struct { + srcField = srcField.FieldByName("Embed") + } + + src = srcField.Elem().Interface() + + filter := func(property string, + dstField, srcField reflect.StructField, + dstValue, srcValue interface{}) (bool, error) { + + srcProperty := srcPrefix + "." + property + + if !proptools.HasTag(dstField, "android", "arch_variant") { + if ctx.ContainsProperty(srcProperty) { + return false, fmt.Errorf("can't be specific to a build variant") + } else { + return false, nil + } + } + + return true, nil + } + + order := func(property string, + dstField, srcField reflect.StructField, + dstValue, srcValue interface{}) (proptools.Order, error) { + if proptools.HasTag(dstField, "android", "variant_prepend") { + return proptools.Prepend, nil + } else { + return proptools.Append, nil + } + } + + err := proptools.ExtendProperties(dst, src, filter, order) + if err != nil { + if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok { + ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error()) + } else { + panic(err) + } + } + + return ret.Interface() +} + +// Rewrite the module's properties structs to contain arch-specific values. +func (a *ModuleBase) setArchProperties(ctx BottomUpMutatorContext) { + arch := a.commonProperties.CompileArch + hod := a.commonProperties.CompileHostOrDevice + ht := a.commonProperties.CompileHostType + + if arch.ArchType == Common { + return + } + + for i := range a.generalProperties { + genProps := a.generalProperties[i] + archProps := a.archProperties[i] + // Handle arch-specific properties in the form: + // arch: { + // arm64: { + // key: value, + // }, + // }, + t := arch.ArchType + + field := proptools.FieldNameForProperty(t.Name) + prefix := "arch." + t.Name + archStruct := a.appendProperties(ctx, genProps, archProps.Arch, field, prefix) + + // Handle arch-variant-specific properties in the form: + // arch: { + // variant: { + // key: value, + // }, + // }, + v := variantReplacer.Replace(arch.ArchVariant) + if v != "" { + field := proptools.FieldNameForProperty(v) + prefix := "arch." + t.Name + "." + v + a.appendProperties(ctx, genProps, archStruct, field, prefix) + } + + // Handle cpu-variant-specific properties in the form: + // arch: { + // variant: { + // key: value, + // }, + // }, + c := variantReplacer.Replace(arch.CpuVariant) + if c != "" { + field := proptools.FieldNameForProperty(c) + prefix := "arch." + t.Name + "." + c + a.appendProperties(ctx, genProps, archStruct, field, prefix) + } + + // Handle arch-feature-specific properties in the form: + // arch: { + // feature: { + // key: value, + // }, + // }, + for _, feature := range arch.ArchFeatures { + field := proptools.FieldNameForProperty(feature) + prefix := "arch." + t.Name + "." + feature + a.appendProperties(ctx, genProps, archStruct, field, prefix) + } + + // Handle multilib-specific properties in the form: + // multilib: { + // lib32: { + // key: value, + // }, + // }, + field = proptools.FieldNameForProperty(t.Multilib) + prefix = "multilib." + t.Multilib + a.appendProperties(ctx, genProps, archProps.Multilib, field, prefix) + + // Handle host-or-device-specific properties in the form: + // target: { + // host: { + // key: value, + // }, + // }, + hodProperty := hod.Property() + field = proptools.FieldNameForProperty(hodProperty) + prefix = "target." + hodProperty + a.appendProperties(ctx, genProps, archProps.Target, field, prefix) + + // Handle host target properties in the form: + // target: { + // linux: { + // key: value, + // }, + // not_windows: { + // key: value, + // }, + // linux_x86: { + // key: value, + // }, + // linux_arm: { + // key: value, + // }, + // }, + if hod.Host() { + field := ht.Field() + prefix := "target." + ht.String() + a.appendProperties(ctx, genProps, archProps.Target, field, prefix) + + t := arch.ArchType + field = ht.Field() + "_" + t.Name + prefix = "target." + ht.String() + "_" + t.Name + a.appendProperties(ctx, genProps, archProps.Target, field, prefix) + + if ht != Windows { + field := "Not_windows" + prefix := "target.not_windows" + a.appendProperties(ctx, genProps, archProps.Target, field, prefix) + } + } + + // Handle 64-bit device properties in the form: + // target { + // android64 { + // key: value, + // }, + // android32 { + // key: value, + // }, + // }, + // WARNING: this is probably not what you want to use in your blueprints file, it selects + // options for all targets on a device that supports 64-bit binaries, not just the targets + // that are being compiled for 64-bit. Its expected use case is binaries like linker and + // debuggerd that need to know when they are a 32-bit process running on a 64-bit device + if hod.Device() { + if true /* && target_is_64_bit */ { + field := "Android64" + prefix := "target.android64" + a.appendProperties(ctx, genProps, archProps.Target, field, prefix) + } else { + field := "Android32" + prefix := "target.android32" + a.appendProperties(ctx, genProps, archProps.Target, field, prefix) + } + } + + // Handle device architecture properties in the form: + // target { + // android_arm { + // key: value, + // }, + // android_x86 { + // key: value, + // }, + // }, + if hod.Device() { + t := arch.ArchType + field := "Android_" + t.Name + prefix := "target.android_" + t.Name + a.appendProperties(ctx, genProps, archProps.Target, field, prefix) + } + + if ctx.Failed() { + return + } + } +} + +func forEachInterface(v reflect.Value, f func(reflect.Value)) { + switch v.Kind() { + case reflect.Interface: + f(v) + case reflect.Struct: + for i := 0; i < v.NumField(); i++ { + forEachInterface(v.Field(i), f) + } + case reflect.Ptr: + forEachInterface(v.Elem(), f) + default: + panic(fmt.Errorf("Unsupported kind %s", v.Kind())) + } +} + +// Get a list of HostTypes from the product variables +func decodeHostTypesProductVariables(variables productVariables) ([]HostType, error) { + ret := []HostType{CurrentHostType()} + + if variables.CrossHost != nil && *variables.CrossHost != "" { + switch *variables.CrossHost { + case "windows": + ret = append(ret, Windows) + default: + return nil, fmt.Errorf("Unsupported secondary host: %s", *variables.CrossHost) + } + } + + return ret, nil +} + +// Convert the arch product variables into a list of host and device Arch structs +func decodeArchProductVariables(variables productVariables) (map[HostType][]Arch, []Arch, error) { + if variables.HostArch == nil { + return nil, nil, fmt.Errorf("No host primary architecture set") + } + + hostArch, err := decodeArch(*variables.HostArch, nil, nil, nil) + if err != nil { + return nil, nil, err + } + + hostArches := []Arch{hostArch} + + if variables.HostSecondaryArch != nil && *variables.HostSecondaryArch != "" { + hostSecondaryArch, err := decodeArch(*variables.HostSecondaryArch, nil, nil, nil) + if err != nil { + return nil, nil, err + } + hostArches = append(hostArches, hostSecondaryArch) + } + + hostTypeArches := map[HostType][]Arch{ + CurrentHostType(): hostArches, + } + + if variables.CrossHost != nil && *variables.CrossHost != "" { + if variables.CrossHostArch == nil || *variables.CrossHostArch == "" { + return nil, nil, fmt.Errorf("No cross-host primary architecture set") + } + + crossHostArch, err := decodeArch(*variables.CrossHostArch, nil, nil, nil) + if err != nil { + return nil, nil, err + } + + crossHostArches := []Arch{crossHostArch} + + if variables.CrossHostSecondaryArch != nil && *variables.CrossHostSecondaryArch != "" { + crossHostSecondaryArch, err := decodeArch(*variables.CrossHostSecondaryArch, nil, nil, nil) + if err != nil { + return nil, nil, err + } + crossHostArches = append(crossHostArches, crossHostSecondaryArch) + } + + switch *variables.CrossHost { + case "windows": + hostTypeArches[Windows] = crossHostArches + default: + return nil, nil, fmt.Errorf("Unsupported cross-host: %s", *variables.CrossHost) + } + } + + if variables.DeviceArch == nil { + return nil, nil, fmt.Errorf("No device primary architecture set") + } + + deviceArch, err := decodeArch(*variables.DeviceArch, variables.DeviceArchVariant, + variables.DeviceCpuVariant, variables.DeviceAbi) + if err != nil { + return nil, nil, err + } + + deviceArches := []Arch{deviceArch} + + if variables.DeviceSecondaryArch != nil && *variables.DeviceSecondaryArch != "" { + deviceSecondaryArch, err := decodeArch(*variables.DeviceSecondaryArch, + variables.DeviceSecondaryArchVariant, variables.DeviceSecondaryCpuVariant, + variables.DeviceSecondaryAbi) + if err != nil { + return nil, nil, err + } + deviceArches = append(deviceArches, deviceSecondaryArch) + } + + return hostTypeArches, deviceArches, nil +} + +func decodeMegaDevice() ([]Arch, error) { + archSettings := []struct { + arch string + archVariant string + cpuVariant string + abi []string + }{ + // armv5 is only used for unbundled apps + //{"arm", "armv5te", "", []string{"armeabi"}}, + {"arm", "armv7-a", "generic", []string{"armeabi-v7a"}}, + {"arm", "armv7-a-neon", "generic", []string{"armeabi-v7a"}}, + {"arm", "armv7-a-neon", "cortex-a7", []string{"armeabi-v7a"}}, + {"arm", "armv7-a-neon", "cortex-a8", []string{"armeabi-v7a"}}, + {"arm", "armv7-a-neon", "cortex-a9", []string{"armeabi-v7a"}}, + {"arm", "armv7-a-neon", "cortex-a15", []string{"armeabi-v7a"}}, + {"arm", "armv7-a-neon", "cortex-a53", []string{"armeabi-v7a"}}, + {"arm", "armv7-a-neon", "cortex-a53.a57", []string{"armeabi-v7a"}}, + {"arm", "armv7-a-neon", "denver", []string{"armeabi-v7a"}}, + {"arm", "armv7-a-neon", "krait", []string{"armeabi-v7a"}}, + {"arm64", "armv8-a", "cortex-a53", []string{"arm64-v8a"}}, + {"arm64", "armv8-a", "denver64", []string{"arm64-v8a"}}, + {"mips", "mips32-fp", "", []string{"mips"}}, + {"mips", "mips32r2-fp", "", []string{"mips"}}, + {"mips", "mips32r2-fp-xburst", "", []string{"mips"}}, + {"mips", "mips32r6", "", []string{"mips"}}, + // mips32r2dsp[r2]-fp fails in the assembler for divdf3.c in compiler-rt: + // (same errors in make and soong) + // Error: invalid operands `mtlo $ac0,$11' + // Error: invalid operands `mthi $ac0,$12' + //{"mips", "mips32r2dsp-fp", "", []string{"mips"}}, + //{"mips", "mips32r2dspr2-fp", "", []string{"mips"}}, + // mips64r2 is mismatching 64r2 and 64r6 libraries during linking to libgcc + //{"mips64", "mips64r2", "", []string{"mips64"}}, + {"mips64", "mips64r6", "", []string{"mips64"}}, + {"x86", "", "", []string{"x86"}}, + {"x86", "atom", "", []string{"x86"}}, + {"x86", "haswell", "", []string{"x86"}}, + {"x86", "ivybridge", "", []string{"x86"}}, + {"x86", "sandybridge", "", []string{"x86"}}, + {"x86", "silvermont", "", []string{"x86"}}, + {"x86", "x86_64", "", []string{"x86"}}, + {"x86_64", "", "", []string{"x86_64"}}, + {"x86_64", "haswell", "", []string{"x86_64"}}, + {"x86_64", "ivybridge", "", []string{"x86_64"}}, + {"x86_64", "sandybridge", "", []string{"x86_64"}}, + {"x86_64", "silvermont", "", []string{"x86_64"}}, + } + + var ret []Arch + + for _, config := range archSettings { + arch, err := decodeArch(config.arch, &config.archVariant, + &config.cpuVariant, &config.abi) + if err != nil { + return nil, err + } + ret = append(ret, arch) + } + + return ret, nil +} + +// Convert a set of strings from product variables into a single Arch struct +func decodeArch(arch string, archVariant, cpuVariant *string, abi *[]string) (Arch, error) { + stringPtr := func(p *string) string { + if p != nil { + return *p + } + return "" + } + + slicePtr := func(p *[]string) []string { + if p != nil { + return *p + } + return nil + } + + archType, ok := archTypeMap[arch] + if !ok { + return Arch{}, fmt.Errorf("unknown arch %q", arch) + } + + a := Arch{ + ArchType: archType, + ArchVariant: stringPtr(archVariant), + CpuVariant: stringPtr(cpuVariant), + Abi: slicePtr(abi), + } + + if a.ArchVariant == a.ArchType.Name || a.ArchVariant == "generic" { + a.ArchVariant = "" + } + + if a.CpuVariant == a.ArchType.Name || a.CpuVariant == "generic" { + a.CpuVariant = "" + } + + for i := 0; i < len(a.Abi); i++ { + if a.Abi[i] == "" { + a.Abi = append(a.Abi[:i], a.Abi[i+1:]...) + i-- + } + } + + if featureMap, ok := archFeatureMap[archType]; ok { + a.ArchFeatures = featureMap[a.ArchVariant] + } + + return a, nil +} + +// Use the module multilib setting to select one or more arches from an arch list +func decodeMultilib(multilib string, arches []Arch) ([]Arch, error) { + buildArches := []Arch{} + switch multilib { + case "common": + buildArches = append(buildArches, commonArch) + case "both": + buildArches = append(buildArches, arches...) + case "first": + buildArches = append(buildArches, arches[0]) + case "32": + for _, a := range arches { + if a.ArchType.Multilib == "lib32" { + buildArches = append(buildArches, a) + } + } + case "64": + for _, a := range arches { + if a.ArchType.Multilib == "lib64" { + buildArches = append(buildArches, a) + } + } + default: + return nil, fmt.Errorf(`compile_multilib must be "both", "first", "32", or "64", found %q`, + multilib) + //buildArches = append(buildArches, arches[0]) + } + + return buildArches, nil +} |