Home | History | Annotate | Download | only in common
      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 common
     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 func init() {
     28 	RegisterBottomUpMutator("defaults_deps", defaultsDepsMutator)
     29 	RegisterTopDownMutator("defaults", defaultsMutator)
     30 
     31 	RegisterBottomUpMutator("host_or_device", HostOrDeviceMutator)
     32 	RegisterBottomUpMutator("host_type", HostTypeMutator)
     33 	RegisterBottomUpMutator("arch", ArchMutator)
     34 }
     35 
     36 var (
     37 	Arm    = newArch("arm", "lib32")
     38 	Arm64  = newArch("arm64", "lib64")
     39 	Mips   = newArch("mips", "lib32")
     40 	Mips64 = newArch("mips64", "lib64")
     41 	X86    = newArch("x86", "lib32")
     42 	X86_64 = newArch("x86_64", "lib64")
     43 
     44 	Common = ArchType{
     45 		Name: "common",
     46 	}
     47 )
     48 
     49 var archTypeMap = map[string]ArchType{
     50 	"arm":    Arm,
     51 	"arm64":  Arm64,
     52 	"mips":   Mips,
     53 	"mips64": Mips64,
     54 	"x86":    X86,
     55 	"x86_64": X86_64,
     56 }
     57 
     58 /*
     59 Example blueprints file containing all variant property groups, with comment listing what type
     60 of variants get properties in that group:
     61 
     62 module {
     63     arch: {
     64         arm: {
     65             // Host or device variants with arm architecture
     66         },
     67         arm64: {
     68             // Host or device variants with arm64 architecture
     69         },
     70         mips: {
     71             // Host or device variants with mips architecture
     72         },
     73         mips64: {
     74             // Host or device variants with mips64 architecture
     75         },
     76         x86: {
     77             // Host or device variants with x86 architecture
     78         },
     79         x86_64: {
     80             // Host or device variants with x86_64 architecture
     81         },
     82     },
     83     multilib: {
     84         lib32: {
     85             // Host or device variants for 32-bit architectures
     86         },
     87         lib64: {
     88             // Host or device variants for 64-bit architectures
     89         },
     90     },
     91     target: {
     92         android: {
     93             // Device variants
     94         },
     95         host: {
     96             // Host variants
     97         },
     98         linux: {
     99             // Linux host variants
    100         },
    101         darwin: {
    102             // Darwin host variants
    103         },
    104         windows: {
    105             // Windows host variants
    106         },
    107         not_windows: {
    108             // Non-windows host variants
    109         },
    110     },
    111 }
    112 */
    113 
    114 type Embed interface{}
    115 
    116 type archProperties struct {
    117 	// Properties to vary by target architecture
    118 	Arch struct {
    119 		// Properties for module variants being built to run on arm (host or device)
    120 		Arm struct {
    121 			Embed `blueprint:"filter(android:\"arch_variant\")"`
    122 
    123 			// Arm arch variants
    124 			Armv5te      interface{} `blueprint:"filter(android:\"arch_variant\")"`
    125 			Armv7_a      interface{} `blueprint:"filter(android:\"arch_variant\")"`
    126 			Armv7_a_neon interface{} `blueprint:"filter(android:\"arch_variant\")"`
    127 
    128 			// Arm cpu variants
    129 			Cortex_a7      interface{} `blueprint:"filter(android:\"arch_variant\")"`
    130 			Cortex_a8      interface{} `blueprint:"filter(android:\"arch_variant\")"`
    131 			Cortex_a9      interface{} `blueprint:"filter(android:\"arch_variant\")"`
    132 			Cortex_a15     interface{} `blueprint:"filter(android:\"arch_variant\")"`
    133 			Cortex_a53     interface{} `blueprint:"filter(android:\"arch_variant\")"`
    134 			Cortex_a53_a57 interface{} `blueprint:"filter(android:\"arch_variant\")"`
    135 			Krait          interface{} `blueprint:"filter(android:\"arch_variant\")"`
    136 			Denver         interface{} `blueprint:"filter(android:\"arch_variant\")"`
    137 		}
    138 
    139 		// Properties for module variants being built to run on arm64 (host or device)
    140 		Arm64 struct {
    141 			Embed `blueprint:"filter(android:\"arch_variant\")"`
    142 
    143 			// Arm64 arch variants
    144 			Armv8_a interface{} `blueprint:"filter(android:\"arch_variant\")"`
    145 
    146 			// Arm64 cpu variants
    147 			Cortex_a53 interface{} `blueprint:"filter(android:\"arch_variant\")"`
    148 			Denver64   interface{} `blueprint:"filter(android:\"arch_variant\")"`
    149 		}
    150 
    151 		// Properties for module variants being built to run on mips (host or device)
    152 		Mips struct {
    153 			Embed `blueprint:"filter(android:\"arch_variant\")"`
    154 
    155 			// Mips arch variants
    156 			Mips32_fp          interface{} `blueprint:"filter(android:\"arch_variant\")"`
    157 			Mips32r2_fp        interface{} `blueprint:"filter(android:\"arch_variant\")"`
    158 			Mips32r2_fp_xburst interface{} `blueprint:"filter(android:\"arch_variant\")"`
    159 			Mips32r2dsp_fp     interface{} `blueprint:"filter(android:\"arch_variant\")"`
    160 			Mips32r2dspr2_fp   interface{} `blueprint:"filter(android:\"arch_variant\")"`
    161 			Mips32r6           interface{} `blueprint:"filter(android:\"arch_variant\")"`
    162 
    163 			// Mips arch features
    164 			Rev6 interface{} `blueprint:"filter(android:\"arch_variant\")"`
    165 		}
    166 
    167 		// Properties for module variants being built to run on mips64 (host or device)
    168 		Mips64 struct {
    169 			Embed `blueprint:"filter(android:\"arch_variant\")"`
    170 
    171 			// Mips64 arch variants
    172 			Mips64r2 interface{} `blueprint:"filter(android:\"arch_variant\")"`
    173 			Mips64r6 interface{} `blueprint:"filter(android:\"arch_variant\")"`
    174 
    175 			// Mips64 arch features
    176 			Rev6 interface{} `blueprint:"filter(android:\"arch_variant\")"`
    177 		}
    178 
    179 		// Properties for module variants being built to run on x86 (host or device)
    180 		X86 struct {
    181 			Embed `blueprint:"filter(android:\"arch_variant\")"`
    182 
    183 			// X86 arch variants
    184 			Atom        interface{} `blueprint:"filter(android:\"arch_variant\")"`
    185 			Haswell     interface{} `blueprint:"filter(android:\"arch_variant\")"`
    186 			Ivybridge   interface{} `blueprint:"filter(android:\"arch_variant\")"`
    187 			Sandybridge interface{} `blueprint:"filter(android:\"arch_variant\")"`
    188 			Silvermont  interface{} `blueprint:"filter(android:\"arch_variant\")"`
    189 
    190 			// X86 arch features
    191 			Ssse3  interface{} `blueprint:"filter(android:\"arch_variant\")"`
    192 			Sse4   interface{} `blueprint:"filter(android:\"arch_variant\")"`
    193 			Sse4_1 interface{} `blueprint:"filter(android:\"arch_variant\")"`
    194 			Sse4_2 interface{} `blueprint:"filter(android:\"arch_variant\")"`
    195 			Aes_ni interface{} `blueprint:"filter(android:\"arch_variant\")"`
    196 			Avx    interface{} `blueprint:"filter(android:\"arch_variant\")"`
    197 			Popcnt interface{} `blueprint:"filter(android:\"arch_variant\")"`
    198 			Movbe  interface{} `blueprint:"filter(android:\"arch_variant\")"`
    199 		}
    200 
    201 		// Properties for module variants being built to run on x86_64 (host or device)
    202 		X86_64 struct {
    203 			Embed `blueprint:"filter(android:\"arch_variant\")"`
    204 
    205 			// X86 arch variants
    206 			Haswell     interface{} `blueprint:"filter(android:\"arch_variant\")"`
    207 			Ivybridge   interface{} `blueprint:"filter(android:\"arch_variant\")"`
    208 			Sandybridge interface{} `blueprint:"filter(android:\"arch_variant\")"`
    209 			Silvermont  interface{} `blueprint:"filter(android:\"arch_variant\")"`
    210 
    211 			// X86 arch features
    212 			Ssse3  interface{} `blueprint:"filter(android:\"arch_variant\")"`
    213 			Sse4   interface{} `blueprint:"filter(android:\"arch_variant\")"`
    214 			Sse4_1 interface{} `blueprint:"filter(android:\"arch_variant\")"`
    215 			Sse4_2 interface{} `blueprint:"filter(android:\"arch_variant\")"`
    216 			Aes_ni interface{} `blueprint:"filter(android:\"arch_variant\")"`
    217 			Avx    interface{} `blueprint:"filter(android:\"arch_variant\")"`
    218 			Popcnt interface{} `blueprint:"filter(android:\"arch_variant\")"`
    219 		}
    220 	}
    221 
    222 	// Properties to vary by 32-bit or 64-bit
    223 	Multilib struct {
    224 		// Properties for module variants being built to run on 32-bit devices
    225 		Lib32 interface{} `blueprint:"filter(android:\"arch_variant\")"`
    226 		// Properties for module variants being built to run on 64-bit devices
    227 		Lib64 interface{} `blueprint:"filter(android:\"arch_variant\")"`
    228 	}
    229 	// Properties to vary by build target (host or device, os, os+archictecture)
    230 	Target struct {
    231 		// Properties for module variants being built to run on the host
    232 		Host interface{} `blueprint:"filter(android:\"arch_variant\")"`
    233 		// Properties for module variants being built to run on the device
    234 		Android interface{} `blueprint:"filter(android:\"arch_variant\")"`
    235 		// Properties for module variants being built to run on arm devices
    236 		Android_arm interface{} `blueprint:"filter(android:\"arch_variant\")"`
    237 		// Properties for module variants being built to run on arm64 devices
    238 		Android_arm64 interface{} `blueprint:"filter(android:\"arch_variant\")"`
    239 		// Properties for module variants being built to run on mips devices
    240 		Android_mips interface{} `blueprint:"filter(android:\"arch_variant\")"`
    241 		// Properties for module variants being built to run on mips64 devices
    242 		Android_mips64 interface{} `blueprint:"filter(android:\"arch_variant\")"`
    243 		// Properties for module variants being built to run on x86 devices
    244 		Android_x86 interface{} `blueprint:"filter(android:\"arch_variant\")"`
    245 		// Properties for module variants being built to run on x86_64 devices
    246 		Android_x86_64 interface{} `blueprint:"filter(android:\"arch_variant\")"`
    247 		// Properties for module variants being built to run on devices that support 64-bit
    248 		Android64 interface{} `blueprint:"filter(android:\"arch_variant\")"`
    249 		// Properties for module variants being built to run on devices that do not support 64-bit
    250 		Android32 interface{} `blueprint:"filter(android:\"arch_variant\")"`
    251 		// Properties for module variants being built to run on linux hosts
    252 		Linux interface{} `blueprint:"filter(android:\"arch_variant\")"`
    253 		// Properties for module variants being built to run on linux x86 hosts
    254 		Linux_x86 interface{} `blueprint:"filter(android:\"arch_variant\")"`
    255 		// Properties for module variants being built to run on linux x86_64 hosts
    256 		Linux_x86_64 interface{} `blueprint:"filter(android:\"arch_variant\")"`
    257 		// Properties for module variants being built to run on darwin hosts
    258 		Darwin interface{} `blueprint:"filter(android:\"arch_variant\")"`
    259 		// Properties for module variants being built to run on darwin x86 hosts
    260 		Darwin_x86 interface{} `blueprint:"filter(android:\"arch_variant\")"`
    261 		// Properties for module variants being built to run on darwin x86_64 hosts
    262 		Darwin_x86_64 interface{} `blueprint:"filter(android:\"arch_variant\")"`
    263 		// Properties for module variants being built to run on windows hosts
    264 		Windows interface{} `blueprint:"filter(android:\"arch_variant\")"`
    265 		// Properties for module variants being built to run on windows x86 hosts
    266 		Windows_x86 interface{} `blueprint:"filter(android:\"arch_variant\")"`
    267 		// Properties for module variants being built to run on windows x86_64 hosts
    268 		Windows_x86_64 interface{} `blueprint:"filter(android:\"arch_variant\")"`
    269 		// Properties for module variants being built to run on linux or darwin hosts
    270 		Not_windows interface{} `blueprint:"filter(android:\"arch_variant\")"`
    271 	}
    272 }
    273 
    274 var archFeatureMap = map[ArchType]map[string][]string{}
    275 
    276 func RegisterArchFeatures(arch ArchType, variant string, features ...string) {
    277 	archField := proptools.FieldNameForProperty(arch.Name)
    278 	variantField := proptools.FieldNameForProperty(variant)
    279 	archStruct := reflect.ValueOf(archProperties{}.Arch).FieldByName(archField)
    280 	if variant != "" {
    281 		if !archStruct.FieldByName(variantField).IsValid() {
    282 			panic(fmt.Errorf("Invalid variant %q for arch %q", variant, arch))
    283 		}
    284 	}
    285 	for _, feature := range features {
    286 		field := proptools.FieldNameForProperty(feature)
    287 		if !archStruct.FieldByName(field).IsValid() {
    288 			panic(fmt.Errorf("Invalid feature %q for arch %q variant %q", feature, arch, variant))
    289 		}
    290 	}
    291 	if archFeatureMap[arch] == nil {
    292 		archFeatureMap[arch] = make(map[string][]string)
    293 	}
    294 	archFeatureMap[arch][variant] = features
    295 }
    296 
    297 // An Arch indicates a single CPU architecture.
    298 type Arch struct {
    299 	ArchType     ArchType
    300 	ArchVariant  string
    301 	CpuVariant   string
    302 	Abi          []string
    303 	ArchFeatures []string
    304 }
    305 
    306 func (a Arch) String() string {
    307 	s := a.ArchType.String()
    308 	if a.ArchVariant != "" {
    309 		s += "_" + a.ArchVariant
    310 	}
    311 	if a.CpuVariant != "" {
    312 		s += "_" + a.CpuVariant
    313 	}
    314 	return s
    315 }
    316 
    317 type ArchType struct {
    318 	Name     string
    319 	Multilib string
    320 }
    321 
    322 func newArch(name, multilib string) ArchType {
    323 	return ArchType{
    324 		Name:     name,
    325 		Multilib: multilib,
    326 	}
    327 }
    328 
    329 func (a ArchType) String() string {
    330 	return a.Name
    331 }
    332 
    333 type HostOrDeviceSupported int
    334 
    335 const (
    336 	_ HostOrDeviceSupported = iota
    337 	HostSupported
    338 	DeviceSupported
    339 	HostAndDeviceSupported
    340 	HostAndDeviceDefault
    341 )
    342 
    343 type HostOrDevice int
    344 
    345 const (
    346 	_ HostOrDevice = iota
    347 	Host
    348 	Device
    349 )
    350 
    351 func (hod HostOrDevice) String() string {
    352 	switch hod {
    353 	case Device:
    354 		return "device"
    355 	case Host:
    356 		return "host"
    357 	default:
    358 		panic(fmt.Sprintf("unexpected HostOrDevice value %d", hod))
    359 	}
    360 }
    361 
    362 func (hod HostOrDevice) Property() string {
    363 	switch hod {
    364 	case Device:
    365 		return "android"
    366 	case Host:
    367 		return "host"
    368 	default:
    369 		panic(fmt.Sprintf("unexpected HostOrDevice value %d", hod))
    370 	}
    371 }
    372 
    373 func (hod HostOrDevice) Host() bool {
    374 	if hod == 0 {
    375 		panic("HostOrDevice unset")
    376 	}
    377 	return hod == Host
    378 }
    379 
    380 func (hod HostOrDevice) Device() bool {
    381 	if hod == 0 {
    382 		panic("HostOrDevice unset")
    383 	}
    384 	return hod == Device
    385 }
    386 
    387 var hostOrDeviceName = map[HostOrDevice]string{
    388 	Device: "device",
    389 	Host:   "host",
    390 }
    391 
    392 type HostType int
    393 
    394 const (
    395 	NoHostType HostType = iota
    396 	Linux
    397 	Darwin
    398 	Windows
    399 )
    400 
    401 func CurrentHostType() HostType {
    402 	switch runtime.GOOS {
    403 	case "linux":
    404 		return Linux
    405 	case "darwin":
    406 		return Darwin
    407 	default:
    408 		panic(fmt.Sprintf("unsupported OS: %s", runtime.GOOS))
    409 	}
    410 }
    411 
    412 func (ht HostType) String() string {
    413 	switch ht {
    414 	case Linux:
    415 		return "linux"
    416 	case Darwin:
    417 		return "darwin"
    418 	case Windows:
    419 		return "windows"
    420 	default:
    421 		panic(fmt.Sprintf("unexpected HostType value %d", ht))
    422 	}
    423 }
    424 
    425 func (ht HostType) Field() string {
    426 	switch ht {
    427 	case Linux:
    428 		return "Linux"
    429 	case Darwin:
    430 		return "Darwin"
    431 	case Windows:
    432 		return "Windows"
    433 	default:
    434 		panic(fmt.Sprintf("unexpected HostType value %d", ht))
    435 	}
    436 }
    437 
    438 var (
    439 	commonArch = Arch{
    440 		ArchType: Common,
    441 	}
    442 )
    443 
    444 func HostOrDeviceMutator(mctx AndroidBottomUpMutatorContext) {
    445 	var module AndroidModule
    446 	var ok bool
    447 	if module, ok = mctx.Module().(AndroidModule); !ok {
    448 		return
    449 	}
    450 
    451 	hods := []HostOrDevice{}
    452 
    453 	if module.base().HostSupported() {
    454 		hods = append(hods, Host)
    455 	}
    456 
    457 	if module.base().DeviceSupported() {
    458 		hods = append(hods, Device)
    459 	}
    460 
    461 	if len(hods) == 0 {
    462 		return
    463 	}
    464 
    465 	hodNames := []string{}
    466 	for _, hod := range hods {
    467 		hodNames = append(hodNames, hod.String())
    468 	}
    469 
    470 	modules := mctx.CreateVariations(hodNames...)
    471 	for i, m := range modules {
    472 		m.(AndroidModule).base().SetHostOrDevice(hods[i])
    473 	}
    474 }
    475 
    476 func HostTypeMutator(mctx AndroidBottomUpMutatorContext) {
    477 	var module AndroidModule
    478 	var ok bool
    479 	if module, ok = mctx.Module().(AndroidModule); !ok {
    480 		return
    481 	}
    482 
    483 	if !module.base().HostSupported() || !module.base().HostOrDevice().Host() {
    484 		return
    485 	}
    486 
    487 	buildTypes, err := decodeHostTypesProductVariables(mctx.Config().(Config).ProductVariables)
    488 	if err != nil {
    489 		mctx.ModuleErrorf("%s", err.Error())
    490 		return
    491 	}
    492 
    493 	typeNames := []string{}
    494 	for _, ht := range buildTypes {
    495 		typeNames = append(typeNames, ht.String())
    496 	}
    497 
    498 	modules := mctx.CreateVariations(typeNames...)
    499 	for i, m := range modules {
    500 		m.(AndroidModule).base().SetHostType(buildTypes[i])
    501 	}
    502 }
    503 
    504 func ArchMutator(mctx AndroidBottomUpMutatorContext) {
    505 	var module AndroidModule
    506 	var ok bool
    507 	if module, ok = mctx.Module().(AndroidModule); !ok {
    508 		return
    509 	}
    510 
    511 	moduleArches := []Arch{}
    512 	multilib := module.base().commonProperties.Compile_multilib
    513 
    514 	if module.base().HostSupported() && module.base().HostOrDevice().Host() {
    515 		hostModuleArches, err := decodeMultilib(multilib, mctx.Config().(Config).HostArches[module.base().HostType()])
    516 		if err != nil {
    517 			mctx.ModuleErrorf("%s", err.Error())
    518 		}
    519 
    520 		moduleArches = append(moduleArches, hostModuleArches...)
    521 	}
    522 
    523 	if module.base().DeviceSupported() && module.base().HostOrDevice().Device() {
    524 		deviceModuleArches, err := decodeMultilib(multilib, mctx.Config().(Config).DeviceArches)
    525 		if err != nil {
    526 			mctx.ModuleErrorf("%s", err.Error())
    527 		}
    528 
    529 		moduleArches = append(moduleArches, deviceModuleArches...)
    530 	}
    531 
    532 	if len(moduleArches) == 0 {
    533 		return
    534 	}
    535 
    536 	archNames := []string{}
    537 	for _, arch := range moduleArches {
    538 		archNames = append(archNames, arch.String())
    539 	}
    540 
    541 	modules := mctx.CreateVariations(archNames...)
    542 
    543 	for i, m := range modules {
    544 		m.(AndroidModule).base().SetArch(moduleArches[i])
    545 		m.(AndroidModule).base().setArchProperties(mctx)
    546 	}
    547 }
    548 
    549 func InitArchModule(m AndroidModule,
    550 	propertyStructs ...interface{}) (blueprint.Module, []interface{}) {
    551 
    552 	base := m.base()
    553 
    554 	base.generalProperties = append(base.generalProperties,
    555 		propertyStructs...)
    556 
    557 	for _, properties := range base.generalProperties {
    558 		propertiesValue := reflect.ValueOf(properties)
    559 		if propertiesValue.Kind() != reflect.Ptr {
    560 			panic(fmt.Errorf("properties must be a pointer to a struct, got %T",
    561 				propertiesValue.Interface()))
    562 		}
    563 
    564 		propertiesValue = propertiesValue.Elem()
    565 		if propertiesValue.Kind() != reflect.Struct {
    566 			panic(fmt.Errorf("properties must be a pointer to a struct, got %T",
    567 				propertiesValue.Interface()))
    568 		}
    569 
    570 		archProperties := &archProperties{}
    571 		forEachInterface(reflect.ValueOf(archProperties), func(v reflect.Value) {
    572 			newValue := proptools.CloneEmptyProperties(propertiesValue)
    573 			v.Set(newValue)
    574 		})
    575 
    576 		base.archProperties = append(base.archProperties, archProperties)
    577 	}
    578 
    579 	var allProperties []interface{}
    580 	allProperties = append(allProperties, base.generalProperties...)
    581 	for _, asp := range base.archProperties {
    582 		allProperties = append(allProperties, asp)
    583 	}
    584 
    585 	return m, allProperties
    586 }
    587 
    588 var variantReplacer = strings.NewReplacer("-", "_", ".", "_")
    589 
    590 func (a *AndroidModuleBase) appendProperties(ctx AndroidBottomUpMutatorContext,
    591 	dst, src interface{}, field, srcPrefix string) interface{} {
    592 
    593 	srcField := reflect.ValueOf(src).FieldByName(field)
    594 	if !srcField.IsValid() {
    595 		ctx.ModuleErrorf("field %q does not exist", srcPrefix)
    596 		return nil
    597 	}
    598 
    599 	ret := srcField
    600 
    601 	if srcField.Kind() == reflect.Struct {
    602 		srcField = srcField.FieldByName("Embed")
    603 	}
    604 
    605 	src = srcField.Elem().Interface()
    606 
    607 	filter := func(property string,
    608 		dstField, srcField reflect.StructField,
    609 		dstValue, srcValue interface{}) (bool, error) {
    610 
    611 		srcProperty := srcPrefix + "." + property
    612 
    613 		if !proptools.HasTag(dstField, "android", "arch_variant") {
    614 			if ctx.ContainsProperty(srcProperty) {
    615 				return false, fmt.Errorf("can't be specific to a build variant")
    616 			} else {
    617 				return false, nil
    618 			}
    619 		}
    620 
    621 		return true, nil
    622 	}
    623 
    624 	err := proptools.AppendProperties(dst, src, filter)
    625 	if err != nil {
    626 		if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
    627 			ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
    628 		} else {
    629 			panic(err)
    630 		}
    631 	}
    632 
    633 	return ret.Interface()
    634 }
    635 
    636 // Rewrite the module's properties structs to contain arch-specific values.
    637 func (a *AndroidModuleBase) setArchProperties(ctx AndroidBottomUpMutatorContext) {
    638 	arch := a.commonProperties.CompileArch
    639 	hod := a.commonProperties.CompileHostOrDevice
    640 	ht := a.commonProperties.CompileHostType
    641 
    642 	if arch.ArchType == Common {
    643 		return
    644 	}
    645 
    646 	for i := range a.generalProperties {
    647 		genProps := a.generalProperties[i]
    648 		archProps := a.archProperties[i]
    649 		// Handle arch-specific properties in the form:
    650 		// arch: {
    651 		//     arm64: {
    652 		//         key: value,
    653 		//     },
    654 		// },
    655 		t := arch.ArchType
    656 
    657 		field := proptools.FieldNameForProperty(t.Name)
    658 		prefix := "arch." + t.Name
    659 		archStruct := a.appendProperties(ctx, genProps, archProps.Arch, field, prefix)
    660 
    661 		// Handle arch-variant-specific properties in the form:
    662 		// arch: {
    663 		//     variant: {
    664 		//         key: value,
    665 		//     },
    666 		// },
    667 		v := variantReplacer.Replace(arch.ArchVariant)
    668 		if v != "" {
    669 			field := proptools.FieldNameForProperty(v)
    670 			prefix := "arch." + t.Name + "." + v
    671 			a.appendProperties(ctx, genProps, archStruct, field, prefix)
    672 		}
    673 
    674 		// Handle cpu-variant-specific properties in the form:
    675 		// arch: {
    676 		//     variant: {
    677 		//         key: value,
    678 		//     },
    679 		// },
    680 		c := variantReplacer.Replace(arch.CpuVariant)
    681 		if c != "" {
    682 			field := proptools.FieldNameForProperty(c)
    683 			prefix := "arch." + t.Name + "." + c
    684 			a.appendProperties(ctx, genProps, archStruct, field, prefix)
    685 		}
    686 
    687 		// Handle arch-feature-specific properties in the form:
    688 		// arch: {
    689 		//     feature: {
    690 		//         key: value,
    691 		//     },
    692 		// },
    693 		for _, feature := range arch.ArchFeatures {
    694 			field := proptools.FieldNameForProperty(feature)
    695 			prefix := "arch." + t.Name + "." + feature
    696 			a.appendProperties(ctx, genProps, archStruct, field, prefix)
    697 		}
    698 
    699 		// Handle multilib-specific properties in the form:
    700 		// multilib: {
    701 		//     lib32: {
    702 		//         key: value,
    703 		//     },
    704 		// },
    705 		field = proptools.FieldNameForProperty(t.Multilib)
    706 		prefix = "multilib." + t.Multilib
    707 		a.appendProperties(ctx, genProps, archProps.Multilib, field, prefix)
    708 
    709 		// Handle host-or-device-specific properties in the form:
    710 		// target: {
    711 		//     host: {
    712 		//         key: value,
    713 		//     },
    714 		// },
    715 		hodProperty := hod.Property()
    716 		field = proptools.FieldNameForProperty(hodProperty)
    717 		prefix = "target." + hodProperty
    718 		a.appendProperties(ctx, genProps, archProps.Target, field, prefix)
    719 
    720 		// Handle host target properties in the form:
    721 		// target: {
    722 		//     linux: {
    723 		//         key: value,
    724 		//     },
    725 		//     not_windows: {
    726 		//         key: value,
    727 		//     },
    728 		//     linux_x86: {
    729 		//         key: value,
    730 		//     },
    731 		//     linux_arm: {
    732 		//         key: value,
    733 		//     },
    734 		// },
    735 		if hod.Host() {
    736 			field := ht.Field()
    737 			prefix := "target." + ht.String()
    738 			a.appendProperties(ctx, genProps, archProps.Target, field, prefix)
    739 
    740 			t := arch.ArchType
    741 			field = ht.Field() + "_" + t.Name
    742 			prefix = "target." + ht.String() + "_" + t.Name
    743 			a.appendProperties(ctx, genProps, archProps.Target, field, prefix)
    744 
    745 			if ht != Windows {
    746 				field := "Not_windows"
    747 				prefix := "target.not_windows"
    748 				a.appendProperties(ctx, genProps, archProps.Target, field, prefix)
    749 			}
    750 		}
    751 
    752 		// Handle 64-bit device properties in the form:
    753 		// target {
    754 		//     android64 {
    755 		//         key: value,
    756 		//     },
    757 		//     android32 {
    758 		//         key: value,
    759 		//     },
    760 		// },
    761 		// WARNING: this is probably not what you want to use in your blueprints file, it selects
    762 		// options for all targets on a device that supports 64-bit binaries, not just the targets
    763 		// that are being compiled for 64-bit.  Its expected use case is binaries like linker and
    764 		// debuggerd that need to know when they are a 32-bit process running on a 64-bit device
    765 		if hod.Device() {
    766 			if true /* && target_is_64_bit */ {
    767 				field := "Android64"
    768 				prefix := "target.android64"
    769 				a.appendProperties(ctx, genProps, archProps.Target, field, prefix)
    770 			} else {
    771 				field := "Android32"
    772 				prefix := "target.android32"
    773 				a.appendProperties(ctx, genProps, archProps.Target, field, prefix)
    774 			}
    775 		}
    776 
    777 		// Handle device architecture properties in the form:
    778 		// target {
    779 		//     android_arm {
    780 		//         key: value,
    781 		//     },
    782 		//     android_x86 {
    783 		//         key: value,
    784 		//     },
    785 		// },
    786 		if hod.Device() {
    787 			t := arch.ArchType
    788 			field := "Android_" + t.Name
    789 			prefix := "target.android_" + t.Name
    790 			a.appendProperties(ctx, genProps, archProps.Target, field, prefix)
    791 		}
    792 
    793 		if ctx.Failed() {
    794 			return
    795 		}
    796 	}
    797 }
    798 
    799 func forEachInterface(v reflect.Value, f func(reflect.Value)) {
    800 	switch v.Kind() {
    801 	case reflect.Interface:
    802 		f(v)
    803 	case reflect.Struct:
    804 		for i := 0; i < v.NumField(); i++ {
    805 			forEachInterface(v.Field(i), f)
    806 		}
    807 	case reflect.Ptr:
    808 		forEachInterface(v.Elem(), f)
    809 	default:
    810 		panic(fmt.Errorf("Unsupported kind %s", v.Kind()))
    811 	}
    812 }
    813 
    814 // Get a list of HostTypes from the product variables
    815 func decodeHostTypesProductVariables(variables productVariables) ([]HostType, error) {
    816 	ret := []HostType{CurrentHostType()}
    817 
    818 	if variables.CrossHost != nil && *variables.CrossHost != "" {
    819 		switch *variables.CrossHost {
    820 		case "windows":
    821 			ret = append(ret, Windows)
    822 		default:
    823 			return nil, fmt.Errorf("Unsupported secondary host: %s", *variables.CrossHost)
    824 		}
    825 	}
    826 
    827 	return ret, nil
    828 }
    829 
    830 // Convert the arch product variables into a list of host and device Arch structs
    831 func decodeArchProductVariables(variables productVariables) (map[HostType][]Arch, []Arch, error) {
    832 	if variables.HostArch == nil {
    833 		return nil, nil, fmt.Errorf("No host primary architecture set")
    834 	}
    835 
    836 	hostArch, err := decodeArch(*variables.HostArch, nil, nil, nil)
    837 	if err != nil {
    838 		return nil, nil, err
    839 	}
    840 
    841 	hostArches := []Arch{hostArch}
    842 
    843 	if variables.HostSecondaryArch != nil && *variables.HostSecondaryArch != "" {
    844 		hostSecondaryArch, err := decodeArch(*variables.HostSecondaryArch, nil, nil, nil)
    845 		if err != nil {
    846 			return nil, nil, err
    847 		}
    848 		hostArches = append(hostArches, hostSecondaryArch)
    849 	}
    850 
    851 	hostTypeArches := map[HostType][]Arch{
    852 		CurrentHostType(): hostArches,
    853 	}
    854 
    855 	if variables.CrossHost != nil && *variables.CrossHost != "" {
    856 		if variables.CrossHostArch == nil || *variables.CrossHostArch == "" {
    857 			return nil, nil, fmt.Errorf("No cross-host primary architecture set")
    858 		}
    859 
    860 		crossHostArch, err := decodeArch(*variables.CrossHostArch, nil, nil, nil)
    861 		if err != nil {
    862 			return nil, nil, err
    863 		}
    864 
    865 		crossHostArches := []Arch{crossHostArch}
    866 
    867 		if variables.CrossHostSecondaryArch != nil && *variables.CrossHostSecondaryArch != "" {
    868 			crossHostSecondaryArch, err := decodeArch(*variables.CrossHostSecondaryArch, nil, nil, nil)
    869 			if err != nil {
    870 				return nil, nil, err
    871 			}
    872 			crossHostArches = append(crossHostArches, crossHostSecondaryArch)
    873 		}
    874 
    875 		switch *variables.CrossHost {
    876 		case "windows":
    877 			hostTypeArches[Windows] = crossHostArches
    878 		default:
    879 			return nil, nil, fmt.Errorf("Unsupported cross-host: %s", *variables.CrossHost)
    880 		}
    881 	}
    882 
    883 	if variables.DeviceArch == nil {
    884 		return nil, nil, fmt.Errorf("No device primary architecture set")
    885 	}
    886 
    887 	deviceArch, err := decodeArch(*variables.DeviceArch, variables.DeviceArchVariant,
    888 		variables.DeviceCpuVariant, variables.DeviceAbi)
    889 	if err != nil {
    890 		return nil, nil, err
    891 	}
    892 
    893 	deviceArches := []Arch{deviceArch}
    894 
    895 	if variables.DeviceSecondaryArch != nil && *variables.DeviceSecondaryArch != "" {
    896 		deviceSecondaryArch, err := decodeArch(*variables.DeviceSecondaryArch,
    897 			variables.DeviceSecondaryArchVariant, variables.DeviceSecondaryCpuVariant,
    898 			variables.DeviceSecondaryAbi)
    899 		if err != nil {
    900 			return nil, nil, err
    901 		}
    902 		deviceArches = append(deviceArches, deviceSecondaryArch)
    903 	}
    904 
    905 	return hostTypeArches, deviceArches, nil
    906 }
    907 
    908 func decodeMegaDevice() ([]Arch, error) {
    909 	archSettings := []struct {
    910 		arch        string
    911 		archVariant string
    912 		cpuVariant  string
    913 		abi         []string
    914 	}{
    915 		{"arm", "armv7-a-neon", "cortex-a7", []string{"armeabi-v7a"}},
    916 		{"arm", "armv7-a-neon", "cortex-a8", []string{"armeabi-v7a"}},
    917 		// gtest_all_test.cc fails to build:
    918 		//   error in backend: Unsupported library call operation!
    919 		//{"arm", "armv7-a-neon", "cortex-a9", []string{"armeabi-v7a"}},
    920 		{"arm", "armv7-a-neon", "cortex-a15", []string{"armeabi-v7a"}},
    921 		{"arm", "armv7-a-neon", "cortex-a53", []string{"armeabi-v7a"}},
    922 		{"arm", "armv7-a-neon", "cortex-a53.a57", []string{"armeabi-v7a"}},
    923 		{"arm", "armv7-a-neon", "denver", []string{"armeabi-v7a"}},
    924 		{"arm", "armv7-a-neon", "krait", []string{"armeabi-v7a"}},
    925 		{"arm64", "", "cortex-a53", []string{"arm64-v8a"}},
    926 		{"arm64", "", "denver64", []string{"arm64-v8a"}},
    927 		{"mips", "mips32-fp", "", []string{"mips"}},
    928 		{"mips", "mips32r2-fp", "", []string{"mips"}},
    929 		{"mips", "mips32r2-fp-xburst", "", []string{"mips"}},
    930 		{"mips", "mips32r6", "", []string{"mips32r6"}},
    931 		// mips32r2dsp[r2]-fp fails in the assembler for divdf3.c in compiler-rt:
    932 		// (same errors in make and soong)
    933 		//   Error: invalid operands `mtlo $ac0,$11'
    934 		//   Error: invalid operands `mthi $ac0,$12'
    935 		//{"mips", "mips32r2dsp-fp", "", []string{"mips"}},
    936 		//{"mips", "mips32r2dspr2-fp", "", []string{"mips"}},
    937 		// mips64r2 is mismatching 64r2 and 64r6 libraries during linking to libgcc
    938 		//{"mips64", "mips64r2", "", []string{"mips64"}},
    939 		{"mips64", "mips64r6", "", []string{"mips64"}},
    940 		{"x86", "", "", []string{"x86"}},
    941 		{"x86", "atom", "", []string{"x86"}},
    942 		{"x86", "haswell", "", []string{"x86"}},
    943 		{"x86", "ivybridge", "", []string{"x86"}},
    944 		{"x86", "sandybridge", "", []string{"x86"}},
    945 		{"x86", "silvermont", "", []string{"x86"}},
    946 		{"x86_64", "", "", []string{"x86_64"}},
    947 		{"x86_64", "haswell", "", []string{"x86_64"}},
    948 		{"x86_64", "ivybridge", "", []string{"x86_64"}},
    949 		{"x86_64", "sandybridge", "", []string{"x86_64"}},
    950 		{"x86_64", "silvermont", "", []string{"x86_64"}},
    951 	}
    952 
    953 	var ret []Arch
    954 
    955 	for _, config := range archSettings {
    956 		arch, err := decodeArch(config.arch, &config.archVariant,
    957 			&config.cpuVariant, &config.abi)
    958 		if err != nil {
    959 			return nil, err
    960 		}
    961 		ret = append(ret, arch)
    962 	}
    963 
    964 	return ret, nil
    965 }
    966 
    967 // Convert a set of strings from product variables into a single Arch struct
    968 func decodeArch(arch string, archVariant, cpuVariant *string, abi *[]string) (Arch, error) {
    969 	stringPtr := func(p *string) string {
    970 		if p != nil {
    971 			return *p
    972 		}
    973 		return ""
    974 	}
    975 
    976 	slicePtr := func(p *[]string) []string {
    977 		if p != nil {
    978 			return *p
    979 		}
    980 		return nil
    981 	}
    982 
    983 	archType, ok := archTypeMap[arch]
    984 	if !ok {
    985 		return Arch{}, fmt.Errorf("unknown arch %q", arch)
    986 	}
    987 
    988 	a := Arch{
    989 		ArchType:    archType,
    990 		ArchVariant: stringPtr(archVariant),
    991 		CpuVariant:  stringPtr(cpuVariant),
    992 		Abi:         slicePtr(abi),
    993 	}
    994 
    995 	if a.ArchVariant == a.ArchType.Name || a.ArchVariant == "generic" {
    996 		a.ArchVariant = ""
    997 	}
    998 
    999 	if a.CpuVariant == a.ArchType.Name || a.CpuVariant == "generic" {
   1000 		a.CpuVariant = ""
   1001 	}
   1002 
   1003 	for i := 0; i < len(a.Abi); i++ {
   1004 		if a.Abi[i] == "" {
   1005 			a.Abi = append(a.Abi[:i], a.Abi[i+1:]...)
   1006 			i--
   1007 		}
   1008 	}
   1009 
   1010 	if featureMap, ok := archFeatureMap[archType]; ok {
   1011 		a.ArchFeatures = featureMap[stringPtr(archVariant)]
   1012 	}
   1013 
   1014 	return a, nil
   1015 }
   1016 
   1017 // Use the module multilib setting to select one or more arches from an arch list
   1018 func decodeMultilib(multilib string, arches []Arch) ([]Arch, error) {
   1019 	buildArches := []Arch{}
   1020 	switch multilib {
   1021 	case "common":
   1022 		buildArches = append(buildArches, commonArch)
   1023 	case "both":
   1024 		buildArches = append(buildArches, arches...)
   1025 	case "first":
   1026 		buildArches = append(buildArches, arches[0])
   1027 	case "32":
   1028 		for _, a := range arches {
   1029 			if a.ArchType.Multilib == "lib32" {
   1030 				buildArches = append(buildArches, a)
   1031 			}
   1032 		}
   1033 	case "64":
   1034 		for _, a := range arches {
   1035 			if a.ArchType.Multilib == "lib64" {
   1036 				buildArches = append(buildArches, a)
   1037 			}
   1038 		}
   1039 	default:
   1040 		return nil, fmt.Errorf(`compile_multilib must be "both", "first", "32", or "64", found %q`,
   1041 			multilib)
   1042 		//buildArches = append(buildArches, arches[0])
   1043 	}
   1044 
   1045 	return buildArches, nil
   1046 }
   1047