• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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	"encoding"
19	"fmt"
20	"reflect"
21	"runtime"
22	"strconv"
23	"strings"
24
25	"github.com/google/blueprint/proptools"
26)
27
28var (
29	archTypeList []ArchType
30
31	Arm    = newArch("arm", "lib32")
32	Arm64  = newArch("arm64", "lib64")
33	Mips   = newArch("mips", "lib32")
34	Mips64 = newArch("mips64", "lib64")
35	X86    = newArch("x86", "lib32")
36	X86_64 = newArch("x86_64", "lib64")
37
38	Common = ArchType{
39		Name: "common",
40	}
41)
42
43var archTypeMap = map[string]ArchType{
44	"arm":    Arm,
45	"arm64":  Arm64,
46	"mips":   Mips,
47	"mips64": Mips64,
48	"x86":    X86,
49	"x86_64": X86_64,
50}
51
52/*
53Example blueprints file containing all variant property groups, with comment listing what type
54of variants get properties in that group:
55
56module {
57    arch: {
58        arm: {
59            // Host or device variants with arm architecture
60        },
61        arm64: {
62            // Host or device variants with arm64 architecture
63        },
64        mips: {
65            // Host or device variants with mips architecture
66        },
67        mips64: {
68            // Host or device variants with mips64 architecture
69        },
70        x86: {
71            // Host or device variants with x86 architecture
72        },
73        x86_64: {
74            // Host or device variants with x86_64 architecture
75        },
76    },
77    multilib: {
78        lib32: {
79            // Host or device variants for 32-bit architectures
80        },
81        lib64: {
82            // Host or device variants for 64-bit architectures
83        },
84    },
85    target: {
86        android: {
87            // Device variants
88        },
89        host: {
90            // Host variants
91        },
92        linux_glibc: {
93            // Linux host variants
94        },
95        darwin: {
96            // Darwin host variants
97        },
98        windows: {
99            // Windows host variants
100        },
101        not_windows: {
102            // Non-windows host variants
103        },
104    },
105}
106*/
107
108var archVariants = map[ArchType][]string{
109	Arm: {
110		"armv7-a",
111		"armv7-a-neon",
112		"armv8-a",
113		"armv8-2a",
114		"cortex-a7",
115		"cortex-a8",
116		"cortex-a9",
117		"cortex-a15",
118		"cortex-a53",
119		"cortex-a53-a57",
120		"cortex-a55",
121		"cortex-a72",
122		"cortex-a73",
123		"cortex-a75",
124		"cortex-a76",
125		"krait",
126		"kryo",
127		"kryo385",
128		"exynos-m1",
129		"exynos-m2",
130	},
131	Arm64: {
132		"armv8_a",
133		"armv8_2a",
134		"cortex-a53",
135		"cortex-a55",
136		"cortex-a72",
137		"cortex-a73",
138		"cortex-a75",
139		"cortex-a76",
140		"kryo",
141		"kryo385",
142		"exynos-m1",
143		"exynos-m2",
144	},
145	Mips: {
146		"mips32_fp",
147		"mips32r2_fp",
148		"mips32r2_fp_xburst",
149		"mips32r2dsp_fp",
150		"mips32r2dspr2_fp",
151		"mips32r6",
152	},
153	Mips64: {
154		"mips64r2",
155		"mips64r6",
156	},
157	X86: {
158		"amberlake",
159		"atom",
160		"broadwell",
161		"haswell",
162		"icelake",
163		"ivybridge",
164		"kabylake",
165		"sandybridge",
166		"silvermont",
167		"skylake",
168		"stoneyridge",
169		"tigerlake",
170		"whiskeylake",
171		"x86_64",
172	},
173	X86_64: {
174		"amberlake",
175		"broadwell",
176		"haswell",
177		"icelake",
178		"ivybridge",
179		"kabylake",
180		"sandybridge",
181		"silvermont",
182		"skylake",
183		"stoneyridge",
184		"tigerlake",
185		"whiskeylake",
186	},
187}
188
189var archFeatures = map[ArchType][]string{
190	Arm: {
191		"neon",
192	},
193	Mips: {
194		"dspr2",
195		"rev6",
196		"msa",
197	},
198	Mips64: {
199		"rev6",
200		"msa",
201	},
202	X86: {
203		"ssse3",
204		"sse4",
205		"sse4_1",
206		"sse4_2",
207		"aes_ni",
208		"avx",
209		"avx2",
210		"avx512",
211		"popcnt",
212		"movbe",
213	},
214	X86_64: {
215		"ssse3",
216		"sse4",
217		"sse4_1",
218		"sse4_2",
219		"aes_ni",
220		"avx",
221		"avx2",
222		"avx512",
223		"popcnt",
224	},
225}
226
227var archFeatureMap = map[ArchType]map[string][]string{
228	Arm: {
229		"armv7-a-neon": {
230			"neon",
231		},
232		"armv8-a": {
233			"neon",
234		},
235		"armv8-2a": {
236			"neon",
237		},
238	},
239	Mips: {
240		"mips32r2dspr2_fp": {
241			"dspr2",
242		},
243		"mips32r6": {
244			"rev6",
245		},
246	},
247	Mips64: {
248		"mips64r6": {
249			"rev6",
250		},
251	},
252	X86: {
253		"amberlake": {
254			"ssse3",
255			"sse4",
256			"sse4_1",
257			"sse4_2",
258			"avx",
259			"avx2",
260			"aes_ni",
261			"popcnt",
262		},
263		"atom": {
264			"ssse3",
265			"movbe",
266		},
267		"broadwell": {
268			"ssse3",
269			"sse4",
270			"sse4_1",
271			"sse4_2",
272			"avx",
273			"avx2",
274			"aes_ni",
275			"popcnt",
276		},
277		"haswell": {
278			"ssse3",
279			"sse4",
280			"sse4_1",
281			"sse4_2",
282			"aes_ni",
283			"avx",
284			"popcnt",
285			"movbe",
286		},
287		"icelake": {
288			"ssse3",
289			"sse4",
290			"sse4_1",
291			"sse4_2",
292			"avx",
293			"avx2",
294			"avx512",
295			"aes_ni",
296			"popcnt",
297		},
298		"ivybridge": {
299			"ssse3",
300			"sse4",
301			"sse4_1",
302			"sse4_2",
303			"aes_ni",
304			"avx",
305			"popcnt",
306		},
307		"kabylake": {
308			"ssse3",
309			"sse4",
310			"sse4_1",
311			"sse4_2",
312			"avx",
313			"avx2",
314			"aes_ni",
315			"popcnt",
316		},
317		"sandybridge": {
318			"ssse3",
319			"sse4",
320			"sse4_1",
321			"sse4_2",
322			"popcnt",
323		},
324		"silvermont": {
325			"ssse3",
326			"sse4",
327			"sse4_1",
328			"sse4_2",
329			"aes_ni",
330			"popcnt",
331			"movbe",
332		},
333		"skylake": {
334			"ssse3",
335			"sse4",
336			"sse4_1",
337			"sse4_2",
338			"avx",
339			"avx2",
340			"avx512",
341			"aes_ni",
342			"popcnt",
343		},
344		"stoneyridge": {
345			"ssse3",
346			"sse4",
347			"sse4_1",
348			"sse4_2",
349			"aes_ni",
350			"avx",
351			"avx2",
352			"popcnt",
353			"movbe",
354		},
355		"tigerlake": {
356			"ssse3",
357			"sse4",
358			"sse4_1",
359			"sse4_2",
360			"avx",
361			"avx2",
362			"avx512",
363			"aes_ni",
364			"popcnt",
365		},
366		"whiskeylake": {
367			"ssse3",
368			"sse4",
369			"sse4_1",
370			"sse4_2",
371			"avx",
372			"avx2",
373			"avx512",
374			"aes_ni",
375			"popcnt",
376		},
377		"x86_64": {
378			"ssse3",
379			"sse4",
380			"sse4_1",
381			"sse4_2",
382			"popcnt",
383		},
384	},
385	X86_64: {
386		"amberlake": {
387			"ssse3",
388			"sse4",
389			"sse4_1",
390			"sse4_2",
391			"avx",
392			"avx2",
393			"aes_ni",
394			"popcnt",
395		},
396		"broadwell": {
397			"ssse3",
398			"sse4",
399			"sse4_1",
400			"sse4_2",
401			"avx",
402			"avx2",
403			"aes_ni",
404			"popcnt",
405		},
406		"haswell": {
407			"ssse3",
408			"sse4",
409			"sse4_1",
410			"sse4_2",
411			"aes_ni",
412			"avx",
413			"popcnt",
414		},
415		"icelake": {
416			"ssse3",
417			"sse4",
418			"sse4_1",
419			"sse4_2",
420			"avx",
421			"avx2",
422			"avx512",
423			"aes_ni",
424			"popcnt",
425		},
426		"ivybridge": {
427			"ssse3",
428			"sse4",
429			"sse4_1",
430			"sse4_2",
431			"aes_ni",
432			"avx",
433			"popcnt",
434		},
435		"kabylake": {
436			"ssse3",
437			"sse4",
438			"sse4_1",
439			"sse4_2",
440			"avx",
441			"avx2",
442			"aes_ni",
443			"popcnt",
444		},
445		"sandybridge": {
446			"ssse3",
447			"sse4",
448			"sse4_1",
449			"sse4_2",
450			"popcnt",
451		},
452		"silvermont": {
453			"ssse3",
454			"sse4",
455			"sse4_1",
456			"sse4_2",
457			"aes_ni",
458			"popcnt",
459		},
460		"skylake": {
461			"ssse3",
462			"sse4",
463			"sse4_1",
464			"sse4_2",
465			"avx",
466			"avx2",
467			"avx512",
468			"aes_ni",
469			"popcnt",
470		},
471		"stoneyridge": {
472			"ssse3",
473			"sse4",
474			"sse4_1",
475			"sse4_2",
476			"aes_ni",
477			"avx",
478			"avx2",
479			"popcnt",
480		},
481		"tigerlake": {
482			"ssse3",
483			"sse4",
484			"sse4_1",
485			"sse4_2",
486			"avx",
487			"avx2",
488			"avx512",
489			"aes_ni",
490			"popcnt",
491		},
492		"whiskeylake": {
493			"ssse3",
494			"sse4",
495			"sse4_1",
496			"sse4_2",
497			"avx",
498			"avx2",
499			"avx512",
500			"aes_ni",
501			"popcnt",
502		},
503	},
504}
505
506var defaultArchFeatureMap = map[OsType]map[ArchType][]string{}
507
508func RegisterDefaultArchVariantFeatures(os OsType, arch ArchType, features ...string) {
509	checkCalledFromInit()
510
511	for _, feature := range features {
512		if !InList(feature, archFeatures[arch]) {
513			panic(fmt.Errorf("Invalid feature %q for arch %q variant \"\"", feature, arch))
514		}
515	}
516
517	if defaultArchFeatureMap[os] == nil {
518		defaultArchFeatureMap[os] = make(map[ArchType][]string)
519	}
520	defaultArchFeatureMap[os][arch] = features
521}
522
523// An Arch indicates a single CPU architecture.
524type Arch struct {
525	ArchType     ArchType
526	ArchVariant  string
527	CpuVariant   string
528	Abi          []string
529	ArchFeatures []string
530	Native       bool
531}
532
533func (a Arch) String() string {
534	s := a.ArchType.String()
535	if a.ArchVariant != "" {
536		s += "_" + a.ArchVariant
537	}
538	if a.CpuVariant != "" {
539		s += "_" + a.CpuVariant
540	}
541	return s
542}
543
544type ArchType struct {
545	Name     string
546	Field    string
547	Multilib string
548}
549
550func newArch(name, multilib string) ArchType {
551	archType := ArchType{
552		Name:     name,
553		Field:    proptools.FieldNameForProperty(name),
554		Multilib: multilib,
555	}
556	archTypeList = append(archTypeList, archType)
557	return archType
558}
559
560func (a ArchType) String() string {
561	return a.Name
562}
563
564var _ encoding.TextMarshaler = ArchType{}
565
566func (a ArchType) MarshalText() ([]byte, error) {
567	return []byte(strconv.Quote(a.String())), nil
568}
569
570var _ encoding.TextUnmarshaler = &ArchType{}
571
572func (a *ArchType) UnmarshalText(text []byte) error {
573	if u, ok := archTypeMap[string(text)]; ok {
574		*a = u
575		return nil
576	}
577
578	return fmt.Errorf("unknown ArchType %q", text)
579}
580
581var BuildOs = func() OsType {
582	switch runtime.GOOS {
583	case "linux":
584		return Linux
585	case "darwin":
586		return Darwin
587	default:
588		panic(fmt.Sprintf("unsupported OS: %s", runtime.GOOS))
589	}
590}()
591
592var (
593	osTypeList      []OsType
594	commonTargetMap = make(map[string]Target)
595
596	NoOsType    OsType
597	Linux       = NewOsType("linux_glibc", Host, false)
598	Darwin      = NewOsType("darwin", Host, false)
599	LinuxBionic = NewOsType("linux_bionic", Host, false)
600	Windows     = NewOsType("windows", HostCross, true)
601	Android     = NewOsType("android", Device, false)
602	Fuchsia     = NewOsType("fuchsia", Device, false)
603
604	osArchTypeMap = map[OsType][]ArchType{
605		Linux:       []ArchType{X86, X86_64},
606		LinuxBionic: []ArchType{X86_64},
607		Darwin:      []ArchType{X86_64},
608		Windows:     []ArchType{X86, X86_64},
609		Android:     []ArchType{Arm, Arm64, Mips, Mips64, X86, X86_64},
610		Fuchsia:     []ArchType{Arm64, X86_64},
611	}
612)
613
614type OsType struct {
615	Name, Field string
616	Class       OsClass
617
618	DefaultDisabled bool
619}
620
621type OsClass int
622
623const (
624	Generic OsClass = iota
625	Device
626	Host
627	HostCross
628)
629
630func (class OsClass) String() string {
631	switch class {
632	case Generic:
633		return "generic"
634	case Device:
635		return "device"
636	case Host:
637		return "host"
638	case HostCross:
639		return "host cross"
640	default:
641		panic(fmt.Errorf("unknown class %d", class))
642	}
643}
644
645func (os OsType) String() string {
646	return os.Name
647}
648
649func (os OsType) Bionic() bool {
650	return os == Android || os == LinuxBionic
651}
652
653func (os OsType) Linux() bool {
654	return os == Android || os == Linux || os == LinuxBionic
655}
656
657func NewOsType(name string, class OsClass, defDisabled bool) OsType {
658	os := OsType{
659		Name:  name,
660		Field: strings.Title(name),
661		Class: class,
662
663		DefaultDisabled: defDisabled,
664	}
665	osTypeList = append(osTypeList, os)
666
667	if _, found := commonTargetMap[name]; found {
668		panic(fmt.Errorf("Found Os type duplicate during OsType registration: %q", name))
669	} else {
670		commonTargetMap[name] = Target{Os: os, Arch: Arch{ArchType: Common}}
671	}
672
673	return os
674}
675
676func osByName(name string) OsType {
677	for _, os := range osTypeList {
678		if os.Name == name {
679			return os
680		}
681	}
682
683	return NoOsType
684}
685
686type Target struct {
687	Os   OsType
688	Arch Arch
689}
690
691func (target Target) String() string {
692	return target.Os.String() + "_" + target.Arch.String()
693}
694
695// archMutator splits a module into a variant for each Target requested by the module.  Target selection
696// for a module is in three levels, OsClass, mulitlib, and then Target.
697// OsClass selection is determined by:
698//    - The HostOrDeviceSupported value passed in to InitAndroidArchModule by the module type factory, which selects
699//      whether the module type can compile for host, device or both.
700//    - The host_supported and device_supported properties on the module.
701// If host is supported for the module, the Host and HostCross OsClasses are  are selected.  If device is supported
702// for the module, the Device OsClass is selected.
703// Within each selected OsClass, the multilib selection is determined by:
704//    - The compile_multilib property if it set (which may be overriden by target.android.compile_multlib or
705//      target.host.compile_multilib).
706//    - The default multilib passed to InitAndroidArchModule if compile_multilib was not set.
707// Valid multilib values include:
708//    "both": compile for all Targets supported by the OsClass (generally x86_64 and x86, or arm64 and arm).
709//    "first": compile for only a single preferred Target supported by the OsClass.  This is generally x86_64 or arm64,
710//        but may be arm for a 32-bit only build or a build with TARGET_PREFER_32_BIT=true set.
711//    "32": compile for only a single 32-bit Target supported by the OsClass.
712//    "64": compile for only a single 64-bit Target supported by the OsClass.
713//    "common": compile a for a single Target that will work on all Targets suported by the OsClass (for example Java).
714//
715// Once the list of Targets is determined, the module is split into a variant for each Target.
716//
717// Modules can be initialized with InitAndroidMultiTargetsArchModule, in which case they will be split by OsClass,
718// but will have a common Target that is expected to handle all other selected Targets via ctx.MultiTargets().
719func archMutator(mctx BottomUpMutatorContext) {
720	var module Module
721	var ok bool
722	if module, ok = mctx.Module().(Module); !ok {
723		return
724	}
725
726	base := module.base()
727
728	if !base.ArchSpecific() {
729		return
730	}
731
732	var moduleTargets []Target
733	moduleMultiTargets := make(map[int][]Target)
734	primaryModules := make(map[int]bool)
735	osClasses := base.OsClassSupported()
736
737	for _, os := range osTypeList {
738		supportedClass := false
739		for _, osClass := range osClasses {
740			if os.Class == osClass {
741				supportedClass = true
742			}
743		}
744		if !supportedClass {
745			continue
746		}
747
748		osTargets := mctx.Config().Targets[os]
749		if len(osTargets) == 0 {
750			continue
751		}
752
753		// only the primary arch in the recovery partition
754		if os == Android && module.InstallInRecovery() {
755			osTargets = []Target{osTargets[0]}
756		}
757
758		prefer32 := false
759		if base.prefer32 != nil {
760			prefer32 = base.prefer32(mctx, base, os.Class)
761		}
762
763		multilib, extraMultilib := decodeMultilib(base, os.Class)
764		targets, err := decodeMultilibTargets(multilib, osTargets, prefer32)
765		if err != nil {
766			mctx.ModuleErrorf("%s", err.Error())
767		}
768
769		var multiTargets []Target
770		if extraMultilib != "" {
771			multiTargets, err = decodeMultilibTargets(extraMultilib, osTargets, prefer32)
772			if err != nil {
773				mctx.ModuleErrorf("%s", err.Error())
774			}
775		}
776
777		if len(targets) > 0 {
778			primaryModules[len(moduleTargets)] = true
779			moduleMultiTargets[len(moduleTargets)] = multiTargets
780			moduleTargets = append(moduleTargets, targets...)
781		}
782	}
783
784	if len(moduleTargets) == 0 {
785		base.commonProperties.Enabled = boolPtr(false)
786		return
787	}
788
789	targetNames := make([]string, len(moduleTargets))
790
791	for i, target := range moduleTargets {
792		targetNames[i] = target.String()
793	}
794
795	modules := mctx.CreateVariations(targetNames...)
796	for i, m := range modules {
797		m.(Module).base().SetTarget(moduleTargets[i], moduleMultiTargets[i], primaryModules[i])
798		m.(Module).base().setArchProperties(mctx)
799	}
800}
801
802func decodeMultilib(base *ModuleBase, class OsClass) (multilib, extraMultilib string) {
803	switch class {
804	case Device:
805		multilib = String(base.commonProperties.Target.Android.Compile_multilib)
806	case Host, HostCross:
807		multilib = String(base.commonProperties.Target.Host.Compile_multilib)
808	}
809	if multilib == "" {
810		multilib = String(base.commonProperties.Compile_multilib)
811	}
812	if multilib == "" {
813		multilib = base.commonProperties.Default_multilib
814	}
815
816	if base.commonProperties.UseTargetVariants {
817		return multilib, ""
818	} else {
819		// For app modules a single arch variant will be created per OS class which is expected to handle all the
820		// selected arches.  Return the common-type as multilib and any Android.bp provided multilib as extraMultilib
821		if multilib == base.commonProperties.Default_multilib {
822			multilib = "first"
823		}
824		return base.commonProperties.Default_multilib, multilib
825	}
826}
827
828func filterArchStructFields(fields []reflect.StructField) (filteredFields []reflect.StructField, filtered bool) {
829	for _, field := range fields {
830		if !proptools.HasTag(field, "android", "arch_variant") {
831			filtered = true
832			continue
833		}
834
835		// The arch_variant field isn't necessary past this point
836		// Instead of wasting space, just remove it. Go also has a
837		// 16-bit limit on structure name length. The name is constructed
838		// based on the Go source representation of the structure, so
839		// the tag names count towards that length.
840		//
841		// TODO: handle the uncommon case of other tags being involved
842		if field.Tag == `android:"arch_variant"` {
843			field.Tag = ""
844		}
845
846		// Recurse into structs
847		switch field.Type.Kind() {
848		case reflect.Struct:
849			var subFiltered bool
850			field.Type, subFiltered = filterArchStruct(field.Type)
851			filtered = filtered || subFiltered
852			if field.Type == nil {
853				continue
854			}
855		case reflect.Ptr:
856			if field.Type.Elem().Kind() == reflect.Struct {
857				nestedType, subFiltered := filterArchStruct(field.Type.Elem())
858				filtered = filtered || subFiltered
859				if nestedType == nil {
860					continue
861				}
862				field.Type = reflect.PtrTo(nestedType)
863			}
864		case reflect.Interface:
865			panic("Interfaces are not supported in arch_variant properties")
866		}
867
868		filteredFields = append(filteredFields, field)
869	}
870
871	return filteredFields, filtered
872}
873
874// filterArchStruct takes a reflect.Type that is either a sturct or a pointer to a struct, and returns a reflect.Type
875// that only contains the fields in the original type that have an `android:"arch_variant"` struct tag, and a bool
876// that is true if the new struct type has fewer fields than the original type.  If there are no fields in the
877// original type with the struct tag it returns nil and true.
878func filterArchStruct(prop reflect.Type) (filteredProp reflect.Type, filtered bool) {
879	var fields []reflect.StructField
880
881	ptr := prop.Kind() == reflect.Ptr
882	if ptr {
883		prop = prop.Elem()
884	}
885
886	for i := 0; i < prop.NumField(); i++ {
887		fields = append(fields, prop.Field(i))
888	}
889
890	filteredFields, filtered := filterArchStructFields(fields)
891
892	if len(filteredFields) == 0 {
893		return nil, true
894	}
895
896	if !filtered {
897		if ptr {
898			return reflect.PtrTo(prop), false
899		}
900		return prop, false
901	}
902
903	ret := reflect.StructOf(filteredFields)
904	if ptr {
905		ret = reflect.PtrTo(ret)
906	}
907
908	return ret, true
909}
910
911// filterArchStruct takes a reflect.Type that is either a sturct or a pointer to a struct, and returns a list of
912// reflect.Type that only contains the fields in the original type that have an `android:"arch_variant"` struct tag,
913// and a bool that is true if the new struct type has fewer fields than the original type.  If there are no fields in
914// the original type with the struct tag it returns nil and true.  Each returned struct type will have a maximum of
915// 10 top level fields in it to attempt to avoid hitting the reflect.StructOf name length limit, although the limit
916// can still be reached with a single struct field with many fields in it.
917func filterArchStructSharded(prop reflect.Type) (filteredProp []reflect.Type, filtered bool) {
918	var fields []reflect.StructField
919
920	ptr := prop.Kind() == reflect.Ptr
921	if ptr {
922		prop = prop.Elem()
923	}
924
925	for i := 0; i < prop.NumField(); i++ {
926		fields = append(fields, prop.Field(i))
927	}
928
929	fields, filtered = filterArchStructFields(fields)
930	if !filtered {
931		if ptr {
932			return []reflect.Type{reflect.PtrTo(prop)}, false
933		}
934		return []reflect.Type{prop}, false
935	}
936
937	if len(fields) == 0 {
938		return nil, true
939	}
940
941	shards := shardFields(fields, 10)
942
943	for _, shard := range shards {
944		s := reflect.StructOf(shard)
945		if ptr {
946			s = reflect.PtrTo(s)
947		}
948		filteredProp = append(filteredProp, s)
949	}
950
951	return filteredProp, true
952}
953
954func shardFields(fields []reflect.StructField, shardSize int) [][]reflect.StructField {
955	ret := make([][]reflect.StructField, 0, (len(fields)+shardSize-1)/shardSize)
956	for len(fields) > shardSize {
957		ret = append(ret, fields[0:shardSize])
958		fields = fields[shardSize:]
959	}
960	if len(fields) > 0 {
961		ret = append(ret, fields)
962	}
963	return ret
964}
965
966// createArchType takes a reflect.Type that is either a struct or a pointer to a struct, and returns a list of
967// reflect.Type that contains the arch-variant properties inside structs for each architecture, os, target, multilib,
968// etc.
969func createArchType(props reflect.Type) []reflect.Type {
970	propShards, _ := filterArchStructSharded(props)
971	if len(propShards) == 0 {
972		return nil
973	}
974
975	var ret []reflect.Type
976	for _, props := range propShards {
977
978		variantFields := func(names []string) []reflect.StructField {
979			ret := make([]reflect.StructField, len(names))
980
981			for i, name := range names {
982				ret[i].Name = name
983				ret[i].Type = props
984			}
985
986			return ret
987		}
988
989		archFields := make([]reflect.StructField, len(archTypeList))
990		for i, arch := range archTypeList {
991			variants := []string{}
992
993			for _, archVariant := range archVariants[arch] {
994				archVariant := variantReplacer.Replace(archVariant)
995				variants = append(variants, proptools.FieldNameForProperty(archVariant))
996			}
997			for _, feature := range archFeatures[arch] {
998				feature := variantReplacer.Replace(feature)
999				variants = append(variants, proptools.FieldNameForProperty(feature))
1000			}
1001
1002			fields := variantFields(variants)
1003
1004			fields = append([]reflect.StructField{{
1005				Name:      "BlueprintEmbed",
1006				Type:      props,
1007				Anonymous: true,
1008			}}, fields...)
1009
1010			archFields[i] = reflect.StructField{
1011				Name: arch.Field,
1012				Type: reflect.StructOf(fields),
1013			}
1014		}
1015		archType := reflect.StructOf(archFields)
1016
1017		multilibType := reflect.StructOf(variantFields([]string{"Lib32", "Lib64"}))
1018
1019		targets := []string{
1020			"Host",
1021			"Android64",
1022			"Android32",
1023			"Bionic",
1024			"Linux",
1025			"Not_windows",
1026			"Arm_on_x86",
1027			"Arm_on_x86_64",
1028		}
1029		for _, os := range osTypeList {
1030			targets = append(targets, os.Field)
1031
1032			for _, archType := range osArchTypeMap[os] {
1033				targets = append(targets, os.Field+"_"+archType.Name)
1034
1035				if os.Linux() {
1036					target := "Linux_" + archType.Name
1037					if !InList(target, targets) {
1038						targets = append(targets, target)
1039					}
1040				}
1041				if os.Bionic() {
1042					target := "Bionic_" + archType.Name
1043					if !InList(target, targets) {
1044						targets = append(targets, target)
1045					}
1046				}
1047			}
1048		}
1049
1050		targetType := reflect.StructOf(variantFields(targets))
1051		ret = append(ret, reflect.StructOf([]reflect.StructField{
1052			{
1053				Name: "Arch",
1054				Type: archType,
1055			},
1056			{
1057				Name: "Multilib",
1058				Type: multilibType,
1059			},
1060			{
1061				Name: "Target",
1062				Type: targetType,
1063			},
1064		}))
1065	}
1066	return ret
1067}
1068
1069var archPropTypeMap OncePer
1070
1071func InitArchModule(m Module) {
1072
1073	base := m.base()
1074
1075	base.generalProperties = m.GetProperties()
1076
1077	for _, properties := range base.generalProperties {
1078		propertiesValue := reflect.ValueOf(properties)
1079		t := propertiesValue.Type()
1080		if propertiesValue.Kind() != reflect.Ptr {
1081			panic(fmt.Errorf("properties must be a pointer to a struct, got %T",
1082				propertiesValue.Interface()))
1083		}
1084
1085		propertiesValue = propertiesValue.Elem()
1086		if propertiesValue.Kind() != reflect.Struct {
1087			panic(fmt.Errorf("properties must be a pointer to a struct, got %T",
1088				propertiesValue.Interface()))
1089		}
1090
1091		archPropTypes := archPropTypeMap.Once(NewCustomOnceKey(t), func() interface{} {
1092			return createArchType(t)
1093		}).([]reflect.Type)
1094
1095		var archProperties []interface{}
1096		for _, t := range archPropTypes {
1097			archProperties = append(archProperties, reflect.New(t).Interface())
1098		}
1099		base.archProperties = append(base.archProperties, archProperties)
1100		m.AddProperties(archProperties...)
1101	}
1102
1103	base.customizableProperties = m.GetProperties()
1104}
1105
1106var variantReplacer = strings.NewReplacer("-", "_", ".", "_")
1107
1108func (a *ModuleBase) appendProperties(ctx BottomUpMutatorContext,
1109	dst interface{}, src reflect.Value, field, srcPrefix string) reflect.Value {
1110
1111	src = src.FieldByName(field)
1112	if !src.IsValid() {
1113		ctx.ModuleErrorf("field %q does not exist", srcPrefix)
1114		return src
1115	}
1116
1117	ret := src
1118
1119	if src.Kind() == reflect.Struct {
1120		src = src.FieldByName("BlueprintEmbed")
1121	}
1122
1123	order := func(property string,
1124		dstField, srcField reflect.StructField,
1125		dstValue, srcValue interface{}) (proptools.Order, error) {
1126		if proptools.HasTag(dstField, "android", "variant_prepend") {
1127			return proptools.Prepend, nil
1128		} else {
1129			return proptools.Append, nil
1130		}
1131	}
1132
1133	err := proptools.ExtendMatchingProperties([]interface{}{dst}, src.Interface(), nil, order)
1134	if err != nil {
1135		if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
1136			ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
1137		} else {
1138			panic(err)
1139		}
1140	}
1141
1142	return ret
1143}
1144
1145// Rewrite the module's properties structs to contain arch-specific values.
1146func (a *ModuleBase) setArchProperties(ctx BottomUpMutatorContext) {
1147	arch := a.Arch()
1148	os := a.Os()
1149
1150	for i := range a.generalProperties {
1151		genProps := a.generalProperties[i]
1152		if a.archProperties[i] == nil {
1153			continue
1154		}
1155		for _, archProperties := range a.archProperties[i] {
1156			archPropValues := reflect.ValueOf(archProperties).Elem()
1157
1158			archProp := archPropValues.FieldByName("Arch")
1159			multilibProp := archPropValues.FieldByName("Multilib")
1160			targetProp := archPropValues.FieldByName("Target")
1161
1162			var field string
1163			var prefix string
1164
1165			// Handle arch-specific properties in the form:
1166			// arch: {
1167			//     arm64: {
1168			//         key: value,
1169			//     },
1170			// },
1171			t := arch.ArchType
1172
1173			if arch.ArchType != Common {
1174				field := proptools.FieldNameForProperty(t.Name)
1175				prefix := "arch." + t.Name
1176				archStruct := a.appendProperties(ctx, genProps, archProp, field, prefix)
1177
1178				// Handle arch-variant-specific properties in the form:
1179				// arch: {
1180				//     variant: {
1181				//         key: value,
1182				//     },
1183				// },
1184				v := variantReplacer.Replace(arch.ArchVariant)
1185				if v != "" {
1186					field := proptools.FieldNameForProperty(v)
1187					prefix := "arch." + t.Name + "." + v
1188					a.appendProperties(ctx, genProps, archStruct, field, prefix)
1189				}
1190
1191				// Handle cpu-variant-specific properties in the form:
1192				// arch: {
1193				//     variant: {
1194				//         key: value,
1195				//     },
1196				// },
1197				if arch.CpuVariant != arch.ArchVariant {
1198					c := variantReplacer.Replace(arch.CpuVariant)
1199					if c != "" {
1200						field := proptools.FieldNameForProperty(c)
1201						prefix := "arch." + t.Name + "." + c
1202						a.appendProperties(ctx, genProps, archStruct, field, prefix)
1203					}
1204				}
1205
1206				// Handle arch-feature-specific properties in the form:
1207				// arch: {
1208				//     feature: {
1209				//         key: value,
1210				//     },
1211				// },
1212				for _, feature := range arch.ArchFeatures {
1213					field := proptools.FieldNameForProperty(feature)
1214					prefix := "arch." + t.Name + "." + feature
1215					a.appendProperties(ctx, genProps, archStruct, field, prefix)
1216				}
1217
1218				// Handle multilib-specific properties in the form:
1219				// multilib: {
1220				//     lib32: {
1221				//         key: value,
1222				//     },
1223				// },
1224				field = proptools.FieldNameForProperty(t.Multilib)
1225				prefix = "multilib." + t.Multilib
1226				a.appendProperties(ctx, genProps, multilibProp, field, prefix)
1227			}
1228
1229			// Handle host-specific properties in the form:
1230			// target: {
1231			//     host: {
1232			//         key: value,
1233			//     },
1234			// },
1235			if os.Class == Host || os.Class == HostCross {
1236				field = "Host"
1237				prefix = "target.host"
1238				a.appendProperties(ctx, genProps, targetProp, field, prefix)
1239			}
1240
1241			// Handle target OS generalities of the form:
1242			// target: {
1243			//     bionic: {
1244			//         key: value,
1245			//     },
1246			//     bionic_x86: {
1247			//         key: value,
1248			//     },
1249			// }
1250			if os.Linux() {
1251				field = "Linux"
1252				prefix = "target.linux"
1253				a.appendProperties(ctx, genProps, targetProp, field, prefix)
1254
1255				if arch.ArchType != Common {
1256					field = "Linux_" + arch.ArchType.Name
1257					prefix = "target.linux_" + arch.ArchType.Name
1258					a.appendProperties(ctx, genProps, targetProp, field, prefix)
1259				}
1260			}
1261
1262			if os.Bionic() {
1263				field = "Bionic"
1264				prefix = "target.bionic"
1265				a.appendProperties(ctx, genProps, targetProp, field, prefix)
1266
1267				if arch.ArchType != Common {
1268					field = "Bionic_" + t.Name
1269					prefix = "target.bionic_" + t.Name
1270					a.appendProperties(ctx, genProps, targetProp, field, prefix)
1271				}
1272			}
1273
1274			// Handle target OS properties in the form:
1275			// target: {
1276			//     linux_glibc: {
1277			//         key: value,
1278			//     },
1279			//     not_windows: {
1280			//         key: value,
1281			//     },
1282			//     linux_glibc_x86: {
1283			//         key: value,
1284			//     },
1285			//     linux_glibc_arm: {
1286			//         key: value,
1287			//     },
1288			//     android {
1289			//         key: value,
1290			//     },
1291			//     android_arm {
1292			//         key: value,
1293			//     },
1294			//     android_x86 {
1295			//         key: value,
1296			//     },
1297			// },
1298			field = os.Field
1299			prefix = "target." + os.Name
1300			a.appendProperties(ctx, genProps, targetProp, field, prefix)
1301
1302			if arch.ArchType != Common {
1303				field = os.Field + "_" + t.Name
1304				prefix = "target." + os.Name + "_" + t.Name
1305				a.appendProperties(ctx, genProps, targetProp, field, prefix)
1306			}
1307
1308			if (os.Class == Host || os.Class == HostCross) && os != Windows {
1309				field := "Not_windows"
1310				prefix := "target.not_windows"
1311				a.appendProperties(ctx, genProps, targetProp, field, prefix)
1312			}
1313
1314			// Handle 64-bit device properties in the form:
1315			// target {
1316			//     android64 {
1317			//         key: value,
1318			//     },
1319			//     android32 {
1320			//         key: value,
1321			//     },
1322			// },
1323			// WARNING: this is probably not what you want to use in your blueprints file, it selects
1324			// options for all targets on a device that supports 64-bit binaries, not just the targets
1325			// that are being compiled for 64-bit.  Its expected use case is binaries like linker and
1326			// debuggerd that need to know when they are a 32-bit process running on a 64-bit device
1327			if os.Class == Device {
1328				if ctx.Config().Android64() {
1329					field := "Android64"
1330					prefix := "target.android64"
1331					a.appendProperties(ctx, genProps, targetProp, field, prefix)
1332				} else {
1333					field := "Android32"
1334					prefix := "target.android32"
1335					a.appendProperties(ctx, genProps, targetProp, field, prefix)
1336				}
1337
1338				if (arch.ArchType == X86 && (hasArmAbi(arch) ||
1339					hasArmAndroidArch(ctx.Config().Targets[Android]))) ||
1340					(arch.ArchType == Arm &&
1341						hasX86AndroidArch(ctx.Config().Targets[Android])) {
1342					field := "Arm_on_x86"
1343					prefix := "target.arm_on_x86"
1344					a.appendProperties(ctx, genProps, targetProp, field, prefix)
1345				}
1346				if (arch.ArchType == X86_64 && (hasArmAbi(arch) ||
1347					hasArmAndroidArch(ctx.Config().Targets[Android]))) ||
1348					(arch.ArchType == Arm &&
1349						hasX8664AndroidArch(ctx.Config().Targets[Android])) {
1350					field := "Arm_on_x86_64"
1351					prefix := "target.arm_on_x86_64"
1352					a.appendProperties(ctx, genProps, targetProp, field, prefix)
1353				}
1354			}
1355		}
1356	}
1357}
1358
1359func forEachInterface(v reflect.Value, f func(reflect.Value)) {
1360	switch v.Kind() {
1361	case reflect.Interface:
1362		f(v)
1363	case reflect.Struct:
1364		for i := 0; i < v.NumField(); i++ {
1365			forEachInterface(v.Field(i), f)
1366		}
1367	case reflect.Ptr:
1368		forEachInterface(v.Elem(), f)
1369	default:
1370		panic(fmt.Errorf("Unsupported kind %s", v.Kind()))
1371	}
1372}
1373
1374// Convert the arch product variables into a list of targets for each os class structs
1375func decodeTargetProductVariables(config *config) (map[OsType][]Target, error) {
1376	variables := config.productVariables
1377
1378	targets := make(map[OsType][]Target)
1379	var targetErr error
1380
1381	addTarget := func(os OsType, archName string, archVariant, cpuVariant *string, abi []string) {
1382		if targetErr != nil {
1383			return
1384		}
1385
1386		arch, err := decodeArch(os, archName, archVariant, cpuVariant, abi)
1387		if err != nil {
1388			targetErr = err
1389			return
1390		}
1391
1392		targets[os] = append(targets[os],
1393			Target{
1394				Os:   os,
1395				Arch: arch,
1396			})
1397	}
1398
1399	if variables.HostArch == nil {
1400		return nil, fmt.Errorf("No host primary architecture set")
1401	}
1402
1403	addTarget(BuildOs, *variables.HostArch, nil, nil, nil)
1404
1405	if variables.HostSecondaryArch != nil && *variables.HostSecondaryArch != "" {
1406		addTarget(BuildOs, *variables.HostSecondaryArch, nil, nil, nil)
1407	}
1408
1409	if Bool(config.Host_bionic) {
1410		addTarget(LinuxBionic, "x86_64", nil, nil, nil)
1411	}
1412
1413	if String(variables.CrossHost) != "" {
1414		crossHostOs := osByName(*variables.CrossHost)
1415		if crossHostOs == NoOsType {
1416			return nil, fmt.Errorf("Unknown cross host OS %q", *variables.CrossHost)
1417		}
1418
1419		if String(variables.CrossHostArch) == "" {
1420			return nil, fmt.Errorf("No cross-host primary architecture set")
1421		}
1422
1423		addTarget(crossHostOs, *variables.CrossHostArch, nil, nil, nil)
1424
1425		if variables.CrossHostSecondaryArch != nil && *variables.CrossHostSecondaryArch != "" {
1426			addTarget(crossHostOs, *variables.CrossHostSecondaryArch, nil, nil, nil)
1427		}
1428	}
1429
1430	if variables.DeviceArch != nil && *variables.DeviceArch != "" {
1431		var target = Android
1432		if Bool(variables.Fuchsia) {
1433			target = Fuchsia
1434		}
1435
1436		addTarget(target, *variables.DeviceArch, variables.DeviceArchVariant,
1437			variables.DeviceCpuVariant, variables.DeviceAbi)
1438
1439		if variables.DeviceSecondaryArch != nil && *variables.DeviceSecondaryArch != "" {
1440			addTarget(Android, *variables.DeviceSecondaryArch,
1441				variables.DeviceSecondaryArchVariant, variables.DeviceSecondaryCpuVariant,
1442				variables.DeviceSecondaryAbi)
1443
1444			deviceArches := targets[Android]
1445			if deviceArches[0].Arch.ArchType.Multilib == deviceArches[1].Arch.ArchType.Multilib {
1446				deviceArches[1].Arch.Native = false
1447			}
1448		}
1449	}
1450
1451	if targetErr != nil {
1452		return nil, targetErr
1453	}
1454
1455	return targets, nil
1456}
1457
1458// hasArmAbi returns true if arch has at least one arm ABI
1459func hasArmAbi(arch Arch) bool {
1460	for _, abi := range arch.Abi {
1461		if strings.HasPrefix(abi, "arm") {
1462			return true
1463		}
1464	}
1465	return false
1466}
1467
1468// hasArmArch returns true if targets has at least arm Android arch
1469func hasArmAndroidArch(targets []Target) bool {
1470	for _, target := range targets {
1471		if target.Os == Android && target.Arch.ArchType == Arm {
1472			return true
1473		}
1474	}
1475	return false
1476}
1477
1478// hasX86Arch returns true if targets has at least x86 Android arch
1479func hasX86AndroidArch(targets []Target) bool {
1480	for _, target := range targets {
1481		if target.Os == Android && target.Arch.ArchType == X86 {
1482			return true
1483		}
1484	}
1485	return false
1486}
1487
1488// hasX8664Arch returns true if targets has at least x86_64 Android arch
1489func hasX8664AndroidArch(targets []Target) bool {
1490	for _, target := range targets {
1491		if target.Os == Android && target.Arch.ArchType == X86_64 {
1492			return true
1493		}
1494	}
1495	return false
1496}
1497
1498type archConfig struct {
1499	arch        string
1500	archVariant string
1501	cpuVariant  string
1502	abi         []string
1503}
1504
1505func getMegaDeviceConfig() []archConfig {
1506	return []archConfig{
1507		{"arm", "armv7-a", "generic", []string{"armeabi-v7a"}},
1508		{"arm", "armv7-a-neon", "generic", []string{"armeabi-v7a"}},
1509		{"arm", "armv7-a-neon", "cortex-a7", []string{"armeabi-v7a"}},
1510		{"arm", "armv7-a-neon", "cortex-a8", []string{"armeabi-v7a"}},
1511		{"arm", "armv7-a-neon", "cortex-a9", []string{"armeabi-v7a"}},
1512		{"arm", "armv7-a-neon", "cortex-a15", []string{"armeabi-v7a"}},
1513		{"arm", "armv7-a-neon", "cortex-a53", []string{"armeabi-v7a"}},
1514		{"arm", "armv7-a-neon", "cortex-a53.a57", []string{"armeabi-v7a"}},
1515		{"arm", "armv7-a-neon", "cortex-a72", []string{"armeabi-v7a"}},
1516		{"arm", "armv7-a-neon", "cortex-a73", []string{"armeabi-v7a"}},
1517		{"arm", "armv7-a-neon", "cortex-a75", []string{"armeabi-v7a"}},
1518		{"arm", "armv7-a-neon", "cortex-a76", []string{"armeabi-v7a"}},
1519		{"arm", "armv7-a-neon", "krait", []string{"armeabi-v7a"}},
1520		{"arm", "armv7-a-neon", "kryo", []string{"armeabi-v7a"}},
1521		{"arm", "armv7-a-neon", "kryo385", []string{"armeabi-v7a"}},
1522		{"arm", "armv7-a-neon", "exynos-m1", []string{"armeabi-v7a"}},
1523		{"arm", "armv7-a-neon", "exynos-m2", []string{"armeabi-v7a"}},
1524		{"arm64", "armv8-a", "cortex-a53", []string{"arm64-v8a"}},
1525		{"arm64", "armv8-a", "cortex-a72", []string{"arm64-v8a"}},
1526		{"arm64", "armv8-a", "cortex-a73", []string{"arm64-v8a"}},
1527		{"arm64", "armv8-a", "kryo", []string{"arm64-v8a"}},
1528		{"arm64", "armv8-a", "exynos-m1", []string{"arm64-v8a"}},
1529		{"arm64", "armv8-a", "exynos-m2", []string{"arm64-v8a"}},
1530		{"arm64", "armv8-2a", "cortex-a75", []string{"arm64-v8a"}},
1531		{"arm64", "armv8-2a", "cortex-a76", []string{"arm64-v8a"}},
1532		{"arm64", "armv8-2a", "kryo385", []string{"arm64-v8a"}},
1533		{"mips", "mips32-fp", "", []string{"mips"}},
1534		{"mips", "mips32r2-fp", "", []string{"mips"}},
1535		{"mips", "mips32r2-fp-xburst", "", []string{"mips"}},
1536		//{"mips", "mips32r6", "", []string{"mips"}},
1537		{"mips", "mips32r2dsp-fp", "", []string{"mips"}},
1538		{"mips", "mips32r2dspr2-fp", "", []string{"mips"}},
1539		// mips64r2 is mismatching 64r2 and 64r6 libraries during linking to libgcc
1540		//{"mips64", "mips64r2", "", []string{"mips64"}},
1541		{"mips64", "mips64r6", "", []string{"mips64"}},
1542		{"x86", "", "", []string{"x86"}},
1543		{"x86", "atom", "", []string{"x86"}},
1544		{"x86", "haswell", "", []string{"x86"}},
1545		{"x86", "ivybridge", "", []string{"x86"}},
1546		{"x86", "sandybridge", "", []string{"x86"}},
1547		{"x86", "silvermont", "", []string{"x86"}},
1548		{"x86", "stoneyridge", "", []string{"x86"}},
1549		{"x86", "x86_64", "", []string{"x86"}},
1550		{"x86_64", "", "", []string{"x86_64"}},
1551		{"x86_64", "haswell", "", []string{"x86_64"}},
1552		{"x86_64", "ivybridge", "", []string{"x86_64"}},
1553		{"x86_64", "sandybridge", "", []string{"x86_64"}},
1554		{"x86_64", "silvermont", "", []string{"x86_64"}},
1555		{"x86_64", "stoneyridge", "", []string{"x86_64"}},
1556	}
1557}
1558
1559func getNdkAbisConfig() []archConfig {
1560	return []archConfig{
1561		{"arm", "armv7-a", "", []string{"armeabi"}},
1562		{"arm64", "armv8-a", "", []string{"arm64-v8a"}},
1563		{"x86", "", "", []string{"x86"}},
1564		{"x86_64", "", "", []string{"x86_64"}},
1565	}
1566}
1567
1568func decodeArchSettings(os OsType, archConfigs []archConfig) ([]Target, error) {
1569	var ret []Target
1570
1571	for _, config := range archConfigs {
1572		arch, err := decodeArch(os, config.arch, &config.archVariant,
1573			&config.cpuVariant, config.abi)
1574		if err != nil {
1575			return nil, err
1576		}
1577		arch.Native = false
1578		ret = append(ret, Target{
1579			Os:   Android,
1580			Arch: arch,
1581		})
1582	}
1583
1584	return ret, nil
1585}
1586
1587// Convert a set of strings from product variables into a single Arch struct
1588func decodeArch(os OsType, arch string, archVariant, cpuVariant *string, abi []string) (Arch, error) {
1589	stringPtr := func(p *string) string {
1590		if p != nil {
1591			return *p
1592		}
1593		return ""
1594	}
1595
1596	archType, ok := archTypeMap[arch]
1597	if !ok {
1598		return Arch{}, fmt.Errorf("unknown arch %q", arch)
1599	}
1600
1601	a := Arch{
1602		ArchType:    archType,
1603		ArchVariant: stringPtr(archVariant),
1604		CpuVariant:  stringPtr(cpuVariant),
1605		Abi:         abi,
1606		Native:      true,
1607	}
1608
1609	if a.ArchVariant == a.ArchType.Name || a.ArchVariant == "generic" {
1610		a.ArchVariant = ""
1611	}
1612
1613	if a.CpuVariant == a.ArchType.Name || a.CpuVariant == "generic" {
1614		a.CpuVariant = ""
1615	}
1616
1617	for i := 0; i < len(a.Abi); i++ {
1618		if a.Abi[i] == "" {
1619			a.Abi = append(a.Abi[:i], a.Abi[i+1:]...)
1620			i--
1621		}
1622	}
1623
1624	if a.ArchVariant == "" {
1625		if featureMap, ok := defaultArchFeatureMap[os]; ok {
1626			a.ArchFeatures = featureMap[archType]
1627		}
1628	} else {
1629		if featureMap, ok := archFeatureMap[archType]; ok {
1630			a.ArchFeatures = featureMap[a.ArchVariant]
1631		}
1632	}
1633
1634	return a, nil
1635}
1636
1637func filterMultilibTargets(targets []Target, multilib string) []Target {
1638	var ret []Target
1639	for _, t := range targets {
1640		if t.Arch.ArchType.Multilib == multilib {
1641			ret = append(ret, t)
1642		}
1643	}
1644	return ret
1645}
1646
1647func getCommonTargets(targets []Target) []Target {
1648	var ret []Target
1649	set := make(map[string]bool)
1650
1651	for _, t := range targets {
1652		if _, found := set[t.Os.String()]; !found {
1653			set[t.Os.String()] = true
1654			ret = append(ret, commonTargetMap[t.Os.String()])
1655		}
1656	}
1657
1658	return ret
1659}
1660
1661func firstTarget(targets []Target, filters ...string) []Target {
1662	for _, filter := range filters {
1663		buildTargets := filterMultilibTargets(targets, filter)
1664		if len(buildTargets) > 0 {
1665			return buildTargets[:1]
1666		}
1667	}
1668	return nil
1669}
1670
1671// Use the module multilib setting to select one or more targets from a target list
1672func decodeMultilibTargets(multilib string, targets []Target, prefer32 bool) ([]Target, error) {
1673	buildTargets := []Target{}
1674
1675	switch multilib {
1676	case "common":
1677		buildTargets = getCommonTargets(targets)
1678	case "common_first":
1679		buildTargets = getCommonTargets(targets)
1680		if prefer32 {
1681			buildTargets = append(buildTargets, firstTarget(targets, "lib32", "lib64")...)
1682		} else {
1683			buildTargets = append(buildTargets, firstTarget(targets, "lib64", "lib32")...)
1684		}
1685	case "both":
1686		if prefer32 {
1687			buildTargets = append(buildTargets, filterMultilibTargets(targets, "lib32")...)
1688			buildTargets = append(buildTargets, filterMultilibTargets(targets, "lib64")...)
1689		} else {
1690			buildTargets = append(buildTargets, filterMultilibTargets(targets, "lib64")...)
1691			buildTargets = append(buildTargets, filterMultilibTargets(targets, "lib32")...)
1692		}
1693	case "32":
1694		buildTargets = filterMultilibTargets(targets, "lib32")
1695	case "64":
1696		buildTargets = filterMultilibTargets(targets, "lib64")
1697	case "first":
1698		if prefer32 {
1699			buildTargets = firstTarget(targets, "lib32", "lib64")
1700		} else {
1701			buildTargets = firstTarget(targets, "lib64", "lib32")
1702		}
1703	case "prefer32":
1704		buildTargets = filterMultilibTargets(targets, "lib32")
1705		if len(buildTargets) == 0 {
1706			buildTargets = filterMultilibTargets(targets, "lib64")
1707		}
1708	default:
1709		return nil, fmt.Errorf(`compile_multilib must be "both", "first", "32", "64", or "prefer32" found %q`,
1710			multilib)
1711	}
1712
1713	return buildTargets, nil
1714}
1715