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
15package android
16
17import (
18	"fmt"
19	"reflect"
20	"runtime"
21	"strings"
22
23	"github.com/google/blueprint"
24	"github.com/google/blueprint/proptools"
25)
26
27var (
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
42var 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/*
52Example blueprints file containing all variant property groups, with comment listing what type
53of variants get properties in that group:
54
55module {
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
107var archVariants = map[ArchType][]string{}
108var archFeatures = map[ArchType][]string{}
109var archFeatureMap = map[ArchType]map[string][]string{}
110
111func RegisterArchVariants(arch ArchType, variants ...string) {
112	checkCalledFromInit()
113	archVariants[arch] = append(archVariants[arch], variants...)
114}
115
116func RegisterArchFeatures(arch ArchType, features ...string) {
117	checkCalledFromInit()
118	archFeatures[arch] = append(archFeatures[arch], features...)
119}
120
121func 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.
140type Arch struct {
141	ArchType     ArchType
142	ArchVariant  string
143	CpuVariant   string
144	Abi          []string
145	ArchFeatures []string
146	Native       bool
147}
148
149func (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
160type ArchType struct {
161	Name     string
162	Field    string
163	Multilib string
164}
165
166func 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
176func (a ArchType) String() string {
177	return a.Name
178}
179
180var 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
191var (
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
210type OsType struct {
211	Name, Field string
212	Class       OsClass
213
214	DefaultDisabled bool
215}
216
217type OsClass int
218
219const (
220	Generic OsClass = iota
221	Device
222	Host
223	HostCross
224)
225
226func (os OsType) String() string {
227	return os.Name
228}
229
230func 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
242func 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
252var (
253	commonTarget = Target{
254		Os: Android,
255		Arch: Arch{
256			ArchType: Common,
257		},
258	}
259)
260
261type Target struct {
262	Os   OsType
263	Arch Arch
264}
265
266func (target Target) String() string {
267	return target.Os.String() + "_" + target.Arch.String()
268}
269
270func 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
340func 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
398func 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
476var archPropTypeMap OncePer
477
478func 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
524var variantReplacer = strings.NewReplacer("-", "_", ".", "_")
525
526func (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.
564func (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
734func 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
750func 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
829func 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
838type archConfig struct {
839	arch        string
840	archVariant string
841	cpuVariant  string
842	abi         []string
843}
844
845func 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
889func 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
900func 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
920func 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
970func 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
981func 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