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