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