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