xref: /aosp_15_r20/build/soong/android/arch.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
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	"slices"
23	"strings"
24
25	"github.com/google/blueprint"
26	"github.com/google/blueprint/proptools"
27)
28
29/*
30Example blueprints file containing all variant property groups, with comment listing what type
31of variants get properties in that group:
32
33module {
34    arch: {
35        arm: {
36            // Host or device variants with arm architecture
37        },
38        arm64: {
39            // Host or device variants with arm64 architecture
40        },
41        x86: {
42            // Host or device variants with x86 architecture
43        },
44        x86_64: {
45            // Host or device variants with x86_64 architecture
46        },
47    },
48    multilib: {
49        lib32: {
50            // Host or device variants for 32-bit architectures
51        },
52        lib64: {
53            // Host or device variants for 64-bit architectures
54        },
55    },
56    target: {
57        android: {
58            // Device variants (implies Bionic)
59        },
60        host: {
61            // Host variants
62        },
63        bionic: {
64            // Bionic (device and host) variants
65        },
66        linux_bionic: {
67            // Bionic host variants
68        },
69        linux: {
70            // Bionic (device and host) and Linux glibc variants
71        },
72        linux_glibc: {
73            // Linux host variants (using non-Bionic libc)
74        },
75        darwin: {
76            // Darwin host variants
77        },
78        windows: {
79            // Windows host variants
80        },
81        not_windows: {
82            // Non-windows host variants
83        },
84        android_arm: {
85            // Any <os>_<arch> combination restricts to that os and arch
86        },
87    },
88}
89*/
90
91// An Arch indicates a single CPU architecture.
92type Arch struct {
93	// The type of the architecture (arm, arm64, x86, or x86_64).
94	ArchType ArchType
95
96	// The variant of the architecture, for example "armv7-a" or "armv7-a-neon" for arm.
97	ArchVariant string
98
99	// The variant of the CPU, for example "cortex-a53" for arm64.
100	CpuVariant string
101
102	// The list of Android app ABIs supported by the CPU architecture, for example "arm64-v8a".
103	Abi []string
104
105	// The list of arch-specific features supported by the CPU architecture, for example "neon".
106	ArchFeatures []string
107}
108
109// String returns the Arch as a string.  The value is used as the name of the variant created
110// by archMutator.
111func (a Arch) String() string {
112	s := a.ArchType.String()
113	if a.ArchVariant != "" {
114		s += "_" + a.ArchVariant
115	}
116	if a.CpuVariant != "" {
117		s += "_" + a.CpuVariant
118	}
119	return s
120}
121
122// ArchType is used to define the 4 supported architecture types (arm, arm64, x86, x86_64), as
123// well as the "common" architecture used for modules that support multiple architectures, for
124// example Java modules.
125type ArchType struct {
126	// Name is the name of the architecture type, "arm", "arm64", "x86", or "x86_64".
127	Name string
128
129	// Field is the name of the field used in properties that refer to the architecture, e.g. "Arm64".
130	Field string
131
132	// Multilib is either "lib32" or "lib64" for 32-bit or 64-bit architectures.
133	Multilib string
134}
135
136// String returns the name of the ArchType.
137func (a ArchType) String() string {
138	return a.Name
139}
140
141func (a ArchType) Bitness() string {
142	if a.Multilib == "lib32" {
143		return "32"
144	}
145	if a.Multilib == "lib64" {
146		return "64"
147	}
148	panic("Bitness is not defined for the common variant")
149}
150
151const COMMON_VARIANT = "common"
152
153var (
154	archTypeList []ArchType
155
156	Arm     = newArch("arm", "lib32")
157	Arm64   = newArch("arm64", "lib64")
158	Riscv64 = newArch("riscv64", "lib64")
159	X86     = newArch("x86", "lib32")
160	X86_64  = newArch("x86_64", "lib64")
161
162	Common = ArchType{
163		Name: COMMON_VARIANT,
164	}
165)
166
167var archTypeMap = map[string]ArchType{}
168
169func newArch(name, multilib string) ArchType {
170	archType := ArchType{
171		Name:     name,
172		Field:    proptools.FieldNameForProperty(name),
173		Multilib: multilib,
174	}
175	archTypeList = append(archTypeList, archType)
176	archTypeMap[name] = archType
177	return archType
178}
179
180// ArchTypeList returns a slice copy of the 4 supported ArchTypes for arm,
181// arm64, x86 and x86_64.
182func ArchTypeList() []ArchType {
183	return append([]ArchType(nil), archTypeList...)
184}
185
186// MarshalText allows an ArchType to be serialized through any encoder that supports
187// encoding.TextMarshaler.
188func (a ArchType) MarshalText() ([]byte, error) {
189	return []byte(a.String()), nil
190}
191
192var _ encoding.TextMarshaler = ArchType{}
193
194// UnmarshalText allows an ArchType to be deserialized through any decoder that supports
195// encoding.TextUnmarshaler.
196func (a *ArchType) UnmarshalText(text []byte) error {
197	if u, ok := archTypeMap[string(text)]; ok {
198		*a = u
199		return nil
200	}
201
202	return fmt.Errorf("unknown ArchType %q", text)
203}
204
205var _ encoding.TextUnmarshaler = &ArchType{}
206
207// OsClass is an enum that describes whether a variant of a module runs on the host, on the device,
208// or is generic.
209type OsClass int
210
211const (
212	// Generic is used for variants of modules that are not OS-specific.
213	Generic OsClass = iota
214	// Device is used for variants of modules that run on the device.
215	Device
216	// Host is used for variants of modules that run on the host.
217	Host
218)
219
220// String returns the OsClass as a string.
221func (class OsClass) String() string {
222	switch class {
223	case Generic:
224		return "generic"
225	case Device:
226		return "device"
227	case Host:
228		return "host"
229	default:
230		panic(fmt.Errorf("unknown class %d", class))
231	}
232}
233
234// OsType describes an OS variant of a module.
235type OsType struct {
236	// Name is the name of the OS.  It is also used as the name of the property in Android.bp
237	// files.
238	Name string
239
240	// Field is the name of the OS converted to an exported field name, i.e. with the first
241	// character capitalized.
242	Field string
243
244	// Class is the OsClass of the OS.
245	Class OsClass
246
247	// DefaultDisabled is set when the module variants for the OS should not be created unless
248	// the module explicitly requests them.  This is used to limit Windows cross compilation to
249	// only modules that need it.
250	DefaultDisabled bool
251}
252
253// String returns the name of the OsType.
254func (os OsType) String() string {
255	return os.Name
256}
257
258// Bionic returns true if the OS uses the Bionic libc runtime, i.e. if the OS is Android or
259// is Linux with Bionic.
260func (os OsType) Bionic() bool {
261	return os == Android || os == LinuxBionic
262}
263
264// Linux returns true if the OS uses the Linux kernel, i.e. if the OS is Android or is Linux
265// with or without the Bionic libc runtime.
266func (os OsType) Linux() bool {
267	return os == Android || os == Linux || os == LinuxBionic || os == LinuxMusl
268}
269
270// newOsType constructs an OsType and adds it to the global lists.
271func newOsType(name string, class OsClass, defDisabled bool, archTypes ...ArchType) OsType {
272	checkCalledFromInit()
273	os := OsType{
274		Name:  name,
275		Field: proptools.FieldNameForProperty(name),
276		Class: class,
277
278		DefaultDisabled: defDisabled,
279	}
280	osTypeList = append(osTypeList, os)
281
282	if _, found := commonTargetMap[name]; found {
283		panic(fmt.Errorf("Found Os type duplicate during OsType registration: %q", name))
284	} else {
285		commonTargetMap[name] = Target{Os: os, Arch: CommonArch}
286	}
287	osArchTypeMap[os] = archTypes
288
289	return os
290}
291
292// osByName returns the OsType that has the given name, or NoOsType if none match.
293func osByName(name string) OsType {
294	for _, os := range osTypeList {
295		if os.Name == name {
296			return os
297		}
298	}
299
300	return NoOsType
301}
302
303var (
304	// osTypeList contains a list of all the supported OsTypes, including ones not supported
305	// by the current build host or the target device.
306	osTypeList []OsType
307	// commonTargetMap maps names of OsTypes to the corresponding common Target, i.e. the
308	// Target with the same OsType and the common ArchType.
309	commonTargetMap = make(map[string]Target)
310	// osArchTypeMap maps OsTypes to the list of supported ArchTypes for that OS.
311	osArchTypeMap = map[OsType][]ArchType{}
312
313	// NoOsType is a placeholder for when no OS is needed.
314	NoOsType OsType
315	// Linux is the OS for the Linux kernel plus the glibc runtime.
316	Linux = newOsType("linux_glibc", Host, false, X86, X86_64)
317	// LinuxMusl is the OS for the Linux kernel plus the musl runtime.
318	LinuxMusl = newOsType("linux_musl", Host, false, X86, X86_64, Arm64, Arm)
319	// Darwin is the OS for MacOS/Darwin host machines.
320	Darwin = newOsType("darwin", Host, false, Arm64, X86_64)
321	// LinuxBionic is the OS for the Linux kernel plus the Bionic libc runtime, but without the
322	// rest of Android.
323	LinuxBionic = newOsType("linux_bionic", Host, false, Arm64, X86_64)
324	// Windows the OS for Windows host machines.
325	Windows = newOsType("windows", Host, true, X86, X86_64)
326	// Android is the OS for target devices that run all of Android, including the Linux kernel
327	// and the Bionic libc runtime.
328	Android = newOsType("android", Device, false, Arm, Arm64, Riscv64, X86, X86_64)
329
330	// CommonOS is a pseudo OSType for a common OS variant, which is OsType agnostic and which
331	// has dependencies on all the OS variants.
332	CommonOS = newOsType("common_os", Generic, false)
333
334	// CommonArch is the Arch for all modules that are os-specific but not arch specific,
335	// for example most Java modules.
336	CommonArch = Arch{ArchType: Common}
337)
338
339// OsTypeList returns a slice copy of the supported OsTypes.
340func OsTypeList() []OsType {
341	return append([]OsType(nil), osTypeList...)
342}
343
344// Target specifies the OS and architecture that a module is being compiled for.
345type Target struct {
346	// Os the OS that the module is being compiled for (e.g. "linux_glibc", "android").
347	Os OsType
348	// Arch is the architecture that the module is being compiled for.
349	Arch Arch
350	// NativeBridge is NativeBridgeEnabled if the architecture is supported using NativeBridge
351	// (i.e. arm on x86) for this device.
352	NativeBridge NativeBridgeSupport
353	// NativeBridgeHostArchName is the name of the real architecture that is used to implement
354	// the NativeBridge architecture.  For example, for arm on x86 this would be "x86".
355	NativeBridgeHostArchName string
356	// NativeBridgeRelativePath is the name of the subdirectory that will contain NativeBridge
357	// libraries and binaries.
358	NativeBridgeRelativePath string
359
360	// HostCross is true when the target cannot run natively on the current build host.
361	// For example, linux_glibc_x86 returns true on a regular x86/i686/Linux machines, but returns false
362	// on Mac (different OS), or on 64-bit only i686/Linux machines (unsupported arch).
363	HostCross bool
364}
365
366// NativeBridgeSupport is an enum that specifies if a Target supports NativeBridge.
367type NativeBridgeSupport bool
368
369const (
370	NativeBridgeDisabled NativeBridgeSupport = false
371	NativeBridgeEnabled  NativeBridgeSupport = true
372)
373
374// String returns the OS and arch variations used for the Target.
375func (target Target) String() string {
376	return target.OsVariation() + "_" + target.ArchVariation()
377}
378
379// OsVariation returns the name of the variation used by the osMutator for the Target.
380func (target Target) OsVariation() string {
381	return target.Os.String()
382}
383
384// ArchVariation returns the name of the variation used by the archMutator for the Target.
385func (target Target) ArchVariation() string {
386	var variation string
387	if target.NativeBridge {
388		variation = "native_bridge_"
389	}
390	variation += target.Arch.String()
391
392	return variation
393}
394
395// Variations returns a list of blueprint.Variations for the osMutator and archMutator for the
396// Target.
397func (target Target) Variations() []blueprint.Variation {
398	return []blueprint.Variation{
399		{Mutator: "os", Variation: target.OsVariation()},
400		{Mutator: "arch", Variation: target.ArchVariation()},
401	}
402}
403
404// osMutator splits an arch-specific module into a variant for each OS that is enabled for the
405// module.  It uses the HostOrDevice value passed to InitAndroidArchModule and the
406// device_supported and host_supported properties to determine which OsTypes are enabled for this
407// module, then searches through the Targets to determine which have enabled Targets for this
408// module.
409type osTransitionMutator struct{}
410
411type allOsInfo struct {
412	Os         map[string]OsType
413	Variations []string
414}
415
416var allOsProvider = blueprint.NewMutatorProvider[*allOsInfo]("os_propagate")
417
418// moduleOSList collects a list of OSTypes supported by this module based on the HostOrDevice
419// value passed to InitAndroidArchModule and the device_supported and host_supported properties.
420func moduleOSList(ctx ConfigContext, base *ModuleBase) []OsType {
421	var moduleOSList []OsType
422	for _, os := range osTypeList {
423		for _, t := range ctx.Config().Targets[os] {
424			if base.supportsTarget(t) {
425				moduleOSList = append(moduleOSList, os)
426				break
427			}
428		}
429	}
430
431	if base.commonProperties.CreateCommonOSVariant {
432		// A CommonOS variant was requested so add it to the list of OS variants to
433		// create. It needs to be added to the end because it needs to depend on the
434		// the other variants and inter variant dependencies can only be created from a
435		// later variant in that list to an earlier one. That is because variants are
436		// always processed in the order in which they are created.
437		moduleOSList = append(moduleOSList, CommonOS)
438	}
439
440	return moduleOSList
441}
442
443func (o *osTransitionMutator) Split(ctx BaseModuleContext) []string {
444	module := ctx.Module()
445	base := module.base()
446
447	// Nothing to do for modules that are not architecture specific (e.g. a genrule).
448	if !base.ArchSpecific() {
449		return []string{""}
450	}
451
452	moduleOSList := moduleOSList(ctx, base)
453
454	// If there are no supported OSes then disable the module.
455	if len(moduleOSList) == 0 {
456		base.Disable()
457		return []string{""}
458	}
459
460	// Convert the list of supported OsTypes to the variation names.
461	osNames := make([]string, len(moduleOSList))
462	osMapping := make(map[string]OsType, len(moduleOSList))
463	for i, os := range moduleOSList {
464		osNames[i] = os.String()
465		osMapping[osNames[i]] = os
466	}
467
468	SetProvider(ctx, allOsProvider, &allOsInfo{
469		Os:         osMapping,
470		Variations: osNames,
471	})
472
473	return osNames
474}
475
476func (o *osTransitionMutator) OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string {
477	return sourceVariation
478}
479
480func (o *osTransitionMutator) IncomingTransition(ctx IncomingTransitionContext, incomingVariation string) string {
481	module := ctx.Module()
482	base := module.base()
483
484	if !base.ArchSpecific() {
485		return ""
486	}
487
488	return incomingVariation
489}
490
491func (o *osTransitionMutator) Mutate(ctx BottomUpMutatorContext, variation string) {
492	module := ctx.Module()
493	base := module.base()
494
495	if variation == "" {
496		return
497	}
498
499	allOsInfo, ok := ModuleProvider(ctx, allOsProvider)
500	if !ok {
501		panic(fmt.Errorf("missing allOsProvider"))
502	}
503
504	// Annotate this variant with which OS it was created for, and
505	// squash the appropriate OS-specific properties into the top level properties.
506	base.commonProperties.CompileOS = allOsInfo.Os[variation]
507	base.setOSProperties(ctx)
508
509	if variation == CommonOS.String() {
510		// A CommonOS variant was requested so add dependencies from it (the last one in
511		// the list) to the OS type specific variants.
512		osList := allOsInfo.Variations[:len(allOsInfo.Variations)-1]
513		for _, os := range osList {
514			variation := []blueprint.Variation{{"os", os}}
515			ctx.AddVariationDependencies(variation, commonOsToOsSpecificVariantTag, ctx.ModuleName())
516		}
517	}
518}
519
520type archDepTag struct {
521	blueprint.BaseDependencyTag
522	name string
523}
524
525// Identifies the dependency from CommonOS variant to the os specific variants.
526var commonOsToOsSpecificVariantTag = archDepTag{name: "common os to os specific"}
527
528// Get the OsType specific variants for the current CommonOS variant.
529//
530// The returned list will only contain enabled OsType specific variants of the
531// module referenced in the supplied context. An empty list is returned if there
532// are no enabled variants or the supplied context is not for an CommonOS
533// variant.
534func GetOsSpecificVariantsOfCommonOSVariant(mctx BaseModuleContext) []Module {
535	var variants []Module
536	mctx.VisitDirectDeps(func(m Module) {
537		if mctx.OtherModuleDependencyTag(m) == commonOsToOsSpecificVariantTag {
538			if m.Enabled(mctx) {
539				variants = append(variants, m)
540			}
541		}
542	})
543	return variants
544}
545
546var DarwinUniversalVariantTag = archDepTag{name: "darwin universal binary"}
547
548// archTransitionMutator splits a module into a variant for each Target requested by the module.  Target selection
549// for a module is in three levels, OsClass, multilib, and then Target.
550// OsClass selection is determined by:
551//   - The HostOrDeviceSupported value passed in to InitAndroidArchModule by the module type factory, which selects
552//     whether the module type can compile for host, device or both.
553//   - The host_supported and device_supported properties on the module.
554//
555// If host is supported for the module, the Host and HostCross OsClasses are selected.  If device is supported
556// for the module, the Device OsClass is selected.
557// Within each selected OsClass, the multilib selection is determined by:
558//   - The compile_multilib property if it set (which may be overridden by target.android.compile_multilib or
559//     target.host.compile_multilib).
560//   - The default multilib passed to InitAndroidArchModule if compile_multilib was not set.
561//
562// Valid multilib values include:
563//
564//	"both": compile for all Targets supported by the OsClass (generally x86_64 and x86, or arm64 and arm).
565//	"first": compile for only a single preferred Target supported by the OsClass.  This is generally x86_64 or arm64,
566//	    but may be arm for a 32-bit only build.
567//	"32": compile for only a single 32-bit Target supported by the OsClass.
568//	"64": compile for only a single 64-bit Target supported by the OsClass.
569//	"common": compile a for a single Target that will work on all Targets supported by the OsClass (for example Java).
570//
571// Once the list of Targets is determined, the module is split into a variant for each Target.
572//
573// Modules can be initialized with InitAndroidMultiTargetsArchModule, in which case they will be split by OsClass,
574// but will have a common Target that is expected to handle all other selected Targets via ctx.MultiTargets().
575type archTransitionMutator struct{}
576
577type allArchInfo struct {
578	Targets      map[string]Target
579	MultiTargets []Target
580	Primary      string
581	Multilib     string
582}
583
584var allArchProvider = blueprint.NewMutatorProvider[*allArchInfo]("arch_propagate")
585
586func (a *archTransitionMutator) Split(ctx BaseModuleContext) []string {
587	module := ctx.Module()
588	base := module.base()
589
590	if !base.ArchSpecific() {
591		return []string{""}
592	}
593
594	os := base.commonProperties.CompileOS
595	if os == CommonOS {
596		// Do not create arch specific variants for the CommonOS variant.
597		return []string{""}
598	}
599
600	osTargets := ctx.Config().Targets[os]
601
602	image := base.commonProperties.ImageVariation
603	// Filter NativeBridge targets unless they are explicitly supported.
604	// Skip creating native bridge variants for non-core modules.
605	if os == Android && !(base.IsNativeBridgeSupported() && image == CoreVariation) {
606		osTargets = slices.DeleteFunc(slices.Clone(osTargets), func(t Target) bool {
607			return bool(t.NativeBridge)
608		})
609	}
610
611	// Filter HostCross targets if disabled.
612	if base.HostSupported() && !base.HostCrossSupported() {
613		osTargets = slices.DeleteFunc(slices.Clone(osTargets), func(t Target) bool {
614			return t.HostCross
615		})
616	}
617
618	// only the primary arch in the ramdisk / vendor_ramdisk / recovery partition
619	if os == Android && (module.InstallInRecovery() || module.InstallInRamdisk() || module.InstallInVendorRamdisk() || module.InstallInDebugRamdisk()) {
620		osTargets = []Target{osTargets[0]}
621	}
622
623	// Windows builds always prefer 32-bit
624	prefer32 := os == Windows
625
626	// Determine the multilib selection for this module.
627	multilib, extraMultilib := decodeMultilib(ctx, base)
628
629	// Convert the multilib selection into a list of Targets.
630	targets, err := decodeMultilibTargets(multilib, osTargets, prefer32)
631	if err != nil {
632		ctx.ModuleErrorf("%s", err.Error())
633	}
634
635	// If there are no supported targets disable the module.
636	if len(targets) == 0 {
637		base.Disable()
638		return []string{""}
639	}
640
641	// If the module is using extraMultilib, decode the extraMultilib selection into
642	// a separate list of Targets.
643	var multiTargets []Target
644	if extraMultilib != "" {
645		multiTargets, err = decodeMultilibTargets(extraMultilib, osTargets, prefer32)
646		if err != nil {
647			ctx.ModuleErrorf("%s", err.Error())
648		}
649		multiTargets = filterHostCross(multiTargets, targets[0].HostCross)
650	}
651
652	// Recovery is always the primary architecture, filter out any other architectures.
653	// Common arch is also allowed
654	if image == RecoveryVariation {
655		primaryArch := ctx.Config().DevicePrimaryArchType()
656		targets = filterToArch(targets, primaryArch, Common)
657		multiTargets = filterToArch(multiTargets, primaryArch, Common)
658	}
659
660	// If there are no supported targets disable the module.
661	if len(targets) == 0 {
662		base.Disable()
663		return []string{""}
664	}
665
666	// Convert the targets into a list of arch variation names.
667	targetNames := make([]string, len(targets))
668	targetMapping := make(map[string]Target, len(targets))
669	for i, target := range targets {
670		targetNames[i] = target.ArchVariation()
671		targetMapping[targetNames[i]] = targets[i]
672	}
673
674	SetProvider(ctx, allArchProvider, &allArchInfo{
675		Targets:      targetMapping,
676		MultiTargets: multiTargets,
677		Primary:      targetNames[0],
678		Multilib:     multilib,
679	})
680	return targetNames
681}
682
683func (a *archTransitionMutator) OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string {
684	return sourceVariation
685}
686
687func (a *archTransitionMutator) IncomingTransition(ctx IncomingTransitionContext, incomingVariation string) string {
688	module := ctx.Module()
689	base := module.base()
690
691	if !base.ArchSpecific() {
692		return ""
693	}
694
695	os := base.commonProperties.CompileOS
696	if os == CommonOS {
697		// Do not create arch specific variants for the CommonOS variant.
698		return ""
699	}
700
701	multilib, _ := decodeMultilib(ctx, base)
702	if multilib == "common" {
703		return "common"
704	}
705	return incomingVariation
706}
707
708func (a *archTransitionMutator) Mutate(ctx BottomUpMutatorContext, variation string) {
709	module := ctx.Module()
710	base := module.base()
711	os := base.commonProperties.CompileOS
712
713	if os == CommonOS {
714		// Make sure that the target related properties are initialized for the
715		// CommonOS variant.
716		addTargetProperties(module, commonTargetMap[os.Name], nil, true)
717		return
718	}
719
720	if variation == "" {
721		return
722	}
723
724	if !base.ArchSpecific() {
725		panic(fmt.Errorf("found variation %q for non arch specifc module", variation))
726	}
727
728	allArchInfo, ok := ModuleProvider(ctx, allArchProvider)
729	if !ok {
730		return
731	}
732
733	target, ok := allArchInfo.Targets[variation]
734	if !ok {
735		panic(fmt.Errorf("missing Target for %q", variation))
736	}
737	primary := variation == allArchInfo.Primary
738	multiTargets := allArchInfo.MultiTargets
739
740	// Annotate the new variant with which Target it was created for, and
741	// squash the appropriate arch-specific properties into the top level properties.
742	addTargetProperties(ctx.Module(), target, multiTargets, primary)
743	base.setArchProperties(ctx)
744
745	// Install support doesn't understand Darwin+Arm64
746	if os == Darwin && target.HostCross {
747		base.commonProperties.SkipInstall = true
748	}
749
750	// Create a dependency for Darwin Universal binaries from the primary to secondary
751	// architecture. The module itself will be responsible for calling lipo to merge the outputs.
752	if os == Darwin {
753		isUniversalBinary := allArchInfo.Multilib == "darwin_universal" && len(allArchInfo.Targets) == 2
754		isPrimary := variation == ctx.Config().BuildArch.String()
755		hasSecondaryConfigured := len(ctx.Config().Targets[Darwin]) > 1
756		if isUniversalBinary && isPrimary && hasSecondaryConfigured {
757			secondaryArch := ctx.Config().Targets[Darwin][1].Arch.String()
758			variation := []blueprint.Variation{{"arch", secondaryArch}}
759			ctx.AddVariationDependencies(variation, DarwinUniversalVariantTag, ctx.ModuleName())
760		}
761	}
762
763}
764
765// addTargetProperties annotates a variant with the Target is is being compiled for, the list
766// of additional Targets it is supporting (if any), and whether it is the primary Target for
767// the module.
768func addTargetProperties(m Module, target Target, multiTargets []Target, primaryTarget bool) {
769	m.base().commonProperties.CompileTarget = target
770	m.base().commonProperties.CompileMultiTargets = multiTargets
771	m.base().commonProperties.CompilePrimary = primaryTarget
772	m.base().commonProperties.ArchReady = true
773}
774
775// decodeMultilib returns the appropriate compile_multilib property for the module, or the default
776// multilib from the factory's call to InitAndroidArchModule if none was set.  For modules that
777// called InitAndroidMultiTargetsArchModule it always returns "common" for multilib, and returns
778// the actual multilib in extraMultilib.
779func decodeMultilib(ctx ConfigContext, base *ModuleBase) (multilib, extraMultilib string) {
780	os := base.commonProperties.CompileOS
781	ignorePrefer32OnDevice := ctx.Config().IgnorePrefer32OnDevice()
782	// First check the "android.compile_multilib" or "host.compile_multilib" properties.
783	switch os.Class {
784	case Device:
785		multilib = String(base.commonProperties.Target.Android.Compile_multilib)
786	case Host:
787		multilib = String(base.commonProperties.Target.Host.Compile_multilib)
788	}
789
790	// If those aren't set, try the "compile_multilib" property.
791	if multilib == "" {
792		multilib = String(base.commonProperties.Compile_multilib)
793	}
794
795	// If that wasn't set, use the default multilib set by the factory.
796	if multilib == "" {
797		multilib = base.commonProperties.Default_multilib
798	}
799
800	// If a device is configured with multiple targets, this option
801	// force all device targets that prefer32 to be compiled only as
802	// the first target.
803	if ignorePrefer32OnDevice && os.Class == Device && (multilib == "prefer32" || multilib == "first_prefer32") {
804		multilib = "first"
805	}
806
807	if base.commonProperties.UseTargetVariants {
808		// Darwin has the concept of "universal binaries" which is implemented in Soong by
809		// building both x86_64 and arm64 variants, and having select module types know how to
810		// merge the outputs of their corresponding variants together into a final binary. Most
811		// module types don't need to understand this logic, as we only build a small portion
812		// of the tree for Darwin, and only module types writing macho files need to do the
813		// merging.
814		//
815		// This logic is not enabled for:
816		//  "common", as it's not an arch-specific variant
817		//  "32", as Darwin never has a 32-bit variant
818		//  !UseTargetVariants, as the module has opted into handling the arch-specific logic on
819		//    its own.
820		if os == Darwin && multilib != "common" && multilib != "32" {
821			multilib = "darwin_universal"
822		}
823
824		return multilib, ""
825	} else {
826		// For app modules a single arch variant will be created per OS class which is expected to handle all the
827		// selected arches.  Return the common-type as multilib and any Android.bp provided multilib as extraMultilib
828		if multilib == base.commonProperties.Default_multilib {
829			multilib = "first"
830		}
831		return base.commonProperties.Default_multilib, multilib
832	}
833}
834
835// filterToArch takes a list of Targets and an ArchType, and returns a modified list that contains
836// only Targets that have the specified ArchTypes.
837func filterToArch(targets []Target, archs ...ArchType) []Target {
838	for i := 0; i < len(targets); i++ {
839		found := false
840		for _, arch := range archs {
841			if targets[i].Arch.ArchType == arch {
842				found = true
843				break
844			}
845		}
846		if !found {
847			targets = append(targets[:i], targets[i+1:]...)
848			i--
849		}
850	}
851	return targets
852}
853
854// filterHostCross takes a list of Targets and a hostCross value, and returns a modified list
855// that contains only Targets that have the specified HostCross.
856func filterHostCross(targets []Target, hostCross bool) []Target {
857	for i := 0; i < len(targets); i++ {
858		if targets[i].HostCross != hostCross {
859			targets = append(targets[:i], targets[i+1:]...)
860			i--
861		}
862	}
863	return targets
864}
865
866// archPropRoot is a struct type used as the top level of the arch-specific properties.  It
867// contains the "arch", "multilib", and "target" property structs.  It is used to split up the
868// property structs to limit how much is allocated when a single arch-specific property group is
869// used.  The types are interface{} because they will hold instances of runtime-created types.
870type archPropRoot struct {
871	Arch, Multilib, Target interface{}
872}
873
874// archPropTypeDesc holds the runtime-created types for the property structs to instantiate to
875// create an archPropRoot property struct.
876type archPropTypeDesc struct {
877	arch, multilib, target reflect.Type
878}
879
880// createArchPropTypeDesc takes a reflect.Type that is either a struct or a pointer to a struct, and
881// returns lists of reflect.Types that contains the arch-variant properties inside structs for each
882// arch, multilib and target property.
883//
884// This is a relatively expensive operation, so the results are cached in the global
885// archPropTypeMap.  It is constructed entirely based on compile-time data, so there is no need
886// to isolate the results between multiple tests running in parallel.
887func createArchPropTypeDesc(props reflect.Type) []archPropTypeDesc {
888	// Each property struct shard will be nested many times under the runtime generated arch struct,
889	// which can hit the limit of 64kB for the name of runtime generated structs.  They are nested
890	// 97 times now, which may grow in the future, plus there is some overhead for the containing
891	// type.  This number may need to be reduced if too many are added, but reducing it too far
892	// could cause problems if a single deeply nested property no longer fits in the name.
893	const maxArchTypeNameSize = 500
894
895	// Convert the type to a new set of types that contains only the arch-specific properties
896	// (those that are tagged with `android:"arch_variant"`), and sharded into multiple types
897	// to keep the runtime-generated names under the limit.
898	propShards, _ := proptools.FilterPropertyStructSharded(props, maxArchTypeNameSize, filterArchStruct)
899
900	// If the type has no arch-specific properties there is nothing to do.
901	if len(propShards) == 0 {
902		return nil
903	}
904
905	var ret []archPropTypeDesc
906	for _, props := range propShards {
907
908		// variantFields takes a list of variant property field names and returns a list the
909		// StructFields with the names and the type of the current shard.
910		variantFields := func(names []string) []reflect.StructField {
911			ret := make([]reflect.StructField, len(names))
912
913			for i, name := range names {
914				ret[i].Name = name
915				ret[i].Type = props
916			}
917
918			return ret
919		}
920
921		// Create a type that contains the properties in this shard repeated for each
922		// architecture, architecture variant, and architecture feature.
923		archFields := make([]reflect.StructField, len(archTypeList))
924		for i, arch := range archTypeList {
925			var variants []string
926
927			for _, archVariant := range archVariants[arch] {
928				archVariant := variantReplacer.Replace(archVariant)
929				variants = append(variants, proptools.FieldNameForProperty(archVariant))
930			}
931			for _, cpuVariant := range cpuVariants[arch] {
932				cpuVariant := variantReplacer.Replace(cpuVariant)
933				variants = append(variants, proptools.FieldNameForProperty(cpuVariant))
934			}
935			for _, feature := range archFeatures[arch] {
936				feature := variantReplacer.Replace(feature)
937				variants = append(variants, proptools.FieldNameForProperty(feature))
938			}
939
940			// Create the StructFields for each architecture variant architecture feature
941			// (e.g. "arch.arm.cortex-a53" or "arch.arm.neon").
942			fields := variantFields(variants)
943
944			// Create the StructField for the architecture itself (e.g. "arch.arm").  The special
945			// "BlueprintEmbed" name is used by Blueprint to put the properties in the
946			// parent struct.
947			fields = append([]reflect.StructField{{
948				Name:      "BlueprintEmbed",
949				Type:      props,
950				Anonymous: true,
951			}}, fields...)
952
953			archFields[i] = reflect.StructField{
954				Name: arch.Field,
955				Type: reflect.StructOf(fields),
956			}
957		}
958
959		// Create the type of the "arch" property struct for this shard.
960		archType := reflect.StructOf(archFields)
961
962		// Create the type for the "multilib" property struct for this shard, containing the
963		// "multilib.lib32" and "multilib.lib64" property structs.
964		multilibType := reflect.StructOf(variantFields([]string{"Lib32", "Lib64"}))
965
966		// Start with a list of the special targets
967		targets := []string{
968			"Host",
969			"Android64",
970			"Android32",
971			"Bionic",
972			"Glibc",
973			"Musl",
974			"Linux",
975			"Host_linux",
976			"Not_windows",
977			"Arm_on_x86",
978			"Arm_on_x86_64",
979			"Native_bridge",
980		}
981		for _, os := range osTypeList {
982			// Add all the OSes.
983			targets = append(targets, os.Field)
984
985			// Add the OS/Arch combinations, e.g. "android_arm64".
986			for _, archType := range osArchTypeMap[os] {
987				targets = append(targets, GetCompoundTargetField(os, archType))
988
989				// Also add the special "linux_<arch>", "bionic_<arch>" , "glibc_<arch>", and
990				// "musl_<arch>" property structs.
991				if os.Linux() {
992					target := "Linux_" + archType.Name
993					if !InList(target, targets) {
994						targets = append(targets, target)
995					}
996				}
997				if os.Linux() && os.Class == Host {
998					target := "Host_linux_" + archType.Name
999					if !InList(target, targets) {
1000						targets = append(targets, target)
1001					}
1002				}
1003				if os.Bionic() {
1004					target := "Bionic_" + archType.Name
1005					if !InList(target, targets) {
1006						targets = append(targets, target)
1007					}
1008				}
1009				if os == Linux {
1010					target := "Glibc_" + archType.Name
1011					if !InList(target, targets) {
1012						targets = append(targets, target)
1013					}
1014				}
1015				if os == LinuxMusl {
1016					target := "Musl_" + archType.Name
1017					if !InList(target, targets) {
1018						targets = append(targets, target)
1019					}
1020				}
1021			}
1022		}
1023
1024		// Create the type for the "target" property struct for this shard.
1025		targetType := reflect.StructOf(variantFields(targets))
1026
1027		// Return a descriptor of the 3 runtime-created types.
1028		ret = append(ret, archPropTypeDesc{
1029			arch:     reflect.PtrTo(archType),
1030			multilib: reflect.PtrTo(multilibType),
1031			target:   reflect.PtrTo(targetType),
1032		})
1033	}
1034	return ret
1035}
1036
1037// variantReplacer converts architecture variant or architecture feature names into names that
1038// are valid for an Android.bp file.
1039var variantReplacer = strings.NewReplacer("-", "_", ".", "_")
1040
1041// filterArchStruct returns true if the given field is an architecture specific property.
1042func filterArchStruct(field reflect.StructField, prefix string) (bool, reflect.StructField) {
1043	if proptools.HasTag(field, "android", "arch_variant") {
1044		// The arch_variant field isn't necessary past this point
1045		// Instead of wasting space, just remove it. Go also has a
1046		// 16-bit limit on structure name length. The name is constructed
1047		// based on the Go source representation of the structure, so
1048		// the tag names count towards that length.
1049
1050		androidTag := field.Tag.Get("android")
1051		values := strings.Split(androidTag, ",")
1052
1053		if string(field.Tag) != `android:"`+strings.Join(values, ",")+`"` {
1054			panic(fmt.Errorf("unexpected tag format %q", field.Tag))
1055		}
1056		// these tags don't need to be present in the runtime generated struct type.
1057		// However replace_instead_of_append does, because it's read by the blueprint
1058		// property extending util functions, which can operate on these generated arch
1059		// property structs.
1060		values = RemoveListFromList(values, []string{"arch_variant", "variant_prepend", "path"})
1061		if len(values) > 0 {
1062			if values[0] != "replace_instead_of_append" || len(values) > 1 {
1063				panic(fmt.Errorf("unknown tags %q in field %q", values, prefix+field.Name))
1064			}
1065			field.Tag = `android:"replace_instead_of_append"`
1066		} else {
1067			field.Tag = ``
1068		}
1069		return true, field
1070	}
1071	return false, field
1072}
1073
1074// archPropTypeMap contains a cache of the results of createArchPropTypeDesc for each type.  It is
1075// shared across all Contexts, but is constructed based only on compile-time information so there
1076// is no risk of contaminating one Context with data from another.
1077var archPropTypeMap OncePer
1078
1079// initArchModule adds the architecture-specific property structs to a Module.
1080func initArchModule(m Module) {
1081
1082	base := m.base()
1083
1084	if len(base.archProperties) != 0 {
1085		panic(fmt.Errorf("module %s already has archProperties", m.Name()))
1086	}
1087
1088	getStructType := func(properties interface{}) reflect.Type {
1089		propertiesValue := reflect.ValueOf(properties)
1090		t := propertiesValue.Type()
1091		if propertiesValue.Kind() != reflect.Ptr {
1092			panic(fmt.Errorf("properties must be a pointer to a struct, got %T",
1093				propertiesValue.Interface()))
1094		}
1095
1096		propertiesValue = propertiesValue.Elem()
1097		if propertiesValue.Kind() != reflect.Struct {
1098			panic(fmt.Errorf("properties must be a pointer to a struct, got a pointer to %T",
1099				propertiesValue.Interface()))
1100		}
1101		return t
1102	}
1103
1104	for _, properties := range m.GetProperties() {
1105		t := getStructType(properties)
1106		// Get or create the arch-specific property struct types for this property struct type.
1107		archPropTypes := archPropTypeMap.Once(NewCustomOnceKey(t), func() interface{} {
1108			return createArchPropTypeDesc(t)
1109		}).([]archPropTypeDesc)
1110
1111		// Instantiate one of each arch-specific property struct type and add it to the
1112		// properties for the Module.
1113		var archProperties []interface{}
1114		for _, t := range archPropTypes {
1115			archProperties = append(archProperties, &archPropRoot{
1116				Arch:     reflect.Zero(t.arch).Interface(),
1117				Multilib: reflect.Zero(t.multilib).Interface(),
1118				Target:   reflect.Zero(t.target).Interface(),
1119			})
1120		}
1121		base.archProperties = append(base.archProperties, archProperties)
1122		m.AddProperties(archProperties...)
1123	}
1124
1125}
1126
1127func maybeBlueprintEmbed(src reflect.Value) reflect.Value {
1128	// If the value of the field is a struct (as opposed to a pointer to a struct) then step
1129	// into the BlueprintEmbed field.
1130	if src.Kind() == reflect.Struct {
1131		return src.FieldByName("BlueprintEmbed")
1132	} else {
1133		return src
1134	}
1135}
1136
1137// Merges the property struct in srcValue into dst.
1138func mergePropertyStruct(ctx ArchVariantContext, dst interface{}, srcValue reflect.Value) {
1139	src := maybeBlueprintEmbed(srcValue).Interface()
1140
1141	// order checks the `android:"variant_prepend"` tag to handle properties where the
1142	// arch-specific value needs to come before the generic value, for example for lists of
1143	// include directories.
1144	order := func(dstField, srcField reflect.StructField) (proptools.Order, error) {
1145		if proptools.HasTag(dstField, "android", "variant_prepend") {
1146			return proptools.Prepend, nil
1147		} else {
1148			return proptools.Append, nil
1149		}
1150	}
1151
1152	// Squash the located property struct into the destination property struct.
1153	err := proptools.ExtendMatchingProperties([]interface{}{dst}, src, nil, order)
1154	if err != nil {
1155		if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
1156			ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
1157		} else {
1158			panic(err)
1159		}
1160	}
1161}
1162
1163// Returns the immediate child of the input property struct that corresponds to
1164// the sub-property "field".
1165func getChildPropertyStruct(ctx ArchVariantContext,
1166	src reflect.Value, field, userFriendlyField string) (reflect.Value, bool) {
1167
1168	// Step into non-nil pointers to structs in the src value.
1169	if src.Kind() == reflect.Ptr {
1170		if src.IsNil() {
1171			return reflect.Value{}, false
1172		}
1173		src = src.Elem()
1174	}
1175
1176	// Find the requested field in the src struct.
1177	child := src.FieldByName(proptools.FieldNameForProperty(field))
1178	if !child.IsValid() {
1179		ctx.ModuleErrorf("field %q does not exist", userFriendlyField)
1180		return reflect.Value{}, false
1181	}
1182
1183	if child.IsZero() {
1184		return reflect.Value{}, false
1185	}
1186
1187	return child, true
1188}
1189
1190// Squash the appropriate OS-specific property structs into the matching top level property structs
1191// based on the CompileOS value that was annotated on the variant.
1192func (m *ModuleBase) setOSProperties(ctx BottomUpMutatorContext) {
1193	os := m.commonProperties.CompileOS
1194
1195	for i := range m.archProperties {
1196		genProps := m.GetProperties()[i]
1197		if m.archProperties[i] == nil {
1198			continue
1199		}
1200		for _, archProperties := range m.archProperties[i] {
1201			archPropValues := reflect.ValueOf(archProperties).Elem()
1202
1203			targetProp := archPropValues.FieldByName("Target").Elem()
1204
1205			// Handle host-specific properties in the form:
1206			// target: {
1207			//     host: {
1208			//         key: value,
1209			//     },
1210			// },
1211			if os.Class == Host {
1212				field := "Host"
1213				prefix := "target.host"
1214				if hostProperties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
1215					mergePropertyStruct(ctx, genProps, hostProperties)
1216				}
1217			}
1218
1219			// Handle target OS generalities of the form:
1220			// target: {
1221			//     bionic: {
1222			//         key: value,
1223			//     },
1224			// }
1225			if os.Linux() {
1226				field := "Linux"
1227				prefix := "target.linux"
1228				if linuxProperties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
1229					mergePropertyStruct(ctx, genProps, linuxProperties)
1230				}
1231			}
1232
1233			if os.Linux() && os.Class == Host {
1234				field := "Host_linux"
1235				prefix := "target.host_linux"
1236				if linuxProperties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
1237					mergePropertyStruct(ctx, genProps, linuxProperties)
1238				}
1239			}
1240
1241			if os.Bionic() {
1242				field := "Bionic"
1243				prefix := "target.bionic"
1244				if bionicProperties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
1245					mergePropertyStruct(ctx, genProps, bionicProperties)
1246				}
1247			}
1248
1249			if os == Linux {
1250				field := "Glibc"
1251				prefix := "target.glibc"
1252				if bionicProperties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
1253					mergePropertyStruct(ctx, genProps, bionicProperties)
1254				}
1255			}
1256
1257			if os == LinuxMusl {
1258				field := "Musl"
1259				prefix := "target.musl"
1260				if bionicProperties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
1261					mergePropertyStruct(ctx, genProps, bionicProperties)
1262				}
1263			}
1264
1265			// Handle target OS properties in the form:
1266			// target: {
1267			//     linux_glibc: {
1268			//         key: value,
1269			//     },
1270			//     not_windows: {
1271			//         key: value,
1272			//     },
1273			//     android {
1274			//         key: value,
1275			//     },
1276			// },
1277			field := os.Field
1278			prefix := "target." + os.Name
1279			if osProperties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
1280				mergePropertyStruct(ctx, genProps, osProperties)
1281			}
1282
1283			if os.Class == Host && os != Windows {
1284				field := "Not_windows"
1285				prefix := "target.not_windows"
1286				if notWindowsProperties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
1287					mergePropertyStruct(ctx, genProps, notWindowsProperties)
1288				}
1289			}
1290
1291			// Handle 64-bit device properties in the form:
1292			// target {
1293			//     android64 {
1294			//         key: value,
1295			//     },
1296			//     android32 {
1297			//         key: value,
1298			//     },
1299			// },
1300			// WARNING: this is probably not what you want to use in your blueprints file, it selects
1301			// options for all targets on a device that supports 64-bit binaries, not just the targets
1302			// that are being compiled for 64-bit.  Its expected use case is binaries like linker and
1303			// debuggerd that need to know when they are a 32-bit process running on a 64-bit device
1304			if os.Class == Device {
1305				if ctx.Config().Android64() {
1306					field := "Android64"
1307					prefix := "target.android64"
1308					if android64Properties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
1309						mergePropertyStruct(ctx, genProps, android64Properties)
1310					}
1311				} else {
1312					field := "Android32"
1313					prefix := "target.android32"
1314					if android32Properties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
1315						mergePropertyStruct(ctx, genProps, android32Properties)
1316					}
1317				}
1318			}
1319		}
1320	}
1321}
1322
1323// Returns the struct containing the properties specific to the given
1324// architecture type. These look like this in Blueprint files:
1325//
1326//	arch: {
1327//	    arm64: {
1328//	        key: value,
1329//	    },
1330//	},
1331//
1332// This struct will also contain sub-structs containing to the architecture/CPU
1333// variants and features that themselves contain properties specific to those.
1334func getArchTypeStruct(ctx ArchVariantContext, archProperties interface{}, archType ArchType) (reflect.Value, bool) {
1335	archPropValues := reflect.ValueOf(archProperties).Elem()
1336	archProp := archPropValues.FieldByName("Arch").Elem()
1337	prefix := "arch." + archType.Name
1338	return getChildPropertyStruct(ctx, archProp, archType.Name, prefix)
1339}
1340
1341// Returns the struct containing the properties specific to a given multilib
1342// value. These look like this in the Blueprint file:
1343//
1344//	multilib: {
1345//	    lib32: {
1346//	        key: value,
1347//	    },
1348//	},
1349func getMultilibStruct(ctx ArchVariantContext, archProperties interface{}, archType ArchType) (reflect.Value, bool) {
1350	archPropValues := reflect.ValueOf(archProperties).Elem()
1351	multilibProp := archPropValues.FieldByName("Multilib").Elem()
1352	return getChildPropertyStruct(ctx, multilibProp, archType.Multilib, "multilib."+archType.Multilib)
1353}
1354
1355func GetCompoundTargetField(os OsType, arch ArchType) string {
1356	return os.Field + "_" + arch.Name
1357}
1358
1359// Returns the structs corresponding to the properties specific to the given
1360// architecture and OS in archProperties.
1361func getArchProperties(ctx BaseModuleContext, archProperties interface{}, arch Arch, os OsType, nativeBridgeEnabled bool) []reflect.Value {
1362	result := make([]reflect.Value, 0)
1363	archPropValues := reflect.ValueOf(archProperties).Elem()
1364
1365	targetProp := archPropValues.FieldByName("Target").Elem()
1366
1367	archType := arch.ArchType
1368
1369	if arch.ArchType != Common {
1370		archStruct, ok := getArchTypeStruct(ctx, archProperties, arch.ArchType)
1371		if ok {
1372			result = append(result, archStruct)
1373
1374			// Handle arch-variant-specific properties in the form:
1375			// arch: {
1376			//     arm: {
1377			//         variant: {
1378			//             key: value,
1379			//         },
1380			//     },
1381			// },
1382			v := variantReplacer.Replace(arch.ArchVariant)
1383			if v != "" {
1384				prefix := "arch." + archType.Name + "." + v
1385				if variantProperties, ok := getChildPropertyStruct(ctx, archStruct, v, prefix); ok {
1386					result = append(result, variantProperties)
1387				}
1388			}
1389
1390			// Handle cpu-variant-specific properties in the form:
1391			// arch: {
1392			//     arm: {
1393			//         variant: {
1394			//             key: value,
1395			//         },
1396			//     },
1397			// },
1398			if arch.CpuVariant != arch.ArchVariant {
1399				c := variantReplacer.Replace(arch.CpuVariant)
1400				if c != "" {
1401					prefix := "arch." + archType.Name + "." + c
1402					if cpuVariantProperties, ok := getChildPropertyStruct(ctx, archStruct, c, prefix); ok {
1403						result = append(result, cpuVariantProperties)
1404					}
1405				}
1406			}
1407
1408			// Handle arch-feature-specific properties in the form:
1409			// arch: {
1410			//     arm: {
1411			//         feature: {
1412			//             key: value,
1413			//         },
1414			//     },
1415			// },
1416			for _, feature := range arch.ArchFeatures {
1417				prefix := "arch." + archType.Name + "." + feature
1418				if featureProperties, ok := getChildPropertyStruct(ctx, archStruct, feature, prefix); ok {
1419					result = append(result, featureProperties)
1420				}
1421			}
1422		}
1423
1424		if multilibProperties, ok := getMultilibStruct(ctx, archProperties, archType); ok {
1425			result = append(result, multilibProperties)
1426		}
1427
1428		// Handle combined OS-feature and arch specific properties in the form:
1429		// target: {
1430		//     bionic_x86: {
1431		//         key: value,
1432		//     },
1433		// }
1434		if os.Linux() {
1435			field := "Linux_" + arch.ArchType.Name
1436			userFriendlyField := "target.linux_" + arch.ArchType.Name
1437			if linuxProperties, ok := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField); ok {
1438				result = append(result, linuxProperties)
1439			}
1440		}
1441
1442		if os.Bionic() {
1443			field := "Bionic_" + archType.Name
1444			userFriendlyField := "target.bionic_" + archType.Name
1445			if bionicProperties, ok := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField); ok {
1446				result = append(result, bionicProperties)
1447			}
1448		}
1449
1450		// Handle combined OS and arch specific properties in the form:
1451		// target: {
1452		//     linux_glibc_x86: {
1453		//         key: value,
1454		//     },
1455		//     linux_glibc_arm: {
1456		//         key: value,
1457		//     },
1458		//     android_arm {
1459		//         key: value,
1460		//     },
1461		//     android_x86 {
1462		//         key: value,
1463		//     },
1464		// },
1465		field := GetCompoundTargetField(os, archType)
1466		userFriendlyField := "target." + os.Name + "_" + archType.Name
1467		if osArchProperties, ok := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField); ok {
1468			result = append(result, osArchProperties)
1469		}
1470
1471		if os == Linux {
1472			field := "Glibc_" + archType.Name
1473			userFriendlyField := "target.glibc_" + "_" + archType.Name
1474			if osArchProperties, ok := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField); ok {
1475				result = append(result, osArchProperties)
1476			}
1477		}
1478
1479		if os == LinuxMusl {
1480			field := "Musl_" + archType.Name
1481			userFriendlyField := "target.musl_" + "_" + archType.Name
1482			if osArchProperties, ok := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField); ok {
1483				result = append(result, osArchProperties)
1484			}
1485		}
1486	}
1487
1488	// Handle arm on x86 properties in the form:
1489	// target {
1490	//     arm_on_x86 {
1491	//         key: value,
1492	//     },
1493	//     arm_on_x86_64 {
1494	//         key: value,
1495	//     },
1496	// },
1497	if os.Class == Device {
1498		if arch.ArchType == X86 && (hasArmAbi(arch) ||
1499			hasArmAndroidArch(ctx.Config().Targets[Android])) {
1500			field := "Arm_on_x86"
1501			userFriendlyField := "target.arm_on_x86"
1502			if armOnX86Properties, ok := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField); ok {
1503				result = append(result, armOnX86Properties)
1504			}
1505		}
1506		if arch.ArchType == X86_64 && (hasArmAbi(arch) ||
1507			hasArmAndroidArch(ctx.Config().Targets[Android])) {
1508			field := "Arm_on_x86_64"
1509			userFriendlyField := "target.arm_on_x86_64"
1510			if armOnX8664Properties, ok := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField); ok {
1511				result = append(result, armOnX8664Properties)
1512			}
1513		}
1514		if os == Android && nativeBridgeEnabled {
1515			userFriendlyField := "Native_bridge"
1516			prefix := "target.native_bridge"
1517			if nativeBridgeProperties, ok := getChildPropertyStruct(ctx, targetProp, userFriendlyField, prefix); ok {
1518				result = append(result, nativeBridgeProperties)
1519			}
1520		}
1521	}
1522
1523	return result
1524}
1525
1526// Squash the appropriate arch-specific property structs into the matching top level property
1527// structs based on the CompileTarget value that was annotated on the variant.
1528func (m *ModuleBase) setArchProperties(ctx BottomUpMutatorContext) {
1529	arch := m.Arch()
1530	os := m.Os()
1531
1532	for i := range m.archProperties {
1533		genProps := m.GetProperties()[i]
1534		if m.archProperties[i] == nil {
1535			continue
1536		}
1537
1538		propStructs := make([]reflect.Value, 0)
1539		for _, archProperty := range m.archProperties[i] {
1540			propStructShard := getArchProperties(ctx, archProperty, arch, os, m.Target().NativeBridge == NativeBridgeEnabled)
1541			propStructs = append(propStructs, propStructShard...)
1542		}
1543
1544		for _, propStruct := range propStructs {
1545			mergePropertyStruct(ctx, genProps, propStruct)
1546		}
1547	}
1548}
1549
1550// determineBuildOS stores the OS and architecture used for host targets used during the build into
1551// config based on the runtime OS and architecture determined by Go and the product configuration.
1552func determineBuildOS(config *config) {
1553	config.BuildOS = func() OsType {
1554		switch runtime.GOOS {
1555		case "linux":
1556			if Bool(config.productVariables.HostMusl) {
1557				return LinuxMusl
1558			}
1559			return Linux
1560		case "darwin":
1561			return Darwin
1562		default:
1563			panic(fmt.Sprintf("unsupported OS: %s", runtime.GOOS))
1564		}
1565	}()
1566
1567	config.BuildArch = func() ArchType {
1568		switch runtime.GOARCH {
1569		case "amd64":
1570			return X86_64
1571		default:
1572			panic(fmt.Sprintf("unsupported Arch: %s", runtime.GOARCH))
1573		}
1574	}()
1575
1576}
1577
1578// Convert the arch product variables into a list of targets for each OsType.
1579func decodeTargetProductVariables(config *config) (map[OsType][]Target, error) {
1580	variables := config.productVariables
1581
1582	targets := make(map[OsType][]Target)
1583	var targetErr error
1584
1585	type targetConfig struct {
1586		os                       OsType
1587		archName                 string
1588		archVariant              *string
1589		cpuVariant               *string
1590		abi                      []string
1591		nativeBridgeEnabled      NativeBridgeSupport
1592		nativeBridgeHostArchName *string
1593		nativeBridgeRelativePath *string
1594	}
1595
1596	addTarget := func(target targetConfig) {
1597		if targetErr != nil {
1598			return
1599		}
1600
1601		arch, err := decodeArch(target.os, target.archName, target.archVariant, target.cpuVariant, target.abi)
1602		if err != nil {
1603			targetErr = err
1604			return
1605		}
1606		nativeBridgeRelativePathStr := String(target.nativeBridgeRelativePath)
1607		nativeBridgeHostArchNameStr := String(target.nativeBridgeHostArchName)
1608
1609		// Use guest arch as relative install path by default
1610		if target.nativeBridgeEnabled && nativeBridgeRelativePathStr == "" {
1611			nativeBridgeRelativePathStr = arch.ArchType.String()
1612		}
1613
1614		// A target is considered as HostCross if it's a host target which can't run natively on
1615		// the currently configured build machine (either because the OS is different or because of
1616		// the unsupported arch)
1617		hostCross := false
1618		if target.os.Class == Host {
1619			var osSupported bool
1620			if target.os == config.BuildOS {
1621				osSupported = true
1622			} else if config.BuildOS.Linux() && target.os.Linux() {
1623				// LinuxBionic and Linux are compatible
1624				osSupported = true
1625			} else {
1626				osSupported = false
1627			}
1628
1629			var archSupported bool
1630			if arch.ArchType == Common {
1631				archSupported = true
1632			} else if arch.ArchType.Name == *variables.HostArch {
1633				archSupported = true
1634			} else if variables.HostSecondaryArch != nil && arch.ArchType.Name == *variables.HostSecondaryArch {
1635				archSupported = true
1636			} else {
1637				archSupported = false
1638			}
1639			if !osSupported || !archSupported {
1640				hostCross = true
1641			}
1642		}
1643
1644		targets[target.os] = append(targets[target.os],
1645			Target{
1646				Os:                       target.os,
1647				Arch:                     arch,
1648				NativeBridge:             target.nativeBridgeEnabled,
1649				NativeBridgeHostArchName: nativeBridgeHostArchNameStr,
1650				NativeBridgeRelativePath: nativeBridgeRelativePathStr,
1651				HostCross:                hostCross,
1652			})
1653	}
1654
1655	if variables.HostArch == nil {
1656		return nil, fmt.Errorf("No host primary architecture set")
1657	}
1658
1659	// The primary host target, which must always exist.
1660	addTarget(targetConfig{os: config.BuildOS, archName: *variables.HostArch, nativeBridgeEnabled: NativeBridgeDisabled})
1661
1662	// An optional secondary host target.
1663	if variables.HostSecondaryArch != nil && *variables.HostSecondaryArch != "" {
1664		addTarget(targetConfig{os: config.BuildOS, archName: *variables.HostSecondaryArch, nativeBridgeEnabled: NativeBridgeDisabled})
1665	}
1666
1667	// Optional cross-compiled host targets, generally Windows.
1668	if String(variables.CrossHost) != "" {
1669		crossHostOs := osByName(*variables.CrossHost)
1670		if crossHostOs == NoOsType {
1671			return nil, fmt.Errorf("Unknown cross host OS %q", *variables.CrossHost)
1672		}
1673
1674		if String(variables.CrossHostArch) == "" {
1675			return nil, fmt.Errorf("No cross-host primary architecture set")
1676		}
1677
1678		// The primary cross-compiled host target.
1679		addTarget(targetConfig{os: crossHostOs, archName: *variables.CrossHostArch, nativeBridgeEnabled: NativeBridgeDisabled})
1680
1681		// An optional secondary cross-compiled host target.
1682		if variables.CrossHostSecondaryArch != nil && *variables.CrossHostSecondaryArch != "" {
1683			addTarget(targetConfig{os: crossHostOs, archName: *variables.CrossHostSecondaryArch, nativeBridgeEnabled: NativeBridgeDisabled})
1684		}
1685	}
1686
1687	// Optional device targets
1688	if variables.DeviceArch != nil && *variables.DeviceArch != "" {
1689		// The primary device target.
1690		addTarget(targetConfig{
1691			os:                  Android,
1692			archName:            *variables.DeviceArch,
1693			archVariant:         variables.DeviceArchVariant,
1694			cpuVariant:          variables.DeviceCpuVariant,
1695			abi:                 variables.DeviceAbi,
1696			nativeBridgeEnabled: NativeBridgeDisabled,
1697		})
1698
1699		// An optional secondary device target.
1700		if variables.DeviceSecondaryArch != nil && *variables.DeviceSecondaryArch != "" {
1701			addTarget(targetConfig{
1702				os:                  Android,
1703				archName:            *variables.DeviceSecondaryArch,
1704				archVariant:         variables.DeviceSecondaryArchVariant,
1705				cpuVariant:          variables.DeviceSecondaryCpuVariant,
1706				abi:                 variables.DeviceSecondaryAbi,
1707				nativeBridgeEnabled: NativeBridgeDisabled,
1708			})
1709		}
1710
1711		// An optional NativeBridge device target.
1712		if variables.NativeBridgeArch != nil && *variables.NativeBridgeArch != "" {
1713			addTarget(targetConfig{
1714				os:                       Android,
1715				archName:                 *variables.NativeBridgeArch,
1716				archVariant:              variables.NativeBridgeArchVariant,
1717				cpuVariant:               variables.NativeBridgeCpuVariant,
1718				abi:                      variables.NativeBridgeAbi,
1719				nativeBridgeEnabled:      NativeBridgeEnabled,
1720				nativeBridgeHostArchName: variables.DeviceArch,
1721				nativeBridgeRelativePath: variables.NativeBridgeRelativePath,
1722			})
1723		}
1724
1725		// An optional secondary NativeBridge device target.
1726		if variables.DeviceSecondaryArch != nil && *variables.DeviceSecondaryArch != "" &&
1727			variables.NativeBridgeSecondaryArch != nil && *variables.NativeBridgeSecondaryArch != "" {
1728			addTarget(targetConfig{
1729				os:                       Android,
1730				archName:                 *variables.NativeBridgeSecondaryArch,
1731				archVariant:              variables.NativeBridgeSecondaryArchVariant,
1732				cpuVariant:               variables.NativeBridgeSecondaryCpuVariant,
1733				abi:                      variables.NativeBridgeSecondaryAbi,
1734				nativeBridgeEnabled:      NativeBridgeEnabled,
1735				nativeBridgeHostArchName: variables.DeviceSecondaryArch,
1736				nativeBridgeRelativePath: variables.NativeBridgeSecondaryRelativePath,
1737			})
1738		}
1739	}
1740
1741	if targetErr != nil {
1742		return nil, targetErr
1743	}
1744
1745	return targets, nil
1746}
1747
1748// hasArmAbi returns true if arch has at least one arm ABI
1749func hasArmAbi(arch Arch) bool {
1750	return PrefixInList(arch.Abi, "arm")
1751}
1752
1753// hasArmAndroidArch returns true if targets has at least
1754// one arm Android arch (possibly native bridged)
1755func hasArmAndroidArch(targets []Target) bool {
1756	for _, target := range targets {
1757		if target.Os == Android &&
1758			(target.Arch.ArchType == Arm || target.Arch.ArchType == Arm64) {
1759			return true
1760		}
1761	}
1762	return false
1763}
1764
1765// archConfig describes a built-in configuration.
1766type archConfig struct {
1767	Arch        string   `json:"arch"`
1768	ArchVariant string   `json:"arch_variant"`
1769	CpuVariant  string   `json:"cpu_variant"`
1770	Abi         []string `json:"abis"`
1771}
1772
1773// getNdkAbisConfig returns the list of archConfigs that are used for building
1774// the API stubs and static libraries that are included in the NDK.
1775func getNdkAbisConfig() []archConfig {
1776	return []archConfig{
1777		{"arm64", "armv8-a-branchprot", "", []string{"arm64-v8a"}},
1778		{"arm", "armv7-a-neon", "", []string{"armeabi-v7a"}},
1779		{"riscv64", "", "", []string{"riscv64"}},
1780		{"x86_64", "", "", []string{"x86_64"}},
1781		{"x86", "", "", []string{"x86"}},
1782	}
1783}
1784
1785// getAmlAbisConfig returns a list of archConfigs for the ABIs supported by mainline modules.
1786func getAmlAbisConfig() []archConfig {
1787	return []archConfig{
1788		{"arm64", "armv8-a", "", []string{"arm64-v8a"}},
1789		{"arm", "armv7-a-neon", "", []string{"armeabi-v7a"}},
1790		{"x86_64", "", "", []string{"x86_64"}},
1791		{"x86", "", "", []string{"x86"}},
1792	}
1793}
1794
1795// decodeArchSettings converts a list of archConfigs into a list of Targets for the given OsType.
1796func decodeAndroidArchSettings(archConfigs []archConfig) ([]Target, error) {
1797	var ret []Target
1798
1799	for _, config := range archConfigs {
1800		arch, err := decodeArch(Android, config.Arch, &config.ArchVariant,
1801			&config.CpuVariant, config.Abi)
1802		if err != nil {
1803			return nil, err
1804		}
1805
1806		ret = append(ret, Target{
1807			Os:   Android,
1808			Arch: arch,
1809		})
1810	}
1811
1812	return ret, nil
1813}
1814
1815// decodeArch converts a set of strings from product variables into an Arch struct.
1816func decodeArch(os OsType, arch string, archVariant, cpuVariant *string, abi []string) (Arch, error) {
1817	// Verify the arch is valid
1818	archType, ok := archTypeMap[arch]
1819	if !ok {
1820		return Arch{}, fmt.Errorf("unknown arch %q", arch)
1821	}
1822
1823	a := Arch{
1824		ArchType:    archType,
1825		ArchVariant: String(archVariant),
1826		CpuVariant:  String(cpuVariant),
1827		Abi:         abi,
1828	}
1829
1830	// Convert generic arch variants into the empty string.
1831	if a.ArchVariant == a.ArchType.Name || a.ArchVariant == "generic" {
1832		a.ArchVariant = ""
1833	}
1834
1835	// Convert generic CPU variants into the empty string.
1836	if a.CpuVariant == a.ArchType.Name || a.CpuVariant == "generic" {
1837		a.CpuVariant = ""
1838	}
1839
1840	if a.ArchVariant != "" {
1841		if validArchVariants := archVariants[archType]; !InList(a.ArchVariant, validArchVariants) {
1842			return Arch{}, fmt.Errorf("[%q] unknown arch variant %q, support variants: %q", archType, a.ArchVariant, validArchVariants)
1843		}
1844	}
1845
1846	if a.CpuVariant != "" {
1847		if validCpuVariants := cpuVariants[archType]; !InList(a.CpuVariant, validCpuVariants) {
1848			return Arch{}, fmt.Errorf("[%q] unknown cpu variant %q, support variants: %q", archType, a.CpuVariant, validCpuVariants)
1849		}
1850	}
1851
1852	// Filter empty ABIs out of the list.
1853	for i := 0; i < len(a.Abi); i++ {
1854		if a.Abi[i] == "" {
1855			a.Abi = append(a.Abi[:i], a.Abi[i+1:]...)
1856			i--
1857		}
1858	}
1859
1860	// Set ArchFeatures from the arch type. for Android OS, other os-es do not specify features
1861	if os == Android {
1862		if featureMap, ok := androidArchFeatureMap[archType]; ok {
1863			a.ArchFeatures = featureMap[a.ArchVariant]
1864		}
1865	}
1866
1867	return a, nil
1868}
1869
1870// filterMultilibTargets takes a list of Targets and a multilib value and returns a new list of
1871// Targets containing only those that have the given multilib value.
1872func filterMultilibTargets(targets []Target, multilib string) []Target {
1873	var ret []Target
1874	for _, t := range targets {
1875		if t.Arch.ArchType.Multilib == multilib {
1876			ret = append(ret, t)
1877		}
1878	}
1879	return ret
1880}
1881
1882// getCommonTargets returns the set of Os specific common architecture targets for each Os in a list
1883// of targets.
1884func getCommonTargets(targets []Target) []Target {
1885	var ret []Target
1886	set := make(map[string]bool)
1887
1888	for _, t := range targets {
1889		if _, found := set[t.Os.String()]; !found {
1890			set[t.Os.String()] = true
1891			common := commonTargetMap[t.Os.String()]
1892			common.HostCross = t.HostCross
1893			ret = append(ret, common)
1894		}
1895	}
1896
1897	return ret
1898}
1899
1900// FirstTarget takes a list of Targets and a list of multilib values and returns a list of Targets
1901// that contains zero or one Target for each OsType and HostCross, selecting the one that matches
1902// the earliest filter.
1903func FirstTarget(targets []Target, filters ...string) []Target {
1904	// find the first target from each OS
1905	var ret []Target
1906	type osHostCross struct {
1907		os        OsType
1908		hostCross bool
1909	}
1910	set := make(map[osHostCross]bool)
1911
1912	for _, filter := range filters {
1913		buildTargets := filterMultilibTargets(targets, filter)
1914		for _, t := range buildTargets {
1915			key := osHostCross{t.Os, t.HostCross}
1916			if _, found := set[key]; !found {
1917				set[key] = true
1918				ret = append(ret, t)
1919			}
1920		}
1921	}
1922	return ret
1923}
1924
1925// decodeMultilibTargets uses the module's multilib setting to select one or more targets from a
1926// list of Targets.
1927func decodeMultilibTargets(multilib string, targets []Target, prefer32 bool) ([]Target, error) {
1928	var buildTargets []Target
1929
1930	switch multilib {
1931	case "common":
1932		buildTargets = getCommonTargets(targets)
1933	case "both":
1934		if prefer32 {
1935			buildTargets = append(buildTargets, filterMultilibTargets(targets, "lib32")...)
1936			buildTargets = append(buildTargets, filterMultilibTargets(targets, "lib64")...)
1937		} else {
1938			buildTargets = append(buildTargets, filterMultilibTargets(targets, "lib64")...)
1939			buildTargets = append(buildTargets, filterMultilibTargets(targets, "lib32")...)
1940		}
1941	case "32":
1942		buildTargets = filterMultilibTargets(targets, "lib32")
1943	case "64":
1944		buildTargets = filterMultilibTargets(targets, "lib64")
1945	case "first":
1946		if prefer32 {
1947			buildTargets = FirstTarget(targets, "lib32", "lib64")
1948		} else {
1949			buildTargets = FirstTarget(targets, "lib64", "lib32")
1950		}
1951	case "first_prefer32":
1952		buildTargets = FirstTarget(targets, "lib32", "lib64")
1953	case "prefer32":
1954		buildTargets = filterMultilibTargets(targets, "lib32")
1955		if len(buildTargets) == 0 {
1956			buildTargets = filterMultilibTargets(targets, "lib64")
1957		}
1958	case "darwin_universal":
1959		buildTargets = filterMultilibTargets(targets, "lib64")
1960		// Reverse the targets so that the first architecture can depend on the second
1961		// architecture module in order to merge the outputs.
1962		ReverseSliceInPlace(buildTargets)
1963	default:
1964		return nil, fmt.Errorf(`compile_multilib must be "both", "first", "32", "64", "prefer32" or "first_prefer32" found %q`,
1965			multilib)
1966	}
1967
1968	return buildTargets, nil
1969}
1970
1971// ArchVariantContext defines the limited context necessary to retrieve arch_variant properties.
1972type ArchVariantContext interface {
1973	ModuleErrorf(fmt string, args ...interface{})
1974	PropertyErrorf(property, fmt string, args ...interface{})
1975}
1976