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