Home | History | Annotate | Download | only in android
      1 // Copyright 2015 Google Inc. All rights reserved.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //     http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 package android
     16 
     17 import (
     18 	"fmt"
     19 	"reflect"
     20 	"runtime"
     21 	"strings"
     22 
     23 	"github.com/google/blueprint"
     24 	"github.com/google/blueprint/proptools"
     25 )
     26 
     27 var (
     28 	archTypeList []ArchType
     29 
     30 	Arm    = newArch("arm", "lib32")
     31 	Arm64  = newArch("arm64", "lib64")
     32 	Mips   = newArch("mips", "lib32")
     33 	Mips64 = newArch("mips64", "lib64")
     34 	X86    = newArch("x86", "lib32")
     35 	X86_64 = newArch("x86_64", "lib64")
     36 
     37 	Common = ArchType{
     38 		Name: "common",
     39 	}
     40 )
     41 
     42 var archTypeMap = map[string]ArchType{
     43 	"arm":    Arm,
     44 	"arm64":  Arm64,
     45 	"mips":   Mips,
     46 	"mips64": Mips64,
     47 	"x86":    X86,
     48 	"x86_64": X86_64,
     49 }
     50 
     51 /*
     52 Example blueprints file containing all variant property groups, with comment listing what type
     53 of variants get properties in that group:
     54 
     55 module {
     56     arch: {
     57         arm: {
     58             // Host or device variants with arm architecture
     59         },
     60         arm64: {
     61             // Host or device variants with arm64 architecture
     62         },
     63         mips: {
     64             // Host or device variants with mips architecture
     65         },
     66         mips64: {
     67             // Host or device variants with mips64 architecture
     68         },
     69         x86: {
     70             // Host or device variants with x86 architecture
     71         },
     72         x86_64: {
     73             // Host or device variants with x86_64 architecture
     74         },
     75     },
     76     multilib: {
     77         lib32: {
     78             // Host or device variants for 32-bit architectures
     79         },
     80         lib64: {
     81             // Host or device variants for 64-bit architectures
     82         },
     83     },
     84     target: {
     85         android: {
     86             // Device variants
     87         },
     88         host: {
     89             // Host variants
     90         },
     91         linux: {
     92             // Linux host variants
     93         },
     94         darwin: {
     95             // Darwin host variants
     96         },
     97         windows: {
     98             // Windows host variants
     99         },
    100         not_windows: {
    101             // Non-windows host variants
    102         },
    103     },
    104 }
    105 */
    106 
    107 var archVariants = map[ArchType][]string{}
    108 var archFeatures = map[ArchType][]string{}
    109 var archFeatureMap = map[ArchType]map[string][]string{}
    110 
    111 func RegisterArchVariants(arch ArchType, variants ...string) {
    112 	checkCalledFromInit()
    113 	archVariants[arch] = append(archVariants[arch], variants...)
    114 }
    115 
    116 func RegisterArchFeatures(arch ArchType, features ...string) {
    117 	checkCalledFromInit()
    118 	archFeatures[arch] = append(archFeatures[arch], features...)
    119 }
    120 
    121 func RegisterArchVariantFeatures(arch ArchType, variant string, features ...string) {
    122 	checkCalledFromInit()
    123 	if variant != "" && !inList(variant, archVariants[arch]) {
    124 		panic(fmt.Errorf("Invalid variant %q for arch %q", variant, arch))
    125 	}
    126 
    127 	for _, feature := range features {
    128 		if !inList(feature, archFeatures[arch]) {
    129 			panic(fmt.Errorf("Invalid feature %q for arch %q variant %q", feature, arch, variant))
    130 		}
    131 	}
    132 
    133 	if archFeatureMap[arch] == nil {
    134 		archFeatureMap[arch] = make(map[string][]string)
    135 	}
    136 	archFeatureMap[arch][variant] = features
    137 }
    138 
    139 // An Arch indicates a single CPU architecture.
    140 type Arch struct {
    141 	ArchType     ArchType
    142 	ArchVariant  string
    143 	CpuVariant   string
    144 	Abi          []string
    145 	ArchFeatures []string
    146 	Native       bool
    147 }
    148 
    149 func (a Arch) String() string {
    150 	s := a.ArchType.String()
    151 	if a.ArchVariant != "" {
    152 		s += "_" + a.ArchVariant
    153 	}
    154 	if a.CpuVariant != "" {
    155 		s += "_" + a.CpuVariant
    156 	}
    157 	return s
    158 }
    159 
    160 type ArchType struct {
    161 	Name     string
    162 	Field    string
    163 	Multilib string
    164 }
    165 
    166 func newArch(name, multilib string) ArchType {
    167 	archType := ArchType{
    168 		Name:     name,
    169 		Field:    proptools.FieldNameForProperty(name),
    170 		Multilib: multilib,
    171 	}
    172 	archTypeList = append(archTypeList, archType)
    173 	return archType
    174 }
    175 
    176 func (a ArchType) String() string {
    177 	return a.Name
    178 }
    179 
    180 var BuildOs = func() OsType {
    181 	switch runtime.GOOS {
    182 	case "linux":
    183 		return Linux
    184 	case "darwin":
    185 		return Darwin
    186 	default:
    187 		panic(fmt.Sprintf("unsupported OS: %s", runtime.GOOS))
    188 	}
    189 }()
    190 
    191 var (
    192 	osTypeList []OsType
    193 
    194 	NoOsType    OsType
    195 	Linux       = NewOsType("linux", Host, false)
    196 	Darwin      = NewOsType("darwin", Host, false)
    197 	LinuxBionic = NewOsType("linux_bionic", Host, true)
    198 	Windows     = NewOsType("windows", HostCross, true)
    199 	Android     = NewOsType("android", Device, false)
    200 
    201 	osArchTypeMap = map[OsType][]ArchType{
    202 		Linux:       []ArchType{X86, X86_64},
    203 		LinuxBionic: []ArchType{X86_64},
    204 		Darwin:      []ArchType{X86, X86_64},
    205 		Windows:     []ArchType{X86, X86_64},
    206 		Android:     []ArchType{Arm, Arm64, Mips, Mips64, X86, X86_64},
    207 	}
    208 )
    209 
    210 type OsType struct {
    211 	Name, Field string
    212 	Class       OsClass
    213 
    214 	DefaultDisabled bool
    215 }
    216 
    217 type OsClass int
    218 
    219 const (
    220 	Generic OsClass = iota
    221 	Device
    222 	Host
    223 	HostCross
    224 )
    225 
    226 func (os OsType) String() string {
    227 	return os.Name
    228 }
    229 
    230 func NewOsType(name string, class OsClass, defDisabled bool) OsType {
    231 	os := OsType{
    232 		Name:  name,
    233 		Field: strings.Title(name),
    234 		Class: class,
    235 
    236 		DefaultDisabled: defDisabled,
    237 	}
    238 	osTypeList = append(osTypeList, os)
    239 	return os
    240 }
    241 
    242 func osByName(name string) OsType {
    243 	for _, os := range osTypeList {
    244 		if os.Name == name {
    245 			return os
    246 		}
    247 	}
    248 
    249 	return NoOsType
    250 }
    251 
    252 var (
    253 	commonTarget = Target{
    254 		Os: Android,
    255 		Arch: Arch{
    256 			ArchType: Common,
    257 		},
    258 	}
    259 )
    260 
    261 type Target struct {
    262 	Os   OsType
    263 	Arch Arch
    264 }
    265 
    266 func (target Target) String() string {
    267 	return target.Os.String() + "_" + target.Arch.String()
    268 }
    269 
    270 func archMutator(mctx BottomUpMutatorContext) {
    271 	var module Module
    272 	var ok bool
    273 	if module, ok = mctx.Module().(Module); !ok {
    274 		return
    275 	}
    276 
    277 	if !module.base().ArchSpecific() {
    278 		return
    279 	}
    280 
    281 	osClasses := module.base().OsClassSupported()
    282 
    283 	var moduleTargets []Target
    284 	primaryModules := make(map[int]bool)
    285 
    286 	for _, class := range osClasses {
    287 		targets := mctx.AConfig().Targets[class]
    288 		if len(targets) == 0 {
    289 			continue
    290 		}
    291 		var multilib string
    292 		switch class {
    293 		case Device:
    294 			multilib = module.base().commonProperties.Target.Android.Compile_multilib
    295 		case Host, HostCross:
    296 			multilib = module.base().commonProperties.Target.Host.Compile_multilib
    297 		}
    298 		if multilib == "" {
    299 			multilib = module.base().commonProperties.Compile_multilib
    300 		}
    301 		if multilib == "" {
    302 			multilib = module.base().commonProperties.Default_multilib
    303 		}
    304 		var prefer32 bool
    305 		switch class {
    306 		case Device:
    307 			prefer32 = mctx.AConfig().DevicePrefer32BitExecutables()
    308 		case HostCross:
    309 			// Windows builds always prefer 32-bit
    310 			prefer32 = true
    311 		}
    312 		targets, err := decodeMultilib(multilib, targets, prefer32)
    313 		if err != nil {
    314 			mctx.ModuleErrorf("%s", err.Error())
    315 		}
    316 		if len(targets) > 0 {
    317 			primaryModules[len(moduleTargets)] = true
    318 			moduleTargets = append(moduleTargets, targets...)
    319 		}
    320 	}
    321 
    322 	if len(moduleTargets) == 0 {
    323 		module.base().commonProperties.Enabled = boolPtr(false)
    324 		return
    325 	}
    326 
    327 	targetNames := make([]string, len(moduleTargets))
    328 
    329 	for i, target := range moduleTargets {
    330 		targetNames[i] = target.String()
    331 	}
    332 
    333 	modules := mctx.CreateVariations(targetNames...)
    334 	for i, m := range modules {
    335 		m.(Module).base().SetTarget(moduleTargets[i], primaryModules[i])
    336 		m.(Module).base().setArchProperties(mctx)
    337 	}
    338 }
    339 
    340 func filterArchStruct(prop reflect.Type) (reflect.Type, bool) {
    341 	var fields []reflect.StructField
    342 
    343 	ptr := prop.Kind() == reflect.Ptr
    344 	if ptr {
    345 		prop = prop.Elem()
    346 	}
    347 
    348 	for i := 0; i < prop.NumField(); i++ {
    349 		field := prop.Field(i)
    350 		if !proptools.HasTag(field, "android", "arch_variant") {
    351 			continue
    352 		}
    353 
    354 		// The arch_variant field isn't necessary past this point
    355 		// Instead of wasting space, just remove it. Go also has a
    356 		// 16-bit limit on structure name length. The name is constructed
    357 		// based on the Go source representation of the structure, so
    358 		// the tag names count towards that length.
    359 		//
    360 		// TODO: handle the uncommon case of other tags being involved
    361 		if field.Tag == `android:"arch_variant"` {
    362 			field.Tag = ""
    363 		}
    364 
    365 		// Recurse into structs
    366 		switch field.Type.Kind() {
    367 		case reflect.Struct:
    368 			var ok bool
    369 			field.Type, ok = filterArchStruct(field.Type)
    370 			if !ok {
    371 				continue
    372 			}
    373 		case reflect.Ptr:
    374 			if field.Type.Elem().Kind() == reflect.Struct {
    375 				nestedType, ok := filterArchStruct(field.Type.Elem())
    376 				if !ok {
    377 					continue
    378 				}
    379 				field.Type = reflect.PtrTo(nestedType)
    380 			}
    381 		case reflect.Interface:
    382 			panic("Interfaces are not supported in arch_variant properties")
    383 		}
    384 
    385 		fields = append(fields, field)
    386 	}
    387 	if len(fields) == 0 {
    388 		return nil, false
    389 	}
    390 
    391 	ret := reflect.StructOf(fields)
    392 	if ptr {
    393 		ret = reflect.PtrTo(ret)
    394 	}
    395 	return ret, true
    396 }
    397 
    398 func createArchType(props reflect.Type) reflect.Type {
    399 	props, ok := filterArchStruct(props)
    400 	if !ok {
    401 		return nil
    402 	}
    403 
    404 	variantFields := func(names []string) []reflect.StructField {
    405 		ret := make([]reflect.StructField, len(names))
    406 
    407 		for i, name := range names {
    408 			ret[i].Name = name
    409 			ret[i].Type = props
    410 		}
    411 
    412 		return ret
    413 	}
    414 
    415 	archFields := make([]reflect.StructField, len(archTypeList))
    416 	for i, arch := range archTypeList {
    417 		variants := []string{}
    418 
    419 		for _, archVariant := range archVariants[arch] {
    420 			variants = append(variants, proptools.FieldNameForProperty(archVariant))
    421 		}
    422 		for _, feature := range archFeatures[arch] {
    423 			variants = append(variants, proptools.FieldNameForProperty(feature))
    424 		}
    425 
    426 		fields := variantFields(variants)
    427 
    428 		fields = append([]reflect.StructField{reflect.StructField{
    429 			Name:      "BlueprintEmbed",
    430 			Type:      props,
    431 			Anonymous: true,
    432 		}}, fields...)
    433 
    434 		archFields[i] = reflect.StructField{
    435 			Name: arch.Field,
    436 			Type: reflect.StructOf(fields),
    437 		}
    438 	}
    439 	archType := reflect.StructOf(archFields)
    440 
    441 	multilibType := reflect.StructOf(variantFields([]string{"Lib32", "Lib64"}))
    442 
    443 	targets := []string{
    444 		"Host",
    445 		"Android64",
    446 		"Android32",
    447 		"Not_windows",
    448 		"Arm_on_x86",
    449 		"Arm_on_x86_64",
    450 	}
    451 	for _, os := range osTypeList {
    452 		targets = append(targets, os.Field)
    453 
    454 		for _, archType := range osArchTypeMap[os] {
    455 			targets = append(targets, os.Field+"_"+archType.Name)
    456 		}
    457 	}
    458 
    459 	targetType := reflect.StructOf(variantFields(targets))
    460 	return reflect.StructOf([]reflect.StructField{
    461 		reflect.StructField{
    462 			Name: "Arch",
    463 			Type: archType,
    464 		},
    465 		reflect.StructField{
    466 			Name: "Multilib",
    467 			Type: multilibType,
    468 		},
    469 		reflect.StructField{
    470 			Name: "Target",
    471 			Type: targetType,
    472 		},
    473 	})
    474 }
    475 
    476 var archPropTypeMap OncePer
    477 
    478 func InitArchModule(m Module,
    479 	propertyStructs ...interface{}) (blueprint.Module, []interface{}) {
    480 
    481 	base := m.base()
    482 
    483 	base.generalProperties = append(base.generalProperties,
    484 		propertyStructs...)
    485 
    486 	for _, properties := range base.generalProperties {
    487 		propertiesValue := reflect.ValueOf(properties)
    488 		t := propertiesValue.Type()
    489 		if propertiesValue.Kind() != reflect.Ptr {
    490 			panic(fmt.Errorf("properties must be a pointer to a struct, got %T",
    491 				propertiesValue.Interface()))
    492 		}
    493 
    494 		propertiesValue = propertiesValue.Elem()
    495 		if propertiesValue.Kind() != reflect.Struct {
    496 			panic(fmt.Errorf("properties must be a pointer to a struct, got %T",
    497 				propertiesValue.Interface()))
    498 		}
    499 
    500 		archPropType := archPropTypeMap.Once(t, func() interface{} {
    501 			return createArchType(t)
    502 		})
    503 
    504 		if archPropType != nil {
    505 			base.archProperties = append(base.archProperties, reflect.New(archPropType.(reflect.Type)).Interface())
    506 		} else {
    507 			base.archProperties = append(base.archProperties, nil)
    508 		}
    509 	}
    510 
    511 	var allProperties []interface{}
    512 	allProperties = append(allProperties, base.generalProperties...)
    513 	for _, asp := range base.archProperties {
    514 		if asp != nil {
    515 			allProperties = append(allProperties, asp)
    516 		}
    517 	}
    518 
    519 	base.customizableProperties = allProperties
    520 
    521 	return m, allProperties
    522 }
    523 
    524 var variantReplacer = strings.NewReplacer("-", "_", ".", "_")
    525 
    526 func (a *ModuleBase) appendProperties(ctx BottomUpMutatorContext,
    527 	dst interface{}, src reflect.Value, field, srcPrefix string) reflect.Value {
    528 
    529 	src = src.FieldByName(field)
    530 	if !src.IsValid() {
    531 		ctx.ModuleErrorf("field %q does not exist", srcPrefix)
    532 		return src
    533 	}
    534 
    535 	ret := src
    536 
    537 	if src.Kind() == reflect.Struct {
    538 		src = src.FieldByName("BlueprintEmbed")
    539 	}
    540 
    541 	order := func(property string,
    542 		dstField, srcField reflect.StructField,
    543 		dstValue, srcValue interface{}) (proptools.Order, error) {
    544 		if proptools.HasTag(dstField, "android", "variant_prepend") {
    545 			return proptools.Prepend, nil
    546 		} else {
    547 			return proptools.Append, nil
    548 		}
    549 	}
    550 
    551 	err := proptools.ExtendMatchingProperties([]interface{}{dst}, src.Interface(), nil, order)
    552 	if err != nil {
    553 		if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
    554 			ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
    555 		} else {
    556 			panic(err)
    557 		}
    558 	}
    559 
    560 	return ret
    561 }
    562 
    563 // Rewrite the module's properties structs to contain arch-specific values.
    564 func (a *ModuleBase) setArchProperties(ctx BottomUpMutatorContext) {
    565 	arch := a.Arch()
    566 	os := a.Os()
    567 
    568 	if arch.ArchType == Common {
    569 		return
    570 	}
    571 
    572 	for i := range a.generalProperties {
    573 		genProps := a.generalProperties[i]
    574 		if a.archProperties[i] == nil {
    575 			continue
    576 		}
    577 		archProps := reflect.ValueOf(a.archProperties[i]).Elem()
    578 
    579 		archProp := archProps.FieldByName("Arch")
    580 		multilibProp := archProps.FieldByName("Multilib")
    581 		targetProp := archProps.FieldByName("Target")
    582 
    583 		// Handle arch-specific properties in the form:
    584 		// arch: {
    585 		//     arm64: {
    586 		//         key: value,
    587 		//     },
    588 		// },
    589 		t := arch.ArchType
    590 
    591 		field := proptools.FieldNameForProperty(t.Name)
    592 		prefix := "arch." + t.Name
    593 		archStruct := a.appendProperties(ctx, genProps, archProp, field, prefix)
    594 
    595 		// Handle arch-variant-specific properties in the form:
    596 		// arch: {
    597 		//     variant: {
    598 		//         key: value,
    599 		//     },
    600 		// },
    601 		v := variantReplacer.Replace(arch.ArchVariant)
    602 		if v != "" {
    603 			field := proptools.FieldNameForProperty(v)
    604 			prefix := "arch." + t.Name + "." + v
    605 			a.appendProperties(ctx, genProps, archStruct, field, prefix)
    606 		}
    607 
    608 		// Handle cpu-variant-specific properties in the form:
    609 		// arch: {
    610 		//     variant: {
    611 		//         key: value,
    612 		//     },
    613 		// },
    614 		if arch.CpuVariant != arch.ArchVariant {
    615 			c := variantReplacer.Replace(arch.CpuVariant)
    616 			if c != "" {
    617 				field := proptools.FieldNameForProperty(c)
    618 				prefix := "arch." + t.Name + "." + c
    619 				a.appendProperties(ctx, genProps, archStruct, field, prefix)
    620 			}
    621 		}
    622 
    623 		// Handle arch-feature-specific properties in the form:
    624 		// arch: {
    625 		//     feature: {
    626 		//         key: value,
    627 		//     },
    628 		// },
    629 		for _, feature := range arch.ArchFeatures {
    630 			field := proptools.FieldNameForProperty(feature)
    631 			prefix := "arch." + t.Name + "." + feature
    632 			a.appendProperties(ctx, genProps, archStruct, field, prefix)
    633 		}
    634 
    635 		// Handle multilib-specific properties in the form:
    636 		// multilib: {
    637 		//     lib32: {
    638 		//         key: value,
    639 		//     },
    640 		// },
    641 		field = proptools.FieldNameForProperty(t.Multilib)
    642 		prefix = "multilib." + t.Multilib
    643 		a.appendProperties(ctx, genProps, multilibProp, field, prefix)
    644 
    645 		// Handle host-specific properties in the form:
    646 		// target: {
    647 		//     host: {
    648 		//         key: value,
    649 		//     },
    650 		// },
    651 		if os.Class == Host || os.Class == HostCross {
    652 			field = "Host"
    653 			prefix = "target.host"
    654 			a.appendProperties(ctx, genProps, targetProp, field, prefix)
    655 		}
    656 
    657 		// Handle target OS properties in the form:
    658 		// target: {
    659 		//     linux: {
    660 		//         key: value,
    661 		//     },
    662 		//     not_windows: {
    663 		//         key: value,
    664 		//     },
    665 		//     linux_x86: {
    666 		//         key: value,
    667 		//     },
    668 		//     linux_arm: {
    669 		//         key: value,
    670 		//     },
    671 		//     android {
    672 		//         key: value,
    673 		//     },
    674 		//     android_arm {
    675 		//         key: value,
    676 		//     },
    677 		//     android_x86 {
    678 		//         key: value,
    679 		//     },
    680 		// },
    681 		// },
    682 		field = os.Field
    683 		prefix = "target." + os.Name
    684 		a.appendProperties(ctx, genProps, targetProp, field, prefix)
    685 
    686 		field = os.Field + "_" + t.Name
    687 		prefix = "target." + os.Name + "_" + t.Name
    688 		a.appendProperties(ctx, genProps, targetProp, field, prefix)
    689 
    690 		if (os.Class == Host || os.Class == HostCross) && os != Windows {
    691 			field := "Not_windows"
    692 			prefix := "target.not_windows"
    693 			a.appendProperties(ctx, genProps, targetProp, field, prefix)
    694 		}
    695 
    696 		// Handle 64-bit device properties in the form:
    697 		// target {
    698 		//     android64 {
    699 		//         key: value,
    700 		//     },
    701 		//     android32 {
    702 		//         key: value,
    703 		//     },
    704 		// },
    705 		// WARNING: this is probably not what you want to use in your blueprints file, it selects
    706 		// options for all targets on a device that supports 64-bit binaries, not just the targets
    707 		// that are being compiled for 64-bit.  Its expected use case is binaries like linker and
    708 		// debuggerd that need to know when they are a 32-bit process running on a 64-bit device
    709 		if os.Class == Device {
    710 			if ctx.AConfig().Android64() {
    711 				field := "Android64"
    712 				prefix := "target.android64"
    713 				a.appendProperties(ctx, genProps, targetProp, field, prefix)
    714 			} else {
    715 				field := "Android32"
    716 				prefix := "target.android32"
    717 				a.appendProperties(ctx, genProps, targetProp, field, prefix)
    718 			}
    719 		}
    720 
    721 		if arch.ArchType == X86 && hasArmAbi(arch) {
    722 			field := "Arm_on_x86"
    723 			prefix := "target.arm_on_x86"
    724 			a.appendProperties(ctx, genProps, targetProp, field, prefix)
    725 		}
    726 		if arch.ArchType == X86_64 && hasArmAbi(arch) {
    727 			field := "Arm_on_x86_64"
    728 			prefix := "target.arm_on_x86_64"
    729 			a.appendProperties(ctx, genProps, targetProp, field, prefix)
    730 		}
    731 	}
    732 }
    733 
    734 func forEachInterface(v reflect.Value, f func(reflect.Value)) {
    735 	switch v.Kind() {
    736 	case reflect.Interface:
    737 		f(v)
    738 	case reflect.Struct:
    739 		for i := 0; i < v.NumField(); i++ {
    740 			forEachInterface(v.Field(i), f)
    741 		}
    742 	case reflect.Ptr:
    743 		forEachInterface(v.Elem(), f)
    744 	default:
    745 		panic(fmt.Errorf("Unsupported kind %s", v.Kind()))
    746 	}
    747 }
    748 
    749 // Convert the arch product variables into a list of targets for each os class structs
    750 func decodeTargetProductVariables(config *config) (map[OsClass][]Target, error) {
    751 	variables := config.ProductVariables
    752 
    753 	targets := make(map[OsClass][]Target)
    754 	var targetErr error
    755 
    756 	addTarget := func(os OsType, archName string, archVariant, cpuVariant *string, abi *[]string) {
    757 		if targetErr != nil {
    758 			return
    759 		}
    760 
    761 		arch, err := decodeArch(archName, archVariant, cpuVariant, abi)
    762 		if err != nil {
    763 			targetErr = err
    764 			return
    765 		}
    766 
    767 		targets[os.Class] = append(targets[os.Class],
    768 			Target{
    769 				Os:   os,
    770 				Arch: arch,
    771 			})
    772 	}
    773 
    774 	if variables.HostArch == nil {
    775 		return nil, fmt.Errorf("No host primary architecture set")
    776 	}
    777 
    778 	addTarget(BuildOs, *variables.HostArch, nil, nil, nil)
    779 
    780 	if variables.HostSecondaryArch != nil && *variables.HostSecondaryArch != "" {
    781 		addTarget(BuildOs, *variables.HostSecondaryArch, nil, nil, nil)
    782 	}
    783 
    784 	if config.Host_bionic != nil && *config.Host_bionic {
    785 		addTarget(LinuxBionic, "x86_64", nil, nil, nil)
    786 	}
    787 
    788 	if variables.CrossHost != nil && *variables.CrossHost != "" {
    789 		crossHostOs := osByName(*variables.CrossHost)
    790 		if crossHostOs == NoOsType {
    791 			return nil, fmt.Errorf("Unknown cross host OS %q", *variables.CrossHost)
    792 		}
    793 
    794 		if variables.CrossHostArch == nil || *variables.CrossHostArch == "" {
    795 			return nil, fmt.Errorf("No cross-host primary architecture set")
    796 		}
    797 
    798 		addTarget(crossHostOs, *variables.CrossHostArch, nil, nil, nil)
    799 
    800 		if variables.CrossHostSecondaryArch != nil && *variables.CrossHostSecondaryArch != "" {
    801 			addTarget(crossHostOs, *variables.CrossHostSecondaryArch, nil, nil, nil)
    802 		}
    803 	}
    804 
    805 	if variables.DeviceArch != nil && *variables.DeviceArch != "" {
    806 		addTarget(Android, *variables.DeviceArch, variables.DeviceArchVariant,
    807 			variables.DeviceCpuVariant, variables.DeviceAbi)
    808 
    809 		if variables.DeviceSecondaryArch != nil && *variables.DeviceSecondaryArch != "" {
    810 			addTarget(Android, *variables.DeviceSecondaryArch,
    811 				variables.DeviceSecondaryArchVariant, variables.DeviceSecondaryCpuVariant,
    812 				variables.DeviceSecondaryAbi)
    813 
    814 			deviceArches := targets[Device]
    815 			if deviceArches[0].Arch.ArchType.Multilib == deviceArches[1].Arch.ArchType.Multilib {
    816 				deviceArches[1].Arch.Native = false
    817 			}
    818 		}
    819 	}
    820 
    821 	if targetErr != nil {
    822 		return nil, targetErr
    823 	}
    824 
    825 	return targets, nil
    826 }
    827 
    828 // hasArmAbi returns true if arch has at least one arm ABI
    829 func hasArmAbi(arch Arch) bool {
    830 	for _, abi := range arch.Abi {
    831 		if strings.HasPrefix(abi, "arm") {
    832 			return true
    833 		}
    834 	}
    835 	return false
    836 }
    837 
    838 type archConfig struct {
    839 	arch        string
    840 	archVariant string
    841 	cpuVariant  string
    842 	abi         []string
    843 }
    844 
    845 func getMegaDeviceConfig() []archConfig {
    846 	return []archConfig{
    847 		// armv5 is only used for unbundled apps
    848 		//{"arm", "armv5te", "", []string{"armeabi"}},
    849 		{"arm", "armv7-a", "generic", []string{"armeabi-v7a"}},
    850 		{"arm", "armv7-a-neon", "generic", []string{"armeabi-v7a"}},
    851 		{"arm", "armv7-a-neon", "cortex-a7", []string{"armeabi-v7a"}},
    852 		{"arm", "armv7-a-neon", "cortex-a8", []string{"armeabi-v7a"}},
    853 		{"arm", "armv7-a-neon", "cortex-a9", []string{"armeabi-v7a"}},
    854 		{"arm", "armv7-a-neon", "cortex-a15", []string{"armeabi-v7a"}},
    855 		{"arm", "armv7-a-neon", "cortex-a53", []string{"armeabi-v7a"}},
    856 		{"arm", "armv7-a-neon", "cortex-a53.a57", []string{"armeabi-v7a"}},
    857 		{"arm", "armv7-a-neon", "denver", []string{"armeabi-v7a"}},
    858 		{"arm", "armv7-a-neon", "krait", []string{"armeabi-v7a"}},
    859 		{"arm64", "armv8-a", "cortex-a53", []string{"arm64-v8a"}},
    860 		{"arm64", "armv8-a", "denver64", []string{"arm64-v8a"}},
    861 		{"mips", "mips32-fp", "", []string{"mips"}},
    862 		{"mips", "mips32r2-fp", "", []string{"mips"}},
    863 		{"mips", "mips32r2-fp-xburst", "", []string{"mips"}},
    864 		//{"mips", "mips32r6", "", []string{"mips"}},
    865 		// mips32r2dsp[r2]-fp fails in the assembler for divdf3.c in compiler-rt:
    866 		// (same errors in make and soong)
    867 		//   Error: invalid operands `mtlo $ac0,$11'
    868 		//   Error: invalid operands `mthi $ac0,$12'
    869 		//{"mips", "mips32r2dsp-fp", "", []string{"mips"}},
    870 		//{"mips", "mips32r2dspr2-fp", "", []string{"mips"}},
    871 		// mips64r2 is mismatching 64r2 and 64r6 libraries during linking to libgcc
    872 		//{"mips64", "mips64r2", "", []string{"mips64"}},
    873 		{"mips64", "mips64r6", "", []string{"mips64"}},
    874 		{"x86", "", "", []string{"x86"}},
    875 		{"x86", "atom", "", []string{"x86"}},
    876 		{"x86", "haswell", "", []string{"x86"}},
    877 		{"x86", "ivybridge", "", []string{"x86"}},
    878 		{"x86", "sandybridge", "", []string{"x86"}},
    879 		{"x86", "silvermont", "", []string{"x86"}},
    880 		{"x86", "x86_64", "", []string{"x86"}},
    881 		{"x86_64", "", "", []string{"x86_64"}},
    882 		{"x86_64", "haswell", "", []string{"x86_64"}},
    883 		{"x86_64", "ivybridge", "", []string{"x86_64"}},
    884 		{"x86_64", "sandybridge", "", []string{"x86_64"}},
    885 		{"x86_64", "silvermont", "", []string{"x86_64"}},
    886 	}
    887 }
    888 
    889 func getNdkAbisConfig() []archConfig {
    890 	return []archConfig{
    891 		{"arm", "armv5te", "", []string{"armeabi"}},
    892 		{"arm64", "armv8-a", "", []string{"arm64-v8a"}},
    893 		{"mips", "mips32-fp", "", []string{"mips"}},
    894 		{"mips64", "mips64r6", "", []string{"mips64"}},
    895 		{"x86", "", "", []string{"x86"}},
    896 		{"x86_64", "", "", []string{"x86_64"}},
    897 	}
    898 }
    899 
    900 func decodeArchSettings(archConfigs []archConfig) ([]Target, error) {
    901 	var ret []Target
    902 
    903 	for _, config := range archConfigs {
    904 		arch, err := decodeArch(config.arch, &config.archVariant,
    905 			&config.cpuVariant, &config.abi)
    906 		if err != nil {
    907 			return nil, err
    908 		}
    909 		arch.Native = false
    910 		ret = append(ret, Target{
    911 			Os:   Android,
    912 			Arch: arch,
    913 		})
    914 	}
    915 
    916 	return ret, nil
    917 }
    918 
    919 // Convert a set of strings from product variables into a single Arch struct
    920 func decodeArch(arch string, archVariant, cpuVariant *string, abi *[]string) (Arch, error) {
    921 	stringPtr := func(p *string) string {
    922 		if p != nil {
    923 			return *p
    924 		}
    925 		return ""
    926 	}
    927 
    928 	slicePtr := func(p *[]string) []string {
    929 		if p != nil {
    930 			return *p
    931 		}
    932 		return nil
    933 	}
    934 
    935 	archType, ok := archTypeMap[arch]
    936 	if !ok {
    937 		return Arch{}, fmt.Errorf("unknown arch %q", arch)
    938 	}
    939 
    940 	a := Arch{
    941 		ArchType:    archType,
    942 		ArchVariant: stringPtr(archVariant),
    943 		CpuVariant:  stringPtr(cpuVariant),
    944 		Abi:         slicePtr(abi),
    945 		Native:      true,
    946 	}
    947 
    948 	if a.ArchVariant == a.ArchType.Name || a.ArchVariant == "generic" {
    949 		a.ArchVariant = ""
    950 	}
    951 
    952 	if a.CpuVariant == a.ArchType.Name || a.CpuVariant == "generic" {
    953 		a.CpuVariant = ""
    954 	}
    955 
    956 	for i := 0; i < len(a.Abi); i++ {
    957 		if a.Abi[i] == "" {
    958 			a.Abi = append(a.Abi[:i], a.Abi[i+1:]...)
    959 			i--
    960 		}
    961 	}
    962 
    963 	if featureMap, ok := archFeatureMap[archType]; ok {
    964 		a.ArchFeatures = featureMap[a.ArchVariant]
    965 	}
    966 
    967 	return a, nil
    968 }
    969 
    970 func filterMultilibTargets(targets []Target, multilib string) []Target {
    971 	var ret []Target
    972 	for _, t := range targets {
    973 		if t.Arch.ArchType.Multilib == multilib {
    974 			ret = append(ret, t)
    975 		}
    976 	}
    977 	return ret
    978 }
    979 
    980 // Use the module multilib setting to select one or more targets from a target list
    981 func decodeMultilib(multilib string, targets []Target, prefer32 bool) ([]Target, error) {
    982 	buildTargets := []Target{}
    983 	if multilib == "first" {
    984 		if prefer32 {
    985 			multilib = "prefer32"
    986 		} else {
    987 			multilib = "prefer64"
    988 		}
    989 	}
    990 	switch multilib {
    991 	case "common":
    992 		buildTargets = append(buildTargets, commonTarget)
    993 	case "both":
    994 		if prefer32 {
    995 			buildTargets = append(buildTargets, filterMultilibTargets(targets, "lib32")...)
    996 			buildTargets = append(buildTargets, filterMultilibTargets(targets, "lib64")...)
    997 		} else {
    998 			buildTargets = append(buildTargets, filterMultilibTargets(targets, "lib64")...)
    999 			buildTargets = append(buildTargets, filterMultilibTargets(targets, "lib32")...)
   1000 		}
   1001 	case "32":
   1002 		buildTargets = filterMultilibTargets(targets, "lib32")
   1003 	case "64":
   1004 		buildTargets = filterMultilibTargets(targets, "lib64")
   1005 	case "prefer32":
   1006 		buildTargets = filterMultilibTargets(targets, "lib32")
   1007 		if len(buildTargets) == 0 {
   1008 			buildTargets = filterMultilibTargets(targets, "lib64")
   1009 		}
   1010 	case "prefer64":
   1011 		buildTargets = filterMultilibTargets(targets, "lib64")
   1012 		if len(buildTargets) == 0 {
   1013 			buildTargets = filterMultilibTargets(targets, "lib32")
   1014 		}
   1015 	default:
   1016 		return nil, fmt.Errorf(`compile_multilib must be "both", "first", "32", "64", or "prefer32" found %q`,
   1017 			multilib)
   1018 	}
   1019 
   1020 	return buildTargets, nil
   1021 }
   1022