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