platform_build_soong/android/arch.go
Jiyong Park 37b252096a Don't create non-primary arch variant for recovery-only module
To save space, only the primary arch variant is installed to the
recovery partition. This has been done in the imageMutator by not
creating recovery variant for the non-primary arch.

However, this caused a problem for recover-only module, i.e., recovery:
true. Such module ends up creating no variant for the non-primary arch.
Since every other modules are at least in one image variant, any
dependency fro such module with no image variant can't be satisfied.

In order to solve the problem, archMutator is modified to create only
the primary arch for recovery-only modules.

Bug: 111321972
Test: m -j (TestRecovery added)
Change-Id: Ie32ae06fb094efcfd8531cdf6071139d292d93ab
2018-07-12 10:49:30 +09:00

1153 lines
29 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/proptools"
)
var (
archTypeList []ArchType
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_glibc: {
// Linux host variants
},
darwin: {
// Darwin host variants
},
windows: {
// Windows host variants
},
not_windows: {
// Non-windows host variants
},
},
}
*/
var archVariants = map[ArchType][]string{}
var archFeatures = map[ArchType][]string{}
var archFeatureMap = map[ArchType]map[string][]string{}
func RegisterArchVariants(arch ArchType, variants ...string) {
checkCalledFromInit()
archVariants[arch] = append(archVariants[arch], variants...)
}
func RegisterArchFeatures(arch ArchType, features ...string) {
checkCalledFromInit()
archFeatures[arch] = append(archFeatures[arch], features...)
}
func RegisterArchVariantFeatures(arch ArchType, variant string, features ...string) {
checkCalledFromInit()
if variant != "" && !InList(variant, archVariants[arch]) {
panic(fmt.Errorf("Invalid variant %q for arch %q", variant, arch))
}
for _, feature := range features {
if !InList(feature, archFeatures[arch]) {
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
Field string
Multilib string
}
func newArch(name, multilib string) ArchType {
archType := ArchType{
Name: name,
Field: proptools.FieldNameForProperty(name),
Multilib: multilib,
}
archTypeList = append(archTypeList, archType)
return archType
}
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
commonTargetMap = make(map[string]Target)
NoOsType OsType
Linux = NewOsType("linux_glibc", Host, false)
Darwin = NewOsType("darwin", Host, false)
LinuxBionic = NewOsType("linux_bionic", Host, true)
Windows = NewOsType("windows", HostCross, true)
Android = NewOsType("android", Device, false)
osArchTypeMap = map[OsType][]ArchType{
Linux: []ArchType{X86, X86_64},
LinuxBionic: []ArchType{X86_64},
Darwin: []ArchType{X86, X86_64},
Windows: []ArchType{X86, X86_64},
Android: []ArchType{Arm, Arm64, Mips, Mips64, X86, X86_64},
}
)
type OsType struct {
Name, Field string
Class OsClass
DefaultDisabled bool
}
type OsClass int
const (
Generic OsClass = iota
Device
Host
HostCross
)
func (class OsClass) String() string {
switch class {
case Generic:
return "generic"
case Device:
return "device"
case Host:
return "host"
case HostCross:
return "host cross"
default:
panic(fmt.Errorf("unknown class %d", class))
}
}
func (os OsType) String() string {
return os.Name
}
func (os OsType) Bionic() bool {
return os == Android || os == LinuxBionic
}
func (os OsType) Linux() bool {
return os == Android || os == Linux || os == LinuxBionic
}
func NewOsType(name string, class OsClass, defDisabled bool) OsType {
os := OsType{
Name: name,
Field: strings.Title(name),
Class: class,
DefaultDisabled: defDisabled,
}
osTypeList = append(osTypeList, os)
if _, found := commonTargetMap[name]; found {
panic(fmt.Errorf("Found Os type duplicate during OsType registration: %q", name))
} else {
commonTargetMap[name] = Target{Os: os, Arch: Arch{ArchType: Common}}
}
return os
}
func osByName(name string) OsType {
for _, os := range osTypeList {
if os.Name == name {
return os
}
}
return NoOsType
}
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
}
if !module.base().ArchSpecific() {
return
}
osClasses := module.base().OsClassSupported()
var moduleTargets []Target
primaryModules := make(map[int]bool)
for _, class := range osClasses {
targets := mctx.Config().Targets[class]
if len(targets) == 0 {
continue
}
var multilib string
switch class {
case Device:
multilib = String(module.base().commonProperties.Target.Android.Compile_multilib)
case Host, HostCross:
multilib = String(module.base().commonProperties.Target.Host.Compile_multilib)
}
if multilib == "" {
multilib = String(module.base().commonProperties.Compile_multilib)
}
if multilib == "" {
multilib = module.base().commonProperties.Default_multilib
}
var prefer32 bool
switch class {
case Device:
prefer32 = mctx.Config().DevicePrefer32BitExecutables()
case HostCross:
// Windows builds always prefer 32-bit
prefer32 = true
}
// only the primary arch in the recovery partition
if module.InstallInRecovery() {
targets = []Target{mctx.Config().Targets[Device][0]}
}
targets, err := decodeMultilib(multilib, targets, prefer32)
if err != nil {
mctx.ModuleErrorf("%s", err.Error())
}
if len(targets) > 0 {
primaryModules[len(moduleTargets)] = true
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], primaryModules[i])
m.(Module).base().setArchProperties(mctx)
}
}
func filterArchStruct(prop reflect.Type) (reflect.Type, bool) {
var fields []reflect.StructField
ptr := prop.Kind() == reflect.Ptr
if ptr {
prop = prop.Elem()
}
for i := 0; i < prop.NumField(); i++ {
field := prop.Field(i)
if !proptools.HasTag(field, "android", "arch_variant") {
continue
}
// The arch_variant field isn't necessary past this point
// Instead of wasting space, just remove it. Go also has a
// 16-bit limit on structure name length. The name is constructed
// based on the Go source representation of the structure, so
// the tag names count towards that length.
//
// TODO: handle the uncommon case of other tags being involved
if field.Tag == `android:"arch_variant"` {
field.Tag = ""
}
// Recurse into structs
switch field.Type.Kind() {
case reflect.Struct:
var ok bool
field.Type, ok = filterArchStruct(field.Type)
if !ok {
continue
}
case reflect.Ptr:
if field.Type.Elem().Kind() == reflect.Struct {
nestedType, ok := filterArchStruct(field.Type.Elem())
if !ok {
continue
}
field.Type = reflect.PtrTo(nestedType)
}
case reflect.Interface:
panic("Interfaces are not supported in arch_variant properties")
}
fields = append(fields, field)
}
if len(fields) == 0 {
return nil, false
}
ret := reflect.StructOf(fields)
if ptr {
ret = reflect.PtrTo(ret)
}
return ret, true
}
func createArchType(props reflect.Type) reflect.Type {
props, ok := filterArchStruct(props)
if !ok {
return nil
}
variantFields := func(names []string) []reflect.StructField {
ret := make([]reflect.StructField, len(names))
for i, name := range names {
ret[i].Name = name
ret[i].Type = props
}
return ret
}
archFields := make([]reflect.StructField, len(archTypeList))
for i, arch := range archTypeList {
variants := []string{}
for _, archVariant := range archVariants[arch] {
archVariant := variantReplacer.Replace(archVariant)
variants = append(variants, proptools.FieldNameForProperty(archVariant))
}
for _, feature := range archFeatures[arch] {
feature := variantReplacer.Replace(feature)
variants = append(variants, proptools.FieldNameForProperty(feature))
}
fields := variantFields(variants)
fields = append([]reflect.StructField{reflect.StructField{
Name: "BlueprintEmbed",
Type: props,
Anonymous: true,
}}, fields...)
archFields[i] = reflect.StructField{
Name: arch.Field,
Type: reflect.StructOf(fields),
}
}
archType := reflect.StructOf(archFields)
multilibType := reflect.StructOf(variantFields([]string{"Lib32", "Lib64"}))
targets := []string{
"Host",
"Android64",
"Android32",
"Bionic",
"Linux",
"Not_windows",
"Arm_on_x86",
"Arm_on_x86_64",
}
for _, os := range osTypeList {
targets = append(targets, os.Field)
for _, archType := range osArchTypeMap[os] {
targets = append(targets, os.Field+"_"+archType.Name)
if os.Linux() {
target := "Linux_" + archType.Name
if !InList(target, targets) {
targets = append(targets, target)
}
}
if os.Bionic() {
target := "Bionic_" + archType.Name
if !InList(target, targets) {
targets = append(targets, target)
}
}
}
}
targetType := reflect.StructOf(variantFields(targets))
return reflect.StructOf([]reflect.StructField{
reflect.StructField{
Name: "Arch",
Type: archType,
},
reflect.StructField{
Name: "Multilib",
Type: multilibType,
},
reflect.StructField{
Name: "Target",
Type: targetType,
},
})
}
var archPropTypeMap OncePer
func InitArchModule(m Module) {
base := m.base()
base.generalProperties = m.GetProperties()
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()))
}
archPropType := archPropTypeMap.Once(t, func() interface{} {
return createArchType(t)
})
if archPropType != nil {
base.archProperties = append(base.archProperties, reflect.New(archPropType.(reflect.Type)).Interface())
} else {
base.archProperties = append(base.archProperties, nil)
}
}
for _, asp := range base.archProperties {
if asp != nil {
m.AddProperties(asp)
}
}
base.customizableProperties = m.GetProperties()
}
var variantReplacer = strings.NewReplacer("-", "_", ".", "_")
func (a *ModuleBase) appendProperties(ctx BottomUpMutatorContext,
dst interface{}, src reflect.Value, field, srcPrefix string) reflect.Value {
src = src.FieldByName(field)
if !src.IsValid() {
ctx.ModuleErrorf("field %q does not exist", srcPrefix)
return src
}
ret := src
if src.Kind() == reflect.Struct {
src = src.FieldByName("BlueprintEmbed")
}
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.ExtendMatchingProperties([]interface{}{dst}, src.Interface(), nil, order)
if err != nil {
if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
} else {
panic(err)
}
}
return ret
}
// Rewrite the module's properties structs to contain arch-specific values.
func (a *ModuleBase) setArchProperties(ctx BottomUpMutatorContext) {
arch := a.Arch()
os := a.Os()
for i := range a.generalProperties {
genProps := a.generalProperties[i]
if a.archProperties[i] == nil {
continue
}
archProps := reflect.ValueOf(a.archProperties[i]).Elem()
archProp := archProps.FieldByName("Arch")
multilibProp := archProps.FieldByName("Multilib")
targetProp := archProps.FieldByName("Target")
var field string
var prefix string
// Handle arch-specific properties in the form:
// arch: {
// arm64: {
// key: value,
// },
// },
t := arch.ArchType
if arch.ArchType != Common {
field := proptools.FieldNameForProperty(t.Name)
prefix := "arch." + t.Name
archStruct := a.appendProperties(ctx, genProps, archProp, 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,
// },
// },
if arch.CpuVariant != arch.ArchVariant {
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, multilibProp, 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, targetProp, field, prefix)
}
// Handle target OS generalities of the form:
// target: {
// bionic: {
// key: value,
// },
// bionic_x86: {
// key: value,
// },
// }
if os.Linux() {
field = "Linux"
prefix = "target.linux"
a.appendProperties(ctx, genProps, targetProp, field, prefix)
if arch.ArchType != Common {
field = "Linux_" + arch.ArchType.Name
prefix = "target.linux_" + arch.ArchType.Name
a.appendProperties(ctx, genProps, targetProp, field, prefix)
}
}
if os.Bionic() {
field = "Bionic"
prefix = "target.bionic"
a.appendProperties(ctx, genProps, targetProp, field, prefix)
if arch.ArchType != Common {
field = "Bionic_" + t.Name
prefix = "target.bionic_" + t.Name
a.appendProperties(ctx, genProps, targetProp, field, prefix)
}
}
// Handle target OS properties in the form:
// target: {
// linux_glibc: {
// key: value,
// },
// not_windows: {
// key: value,
// },
// linux_glibc_x86: {
// key: value,
// },
// linux_glibc_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, targetProp, field, prefix)
if arch.ArchType != Common {
field = os.Field + "_" + t.Name
prefix = "target." + os.Name + "_" + t.Name
a.appendProperties(ctx, genProps, targetProp, field, prefix)
}
if (os.Class == Host || os.Class == HostCross) && os != Windows {
field := "Not_windows"
prefix := "target.not_windows"
a.appendProperties(ctx, genProps, targetProp, 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.Config().Android64() {
field := "Android64"
prefix := "target.android64"
a.appendProperties(ctx, genProps, targetProp, field, prefix)
} else {
field := "Android32"
prefix := "target.android32"
a.appendProperties(ctx, genProps, targetProp, field, prefix)
}
if (arch.ArchType == X86 && (hasArmAbi(arch) ||
hasArmAndroidArch(ctx.Config().Targets[Device]))) ||
(arch.ArchType == Arm &&
hasX86AndroidArch(ctx.Config().Targets[Device])) {
field := "Arm_on_x86"
prefix := "target.arm_on_x86"
a.appendProperties(ctx, genProps, targetProp, field, prefix)
}
if (arch.ArchType == X86_64 && (hasArmAbi(arch) ||
hasArmAndroidArch(ctx.Config().Targets[Device]))) ||
(arch.ArchType == Arm &&
hasX8664AndroidArch(ctx.Config().Targets[Device])) {
field := "Arm_on_x86_64"
prefix := "target.arm_on_x86_64"
a.appendProperties(ctx, genProps, targetProp, 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 Bool(config.Host_bionic) {
addTarget(LinuxBionic, "x86_64", nil, nil, nil)
}
if String(variables.CrossHost) != "" {
crossHostOs := osByName(*variables.CrossHost)
if crossHostOs == NoOsType {
return nil, fmt.Errorf("Unknown cross host OS %q", *variables.CrossHost)
}
if String(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
}
// hasArmAbi returns true if arch has at least one arm ABI
func hasArmAbi(arch Arch) bool {
for _, abi := range arch.Abi {
if strings.HasPrefix(abi, "arm") {
return true
}
}
return false
}
// hasArmArch returns true if targets has at least arm Android arch
func hasArmAndroidArch(targets []Target) bool {
for _, target := range targets {
if target.Os == Android && target.Arch.ArchType == Arm {
return true
}
}
return false
}
// hasX86Arch returns true if targets has at least x86 Android arch
func hasX86AndroidArch(targets []Target) bool {
for _, target := range targets {
if target.Os == Android && target.Arch.ArchType == X86 {
return true
}
}
return false
}
// hasX8664Arch returns true if targets has at least x86_64 Android arch
func hasX8664AndroidArch(targets []Target) bool {
for _, target := range targets {
if target.Os == Android && target.Arch.ArchType == X86_64 {
return true
}
}
return false
}
type archConfig struct {
arch string
archVariant string
cpuVariant string
abi []string
}
func getMegaDeviceConfig() []archConfig {
return []archConfig{
{"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", "cortex-a73", []string{"armeabi-v7a"}},
{"arm", "armv7-a-neon", "cortex-a75", []string{"armeabi-v7a"}},
{"arm", "armv7-a-neon", "denver", []string{"armeabi-v7a"}},
{"arm", "armv7-a-neon", "krait", []string{"armeabi-v7a"}},
{"arm", "armv7-a-neon", "kryo", []string{"armeabi-v7a"}},
{"arm", "armv7-a-neon", "exynos-m1", []string{"armeabi-v7a"}},
{"arm", "armv7-a-neon", "exynos-m2", []string{"armeabi-v7a"}},
{"arm64", "armv8-a", "cortex-a53", []string{"arm64-v8a"}},
{"arm64", "armv8-a", "cortex-a73", []string{"arm64-v8a"}},
{"arm64", "armv8-a", "denver64", []string{"arm64-v8a"}},
{"arm64", "armv8-a", "kryo", []string{"arm64-v8a"}},
{"arm64", "armv8-a", "exynos-m1", []string{"arm64-v8a"}},
{"arm64", "armv8-a", "exynos-m2", []string{"arm64-v8a"}},
{"arm64", "armv8-2a", "cortex-a75", []string{"arm64-v8a"}},
{"mips", "mips32-fp", "", []string{"mips"}},
{"mips", "mips32r2-fp", "", []string{"mips"}},
{"mips", "mips32r2-fp-xburst", "", []string{"mips"}},
//{"mips", "mips32r6", "", []string{"mips"}},
{"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"}},
}
}
func getNdkAbisConfig() []archConfig {
return []archConfig{
{"arm", "armv7-a", "", []string{"armeabi"}},
{"arm64", "armv8-a", "", []string{"arm64-v8a"}},
{"x86", "", "", []string{"x86"}},
{"x86_64", "", "", []string{"x86_64"}},
}
}
func decodeArchSettings(archConfigs []archConfig) ([]Target, error) {
var ret []Target
for _, config := range archConfigs {
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
}
func filterMultilibTargets(targets []Target, multilib string) []Target {
var ret []Target
for _, t := range targets {
if t.Arch.ArchType.Multilib == multilib {
ret = append(ret, t)
}
}
return ret
}
func getCommonTargets(targets []Target) []Target {
var ret []Target
set := make(map[string]bool)
for _, t := range targets {
if _, found := set[t.Os.String()]; !found {
set[t.Os.String()] = true
ret = append(ret, commonTargetMap[t.Os.String()])
}
}
return ret
}
func preferTargets(targets []Target, filters ...string) []Target {
for _, filter := range filters {
buildTargets := filterMultilibTargets(targets, filter)
if len(buildTargets) > 0 {
return buildTargets
}
}
return nil
}
// Use the module multilib setting to select one or more targets from a target list
func decodeMultilib(multilib string, targets []Target, prefer32 bool) ([]Target, error) {
buildTargets := []Target{}
switch multilib {
case "common":
buildTargets = getCommonTargets(targets)
case "common_first":
buildTargets = getCommonTargets(targets)
if prefer32 {
buildTargets = append(buildTargets, preferTargets(targets, "lib32", "lib64")...)
} else {
buildTargets = append(buildTargets, preferTargets(targets, "lib64", "lib32")...)
}
case "both":
if prefer32 {
buildTargets = append(buildTargets, filterMultilibTargets(targets, "lib32")...)
buildTargets = append(buildTargets, filterMultilibTargets(targets, "lib64")...)
} else {
buildTargets = append(buildTargets, filterMultilibTargets(targets, "lib64")...)
buildTargets = append(buildTargets, filterMultilibTargets(targets, "lib32")...)
}
case "32":
buildTargets = filterMultilibTargets(targets, "lib32")
case "64":
buildTargets = filterMultilibTargets(targets, "lib64")
case "first":
if prefer32 {
buildTargets = preferTargets(targets, "lib32", "lib64")
} else {
buildTargets = preferTargets(targets, "lib64", "lib32")
}
case "prefer32":
buildTargets = preferTargets(targets, "lib32", "lib64")
default:
return nil, fmt.Errorf(`compile_multilib must be "both", "first", "32", "64", or "prefer32" found %q`,
multilib)
}
return buildTargets, nil
}