Files
build_soong/android/arch.go
Colin Cross a120ec1c5e Add PropertyCustomizer
Allow any module factory to insert a PropertyCustomizer on the module,
which will be called before any other mutators.  The PropertyCustomizer
can append or prepend to any properties, allowing module types to extend
other module types by modifying the public, stable interface provided by
the properties.

Change-Id: Idff02be80d939a70df1c6bbccffdd1f04ff975d2
2016-08-22 17:08:06 -07:00

935 lines
28 KiB
Go

// 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"
)
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
Native bool
}
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
}
var BuildOs = func() OsType {
switch runtime.GOOS {
case "linux":
return Linux
case "darwin":
return Darwin
default:
panic(fmt.Sprintf("unsupported OS: %s", runtime.GOOS))
}
}()
var (
osTypeList []OsType
NoOsType OsType
Linux = NewOsType("linux", Host)
Darwin = NewOsType("darwin", Host)
Windows = NewOsType("windows", HostCross)
Android = NewOsType("android", Device)
)
type OsType struct {
Name, Field string
Class OsClass
}
type OsClass int
const (
Device OsClass = iota
Host
HostCross
)
func (os OsType) String() string {
return os.Name
}
func NewOsType(name string, class OsClass) OsType {
os := OsType{
Name: name,
Field: strings.Title(name),
Class: class,
}
osTypeList = append(osTypeList, os)
return os
}
func osByName(name string) OsType {
for _, os := range osTypeList {
if os.Name == name {
return os
}
}
return NoOsType
}
var (
commonTarget = Target{
Os: Android,
Arch: Arch{
ArchType: Common,
},
}
)
type Target struct {
Os OsType
Arch Arch
}
func (target Target) String() string {
return target.Os.String() + "_" + target.Arch.String()
}
func ArchMutator(mctx BottomUpMutatorContext) {
var module Module
var ok bool
if module, ok = mctx.Module().(Module); !ok {
return
}
osClasses := module.base().OsClassSupported()
if len(osClasses) == 0 {
return
}
var moduleTargets []Target
for _, class := range osClasses {
targets := mctx.AConfig().Targets[class]
if len(targets) == 0 {
continue
}
multilib := module.base().commonProperties.Compile_multilib
targets, err := decodeMultilib(multilib, targets)
if err != nil {
mctx.ModuleErrorf("%s", err.Error())
}
moduleTargets = append(moduleTargets, targets...)
}
if len(moduleTargets) == 0 {
module.base().commonProperties.Enabled = boolPtr(false)
return
}
targetNames := make([]string, len(moduleTargets))
for i, target := range moduleTargets {
targetNames[i] = target.String()
}
modules := mctx.CreateVariations(targetNames...)
for i, m := range modules {
m.(Module).base().SetTarget(moduleTargets[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)
t := propertiesValue.Type()
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 := reflect.Zero(t)
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)
}
base.customizableProperties = allProperties
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.Arch()
os := a.Os()
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-specific properties in the form:
// target: {
// host: {
// key: value,
// },
// },
if os.Class == Host || os.Class == HostCross {
field = "Host"
prefix = "target.host"
a.appendProperties(ctx, genProps, archProps.Target, field, prefix)
}
// Handle target OS properties in the form:
// target: {
// linux: {
// key: value,
// },
// not_windows: {
// key: value,
// },
// linux_x86: {
// key: value,
// },
// linux_arm: {
// key: value,
// },
// android {
// key: value,
// },
// android_arm {
// key: value,
// },
// android_x86 {
// key: value,
// },
// },
// },
field = os.Field
prefix = "target." + os.Name
a.appendProperties(ctx, genProps, archProps.Target, field, prefix)
field = os.Field + "_" + t.Name
prefix = "target." + os.Name + "_" + t.Name
a.appendProperties(ctx, genProps, archProps.Target, field, prefix)
if (os.Class == Host || os.Class == HostCross) && os != 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 os.Class == Device {
if ctx.AConfig().Android64() {
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)
}
}
}
}
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()))
}
}
// Convert the arch product variables into a list of targets for each os class structs
func decodeTargetProductVariables(config *config) (map[OsClass][]Target, error) {
variables := config.ProductVariables
targets := make(map[OsClass][]Target)
var targetErr error
addTarget := func(os OsType, archName string, archVariant, cpuVariant *string, abi *[]string) {
if targetErr != nil {
return
}
arch, err := decodeArch(archName, archVariant, cpuVariant, abi)
if err != nil {
targetErr = err
return
}
targets[os.Class] = append(targets[os.Class],
Target{
Os: os,
Arch: arch,
})
}
if variables.HostArch == nil {
return nil, fmt.Errorf("No host primary architecture set")
}
addTarget(BuildOs, *variables.HostArch, nil, nil, nil)
if variables.HostSecondaryArch != nil && *variables.HostSecondaryArch != "" {
addTarget(BuildOs, *variables.HostSecondaryArch, nil, nil, nil)
}
if variables.CrossHost != nil && *variables.CrossHost != "" {
crossHostOs := osByName(*variables.CrossHost)
if crossHostOs == NoOsType {
return nil, fmt.Errorf("Unknown cross host OS %q", *variables.CrossHost)
}
if variables.CrossHostArch == nil || *variables.CrossHostArch == "" {
return nil, fmt.Errorf("No cross-host primary architecture set")
}
addTarget(crossHostOs, *variables.CrossHostArch, nil, nil, nil)
if variables.CrossHostSecondaryArch != nil && *variables.CrossHostSecondaryArch != "" {
addTarget(crossHostOs, *variables.CrossHostSecondaryArch, nil, nil, nil)
}
}
if variables.DeviceArch != nil && *variables.DeviceArch != "" {
addTarget(Android, *variables.DeviceArch, variables.DeviceArchVariant,
variables.DeviceCpuVariant, variables.DeviceAbi)
if variables.DeviceSecondaryArch != nil && *variables.DeviceSecondaryArch != "" {
addTarget(Android, *variables.DeviceSecondaryArch,
variables.DeviceSecondaryArchVariant, variables.DeviceSecondaryCpuVariant,
variables.DeviceSecondaryAbi)
deviceArches := targets[Device]
if deviceArches[0].Arch.ArchType.Multilib == deviceArches[1].Arch.ArchType.Multilib {
deviceArches[1].Arch.Native = false
}
}
}
if targetErr != nil {
return nil, targetErr
}
return targets, nil
}
func decodeMegaDevice() ([]Target, 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 []Target
for _, config := range archSettings {
arch, err := decodeArch(config.arch, &config.archVariant,
&config.cpuVariant, &config.abi)
if err != nil {
return nil, err
}
arch.Native = false
ret = append(ret, Target{
Os: Android,
Arch: 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),
Native: true,
}
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 targets from a target list
func decodeMultilib(multilib string, targets []Target) ([]Target, error) {
buildTargets := []Target{}
switch multilib {
case "common":
buildTargets = append(buildTargets, commonTarget)
case "both":
buildTargets = append(buildTargets, targets...)
case "first":
buildTargets = append(buildTargets, targets[0])
case "32":
for _, t := range targets {
if t.Arch.ArchType.Multilib == "lib32" {
buildTargets = append(buildTargets, t)
}
}
case "64":
for _, t := range targets {
if t.Arch.ArchType.Multilib == "lib64" {
buildTargets = append(buildTargets, t)
}
}
default:
return nil, fmt.Errorf(`compile_multilib must be "both", "first", "32", or "64", found %q`,
multilib)
}
return buildTargets, nil
}