blob: d9ecb508dbec516a6a6f38422e5a1954752c00bb [file] [log] [blame]
Colin Cross3f40fa42015-01-30 17:27:36 -08001// 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
Colin Cross635c3b02016-05-18 15:37:25 -070015package android
Colin Cross3f40fa42015-01-30 17:27:36 -080016
17import (
Colin Cross74ba9622019-02-11 15:11:14 -080018 "encoding"
Colin Cross3f40fa42015-01-30 17:27:36 -080019 "fmt"
20 "reflect"
21 "runtime"
Ivan Lozano03b717d2024-07-18 15:13:50 +000022 "slices"
Colin Cross3f40fa42015-01-30 17:27:36 -080023 "strings"
Colin Crossf6566ed2015-03-24 11:13:38 -070024
Colin Cross0f7d2ef2019-10-16 11:03:10 -070025 "github.com/google/blueprint"
Colin Crossf6566ed2015-03-24 11:13:38 -070026 "github.com/google/blueprint/proptools"
Colin Cross3f40fa42015-01-30 17:27:36 -080027)
28
Colin Cross3f40fa42015-01-30 17:27:36 -080029/*
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 },
Colin Cross3f40fa42015-01-30 17:27:36 -080041 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: {
Martin Stjernholme284b482020-09-23 21:03:27 +010058 // Device variants (implies Bionic)
Colin Cross3f40fa42015-01-30 17:27:36 -080059 },
60 host: {
61 // Host variants
62 },
Martin Stjernholme284b482020-09-23 21:03:27 +010063 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 },
Dan Willemsen5746bd42017-10-02 19:42:01 -070072 linux_glibc: {
Martin Stjernholme284b482020-09-23 21:03:27 +010073 // Linux host variants (using non-Bionic libc)
Colin Cross3f40fa42015-01-30 17:27:36 -080074 },
75 darwin: {
76 // Darwin host variants
77 },
78 windows: {
79 // Windows host variants
80 },
81 not_windows: {
82 // Non-windows host variants
83 },
Martin Stjernholme284b482020-09-23 21:03:27 +010084 android_arm: {
85 // Any <os>_<arch> combination restricts to that os and arch
86 },
Colin Cross3f40fa42015-01-30 17:27:36 -080087 },
88}
89*/
Colin Cross7d5136f2015-05-11 13:39:40 -070090
Colin Cross3f40fa42015-01-30 17:27:36 -080091// An Arch indicates a single CPU architecture.
92type Arch struct {
Colin Crossa6845402020-11-16 15:08:19 -080093 // 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".
Colin Crossc5c24ad2015-11-20 15:35:00 -0800106 ArchFeatures []string
Colin Cross3f40fa42015-01-30 17:27:36 -0800107}
108
Colin Crossa6845402020-11-16 15:08:19 -0800109// String returns the Arch as a string. The value is used as the name of the variant created
110// by archMutator.
Colin Cross3f40fa42015-01-30 17:27:36 -0800111func (a Arch) String() string {
Colin Crossd3ba0392015-05-07 14:11:29 -0700112 s := a.ArchType.String()
Colin Cross3f40fa42015-01-30 17:27:36 -0800113 if a.ArchVariant != "" {
114 s += "_" + a.ArchVariant
115 }
116 if a.CpuVariant != "" {
117 s += "_" + a.CpuVariant
118 }
119 return s
120}
121
Colin Crossa6845402020-11-16 15:08:19 -0800122// 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.
Colin Cross3f40fa42015-01-30 17:27:36 -0800125type ArchType struct {
Colin Crossa6845402020-11-16 15:08:19 -0800126 // 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.
Colin Crossec193632015-07-06 17:49:43 -0700133 Multilib string
Colin Cross3f40fa42015-01-30 17:27:36 -0800134}
135
Colin Crossa6845402020-11-16 15:08:19 -0800136// String returns the name of the ArchType.
137func (a ArchType) String() string {
138 return a.Name
139}
140
Spandan Dasd4530d62024-09-26 00:46:12 +0000141func (a ArchType) Bitness() string {
142 if a.Multilib == "lib32" {
143 return "32"
144 }
145 return "64"
146}
147
Colin Crossa6845402020-11-16 15:08:19 -0800148const COMMON_VARIANT = "common"
149
150var (
151 archTypeList []ArchType
152
Colin Crossf05b0d32022-07-14 18:10:34 -0700153 Arm = newArch("arm", "lib32")
154 Arm64 = newArch("arm64", "lib64")
155 Riscv64 = newArch("riscv64", "lib64")
156 X86 = newArch("x86", "lib32")
157 X86_64 = newArch("x86_64", "lib64")
Colin Crossa6845402020-11-16 15:08:19 -0800158
159 Common = ArchType{
160 Name: COMMON_VARIANT,
161 }
162)
163
164var archTypeMap = map[string]ArchType{}
165
Colin Crossec193632015-07-06 17:49:43 -0700166func newArch(name, multilib string) ArchType {
Dan Willemsenb1957a52016-06-23 23:44:54 -0700167 archType := ArchType{
Colin Crossec193632015-07-06 17:49:43 -0700168 Name: name,
Dan Willemsenb1957a52016-06-23 23:44:54 -0700169 Field: proptools.FieldNameForProperty(name),
Colin Crossec193632015-07-06 17:49:43 -0700170 Multilib: multilib,
Colin Cross3f40fa42015-01-30 17:27:36 -0800171 }
Dan Willemsenb1957a52016-06-23 23:44:54 -0700172 archTypeList = append(archTypeList, archType)
Colin Crossa6845402020-11-16 15:08:19 -0800173 archTypeMap[name] = archType
Dan Willemsenb1957a52016-06-23 23:44:54 -0700174 return archType
Colin Cross3f40fa42015-01-30 17:27:36 -0800175}
176
Ustaeabf0f32021-12-06 15:17:23 -0500177// ArchTypeList returns a slice copy of the 4 supported ArchTypes for arm,
Jingwen Chen2f6a21e2021-04-05 07:33:05 +0000178// arm64, x86 and x86_64.
Jaewoong Jung1ce9ac62019-08-13 14:11:33 -0700179func ArchTypeList() []ArchType {
180 return append([]ArchType(nil), archTypeList...)
181}
182
Colin Crossa6845402020-11-16 15:08:19 -0800183// MarshalText allows an ArchType to be serialized through any encoder that supports
184// encoding.TextMarshaler.
Colin Cross74ba9622019-02-11 15:11:14 -0800185func (a ArchType) MarshalText() ([]byte, error) {
Jeongik Chabec4d032021-04-15 08:55:38 +0900186 return []byte(a.String()), nil
Colin Cross74ba9622019-02-11 15:11:14 -0800187}
188
Colin Crossa6845402020-11-16 15:08:19 -0800189var _ encoding.TextMarshaler = ArchType{}
Colin Cross74ba9622019-02-11 15:11:14 -0800190
Colin Crossa6845402020-11-16 15:08:19 -0800191// UnmarshalText allows an ArchType to be deserialized through any decoder that supports
192// encoding.TextUnmarshaler.
Colin Cross74ba9622019-02-11 15:11:14 -0800193func (a *ArchType) UnmarshalText(text []byte) error {
194 if u, ok := archTypeMap[string(text)]; ok {
195 *a = u
196 return nil
197 }
198
199 return fmt.Errorf("unknown ArchType %q", text)
200}
201
Colin Crossa6845402020-11-16 15:08:19 -0800202var _ encoding.TextUnmarshaler = &ArchType{}
Colin Crossa1ad8d12016-06-01 17:09:44 -0700203
Colin Crossa6845402020-11-16 15:08:19 -0800204// OsClass is an enum that describes whether a variant of a module runs on the host, on the device,
205// or is generic.
Colin Crossa1ad8d12016-06-01 17:09:44 -0700206type OsClass int
207
208const (
Colin Crossa6845402020-11-16 15:08:19 -0800209 // Generic is used for variants of modules that are not OS-specific.
Dan Willemsen0e2d97b2016-11-28 17:50:06 -0800210 Generic OsClass = iota
Colin Crossa6845402020-11-16 15:08:19 -0800211 // Device is used for variants of modules that run on the device.
Dan Willemsen0e2d97b2016-11-28 17:50:06 -0800212 Device
Colin Crossa6845402020-11-16 15:08:19 -0800213 // Host is used for variants of modules that run on the host.
Colin Crossa1ad8d12016-06-01 17:09:44 -0700214 Host
Colin Crossa1ad8d12016-06-01 17:09:44 -0700215)
216
Colin Crossa6845402020-11-16 15:08:19 -0800217// String returns the OsClass as a string.
Colin Cross67a5c132017-05-09 13:45:28 -0700218func (class OsClass) String() string {
219 switch class {
220 case Generic:
221 return "generic"
222 case Device:
223 return "device"
224 case Host:
225 return "host"
Colin Cross67a5c132017-05-09 13:45:28 -0700226 default:
227 panic(fmt.Errorf("unknown class %d", class))
228 }
229}
230
Colin Crossa6845402020-11-16 15:08:19 -0800231// OsType describes an OS variant of a module.
232type OsType struct {
233 // Name is the name of the OS. It is also used as the name of the property in Android.bp
234 // files.
235 Name string
236
237 // Field is the name of the OS converted to an exported field name, i.e. with the first
238 // character capitalized.
239 Field string
240
241 // Class is the OsClass of the OS.
242 Class OsClass
243
244 // DefaultDisabled is set when the module variants for the OS should not be created unless
245 // the module explicitly requests them. This is used to limit Windows cross compilation to
246 // only modules that need it.
247 DefaultDisabled bool
248}
249
250// String returns the name of the OsType.
Colin Crossa1ad8d12016-06-01 17:09:44 -0700251func (os OsType) String() string {
252 return os.Name
Colin Cross54c71122016-06-01 17:09:44 -0700253}
254
Colin Crossa6845402020-11-16 15:08:19 -0800255// Bionic returns true if the OS uses the Bionic libc runtime, i.e. if the OS is Android or
256// is Linux with Bionic.
Dan Willemsen866b5632017-09-22 12:28:24 -0700257func (os OsType) Bionic() bool {
258 return os == Android || os == LinuxBionic
259}
260
Colin Crossa6845402020-11-16 15:08:19 -0800261// Linux returns true if the OS uses the Linux kernel, i.e. if the OS is Android or is Linux
262// with or without the Bionic libc runtime.
Dan Willemsen866b5632017-09-22 12:28:24 -0700263func (os OsType) Linux() bool {
Colin Cross528d67e2021-07-23 22:23:07 +0000264 return os == Android || os == Linux || os == LinuxBionic || os == LinuxMusl
Dan Willemsen866b5632017-09-22 12:28:24 -0700265}
266
Colin Crossa6845402020-11-16 15:08:19 -0800267// newOsType constructs an OsType and adds it to the global lists.
268func newOsType(name string, class OsClass, defDisabled bool, archTypes ...ArchType) OsType {
269 checkCalledFromInit()
Colin Crossa1ad8d12016-06-01 17:09:44 -0700270 os := OsType{
271 Name: name,
Colin Crossa6845402020-11-16 15:08:19 -0800272 Field: proptools.FieldNameForProperty(name),
Colin Crossa1ad8d12016-06-01 17:09:44 -0700273 Class: class,
Dan Willemsen0a37a2a2016-11-13 10:16:05 -0800274
275 DefaultDisabled: defDisabled,
Colin Cross54c71122016-06-01 17:09:44 -0700276 }
Jingwen Chen2f6a21e2021-04-05 07:33:05 +0000277 osTypeList = append(osTypeList, os)
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800278
279 if _, found := commonTargetMap[name]; found {
280 panic(fmt.Errorf("Found Os type duplicate during OsType registration: %q", name))
281 } else {
Colin Crosse9fe2942020-11-10 18:12:15 -0800282 commonTargetMap[name] = Target{Os: os, Arch: CommonArch}
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800283 }
Colin Crossa6845402020-11-16 15:08:19 -0800284 osArchTypeMap[os] = archTypes
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800285
Colin Crossa1ad8d12016-06-01 17:09:44 -0700286 return os
287}
288
Colin Crossa6845402020-11-16 15:08:19 -0800289// osByName returns the OsType that has the given name, or NoOsType if none match.
Colin Crossa1ad8d12016-06-01 17:09:44 -0700290func osByName(name string) OsType {
Jingwen Chen2f6a21e2021-04-05 07:33:05 +0000291 for _, os := range osTypeList {
Colin Crossa1ad8d12016-06-01 17:09:44 -0700292 if os.Name == name {
293 return os
294 }
295 }
296
297 return NoOsType
Dan Willemsen490fd492015-11-24 17:53:15 -0800298}
299
Colin Crossa6845402020-11-16 15:08:19 -0800300var (
Jingwen Chen2f6a21e2021-04-05 07:33:05 +0000301 // osTypeList contains a list of all the supported OsTypes, including ones not supported
Colin Crossa6845402020-11-16 15:08:19 -0800302 // by the current build host or the target device.
Jingwen Chen2f6a21e2021-04-05 07:33:05 +0000303 osTypeList []OsType
Colin Crossa6845402020-11-16 15:08:19 -0800304 // commonTargetMap maps names of OsTypes to the corresponding common Target, i.e. the
305 // Target with the same OsType and the common ArchType.
306 commonTargetMap = make(map[string]Target)
307 // osArchTypeMap maps OsTypes to the list of supported ArchTypes for that OS.
308 osArchTypeMap = map[OsType][]ArchType{}
309
310 // NoOsType is a placeholder for when no OS is needed.
311 NoOsType OsType
312 // Linux is the OS for the Linux kernel plus the glibc runtime.
313 Linux = newOsType("linux_glibc", Host, false, X86, X86_64)
Colin Cross528d67e2021-07-23 22:23:07 +0000314 // LinuxMusl is the OS for the Linux kernel plus the musl runtime.
Colin Crossa9b2aac2022-06-15 17:25:51 -0700315 LinuxMusl = newOsType("linux_musl", Host, false, X86, X86_64, Arm64, Arm)
Colin Crossa6845402020-11-16 15:08:19 -0800316 // Darwin is the OS for MacOS/Darwin host machines.
Dan Willemsen8528f4e2021-10-19 00:22:06 -0700317 Darwin = newOsType("darwin", Host, false, Arm64, X86_64)
Colin Crossa6845402020-11-16 15:08:19 -0800318 // LinuxBionic is the OS for the Linux kernel plus the Bionic libc runtime, but without the
319 // rest of Android.
320 LinuxBionic = newOsType("linux_bionic", Host, false, Arm64, X86_64)
321 // Windows the OS for Windows host machines.
322 Windows = newOsType("windows", Host, true, X86, X86_64)
323 // Android is the OS for target devices that run all of Android, including the Linux kernel
324 // and the Bionic libc runtime.
Colin Crossf05b0d32022-07-14 18:10:34 -0700325 Android = newOsType("android", Device, false, Arm, Arm64, Riscv64, X86, X86_64)
Colin Crossa6845402020-11-16 15:08:19 -0800326
327 // CommonOS is a pseudo OSType for a common OS variant, which is OsType agnostic and which
328 // has dependencies on all the OS variants.
329 CommonOS = newOsType("common_os", Generic, false)
Colin Crosse9fe2942020-11-10 18:12:15 -0800330
331 // CommonArch is the Arch for all modules that are os-specific but not arch specific,
332 // for example most Java modules.
333 CommonArch = Arch{ArchType: Common}
dimitry1f33e402019-03-26 12:39:31 +0100334)
335
Jingwen Chen2f6a21e2021-04-05 07:33:05 +0000336// OsTypeList returns a slice copy of the supported OsTypes.
337func OsTypeList() []OsType {
338 return append([]OsType(nil), osTypeList...)
339}
340
Colin Crossa6845402020-11-16 15:08:19 -0800341// Target specifies the OS and architecture that a module is being compiled for.
Colin Crossa1ad8d12016-06-01 17:09:44 -0700342type Target struct {
Colin Crossa6845402020-11-16 15:08:19 -0800343 // Os the OS that the module is being compiled for (e.g. "linux_glibc", "android").
344 Os OsType
345 // Arch is the architecture that the module is being compiled for.
346 Arch Arch
347 // NativeBridge is NativeBridgeEnabled if the architecture is supported using NativeBridge
348 // (i.e. arm on x86) for this device.
349 NativeBridge NativeBridgeSupport
350 // NativeBridgeHostArchName is the name of the real architecture that is used to implement
351 // the NativeBridge architecture. For example, for arm on x86 this would be "x86".
dimitry8d6dde82019-07-11 10:23:53 +0200352 NativeBridgeHostArchName string
Colin Crossa6845402020-11-16 15:08:19 -0800353 // NativeBridgeRelativePath is the name of the subdirectory that will contain NativeBridge
354 // libraries and binaries.
dimitry8d6dde82019-07-11 10:23:53 +0200355 NativeBridgeRelativePath string
Jiyong Park1613e552020-09-14 19:43:17 +0900356
357 // HostCross is true when the target cannot run natively on the current build host.
358 // For example, linux_glibc_x86 returns true on a regular x86/i686/Linux machines, but returns false
359 // on Mac (different OS), or on 64-bit only i686/Linux machines (unsupported arch).
360 HostCross bool
Colin Crossd3ba0392015-05-07 14:11:29 -0700361}
362
Colin Crossa6845402020-11-16 15:08:19 -0800363// NativeBridgeSupport is an enum that specifies if a Target supports NativeBridge.
364type NativeBridgeSupport bool
365
366const (
367 NativeBridgeDisabled NativeBridgeSupport = false
368 NativeBridgeEnabled NativeBridgeSupport = true
369)
370
371// String returns the OS and arch variations used for the Target.
Colin Crossa1ad8d12016-06-01 17:09:44 -0700372func (target Target) String() string {
Colin Crossa195f912019-10-16 11:07:20 -0700373 return target.OsVariation() + "_" + target.ArchVariation()
374}
375
Colin Crossa6845402020-11-16 15:08:19 -0800376// OsVariation returns the name of the variation used by the osMutator for the Target.
Colin Crossa195f912019-10-16 11:07:20 -0700377func (target Target) OsVariation() string {
378 return target.Os.String()
Colin Cross0f7d2ef2019-10-16 11:03:10 -0700379}
380
Colin Crossa6845402020-11-16 15:08:19 -0800381// ArchVariation returns the name of the variation used by the archMutator for the Target.
Colin Cross0f7d2ef2019-10-16 11:03:10 -0700382func (target Target) ArchVariation() string {
383 var variation string
dimitry1f33e402019-03-26 12:39:31 +0100384 if target.NativeBridge {
Colin Cross0f7d2ef2019-10-16 11:03:10 -0700385 variation = "native_bridge_"
dimitry1f33e402019-03-26 12:39:31 +0100386 }
Colin Cross0f7d2ef2019-10-16 11:03:10 -0700387 variation += target.Arch.String()
388
Colin Crossa195f912019-10-16 11:07:20 -0700389 return variation
Colin Cross0f7d2ef2019-10-16 11:03:10 -0700390}
391
Colin Crossa6845402020-11-16 15:08:19 -0800392// Variations returns a list of blueprint.Variations for the osMutator and archMutator for the
393// Target.
Colin Cross0f7d2ef2019-10-16 11:03:10 -0700394func (target Target) Variations() []blueprint.Variation {
395 return []blueprint.Variation{
Colin Crossa195f912019-10-16 11:07:20 -0700396 {Mutator: "os", Variation: target.OsVariation()},
Colin Cross0f7d2ef2019-10-16 11:03:10 -0700397 {Mutator: "arch", Variation: target.ArchVariation()},
398 }
Dan Willemsen490fd492015-11-24 17:53:15 -0800399}
400
Colin Crossa6845402020-11-16 15:08:19 -0800401// osMutator splits an arch-specific module into a variant for each OS that is enabled for the
402// module. It uses the HostOrDevice value passed to InitAndroidArchModule and the
403// device_supported and host_supported properties to determine which OsTypes are enabled for this
404// module, then searches through the Targets to determine which have enabled Targets for this
405// module.
Colin Cross8bbc3d52024-09-11 15:33:54 -0700406type osTransitionMutator struct{}
Colin Crossa195f912019-10-16 11:07:20 -0700407
Colin Cross8bbc3d52024-09-11 15:33:54 -0700408type allOsInfo struct {
409 Os map[string]OsType
410 Variations []string
411}
Colin Crossa195f912019-10-16 11:07:20 -0700412
Colin Cross8bbc3d52024-09-11 15:33:54 -0700413var allOsProvider = blueprint.NewMutatorProvider[*allOsInfo]("os_propagate")
414
415// moduleOSList collects a list of OSTypes supported by this module based on the HostOrDevice
416// value passed to InitAndroidArchModule and the device_supported and host_supported properties.
417func moduleOSList(ctx ConfigContext, base *ModuleBase) []OsType {
Colin Crossa195f912019-10-16 11:07:20 -0700418 var moduleOSList []OsType
Jingwen Chen2f6a21e2021-04-05 07:33:05 +0000419 for _, os := range osTypeList {
Colin Cross8bbc3d52024-09-11 15:33:54 -0700420 for _, t := range ctx.Config().Targets[os] {
Colin Cross08d6f8f2020-11-19 02:33:19 +0000421 if base.supportsTarget(t) {
Jiyong Park1613e552020-09-14 19:43:17 +0900422 moduleOSList = append(moduleOSList, os)
423 break
Colin Crossa195f912019-10-16 11:07:20 -0700424 }
425 }
Colin Crossa195f912019-10-16 11:07:20 -0700426 }
427
Colin Cross8bbc3d52024-09-11 15:33:54 -0700428 if base.commonProperties.CreateCommonOSVariant {
429 // A CommonOS variant was requested so add it to the list of OS variants to
430 // create. It needs to be added to the end because it needs to depend on the
431 // the other variants and inter variant dependencies can only be created from a
432 // later variant in that list to an earlier one. That is because variants are
433 // always processed in the order in which they are created.
434 moduleOSList = append(moduleOSList, CommonOS)
435 }
436
437 return moduleOSList
438}
439
440func (o *osTransitionMutator) Split(ctx BaseModuleContext) []string {
441 module := ctx.Module()
442 base := module.base()
443
444 // Nothing to do for modules that are not architecture specific (e.g. a genrule).
445 if !base.ArchSpecific() {
446 return []string{""}
447 }
448
449 moduleOSList := moduleOSList(ctx, base)
Cole Faust8fc38f32023-12-12 17:14:22 -0800450
Colin Crossa6845402020-11-16 15:08:19 -0800451 // If there are no supported OSes then disable the module.
Colin Cross8bbc3d52024-09-11 15:33:54 -0700452 if len(moduleOSList) == 0 {
Inseob Kimeec88e12020-01-22 11:11:29 +0900453 base.Disable()
Colin Cross8bbc3d52024-09-11 15:33:54 -0700454 return []string{""}
Colin Crossa195f912019-10-16 11:07:20 -0700455 }
456
Colin Crossa6845402020-11-16 15:08:19 -0800457 // Convert the list of supported OsTypes to the variation names.
Colin Crossa195f912019-10-16 11:07:20 -0700458 osNames := make([]string, len(moduleOSList))
Colin Cross8bbc3d52024-09-11 15:33:54 -0700459 osMapping := make(map[string]OsType, len(moduleOSList))
Colin Crossa195f912019-10-16 11:07:20 -0700460 for i, os := range moduleOSList {
461 osNames[i] = os.String()
Colin Cross8bbc3d52024-09-11 15:33:54 -0700462 osMapping[osNames[i]] = os
Colin Crossa195f912019-10-16 11:07:20 -0700463 }
464
Colin Cross8bbc3d52024-09-11 15:33:54 -0700465 SetProvider(ctx, allOsProvider, &allOsInfo{
466 Os: osMapping,
467 Variations: osNames,
468 })
469
470 return osNames
471}
472
473func (o *osTransitionMutator) OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string {
474 return sourceVariation
475}
476
477func (o *osTransitionMutator) IncomingTransition(ctx IncomingTransitionContext, incomingVariation string) string {
478 module := ctx.Module()
479 base := module.base()
480
481 if !base.ArchSpecific() {
482 return ""
Colin Crossa195f912019-10-16 11:07:20 -0700483 }
484
Colin Cross8bbc3d52024-09-11 15:33:54 -0700485 return incomingVariation
486}
487
488func (o *osTransitionMutator) Mutate(ctx BottomUpMutatorContext, variation string) {
489 module := ctx.Module()
490 base := module.base()
491
492 if variation == "" {
493 return
494 }
495
496 allOsInfo, ok := ModuleProvider(ctx, allOsProvider)
497 if !ok {
498 panic(fmt.Errorf("missing allOsProvider"))
499 }
500
501 // Annotate this variant with which OS it was created for, and
Colin Crossa6845402020-11-16 15:08:19 -0800502 // squash the appropriate OS-specific properties into the top level properties.
Colin Cross8bbc3d52024-09-11 15:33:54 -0700503 base.commonProperties.CompileOS = allOsInfo.Os[variation]
504 base.setOSProperties(ctx)
Paul Duffin1356d8c2020-02-25 19:26:33 +0000505
Colin Cross8bbc3d52024-09-11 15:33:54 -0700506 if variation == CommonOS.String() {
Paul Duffin1356d8c2020-02-25 19:26:33 +0000507 // A CommonOS variant was requested so add dependencies from it (the last one in
508 // the list) to the OS type specific variants.
Colin Cross8bbc3d52024-09-11 15:33:54 -0700509 osList := allOsInfo.Variations[:len(allOsInfo.Variations)-1]
510 for _, os := range osList {
511 variation := []blueprint.Variation{{"os", os}}
512 ctx.AddVariationDependencies(variation, commonOsToOsSpecificVariantTag, ctx.ModuleName())
Paul Duffin1356d8c2020-02-25 19:26:33 +0000513 }
514 }
515}
516
Colin Crossc179ea62020-10-09 10:54:15 -0700517type archDepTag struct {
518 blueprint.BaseDependencyTag
519 name string
520}
Paul Duffin1356d8c2020-02-25 19:26:33 +0000521
Colin Crossc179ea62020-10-09 10:54:15 -0700522// Identifies the dependency from CommonOS variant to the os specific variants.
523var commonOsToOsSpecificVariantTag = archDepTag{name: "common os to os specific"}
524
Paul Duffin1356d8c2020-02-25 19:26:33 +0000525// Get the OsType specific variants for the current CommonOS variant.
526//
527// The returned list will only contain enabled OsType specific variants of the
528// module referenced in the supplied context. An empty list is returned if there
529// are no enabled variants or the supplied context is not for an CommonOS
530// variant.
531func GetOsSpecificVariantsOfCommonOSVariant(mctx BaseModuleContext) []Module {
532 var variants []Module
533 mctx.VisitDirectDeps(func(m Module) {
534 if mctx.OtherModuleDependencyTag(m) == commonOsToOsSpecificVariantTag {
Cole Fausta963b942024-04-11 17:43:00 -0700535 if m.Enabled(mctx) {
Paul Duffin1356d8c2020-02-25 19:26:33 +0000536 variants = append(variants, m)
537 }
538 }
539 })
Paul Duffin1356d8c2020-02-25 19:26:33 +0000540 return variants
Colin Crossa195f912019-10-16 11:07:20 -0700541}
542
Dan Willemsen47450072021-10-19 20:24:49 -0700543var DarwinUniversalVariantTag = archDepTag{name: "darwin universal binary"}
544
Colin Cross8bbc3d52024-09-11 15:33:54 -0700545// archTransitionMutator splits a module into a variant for each Target requested by the module. Target selection
Colin Crossa6845402020-11-16 15:08:19 -0800546// for a module is in three levels, OsClass, multilib, and then Target.
Colin Crossee0bc3b2018-10-02 22:01:37 -0700547// OsClass selection is determined by:
Colin Crossd079e0b2022-08-16 10:27:33 -0700548// - The HostOrDeviceSupported value passed in to InitAndroidArchModule by the module type factory, which selects
549// whether the module type can compile for host, device or both.
550// - The host_supported and device_supported properties on the module.
551//
Roland Levillainf5b635d2019-06-05 14:42:57 +0100552// If host is supported for the module, the Host and HostCross OsClasses are selected. If device is supported
Colin Crossee0bc3b2018-10-02 22:01:37 -0700553// for the module, the Device OsClass is selected.
554// Within each selected OsClass, the multilib selection is determined by:
Colin Crossd079e0b2022-08-16 10:27:33 -0700555// - The compile_multilib property if it set (which may be overridden by target.android.compile_multilib or
556// target.host.compile_multilib).
557// - The default multilib passed to InitAndroidArchModule if compile_multilib was not set.
558//
Colin Crossee0bc3b2018-10-02 22:01:37 -0700559// Valid multilib values include:
Colin Crossd079e0b2022-08-16 10:27:33 -0700560//
561// "both": compile for all Targets supported by the OsClass (generally x86_64 and x86, or arm64 and arm).
562// "first": compile for only a single preferred Target supported by the OsClass. This is generally x86_64 or arm64,
563// but may be arm for a 32-bit only build.
564// "32": compile for only a single 32-bit Target supported by the OsClass.
565// "64": compile for only a single 64-bit Target supported by the OsClass.
566// "common": compile a for a single Target that will work on all Targets supported by the OsClass (for example Java).
567// "common_first": compile a for a Target that will work on all Targets supported by the OsClass
568// (same as "common"), plus a second Target for the preferred Target supported by the OsClass
569// (same as "first"). This is used for java_binary that produces a common .jar and a wrapper
570// executable script.
Colin Crossee0bc3b2018-10-02 22:01:37 -0700571//
572// Once the list of Targets is determined, the module is split into a variant for each Target.
573//
574// Modules can be initialized with InitAndroidMultiTargetsArchModule, in which case they will be split by OsClass,
575// but will have a common Target that is expected to handle all other selected Targets via ctx.MultiTargets().
Colin Cross8bbc3d52024-09-11 15:33:54 -0700576type archTransitionMutator struct{}
577
578type allArchInfo struct {
579 Targets map[string]Target
580 MultiTargets []Target
581 Primary string
582 Multilib string
583}
584
585var allArchProvider = blueprint.NewMutatorProvider[*allArchInfo]("arch_propagate")
586
587func (a *archTransitionMutator) Split(ctx BaseModuleContext) []string {
588 module := ctx.Module()
Colin Cross5eca7cb2018-10-02 14:02:10 -0700589 base := module.base()
590
591 if !base.ArchSpecific() {
Colin Cross8bbc3d52024-09-11 15:33:54 -0700592 return []string{""}
Colin Crossb9db4802016-06-03 01:50:47 +0000593 }
594
Colin Crossa195f912019-10-16 11:07:20 -0700595 os := base.commonProperties.CompileOS
Paul Duffin1356d8c2020-02-25 19:26:33 +0000596 if os == CommonOS {
Paul Duffin1356d8c2020-02-25 19:26:33 +0000597 // Do not create arch specific variants for the CommonOS variant.
Colin Cross8bbc3d52024-09-11 15:33:54 -0700598 return []string{""}
Paul Duffin1356d8c2020-02-25 19:26:33 +0000599 }
600
Colin Cross8bbc3d52024-09-11 15:33:54 -0700601 osTargets := ctx.Config().Targets[os]
Ivan Lozanoc7eafa72024-07-16 17:55:33 +0000602
Colin Crossfb0c16e2019-11-20 17:12:35 -0800603 image := base.commonProperties.ImageVariation
Colin Crossa6845402020-11-16 15:08:19 -0800604 // Filter NativeBridge targets unless they are explicitly supported.
605 // Skip creating native bridge variants for non-core modules.
Paul Duffine3d1ae42021-09-03 17:47:17 +0100606 if os == Android && !(base.IsNativeBridgeSupported() && image == CoreVariation) {
Ivan Lozano03b717d2024-07-18 15:13:50 +0000607 osTargets = slices.DeleteFunc(slices.Clone(osTargets), func(t Target) bool {
608 return bool(t.NativeBridge)
609 })
Colin Crossa195f912019-10-16 11:07:20 -0700610 }
Colin Crossee0bc3b2018-10-02 22:01:37 -0700611
Ivan Lozanoc7eafa72024-07-16 17:55:33 +0000612 // Filter HostCross targets if disabled.
613 if base.HostSupported() && !base.HostCrossSupported() {
Ivan Lozano03b717d2024-07-18 15:13:50 +0000614 osTargets = slices.DeleteFunc(slices.Clone(osTargets), func(t Target) bool {
615 return t.HostCross
616 })
Ivan Lozanoc7eafa72024-07-16 17:55:33 +0000617 }
618
Yifan Hong60e0cfb2020-10-21 15:17:56 -0700619 // only the primary arch in the ramdisk / vendor_ramdisk / recovery partition
Inseob Kim08758f02021-04-08 21:13:22 +0900620 if os == Android && (module.InstallInRecovery() || module.InstallInRamdisk() || module.InstallInVendorRamdisk() || module.InstallInDebugRamdisk()) {
Colin Crossa195f912019-10-16 11:07:20 -0700621 osTargets = []Target{osTargets[0]}
622 }
dimitry1f33e402019-03-26 12:39:31 +0100623
Jaewoong Jung003d8082021-02-24 17:39:54 -0800624 // Windows builds always prefer 32-bit
625 prefer32 := os == Windows
dimitry1f33e402019-03-26 12:39:31 +0100626
Colin Crossa6845402020-11-16 15:08:19 -0800627 // Determine the multilib selection for this module.
Colin Cross8bbc3d52024-09-11 15:33:54 -0700628 multilib, extraMultilib := decodeMultilib(ctx, base)
Colin Crossa6845402020-11-16 15:08:19 -0800629
630 // Convert the multilib selection into a list of Targets.
Colin Crossa195f912019-10-16 11:07:20 -0700631 targets, err := decodeMultilibTargets(multilib, osTargets, prefer32)
632 if err != nil {
Colin Cross8bbc3d52024-09-11 15:33:54 -0700633 ctx.ModuleErrorf("%s", err.Error())
Colin Crossa195f912019-10-16 11:07:20 -0700634 }
Colin Cross5eca7cb2018-10-02 14:02:10 -0700635
Colin Crossc0f0eb82022-07-19 14:41:11 -0700636 // If there are no supported targets disable the module.
637 if len(targets) == 0 {
638 base.Disable()
Colin Cross8bbc3d52024-09-11 15:33:54 -0700639 return []string{""}
Colin Crossc0f0eb82022-07-19 14:41:11 -0700640 }
641
Colin Crossa6845402020-11-16 15:08:19 -0800642 // If the module is using extraMultilib, decode the extraMultilib selection into
643 // a separate list of Targets.
Colin Crossa195f912019-10-16 11:07:20 -0700644 var multiTargets []Target
645 if extraMultilib != "" {
646 multiTargets, err = decodeMultilibTargets(extraMultilib, osTargets, prefer32)
Colin Crossa1ad8d12016-06-01 17:09:44 -0700647 if err != nil {
Colin Cross8bbc3d52024-09-11 15:33:54 -0700648 ctx.ModuleErrorf("%s", err.Error())
Colin Crossa1ad8d12016-06-01 17:09:44 -0700649 }
Colin Crossc0f0eb82022-07-19 14:41:11 -0700650 multiTargets = filterHostCross(multiTargets, targets[0].HostCross)
Colin Crossb9db4802016-06-03 01:50:47 +0000651 }
652
Colin Crossa6845402020-11-16 15:08:19 -0800653 // Recovery is always the primary architecture, filter out any other architectures.
Inseob Kim20fb5d42021-02-02 20:07:58 +0900654 // Common arch is also allowed
Colin Crossfb0c16e2019-11-20 17:12:35 -0800655 if image == RecoveryVariation {
Colin Cross8bbc3d52024-09-11 15:33:54 -0700656 primaryArch := ctx.Config().DevicePrimaryArchType()
Inseob Kim20fb5d42021-02-02 20:07:58 +0900657 targets = filterToArch(targets, primaryArch, Common)
658 multiTargets = filterToArch(multiTargets, primaryArch, Common)
Colin Crossfb0c16e2019-11-20 17:12:35 -0800659 }
660
Colin Crossa6845402020-11-16 15:08:19 -0800661 // If there are no supported targets disable the module.
Colin Crossa195f912019-10-16 11:07:20 -0700662 if len(targets) == 0 {
Inseob Kimeec88e12020-01-22 11:11:29 +0900663 base.Disable()
Colin Cross8bbc3d52024-09-11 15:33:54 -0700664 return []string{""}
Dan Willemsen3f32f032016-07-11 14:36:48 -0700665 }
666
Colin Crossa6845402020-11-16 15:08:19 -0800667 // Convert the targets into a list of arch variation names.
Colin Crossa195f912019-10-16 11:07:20 -0700668 targetNames := make([]string, len(targets))
Colin Cross8bbc3d52024-09-11 15:33:54 -0700669 targetMapping := make(map[string]Target, len(targets))
Colin Crossa195f912019-10-16 11:07:20 -0700670 for i, target := range targets {
671 targetNames[i] = target.ArchVariation()
Colin Cross8bbc3d52024-09-11 15:33:54 -0700672 targetMapping[targetNames[i]] = targets[i]
Colin Crossa1ad8d12016-06-01 17:09:44 -0700673 }
674
Colin Cross8bbc3d52024-09-11 15:33:54 -0700675 SetProvider(ctx, allArchProvider, &allArchInfo{
676 Targets: targetMapping,
677 MultiTargets: multiTargets,
678 Primary: targetNames[0],
679 Multilib: multilib,
680 })
681 return targetNames
682}
Dan Willemsen8528f4e2021-10-19 00:22:06 -0700683
Colin Cross8bbc3d52024-09-11 15:33:54 -0700684func (a *archTransitionMutator) OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string {
685 return sourceVariation
686}
687
688func (a *archTransitionMutator) IncomingTransition(ctx IncomingTransitionContext, incomingVariation string) string {
689 module := ctx.Module()
690 base := module.base()
691
692 if !base.ArchSpecific() {
693 return ""
694 }
695
696 os := base.commonProperties.CompileOS
697 if os == CommonOS {
698 // Do not create arch specific variants for the CommonOS variant.
699 return ""
700 }
701
702 if incomingVariation == "" {
703 multilib, _ := decodeMultilib(ctx, base)
704 if multilib == "common" {
705 return "common"
Dan Willemsen8528f4e2021-10-19 00:22:06 -0700706 }
Colin Cross3f40fa42015-01-30 17:27:36 -0800707 }
Colin Cross8bbc3d52024-09-11 15:33:54 -0700708 return incomingVariation
709}
710
711func (a *archTransitionMutator) Mutate(ctx BottomUpMutatorContext, variation string) {
712 module := ctx.Module()
713 base := module.base()
714 os := base.commonProperties.CompileOS
715
716 if os == CommonOS {
717 // Make sure that the target related properties are initialized for the
718 // CommonOS variant.
719 addTargetProperties(module, commonTargetMap[os.Name], nil, true)
720 return
721 }
722
723 if variation == "" {
724 return
725 }
726
727 if !base.ArchSpecific() {
728 panic(fmt.Errorf("found variation %q for non arch specifc module", variation))
729 }
730
731 allArchInfo, ok := ModuleProvider(ctx, allArchProvider)
732 if !ok {
733 return
734 }
735
736 target, ok := allArchInfo.Targets[variation]
737 if !ok {
738 panic(fmt.Errorf("missing Target for %q", variation))
739 }
740 primary := variation == allArchInfo.Primary
741 multiTargets := allArchInfo.MultiTargets
742
743 // Annotate the new variant with which Target it was created for, and
744 // squash the appropriate arch-specific properties into the top level properties.
745 addTargetProperties(ctx.Module(), target, multiTargets, primary)
746 base.setArchProperties(ctx)
747
748 // Install support doesn't understand Darwin+Arm64
749 if os == Darwin && target.HostCross {
750 base.commonProperties.SkipInstall = true
751 }
Dan Willemsen47450072021-10-19 20:24:49 -0700752
753 // Create a dependency for Darwin Universal binaries from the primary to secondary
754 // architecture. The module itself will be responsible for calling lipo to merge the outputs.
755 if os == Darwin {
Colin Cross8bbc3d52024-09-11 15:33:54 -0700756 isUniversalBinary := (allArchInfo.Multilib == "darwin_universal" && len(allArchInfo.Targets) == 2) ||
757 allArchInfo.Multilib == "darwin_universal_common_first" && len(allArchInfo.Targets) == 3
758 isPrimary := variation == ctx.Config().BuildArch.String()
759 hasSecondaryConfigured := len(ctx.Config().Targets[Darwin]) > 1
760 if isUniversalBinary && isPrimary && hasSecondaryConfigured {
761 secondaryArch := ctx.Config().Targets[Darwin][1].Arch.String()
762 variation := []blueprint.Variation{{"arch", secondaryArch}}
763 ctx.AddVariationDependencies(variation, DarwinUniversalVariantTag, ctx.ModuleName())
Dan Willemsen47450072021-10-19 20:24:49 -0700764 }
765 }
Colin Cross8bbc3d52024-09-11 15:33:54 -0700766
Colin Cross3f40fa42015-01-30 17:27:36 -0800767}
768
Colin Crossa6845402020-11-16 15:08:19 -0800769// addTargetProperties annotates a variant with the Target is is being compiled for, the list
770// of additional Targets it is supporting (if any), and whether it is the primary Target for
771// the module.
Paul Duffin1356d8c2020-02-25 19:26:33 +0000772func addTargetProperties(m Module, target Target, multiTargets []Target, primaryTarget bool) {
773 m.base().commonProperties.CompileTarget = target
774 m.base().commonProperties.CompileMultiTargets = multiTargets
775 m.base().commonProperties.CompilePrimary = primaryTarget
Cole Faust0aa21cc2024-03-20 12:28:03 -0700776 m.base().commonProperties.ArchReady = true
Paul Duffin1356d8c2020-02-25 19:26:33 +0000777}
778
Colin Crossa6845402020-11-16 15:08:19 -0800779// decodeMultilib returns the appropriate compile_multilib property for the module, or the default
780// multilib from the factory's call to InitAndroidArchModule if none was set. For modules that
781// called InitAndroidMultiTargetsArchModule it always returns "common" for multilib, and returns
782// the actual multilib in extraMultilib.
Colin Cross8bbc3d52024-09-11 15:33:54 -0700783func decodeMultilib(ctx ConfigContext, base *ModuleBase) (multilib, extraMultilib string) {
784 os := base.commonProperties.CompileOS
785 ignorePrefer32OnDevice := ctx.Config().IgnorePrefer32OnDevice()
Colin Crossa6845402020-11-16 15:08:19 -0800786 // First check the "android.compile_multilib" or "host.compile_multilib" properties.
Dan Willemsen47450072021-10-19 20:24:49 -0700787 switch os.Class {
Colin Crossee0bc3b2018-10-02 22:01:37 -0700788 case Device:
789 multilib = String(base.commonProperties.Target.Android.Compile_multilib)
Jiyong Park1613e552020-09-14 19:43:17 +0900790 case Host:
Colin Crossee0bc3b2018-10-02 22:01:37 -0700791 multilib = String(base.commonProperties.Target.Host.Compile_multilib)
792 }
Colin Crossa6845402020-11-16 15:08:19 -0800793
794 // If those aren't set, try the "compile_multilib" property.
Colin Crossee0bc3b2018-10-02 22:01:37 -0700795 if multilib == "" {
796 multilib = String(base.commonProperties.Compile_multilib)
797 }
Colin Crossa6845402020-11-16 15:08:19 -0800798
799 // If that wasn't set, use the default multilib set by the factory.
Colin Crossee0bc3b2018-10-02 22:01:37 -0700800 if multilib == "" {
801 multilib = base.commonProperties.Default_multilib
802 }
803
Christopher Ferris98f10222022-07-13 23:16:52 -0700804 // If a device is configured with multiple targets, this option
805 // force all device targets that prefer32 to be compiled only as
806 // the first target.
807 if ignorePrefer32OnDevice && os.Class == Device && (multilib == "prefer32" || multilib == "first_prefer32") {
808 multilib = "first"
809 }
810
Colin Crossee0bc3b2018-10-02 22:01:37 -0700811 if base.commonProperties.UseTargetVariants {
Dan Willemsen47450072021-10-19 20:24:49 -0700812 // Darwin has the concept of "universal binaries" which is implemented in Soong by
813 // building both x86_64 and arm64 variants, and having select module types know how to
814 // merge the outputs of their corresponding variants together into a final binary. Most
815 // module types don't need to understand this logic, as we only build a small portion
816 // of the tree for Darwin, and only module types writing macho files need to do the
817 // merging.
818 //
819 // This logic is not enabled for:
820 // "common", as it's not an arch-specific variant
821 // "32", as Darwin never has a 32-bit variant
822 // !UseTargetVariants, as the module has opted into handling the arch-specific logic on
823 // its own.
824 if os == Darwin && multilib != "common" && multilib != "32" {
825 if multilib == "common_first" {
826 multilib = "darwin_universal_common_first"
827 } else {
828 multilib = "darwin_universal"
829 }
830 }
831
Colin Crossee0bc3b2018-10-02 22:01:37 -0700832 return multilib, ""
833 } else {
834 // For app modules a single arch variant will be created per OS class which is expected to handle all the
835 // selected arches. Return the common-type as multilib and any Android.bp provided multilib as extraMultilib
836 if multilib == base.commonProperties.Default_multilib {
837 multilib = "first"
838 }
839 return base.commonProperties.Default_multilib, multilib
840 }
841}
842
Colin Crossa6845402020-11-16 15:08:19 -0800843// filterToArch takes a list of Targets and an ArchType, and returns a modified list that contains
Inseob Kim20fb5d42021-02-02 20:07:58 +0900844// only Targets that have the specified ArchTypes.
845func filterToArch(targets []Target, archs ...ArchType) []Target {
Colin Crossfb0c16e2019-11-20 17:12:35 -0800846 for i := 0; i < len(targets); i++ {
Inseob Kim20fb5d42021-02-02 20:07:58 +0900847 found := false
848 for _, arch := range archs {
849 if targets[i].Arch.ArchType == arch {
850 found = true
851 break
852 }
853 }
854 if !found {
Colin Crossfb0c16e2019-11-20 17:12:35 -0800855 targets = append(targets[:i], targets[i+1:]...)
856 i--
857 }
858 }
859 return targets
860}
861
Colin Crossc0f0eb82022-07-19 14:41:11 -0700862// filterHostCross takes a list of Targets and a hostCross value, and returns a modified list
863// that contains only Targets that have the specified HostCross.
864func filterHostCross(targets []Target, hostCross bool) []Target {
865 for i := 0; i < len(targets); i++ {
866 if targets[i].HostCross != hostCross {
867 targets = append(targets[:i], targets[i+1:]...)
868 i--
869 }
870 }
871 return targets
872}
873
Colin Crossa6845402020-11-16 15:08:19 -0800874// archPropRoot is a struct type used as the top level of the arch-specific properties. It
875// contains the "arch", "multilib", and "target" property structs. It is used to split up the
876// property structs to limit how much is allocated when a single arch-specific property group is
877// used. The types are interface{} because they will hold instances of runtime-created types.
Colin Crosscbbd13f2020-01-17 14:08:22 -0800878type archPropRoot struct {
879 Arch, Multilib, Target interface{}
880}
881
Colin Crossa6845402020-11-16 15:08:19 -0800882// archPropTypeDesc holds the runtime-created types for the property structs to instantiate to
883// create an archPropRoot property struct.
884type archPropTypeDesc struct {
885 arch, multilib, target reflect.Type
886}
887
Colin Crosscbbd13f2020-01-17 14:08:22 -0800888// createArchPropTypeDesc takes a reflect.Type that is either a struct or a pointer to a struct, and
889// returns lists of reflect.Types that contains the arch-variant properties inside structs for each
890// arch, multilib and target property.
Colin Crossa6845402020-11-16 15:08:19 -0800891//
892// This is a relatively expensive operation, so the results are cached in the global
893// archPropTypeMap. It is constructed entirely based on compile-time data, so there is no need
894// to isolate the results between multiple tests running in parallel.
Colin Crosscbbd13f2020-01-17 14:08:22 -0800895func createArchPropTypeDesc(props reflect.Type) []archPropTypeDesc {
Colin Crossb1d8c992020-01-21 11:43:29 -0800896 // Each property struct shard will be nested many times under the runtime generated arch struct,
897 // which can hit the limit of 64kB for the name of runtime generated structs. They are nested
898 // 97 times now, which may grow in the future, plus there is some overhead for the containing
899 // type. This number may need to be reduced if too many are added, but reducing it too far
900 // could cause problems if a single deeply nested property no longer fits in the name.
901 const maxArchTypeNameSize = 500
902
Colin Crossa6845402020-11-16 15:08:19 -0800903 // Convert the type to a new set of types that contains only the arch-specific properties
Usta Shrestha0b52d832022-02-04 21:37:39 -0500904 // (those that are tagged with `android:"arch_variant"`), and sharded into multiple types
Colin Crossa6845402020-11-16 15:08:19 -0800905 // to keep the runtime-generated names under the limit.
Colin Crossb1d8c992020-01-21 11:43:29 -0800906 propShards, _ := proptools.FilterPropertyStructSharded(props, maxArchTypeNameSize, filterArchStruct)
Colin Crossa6845402020-11-16 15:08:19 -0800907
908 // If the type has no arch-specific properties there is nothing to do.
Colin Crosscb988072019-01-24 14:58:11 -0800909 if len(propShards) == 0 {
Dan Willemsenb1957a52016-06-23 23:44:54 -0700910 return nil
911 }
912
Colin Crosscbbd13f2020-01-17 14:08:22 -0800913 var ret []archPropTypeDesc
Colin Crossc17727d2018-10-24 12:42:09 -0700914 for _, props := range propShards {
Dan Willemsenb1957a52016-06-23 23:44:54 -0700915
Colin Crossa6845402020-11-16 15:08:19 -0800916 // variantFields takes a list of variant property field names and returns a list the
917 // StructFields with the names and the type of the current shard.
Colin Crossc17727d2018-10-24 12:42:09 -0700918 variantFields := func(names []string) []reflect.StructField {
919 ret := make([]reflect.StructField, len(names))
Dan Willemsenb1957a52016-06-23 23:44:54 -0700920
Colin Crossc17727d2018-10-24 12:42:09 -0700921 for i, name := range names {
922 ret[i].Name = name
923 ret[i].Type = props
Dan Willemsen866b5632017-09-22 12:28:24 -0700924 }
Colin Crossc17727d2018-10-24 12:42:09 -0700925
926 return ret
927 }
928
Colin Crossa6845402020-11-16 15:08:19 -0800929 // Create a type that contains the properties in this shard repeated for each
930 // architecture, architecture variant, and architecture feature.
Colin Crossc17727d2018-10-24 12:42:09 -0700931 archFields := make([]reflect.StructField, len(archTypeList))
932 for i, arch := range archTypeList {
Colin Crossa6845402020-11-16 15:08:19 -0800933 var variants []string
Colin Crossc17727d2018-10-24 12:42:09 -0700934
935 for _, archVariant := range archVariants[arch] {
936 archVariant := variantReplacer.Replace(archVariant)
937 variants = append(variants, proptools.FieldNameForProperty(archVariant))
938 }
Liz Kammer2c2afe22022-02-11 11:35:03 -0500939 for _, cpuVariant := range cpuVariants[arch] {
940 cpuVariant := variantReplacer.Replace(cpuVariant)
941 variants = append(variants, proptools.FieldNameForProperty(cpuVariant))
942 }
Colin Crossc17727d2018-10-24 12:42:09 -0700943 for _, feature := range archFeatures[arch] {
944 feature := variantReplacer.Replace(feature)
945 variants = append(variants, proptools.FieldNameForProperty(feature))
946 }
947
Colin Crossa6845402020-11-16 15:08:19 -0800948 // Create the StructFields for each architecture variant architecture feature
949 // (e.g. "arch.arm.cortex-a53" or "arch.arm.neon").
Colin Crossc17727d2018-10-24 12:42:09 -0700950 fields := variantFields(variants)
951
Colin Crossa6845402020-11-16 15:08:19 -0800952 // Create the StructField for the architecture itself (e.g. "arch.arm"). The special
953 // "BlueprintEmbed" name is used by Blueprint to put the properties in the
954 // parent struct.
Colin Crossc17727d2018-10-24 12:42:09 -0700955 fields = append([]reflect.StructField{{
956 Name: "BlueprintEmbed",
957 Type: props,
958 Anonymous: true,
959 }}, fields...)
960
961 archFields[i] = reflect.StructField{
962 Name: arch.Field,
963 Type: reflect.StructOf(fields),
964 }
965 }
Colin Crossa6845402020-11-16 15:08:19 -0800966
967 // Create the type of the "arch" property struct for this shard.
Colin Crossc17727d2018-10-24 12:42:09 -0700968 archType := reflect.StructOf(archFields)
969
Colin Crossa6845402020-11-16 15:08:19 -0800970 // Create the type for the "multilib" property struct for this shard, containing the
971 // "multilib.lib32" and "multilib.lib64" property structs.
Colin Crossc17727d2018-10-24 12:42:09 -0700972 multilibType := reflect.StructOf(variantFields([]string{"Lib32", "Lib64"}))
973
Colin Crossa6845402020-11-16 15:08:19 -0800974 // Start with a list of the special targets
Colin Crossc17727d2018-10-24 12:42:09 -0700975 targets := []string{
976 "Host",
977 "Android64",
978 "Android32",
979 "Bionic",
Colin Cross528d67e2021-07-23 22:23:07 +0000980 "Glibc",
981 "Musl",
Colin Crossc17727d2018-10-24 12:42:09 -0700982 "Linux",
Colin Crossa98d36d2022-03-07 14:39:49 -0800983 "Host_linux",
Colin Crossc17727d2018-10-24 12:42:09 -0700984 "Not_windows",
985 "Arm_on_x86",
986 "Arm_on_x86_64",
Victor Khimenkoc26fcf42020-05-07 22:16:33 +0200987 "Native_bridge",
Colin Crossc17727d2018-10-24 12:42:09 -0700988 }
Jingwen Chen2f6a21e2021-04-05 07:33:05 +0000989 for _, os := range osTypeList {
Colin Crossa6845402020-11-16 15:08:19 -0800990 // Add all the OSes.
Colin Crossc17727d2018-10-24 12:42:09 -0700991 targets = append(targets, os.Field)
992
Colin Crossa6845402020-11-16 15:08:19 -0800993 // Add the OS/Arch combinations, e.g. "android_arm64".
Colin Crossc17727d2018-10-24 12:42:09 -0700994 for _, archType := range osArchTypeMap[os] {
Liz Kammer9abd62d2021-05-21 08:37:59 -0400995 targets = append(targets, GetCompoundTargetField(os, archType))
Colin Crossc17727d2018-10-24 12:42:09 -0700996
Colin Cross1aa45b02022-02-10 10:33:10 -0800997 // Also add the special "linux_<arch>", "bionic_<arch>" , "glibc_<arch>", and
998 // "musl_<arch>" property structs.
Colin Crossc17727d2018-10-24 12:42:09 -0700999 if os.Linux() {
1000 target := "Linux_" + archType.Name
1001 if !InList(target, targets) {
1002 targets = append(targets, target)
1003 }
1004 }
Colin Crossa98d36d2022-03-07 14:39:49 -08001005 if os.Linux() && os.Class == Host {
1006 target := "Host_linux_" + archType.Name
1007 if !InList(target, targets) {
1008 targets = append(targets, target)
1009 }
1010 }
Colin Crossc17727d2018-10-24 12:42:09 -07001011 if os.Bionic() {
1012 target := "Bionic_" + archType.Name
1013 if !InList(target, targets) {
1014 targets = append(targets, target)
1015 }
Dan Willemsen866b5632017-09-22 12:28:24 -07001016 }
Colin Cross1aa45b02022-02-10 10:33:10 -08001017 if os == Linux {
1018 target := "Glibc_" + archType.Name
1019 if !InList(target, targets) {
1020 targets = append(targets, target)
1021 }
1022 }
1023 if os == LinuxMusl {
1024 target := "Musl_" + archType.Name
1025 if !InList(target, targets) {
1026 targets = append(targets, target)
1027 }
1028 }
Dan Willemsen866b5632017-09-22 12:28:24 -07001029 }
Dan Willemsenb1957a52016-06-23 23:44:54 -07001030 }
Dan Willemsenb1957a52016-06-23 23:44:54 -07001031
Colin Crossa6845402020-11-16 15:08:19 -08001032 // Create the type for the "target" property struct for this shard.
Colin Crossc17727d2018-10-24 12:42:09 -07001033 targetType := reflect.StructOf(variantFields(targets))
Colin Crosscbbd13f2020-01-17 14:08:22 -08001034
Colin Crossa6845402020-11-16 15:08:19 -08001035 // Return a descriptor of the 3 runtime-created types.
Colin Crosscbbd13f2020-01-17 14:08:22 -08001036 ret = append(ret, archPropTypeDesc{
1037 arch: reflect.PtrTo(archType),
1038 multilib: reflect.PtrTo(multilibType),
1039 target: reflect.PtrTo(targetType),
1040 })
Colin Crossc17727d2018-10-24 12:42:09 -07001041 }
1042 return ret
Dan Willemsenb1957a52016-06-23 23:44:54 -07001043}
1044
Colin Crossa6845402020-11-16 15:08:19 -08001045// variantReplacer converts architecture variant or architecture feature names into names that
1046// are valid for an Android.bp file.
1047var variantReplacer = strings.NewReplacer("-", "_", ".", "_")
1048
1049// filterArchStruct returns true if the given field is an architecture specific property.
Colin Cross74449102019-09-25 11:26:40 -07001050func filterArchStruct(field reflect.StructField, prefix string) (bool, reflect.StructField) {
1051 if proptools.HasTag(field, "android", "arch_variant") {
1052 // The arch_variant field isn't necessary past this point
1053 // Instead of wasting space, just remove it. Go also has a
1054 // 16-bit limit on structure name length. The name is constructed
1055 // based on the Go source representation of the structure, so
1056 // the tag names count towards that length.
Colin Crossb4fecbf2020-01-21 11:38:47 -08001057
1058 androidTag := field.Tag.Get("android")
1059 values := strings.Split(androidTag, ",")
1060
1061 if string(field.Tag) != `android:"`+strings.Join(values, ",")+`"` {
1062 panic(fmt.Errorf("unexpected tag format %q", field.Tag))
Colin Cross74449102019-09-25 11:26:40 -07001063 }
Colin Crossb4fecbf2020-01-21 11:38:47 -08001064 // these tags don't need to be present in the runtime generated struct type.
Cole Faust5fda87b2024-04-24 11:21:14 -07001065 // However replace_instead_of_append does, because it's read by the blueprint
1066 // property extending util functions, which can operate on these generated arch
1067 // property structs.
1068 values = RemoveListFromList(values, []string{"arch_variant", "variant_prepend", "path"})
Liz Kammerff966b12022-07-29 10:49:16 -04001069 if len(values) > 0 {
Cole Faust5fda87b2024-04-24 11:21:14 -07001070 if values[0] != "replace_instead_of_append" || len(values) > 1 {
1071 panic(fmt.Errorf("unknown tags %q in field %q", values, prefix+field.Name))
1072 }
1073 field.Tag = `android:"replace_instead_of_append"`
1074 } else {
1075 field.Tag = ``
Colin Crossb4fecbf2020-01-21 11:38:47 -08001076 }
Colin Cross74449102019-09-25 11:26:40 -07001077 return true, field
1078 }
1079 return false, field
1080}
1081
Colin Crossa6845402020-11-16 15:08:19 -08001082// archPropTypeMap contains a cache of the results of createArchPropTypeDesc for each type. It is
1083// shared across all Contexts, but is constructed based only on compile-time information so there
1084// is no risk of contaminating one Context with data from another.
Dan Willemsenb1957a52016-06-23 23:44:54 -07001085var archPropTypeMap OncePer
1086
Colin Crossa6845402020-11-16 15:08:19 -08001087// initArchModule adds the architecture-specific property structs to a Module.
1088func initArchModule(m Module) {
Colin Cross3f40fa42015-01-30 17:27:36 -08001089
1090 base := m.base()
1091
Ustaeabf0f32021-12-06 15:17:23 -05001092 if len(base.archProperties) != 0 {
1093 panic(fmt.Errorf("module %s already has archProperties", m.Name()))
1094 }
Colin Cross3f40fa42015-01-30 17:27:36 -08001095
Ustaeabf0f32021-12-06 15:17:23 -05001096 getStructType := func(properties interface{}) reflect.Type {
Colin Cross3f40fa42015-01-30 17:27:36 -08001097 propertiesValue := reflect.ValueOf(properties)
Colin Cross62496a02016-08-08 15:49:17 -07001098 t := propertiesValue.Type()
Colin Cross3f40fa42015-01-30 17:27:36 -08001099 if propertiesValue.Kind() != reflect.Ptr {
Colin Crossca860ac2016-01-04 14:34:37 -08001100 panic(fmt.Errorf("properties must be a pointer to a struct, got %T",
1101 propertiesValue.Interface()))
Colin Cross3f40fa42015-01-30 17:27:36 -08001102 }
1103
1104 propertiesValue = propertiesValue.Elem()
1105 if propertiesValue.Kind() != reflect.Struct {
Ustaeabf0f32021-12-06 15:17:23 -05001106 panic(fmt.Errorf("properties must be a pointer to a struct, got a pointer to %T",
Colin Crossca860ac2016-01-04 14:34:37 -08001107 propertiesValue.Interface()))
Colin Cross3f40fa42015-01-30 17:27:36 -08001108 }
Ustaeabf0f32021-12-06 15:17:23 -05001109 return t
1110 }
Colin Cross3f40fa42015-01-30 17:27:36 -08001111
Usta851a3272022-01-05 23:42:33 -05001112 for _, properties := range m.GetProperties() {
Ustaeabf0f32021-12-06 15:17:23 -05001113 t := getStructType(properties)
Colin Crossa6845402020-11-16 15:08:19 -08001114 // Get or create the arch-specific property struct types for this property struct type.
Colin Cross571cccf2019-02-04 11:22:08 -08001115 archPropTypes := archPropTypeMap.Once(NewCustomOnceKey(t), func() interface{} {
Colin Crosscbbd13f2020-01-17 14:08:22 -08001116 return createArchPropTypeDesc(t)
1117 }).([]archPropTypeDesc)
Colin Cross3f40fa42015-01-30 17:27:36 -08001118
Colin Crossa6845402020-11-16 15:08:19 -08001119 // Instantiate one of each arch-specific property struct type and add it to the
1120 // properties for the Module.
Colin Crossc17727d2018-10-24 12:42:09 -07001121 var archProperties []interface{}
1122 for _, t := range archPropTypes {
Colin Crosscbbd13f2020-01-17 14:08:22 -08001123 archProperties = append(archProperties, &archPropRoot{
1124 Arch: reflect.Zero(t.arch).Interface(),
1125 Multilib: reflect.Zero(t.multilib).Interface(),
1126 Target: reflect.Zero(t.target).Interface(),
1127 })
Dan Willemsenb1957a52016-06-23 23:44:54 -07001128 }
Colin Crossc17727d2018-10-24 12:42:09 -07001129 base.archProperties = append(base.archProperties, archProperties)
1130 m.AddProperties(archProperties...)
Colin Cross3f40fa42015-01-30 17:27:36 -08001131 }
1132
Colin Cross3f40fa42015-01-30 17:27:36 -08001133}
1134
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001135func maybeBlueprintEmbed(src reflect.Value) reflect.Value {
Colin Crossa6845402020-11-16 15:08:19 -08001136 // If the value of the field is a struct (as opposed to a pointer to a struct) then step
1137 // into the BlueprintEmbed field.
Dan Willemsenb1957a52016-06-23 23:44:54 -07001138 if src.Kind() == reflect.Struct {
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001139 return src.FieldByName("BlueprintEmbed")
1140 } else {
1141 return src
Colin Cross06a931b2015-10-28 17:23:31 -07001142 }
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001143}
1144
1145// Merges the property struct in srcValue into dst.
Liz Kammerb6dbc872021-05-14 15:14:40 -04001146func mergePropertyStruct(ctx ArchVariantContext, dst interface{}, srcValue reflect.Value) {
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001147 src := maybeBlueprintEmbed(srcValue).Interface()
Colin Cross06a931b2015-10-28 17:23:31 -07001148
Colin Crossa6845402020-11-16 15:08:19 -08001149 // order checks the `android:"variant_prepend"` tag to handle properties where the
1150 // arch-specific value needs to come before the generic value, for example for lists of
1151 // include directories.
Colin Cross1e7e0432024-02-02 10:59:50 -08001152 order := func(dstField, srcField reflect.StructField) (proptools.Order, error) {
Colin Cross6ee75b62016-05-05 15:57:15 -07001153 if proptools.HasTag(dstField, "android", "variant_prepend") {
1154 return proptools.Prepend, nil
1155 } else {
1156 return proptools.Append, nil
1157 }
1158 }
1159
Colin Crossa6845402020-11-16 15:08:19 -08001160 // Squash the located property struct into the destination property struct.
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001161 err := proptools.ExtendMatchingProperties([]interface{}{dst}, src, nil, order)
Colin Cross06a931b2015-10-28 17:23:31 -07001162 if err != nil {
1163 if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
1164 ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
1165 } else {
1166 panic(err)
1167 }
1168 }
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001169}
Colin Cross85a88972015-11-23 13:29:51 -08001170
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001171// Returns the immediate child of the input property struct that corresponds to
1172// the sub-property "field".
Liz Kammerb6dbc872021-05-14 15:14:40 -04001173func getChildPropertyStruct(ctx ArchVariantContext,
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001174 src reflect.Value, field, userFriendlyField string) (reflect.Value, bool) {
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001175
1176 // Step into non-nil pointers to structs in the src value.
1177 if src.Kind() == reflect.Ptr {
1178 if src.IsNil() {
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001179 return reflect.Value{}, false
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001180 }
1181 src = src.Elem()
1182 }
1183
1184 // Find the requested field in the src struct.
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001185 child := src.FieldByName(proptools.FieldNameForProperty(field))
1186 if !child.IsValid() {
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001187 ctx.ModuleErrorf("field %q does not exist", userFriendlyField)
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001188 return reflect.Value{}, false
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001189 }
1190
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001191 if child.IsZero() {
1192 return reflect.Value{}, false
1193 }
1194
1195 return child, true
Colin Cross06a931b2015-10-28 17:23:31 -07001196}
1197
Colin Crossa6845402020-11-16 15:08:19 -08001198// Squash the appropriate OS-specific property structs into the matching top level property structs
1199// based on the CompileOS value that was annotated on the variant.
Colin Crossa195f912019-10-16 11:07:20 -07001200func (m *ModuleBase) setOSProperties(ctx BottomUpMutatorContext) {
1201 os := m.commonProperties.CompileOS
1202
Ustadca02192021-12-20 12:56:46 -05001203 for i := range m.archProperties {
Usta851a3272022-01-05 23:42:33 -05001204 genProps := m.GetProperties()[i]
Colin Crossa195f912019-10-16 11:07:20 -07001205 if m.archProperties[i] == nil {
1206 continue
1207 }
1208 for _, archProperties := range m.archProperties[i] {
1209 archPropValues := reflect.ValueOf(archProperties).Elem()
1210
Colin Crosscbbd13f2020-01-17 14:08:22 -08001211 targetProp := archPropValues.FieldByName("Target").Elem()
Colin Crossa195f912019-10-16 11:07:20 -07001212
1213 // Handle host-specific properties in the form:
1214 // target: {
1215 // host: {
1216 // key: value,
1217 // },
1218 // },
Jiyong Park1613e552020-09-14 19:43:17 +09001219 if os.Class == Host {
Colin Crossa195f912019-10-16 11:07:20 -07001220 field := "Host"
1221 prefix := "target.host"
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001222 if hostProperties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
1223 mergePropertyStruct(ctx, genProps, hostProperties)
1224 }
Colin Crossa195f912019-10-16 11:07:20 -07001225 }
1226
1227 // Handle target OS generalities of the form:
1228 // target: {
1229 // bionic: {
1230 // key: value,
1231 // },
1232 // }
1233 if os.Linux() {
1234 field := "Linux"
1235 prefix := "target.linux"
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001236 if linuxProperties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
1237 mergePropertyStruct(ctx, genProps, linuxProperties)
1238 }
Colin Crossa195f912019-10-16 11:07:20 -07001239 }
1240
Colin Crossa98d36d2022-03-07 14:39:49 -08001241 if os.Linux() && os.Class == Host {
1242 field := "Host_linux"
1243 prefix := "target.host_linux"
1244 if linuxProperties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
1245 mergePropertyStruct(ctx, genProps, linuxProperties)
1246 }
1247 }
1248
Colin Crossa195f912019-10-16 11:07:20 -07001249 if os.Bionic() {
1250 field := "Bionic"
1251 prefix := "target.bionic"
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001252 if bionicProperties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
1253 mergePropertyStruct(ctx, genProps, bionicProperties)
1254 }
Colin Crossa195f912019-10-16 11:07:20 -07001255 }
1256
Colin Cross528d67e2021-07-23 22:23:07 +00001257 if os == Linux {
1258 field := "Glibc"
1259 prefix := "target.glibc"
1260 if bionicProperties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
1261 mergePropertyStruct(ctx, genProps, bionicProperties)
1262 }
1263 }
1264
1265 if os == LinuxMusl {
1266 field := "Musl"
1267 prefix := "target.musl"
1268 if bionicProperties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
1269 mergePropertyStruct(ctx, genProps, bionicProperties)
1270 }
Colin Cross528d67e2021-07-23 22:23:07 +00001271 }
1272
Colin Crossa195f912019-10-16 11:07:20 -07001273 // Handle target OS properties in the form:
1274 // target: {
1275 // linux_glibc: {
1276 // key: value,
1277 // },
1278 // not_windows: {
1279 // key: value,
1280 // },
1281 // android {
1282 // key: value,
1283 // },
1284 // },
1285 field := os.Field
1286 prefix := "target." + os.Name
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001287 if osProperties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
1288 mergePropertyStruct(ctx, genProps, osProperties)
1289 }
Colin Crossa195f912019-10-16 11:07:20 -07001290
Jiyong Park1613e552020-09-14 19:43:17 +09001291 if os.Class == Host && os != Windows {
Colin Crossa195f912019-10-16 11:07:20 -07001292 field := "Not_windows"
1293 prefix := "target.not_windows"
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001294 if notWindowsProperties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
1295 mergePropertyStruct(ctx, genProps, notWindowsProperties)
1296 }
Colin Crossa195f912019-10-16 11:07:20 -07001297 }
1298
1299 // Handle 64-bit device properties in the form:
1300 // target {
1301 // android64 {
1302 // key: value,
1303 // },
1304 // android32 {
1305 // key: value,
1306 // },
1307 // },
1308 // WARNING: this is probably not what you want to use in your blueprints file, it selects
1309 // options for all targets on a device that supports 64-bit binaries, not just the targets
1310 // that are being compiled for 64-bit. Its expected use case is binaries like linker and
1311 // debuggerd that need to know when they are a 32-bit process running on a 64-bit device
1312 if os.Class == Device {
1313 if ctx.Config().Android64() {
1314 field := "Android64"
1315 prefix := "target.android64"
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001316 if android64Properties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
1317 mergePropertyStruct(ctx, genProps, android64Properties)
1318 }
Colin Crossa195f912019-10-16 11:07:20 -07001319 } else {
1320 field := "Android32"
1321 prefix := "target.android32"
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001322 if android32Properties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
1323 mergePropertyStruct(ctx, genProps, android32Properties)
1324 }
Colin Crossa195f912019-10-16 11:07:20 -07001325 }
1326 }
1327 }
1328 }
1329}
1330
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001331// Returns the struct containing the properties specific to the given
1332// architecture type. These look like this in Blueprint files:
Colin Crossd079e0b2022-08-16 10:27:33 -07001333//
1334// arch: {
1335// arm64: {
1336// key: value,
1337// },
1338// },
1339//
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001340// This struct will also contain sub-structs containing to the architecture/CPU
1341// variants and features that themselves contain properties specific to those.
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001342func getArchTypeStruct(ctx ArchVariantContext, archProperties interface{}, archType ArchType) (reflect.Value, bool) {
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001343 archPropValues := reflect.ValueOf(archProperties).Elem()
1344 archProp := archPropValues.FieldByName("Arch").Elem()
1345 prefix := "arch." + archType.Name
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001346 return getChildPropertyStruct(ctx, archProp, archType.Name, prefix)
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001347}
1348
1349// Returns the struct containing the properties specific to a given multilib
1350// value. These look like this in the Blueprint file:
Colin Crossd079e0b2022-08-16 10:27:33 -07001351//
1352// multilib: {
1353// lib32: {
1354// key: value,
1355// },
1356// },
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001357func getMultilibStruct(ctx ArchVariantContext, archProperties interface{}, archType ArchType) (reflect.Value, bool) {
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001358 archPropValues := reflect.ValueOf(archProperties).Elem()
1359 multilibProp := archPropValues.FieldByName("Multilib").Elem()
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001360 return getChildPropertyStruct(ctx, multilibProp, archType.Multilib, "multilib."+archType.Multilib)
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001361}
1362
Liz Kammer9abd62d2021-05-21 08:37:59 -04001363func GetCompoundTargetField(os OsType, arch ArchType) string {
Rupert Shuttleworthc194ffb2021-05-19 06:49:02 -04001364 return os.Field + "_" + arch.Name
1365}
1366
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001367// Returns the structs corresponding to the properties specific to the given
1368// architecture and OS in archProperties.
1369func getArchProperties(ctx BaseMutatorContext, archProperties interface{}, arch Arch, os OsType, nativeBridgeEnabled bool) []reflect.Value {
1370 result := make([]reflect.Value, 0)
1371 archPropValues := reflect.ValueOf(archProperties).Elem()
1372
1373 targetProp := archPropValues.FieldByName("Target").Elem()
1374
1375 archType := arch.ArchType
1376
1377 if arch.ArchType != Common {
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001378 archStruct, ok := getArchTypeStruct(ctx, archProperties, arch.ArchType)
1379 if ok {
1380 result = append(result, archStruct)
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001381
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001382 // Handle arch-variant-specific properties in the form:
1383 // arch: {
1384 // arm: {
1385 // variant: {
1386 // key: value,
1387 // },
1388 // },
1389 // },
1390 v := variantReplacer.Replace(arch.ArchVariant)
1391 if v != "" {
1392 prefix := "arch." + archType.Name + "." + v
1393 if variantProperties, ok := getChildPropertyStruct(ctx, archStruct, v, prefix); ok {
1394 result = append(result, variantProperties)
1395 }
1396 }
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001397
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001398 // Handle cpu-variant-specific properties in the form:
1399 // arch: {
1400 // arm: {
1401 // variant: {
1402 // key: value,
1403 // },
1404 // },
1405 // },
1406 if arch.CpuVariant != arch.ArchVariant {
1407 c := variantReplacer.Replace(arch.CpuVariant)
1408 if c != "" {
1409 prefix := "arch." + archType.Name + "." + c
1410 if cpuVariantProperties, ok := getChildPropertyStruct(ctx, archStruct, c, prefix); ok {
1411 result = append(result, cpuVariantProperties)
1412 }
1413 }
1414 }
1415
1416 // Handle arch-feature-specific properties in the form:
1417 // arch: {
1418 // arm: {
1419 // feature: {
1420 // key: value,
1421 // },
1422 // },
1423 // },
1424 for _, feature := range arch.ArchFeatures {
1425 prefix := "arch." + archType.Name + "." + feature
1426 if featureProperties, ok := getChildPropertyStruct(ctx, archStruct, feature, prefix); ok {
1427 result = append(result, featureProperties)
1428 }
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001429 }
1430 }
1431
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001432 if multilibProperties, ok := getMultilibStruct(ctx, archProperties, archType); ok {
1433 result = append(result, multilibProperties)
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001434 }
1435
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001436 // Handle combined OS-feature and arch specific properties in the form:
1437 // target: {
1438 // bionic_x86: {
1439 // key: value,
1440 // },
1441 // }
1442 if os.Linux() {
1443 field := "Linux_" + arch.ArchType.Name
1444 userFriendlyField := "target.linux_" + arch.ArchType.Name
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001445 if linuxProperties, ok := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField); ok {
1446 result = append(result, linuxProperties)
1447 }
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001448 }
1449
1450 if os.Bionic() {
1451 field := "Bionic_" + archType.Name
1452 userFriendlyField := "target.bionic_" + archType.Name
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001453 if bionicProperties, ok := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField); ok {
1454 result = append(result, bionicProperties)
1455 }
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001456 }
1457
1458 // Handle combined OS and arch specific properties in the form:
1459 // target: {
1460 // linux_glibc_x86: {
1461 // key: value,
1462 // },
1463 // linux_glibc_arm: {
1464 // key: value,
1465 // },
1466 // android_arm {
1467 // key: value,
1468 // },
1469 // android_x86 {
1470 // key: value,
1471 // },
1472 // },
Liz Kammer9abd62d2021-05-21 08:37:59 -04001473 field := GetCompoundTargetField(os, archType)
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001474 userFriendlyField := "target." + os.Name + "_" + archType.Name
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001475 if osArchProperties, ok := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField); ok {
1476 result = append(result, osArchProperties)
1477 }
Colin Cross528d67e2021-07-23 22:23:07 +00001478
Colin Cross1aa45b02022-02-10 10:33:10 -08001479 if os == Linux {
1480 field := "Glibc_" + archType.Name
1481 userFriendlyField := "target.glibc_" + "_" + archType.Name
1482 if osArchProperties, ok := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField); ok {
1483 result = append(result, osArchProperties)
1484 }
1485 }
1486
Colin Cross528d67e2021-07-23 22:23:07 +00001487 if os == LinuxMusl {
Colin Cross1aa45b02022-02-10 10:33:10 -08001488 field := "Musl_" + archType.Name
1489 userFriendlyField := "target.musl_" + "_" + archType.Name
1490 if osArchProperties, ok := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField); ok {
1491 result = append(result, osArchProperties)
1492 }
Colin Cross528d67e2021-07-23 22:23:07 +00001493 }
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001494 }
1495
1496 // Handle arm on x86 properties in the form:
1497 // target {
1498 // arm_on_x86 {
1499 // key: value,
1500 // },
1501 // arm_on_x86_64 {
1502 // key: value,
1503 // },
1504 // },
1505 if os.Class == Device {
1506 if arch.ArchType == X86 && (hasArmAbi(arch) ||
1507 hasArmAndroidArch(ctx.Config().Targets[Android])) {
1508 field := "Arm_on_x86"
1509 userFriendlyField := "target.arm_on_x86"
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001510 if armOnX86Properties, ok := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField); ok {
1511 result = append(result, armOnX86Properties)
1512 }
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001513 }
1514 if arch.ArchType == X86_64 && (hasArmAbi(arch) ||
1515 hasArmAndroidArch(ctx.Config().Targets[Android])) {
1516 field := "Arm_on_x86_64"
1517 userFriendlyField := "target.arm_on_x86_64"
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001518 if armOnX8664Properties, ok := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField); ok {
1519 result = append(result, armOnX8664Properties)
1520 }
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001521 }
1522 if os == Android && nativeBridgeEnabled {
1523 userFriendlyField := "Native_bridge"
1524 prefix := "target.native_bridge"
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001525 if nativeBridgeProperties, ok := getChildPropertyStruct(ctx, targetProp, userFriendlyField, prefix); ok {
1526 result = append(result, nativeBridgeProperties)
1527 }
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001528 }
1529 }
1530
1531 return result
1532}
1533
Colin Crossa6845402020-11-16 15:08:19 -08001534// Squash the appropriate arch-specific property structs into the matching top level property
1535// structs based on the CompileTarget value that was annotated on the variant.
Colin Cross4157e882019-06-06 16:57:04 -07001536func (m *ModuleBase) setArchProperties(ctx BottomUpMutatorContext) {
1537 arch := m.Arch()
1538 os := m.Os()
Colin Crossd3ba0392015-05-07 14:11:29 -07001539
Ustadca02192021-12-20 12:56:46 -05001540 for i := range m.archProperties {
Usta851a3272022-01-05 23:42:33 -05001541 genProps := m.GetProperties()[i]
Colin Cross4157e882019-06-06 16:57:04 -07001542 if m.archProperties[i] == nil {
Dan Willemsenb1957a52016-06-23 23:44:54 -07001543 continue
1544 }
Dan Willemsenb1957a52016-06-23 23:44:54 -07001545
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001546 propStructs := make([]reflect.Value, 0)
1547 for _, archProperty := range m.archProperties[i] {
1548 propStructShard := getArchProperties(ctx, archProperty, arch, os, m.Target().NativeBridge == NativeBridgeEnabled)
1549 propStructs = append(propStructs, propStructShard...)
1550 }
Dan Willemsenb1957a52016-06-23 23:44:54 -07001551
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001552 for _, propStruct := range propStructs {
1553 mergePropertyStruct(ctx, genProps, propStruct)
Colin Crossbb2e2b72016-12-08 17:23:53 -08001554 }
Colin Cross3f40fa42015-01-30 17:27:36 -08001555 }
1556}
1557
Colin Cross0c66bc62021-07-20 09:47:41 -07001558// determineBuildOS stores the OS and architecture used for host targets used during the build into
Colin Cross528d67e2021-07-23 22:23:07 +00001559// config based on the runtime OS and architecture determined by Go and the product configuration.
Colin Cross0c66bc62021-07-20 09:47:41 -07001560func determineBuildOS(config *config) {
1561 config.BuildOS = func() OsType {
1562 switch runtime.GOOS {
1563 case "linux":
Colin Cross528d67e2021-07-23 22:23:07 +00001564 if Bool(config.productVariables.HostMusl) {
1565 return LinuxMusl
1566 }
Colin Cross0c66bc62021-07-20 09:47:41 -07001567 return Linux
1568 case "darwin":
1569 return Darwin
1570 default:
1571 panic(fmt.Sprintf("unsupported OS: %s", runtime.GOOS))
1572 }
1573 }()
1574
1575 config.BuildArch = func() ArchType {
1576 switch runtime.GOARCH {
1577 case "amd64":
1578 return X86_64
1579 default:
1580 panic(fmt.Sprintf("unsupported Arch: %s", runtime.GOARCH))
1581 }
1582 }()
1583
1584}
1585
Colin Crossa6845402020-11-16 15:08:19 -08001586// Convert the arch product variables into a list of targets for each OsType.
Dan Willemsen0ef639b2018-10-10 17:02:29 -07001587func decodeTargetProductVariables(config *config) (map[OsType][]Target, error) {
Dan Willemsen45133ac2018-03-09 21:22:06 -08001588 variables := config.productVariables
Dan Willemsen490fd492015-11-24 17:53:15 -08001589
Dan Willemsen0ef639b2018-10-10 17:02:29 -07001590 targets := make(map[OsType][]Target)
Colin Crossa1ad8d12016-06-01 17:09:44 -07001591 var targetErr error
1592
Liz Kammerb7f33662022-02-28 14:16:16 -05001593 type targetConfig struct {
1594 os OsType
1595 archName string
1596 archVariant *string
1597 cpuVariant *string
1598 abi []string
1599 nativeBridgeEnabled NativeBridgeSupport
1600 nativeBridgeHostArchName *string
1601 nativeBridgeRelativePath *string
1602 }
1603
1604 addTarget := func(target targetConfig) {
Colin Crossa1ad8d12016-06-01 17:09:44 -07001605 if targetErr != nil {
1606 return
Dan Willemsen490fd492015-11-24 17:53:15 -08001607 }
Colin Crossa1ad8d12016-06-01 17:09:44 -07001608
Liz Kammerb7f33662022-02-28 14:16:16 -05001609 arch, err := decodeArch(target.os, target.archName, target.archVariant, target.cpuVariant, target.abi)
Colin Crossa1ad8d12016-06-01 17:09:44 -07001610 if err != nil {
1611 targetErr = err
1612 return
1613 }
Liz Kammerb7f33662022-02-28 14:16:16 -05001614 nativeBridgeRelativePathStr := String(target.nativeBridgeRelativePath)
1615 nativeBridgeHostArchNameStr := String(target.nativeBridgeHostArchName)
dimitry8d6dde82019-07-11 10:23:53 +02001616
1617 // Use guest arch as relative install path by default
Liz Kammerb7f33662022-02-28 14:16:16 -05001618 if target.nativeBridgeEnabled && nativeBridgeRelativePathStr == "" {
dimitry8d6dde82019-07-11 10:23:53 +02001619 nativeBridgeRelativePathStr = arch.ArchType.String()
1620 }
Colin Crossa1ad8d12016-06-01 17:09:44 -07001621
Jiyong Park1613e552020-09-14 19:43:17 +09001622 // A target is considered as HostCross if it's a host target which can't run natively on
1623 // the currently configured build machine (either because the OS is different or because of
1624 // the unsupported arch)
1625 hostCross := false
Liz Kammerb7f33662022-02-28 14:16:16 -05001626 if target.os.Class == Host {
Jiyong Park1613e552020-09-14 19:43:17 +09001627 var osSupported bool
Liz Kammerb7f33662022-02-28 14:16:16 -05001628 if target.os == config.BuildOS {
Jiyong Park1613e552020-09-14 19:43:17 +09001629 osSupported = true
Liz Kammerb7f33662022-02-28 14:16:16 -05001630 } else if config.BuildOS.Linux() && target.os.Linux() {
Jiyong Park1613e552020-09-14 19:43:17 +09001631 // LinuxBionic and Linux are compatible
1632 osSupported = true
1633 } else {
1634 osSupported = false
1635 }
1636
1637 var archSupported bool
1638 if arch.ArchType == Common {
1639 archSupported = true
1640 } else if arch.ArchType.Name == *variables.HostArch {
1641 archSupported = true
1642 } else if variables.HostSecondaryArch != nil && arch.ArchType.Name == *variables.HostSecondaryArch {
1643 archSupported = true
1644 } else {
1645 archSupported = false
1646 }
1647 if !osSupported || !archSupported {
1648 hostCross = true
1649 }
1650 }
1651
Liz Kammerb7f33662022-02-28 14:16:16 -05001652 targets[target.os] = append(targets[target.os],
Colin Crossa1ad8d12016-06-01 17:09:44 -07001653 Target{
Liz Kammerb7f33662022-02-28 14:16:16 -05001654 Os: target.os,
dimitry8d6dde82019-07-11 10:23:53 +02001655 Arch: arch,
Liz Kammerb7f33662022-02-28 14:16:16 -05001656 NativeBridge: target.nativeBridgeEnabled,
dimitry8d6dde82019-07-11 10:23:53 +02001657 NativeBridgeHostArchName: nativeBridgeHostArchNameStr,
1658 NativeBridgeRelativePath: nativeBridgeRelativePathStr,
Jiyong Park1613e552020-09-14 19:43:17 +09001659 HostCross: hostCross,
Colin Crossa1ad8d12016-06-01 17:09:44 -07001660 })
Dan Willemsen490fd492015-11-24 17:53:15 -08001661 }
1662
Colin Cross4225f652015-09-17 14:33:42 -07001663 if variables.HostArch == nil {
Colin Crossa1ad8d12016-06-01 17:09:44 -07001664 return nil, fmt.Errorf("No host primary architecture set")
Colin Cross4225f652015-09-17 14:33:42 -07001665 }
1666
Colin Crossa6845402020-11-16 15:08:19 -08001667 // The primary host target, which must always exist.
Liz Kammerb7f33662022-02-28 14:16:16 -05001668 addTarget(targetConfig{os: config.BuildOS, archName: *variables.HostArch, nativeBridgeEnabled: NativeBridgeDisabled})
Colin Cross4225f652015-09-17 14:33:42 -07001669
Colin Crossa6845402020-11-16 15:08:19 -08001670 // An optional secondary host target.
Colin Crosseeabb892015-11-20 13:07:51 -08001671 if variables.HostSecondaryArch != nil && *variables.HostSecondaryArch != "" {
Liz Kammerb7f33662022-02-28 14:16:16 -05001672 addTarget(targetConfig{os: config.BuildOS, archName: *variables.HostSecondaryArch, nativeBridgeEnabled: NativeBridgeDisabled})
Dan Willemsen490fd492015-11-24 17:53:15 -08001673 }
1674
Colin Crossa6845402020-11-16 15:08:19 -08001675 // Optional cross-compiled host targets, generally Windows.
Colin Crossff3ae9d2018-04-10 16:15:18 -07001676 if String(variables.CrossHost) != "" {
Colin Crossa1ad8d12016-06-01 17:09:44 -07001677 crossHostOs := osByName(*variables.CrossHost)
1678 if crossHostOs == NoOsType {
1679 return nil, fmt.Errorf("Unknown cross host OS %q", *variables.CrossHost)
1680 }
1681
Colin Crossff3ae9d2018-04-10 16:15:18 -07001682 if String(variables.CrossHostArch) == "" {
Colin Crossa1ad8d12016-06-01 17:09:44 -07001683 return nil, fmt.Errorf("No cross-host primary architecture set")
Dan Willemsen490fd492015-11-24 17:53:15 -08001684 }
1685
Colin Crossa6845402020-11-16 15:08:19 -08001686 // The primary cross-compiled host target.
Liz Kammerb7f33662022-02-28 14:16:16 -05001687 addTarget(targetConfig{os: crossHostOs, archName: *variables.CrossHostArch, nativeBridgeEnabled: NativeBridgeDisabled})
Dan Willemsen490fd492015-11-24 17:53:15 -08001688
Colin Crossa6845402020-11-16 15:08:19 -08001689 // An optional secondary cross-compiled host target.
Dan Willemsen490fd492015-11-24 17:53:15 -08001690 if variables.CrossHostSecondaryArch != nil && *variables.CrossHostSecondaryArch != "" {
Liz Kammerb7f33662022-02-28 14:16:16 -05001691 addTarget(targetConfig{os: crossHostOs, archName: *variables.CrossHostSecondaryArch, nativeBridgeEnabled: NativeBridgeDisabled})
Dan Willemsen490fd492015-11-24 17:53:15 -08001692 }
1693 }
1694
Colin Crossa6845402020-11-16 15:08:19 -08001695 // Optional device targets
Dan Willemsen3f32f032016-07-11 14:36:48 -07001696 if variables.DeviceArch != nil && *variables.DeviceArch != "" {
Colin Crossa6845402020-11-16 15:08:19 -08001697 // The primary device target.
Liz Kammerb7f33662022-02-28 14:16:16 -05001698 addTarget(targetConfig{
1699 os: Android,
1700 archName: *variables.DeviceArch,
1701 archVariant: variables.DeviceArchVariant,
1702 cpuVariant: variables.DeviceCpuVariant,
1703 abi: variables.DeviceAbi,
1704 nativeBridgeEnabled: NativeBridgeDisabled,
1705 })
Colin Cross4225f652015-09-17 14:33:42 -07001706
Colin Crossa6845402020-11-16 15:08:19 -08001707 // An optional secondary device target.
Dan Willemsen3f32f032016-07-11 14:36:48 -07001708 if variables.DeviceSecondaryArch != nil && *variables.DeviceSecondaryArch != "" {
Liz Kammerb7f33662022-02-28 14:16:16 -05001709 addTarget(targetConfig{
1710 os: Android,
1711 archName: *variables.DeviceSecondaryArch,
1712 archVariant: variables.DeviceSecondaryArchVariant,
1713 cpuVariant: variables.DeviceSecondaryCpuVariant,
1714 abi: variables.DeviceSecondaryAbi,
1715 nativeBridgeEnabled: NativeBridgeDisabled,
1716 })
Colin Cross4225f652015-09-17 14:33:42 -07001717 }
dimitry1f33e402019-03-26 12:39:31 +01001718
Colin Crossa6845402020-11-16 15:08:19 -08001719 // An optional NativeBridge device target.
dimitry1f33e402019-03-26 12:39:31 +01001720 if variables.NativeBridgeArch != nil && *variables.NativeBridgeArch != "" {
Liz Kammerb7f33662022-02-28 14:16:16 -05001721 addTarget(targetConfig{
1722 os: Android,
1723 archName: *variables.NativeBridgeArch,
1724 archVariant: variables.NativeBridgeArchVariant,
1725 cpuVariant: variables.NativeBridgeCpuVariant,
1726 abi: variables.NativeBridgeAbi,
1727 nativeBridgeEnabled: NativeBridgeEnabled,
1728 nativeBridgeHostArchName: variables.DeviceArch,
1729 nativeBridgeRelativePath: variables.NativeBridgeRelativePath,
1730 })
dimitry1f33e402019-03-26 12:39:31 +01001731 }
1732
Colin Crossa6845402020-11-16 15:08:19 -08001733 // An optional secondary NativeBridge device target.
dimitry1f33e402019-03-26 12:39:31 +01001734 if variables.DeviceSecondaryArch != nil && *variables.DeviceSecondaryArch != "" &&
1735 variables.NativeBridgeSecondaryArch != nil && *variables.NativeBridgeSecondaryArch != "" {
Liz Kammerb7f33662022-02-28 14:16:16 -05001736 addTarget(targetConfig{
1737 os: Android,
1738 archName: *variables.NativeBridgeSecondaryArch,
1739 archVariant: variables.NativeBridgeSecondaryArchVariant,
1740 cpuVariant: variables.NativeBridgeSecondaryCpuVariant,
1741 abi: variables.NativeBridgeSecondaryAbi,
1742 nativeBridgeEnabled: NativeBridgeEnabled,
1743 nativeBridgeHostArchName: variables.DeviceSecondaryArch,
1744 nativeBridgeRelativePath: variables.NativeBridgeSecondaryRelativePath,
1745 })
dimitry1f33e402019-03-26 12:39:31 +01001746 }
Colin Cross4225f652015-09-17 14:33:42 -07001747 }
1748
Colin Crossa1ad8d12016-06-01 17:09:44 -07001749 if targetErr != nil {
1750 return nil, targetErr
1751 }
1752
1753 return targets, nil
Colin Cross4225f652015-09-17 14:33:42 -07001754}
1755
Colin Crossbb2e2b72016-12-08 17:23:53 -08001756// hasArmAbi returns true if arch has at least one arm ABI
1757func hasArmAbi(arch Arch) bool {
Jaewoong Jung3aff5782020-02-11 07:54:35 -08001758 return PrefixInList(arch.Abi, "arm")
Colin Crossbb2e2b72016-12-08 17:23:53 -08001759}
1760
Lev Rumyantsev34581212021-10-13 09:47:59 -07001761// hasArmAndroidArch returns true if targets has at least
1762// one arm Android arch (possibly native bridged)
Colin Cross4247f0d2017-04-13 16:56:14 -07001763func hasArmAndroidArch(targets []Target) bool {
1764 for _, target := range targets {
Lev Rumyantsev34581212021-10-13 09:47:59 -07001765 if target.Os == Android &&
1766 (target.Arch.ArchType == Arm || target.Arch.ArchType == Arm64) {
Victor Khimenko5eb8ec12018-03-21 20:30:54 +01001767 return true
1768 }
1769 }
1770 return false
1771}
1772
Colin Crossa6845402020-11-16 15:08:19 -08001773// archConfig describes a built-in configuration.
Dan Albert4098deb2016-10-19 14:04:41 -07001774type archConfig struct {
Liz Kammer992918d2022-11-11 10:37:54 -05001775 Arch string `json:"arch"`
1776 ArchVariant string `json:"arch_variant"`
1777 CpuVariant string `json:"cpu_variant"`
1778 Abi []string `json:"abis"`
Dan Albert4098deb2016-10-19 14:04:41 -07001779}
1780
Elliott Hughesc55b5862022-10-27 23:46:22 +00001781// getNdkAbisConfig returns the list of archConfigs that are used for building
1782// the API stubs and static libraries that are included in the NDK.
Dan Albert4098deb2016-10-19 14:04:41 -07001783func getNdkAbisConfig() []archConfig {
1784 return []archConfig{
Tamas Petzbca786d2021-01-20 18:56:33 +01001785 {"arm64", "armv8-a-branchprot", "", []string{"arm64-v8a"}},
Elliott Hughesc55b5862022-10-27 23:46:22 +00001786 {"arm", "armv7-a-neon", "", []string{"armeabi-v7a"}},
Elliott Hughesf7d31092023-03-14 23:11:57 +00001787 {"riscv64", "", "", []string{"riscv64"}},
Dan Albert4098deb2016-10-19 14:04:41 -07001788 {"x86_64", "", "", []string{"x86_64"}},
Inseob Kim5219c0e2021-06-17 00:33:00 +09001789 {"x86", "", "", []string{"x86"}},
Dan Albert4098deb2016-10-19 14:04:41 -07001790 }
1791}
1792
Colin Crossa6845402020-11-16 15:08:19 -08001793// getAmlAbisConfig returns a list of archConfigs for the ABIs supported by mainline modules.
Martin Stjernholmc1ecc432019-11-15 15:00:31 +00001794func getAmlAbisConfig() []archConfig {
1795 return []archConfig{
Martin Stjernholmc1ecc432019-11-15 15:00:31 +00001796 {"arm64", "armv8-a", "", []string{"arm64-v8a"}},
Inseob Kim5219c0e2021-06-17 00:33:00 +09001797 {"arm", "armv7-a-neon", "", []string{"armeabi-v7a"}},
Martin Stjernholmc1ecc432019-11-15 15:00:31 +00001798 {"x86_64", "", "", []string{"x86_64"}},
Inseob Kim5219c0e2021-06-17 00:33:00 +09001799 {"x86", "", "", []string{"x86"}},
Martin Stjernholmc1ecc432019-11-15 15:00:31 +00001800 }
1801}
1802
Colin Crossa6845402020-11-16 15:08:19 -08001803// decodeArchSettings converts a list of archConfigs into a list of Targets for the given OsType.
Liz Kammerb7f33662022-02-28 14:16:16 -05001804func decodeAndroidArchSettings(archConfigs []archConfig) ([]Target, error) {
Colin Crossa1ad8d12016-06-01 17:09:44 -07001805 var ret []Target
Dan Willemsen322acaf2016-01-12 23:07:05 -08001806
Dan Albert4098deb2016-10-19 14:04:41 -07001807 for _, config := range archConfigs {
Liz Kammer992918d2022-11-11 10:37:54 -05001808 arch, err := decodeArch(Android, config.Arch, &config.ArchVariant,
1809 &config.CpuVariant, config.Abi)
Dan Willemsen322acaf2016-01-12 23:07:05 -08001810 if err != nil {
1811 return nil, err
1812 }
Colin Cross3b19f5d2019-09-17 14:45:31 -07001813
Colin Crossa1ad8d12016-06-01 17:09:44 -07001814 ret = append(ret, Target{
1815 Os: Android,
1816 Arch: arch,
1817 })
Dan Willemsen322acaf2016-01-12 23:07:05 -08001818 }
1819
1820 return ret, nil
1821}
1822
Colin Crossa6845402020-11-16 15:08:19 -08001823// decodeArch converts a set of strings from product variables into an Arch struct.
Colin Crossa74ca042019-01-31 14:31:51 -08001824func decodeArch(os OsType, arch string, archVariant, cpuVariant *string, abi []string) (Arch, error) {
Colin Crossa6845402020-11-16 15:08:19 -08001825 // Verify the arch is valid
Colin Crosseeabb892015-11-20 13:07:51 -08001826 archType, ok := archTypeMap[arch]
1827 if !ok {
1828 return Arch{}, fmt.Errorf("unknown arch %q", arch)
1829 }
Colin Cross4225f652015-09-17 14:33:42 -07001830
Colin Crosseeabb892015-11-20 13:07:51 -08001831 a := Arch{
Colin Cross4225f652015-09-17 14:33:42 -07001832 ArchType: archType,
Colin Crossa6845402020-11-16 15:08:19 -08001833 ArchVariant: String(archVariant),
1834 CpuVariant: String(cpuVariant),
Colin Crossa74ca042019-01-31 14:31:51 -08001835 Abi: abi,
Colin Crosseeabb892015-11-20 13:07:51 -08001836 }
1837
Colin Crossa6845402020-11-16 15:08:19 -08001838 // Convert generic arch variants into the empty string.
Colin Crosseeabb892015-11-20 13:07:51 -08001839 if a.ArchVariant == a.ArchType.Name || a.ArchVariant == "generic" {
1840 a.ArchVariant = ""
1841 }
1842
Colin Crossa6845402020-11-16 15:08:19 -08001843 // Convert generic CPU variants into the empty string.
Colin Crosseeabb892015-11-20 13:07:51 -08001844 if a.CpuVariant == a.ArchType.Name || a.CpuVariant == "generic" {
1845 a.CpuVariant = ""
1846 }
1847
Liz Kammer2c2afe22022-02-11 11:35:03 -05001848 if a.ArchVariant != "" {
1849 if validArchVariants := archVariants[archType]; !InList(a.ArchVariant, validArchVariants) {
1850 return Arch{}, fmt.Errorf("[%q] unknown arch variant %q, support variants: %q", archType, a.ArchVariant, validArchVariants)
1851 }
1852 }
1853
1854 if a.CpuVariant != "" {
1855 if validCpuVariants := cpuVariants[archType]; !InList(a.CpuVariant, validCpuVariants) {
1856 return Arch{}, fmt.Errorf("[%q] unknown cpu variant %q, support variants: %q", archType, a.CpuVariant, validCpuVariants)
1857 }
1858 }
1859
Colin Crossa6845402020-11-16 15:08:19 -08001860 // Filter empty ABIs out of the list.
Colin Crosseeabb892015-11-20 13:07:51 -08001861 for i := 0; i < len(a.Abi); i++ {
1862 if a.Abi[i] == "" {
1863 a.Abi = append(a.Abi[:i], a.Abi[i+1:]...)
1864 i--
1865 }
1866 }
1867
Liz Kammere8303bd2022-02-16 09:02:48 -05001868 // Set ArchFeatures from the arch type. for Android OS, other os-es do not specify features
1869 if os == Android {
1870 if featureMap, ok := androidArchFeatureMap[archType]; ok {
Dan Willemsen01a3c252019-01-11 19:02:16 -08001871 a.ArchFeatures = featureMap[a.ArchVariant]
1872 }
Colin Crossc5c24ad2015-11-20 15:35:00 -08001873 }
1874
Colin Crosseeabb892015-11-20 13:07:51 -08001875 return a, nil
Colin Cross4225f652015-09-17 14:33:42 -07001876}
1877
Colin Crossa6845402020-11-16 15:08:19 -08001878// filterMultilibTargets takes a list of Targets and a multilib value and returns a new list of
1879// Targets containing only those that have the given multilib value.
Colin Cross69617d32016-09-06 10:39:07 -07001880func filterMultilibTargets(targets []Target, multilib string) []Target {
1881 var ret []Target
1882 for _, t := range targets {
1883 if t.Arch.ArchType.Multilib == multilib {
1884 ret = append(ret, t)
1885 }
1886 }
1887 return ret
1888}
1889
Colin Crossa6845402020-11-16 15:08:19 -08001890// getCommonTargets returns the set of Os specific common architecture targets for each Os in a list
1891// of targets.
Nan Zhangdb0b9a32017-02-27 10:12:13 -08001892func getCommonTargets(targets []Target) []Target {
1893 var ret []Target
1894 set := make(map[string]bool)
1895
1896 for _, t := range targets {
1897 if _, found := set[t.Os.String()]; !found {
1898 set[t.Os.String()] = true
Colin Cross39a18142022-06-24 18:43:40 -07001899 common := commonTargetMap[t.Os.String()]
1900 common.HostCross = t.HostCross
1901 ret = append(ret, common)
Nan Zhangdb0b9a32017-02-27 10:12:13 -08001902 }
1903 }
1904
1905 return ret
1906}
1907
Sam Delmericocc271e22022-06-01 15:45:02 +00001908// FirstTarget takes a list of Targets and a list of multilib values and returns a list of Targets
Colin Crossc0f0eb82022-07-19 14:41:11 -07001909// that contains zero or one Target for each OsType and HostCross, selecting the one that matches
1910// the earliest filter.
Sam Delmericocc271e22022-06-01 15:45:02 +00001911func FirstTarget(targets []Target, filters ...string) []Target {
Jiyong Park22101982020-09-17 19:09:58 +09001912 // find the first target from each OS
1913 var ret []Target
Colin Crossc0f0eb82022-07-19 14:41:11 -07001914 type osHostCross struct {
1915 os OsType
1916 hostCross bool
1917 }
1918 set := make(map[osHostCross]bool)
Jiyong Park22101982020-09-17 19:09:58 +09001919
Colin Cross6b4a32d2017-12-05 13:42:45 -08001920 for _, filter := range filters {
1921 buildTargets := filterMultilibTargets(targets, filter)
Jiyong Park22101982020-09-17 19:09:58 +09001922 for _, t := range buildTargets {
Colin Crossc0f0eb82022-07-19 14:41:11 -07001923 key := osHostCross{t.Os, t.HostCross}
1924 if _, found := set[key]; !found {
1925 set[key] = true
Jiyong Park22101982020-09-17 19:09:58 +09001926 ret = append(ret, t)
1927 }
Colin Cross6b4a32d2017-12-05 13:42:45 -08001928 }
1929 }
Jiyong Park22101982020-09-17 19:09:58 +09001930 return ret
Colin Cross6b4a32d2017-12-05 13:42:45 -08001931}
1932
Colin Crossa6845402020-11-16 15:08:19 -08001933// decodeMultilibTargets uses the module's multilib setting to select one or more targets from a
1934// list of Targets.
Colin Crossee0bc3b2018-10-02 22:01:37 -07001935func decodeMultilibTargets(multilib string, targets []Target, prefer32 bool) ([]Target, error) {
Colin Crossa6845402020-11-16 15:08:19 -08001936 var buildTargets []Target
Colin Cross6b4a32d2017-12-05 13:42:45 -08001937
Colin Cross4225f652015-09-17 14:33:42 -07001938 switch multilib {
1939 case "common":
Colin Cross6b4a32d2017-12-05 13:42:45 -08001940 buildTargets = getCommonTargets(targets)
1941 case "common_first":
1942 buildTargets = getCommonTargets(targets)
1943 if prefer32 {
Sam Delmericocc271e22022-06-01 15:45:02 +00001944 buildTargets = append(buildTargets, FirstTarget(targets, "lib32", "lib64")...)
Colin Cross6b4a32d2017-12-05 13:42:45 -08001945 } else {
Sam Delmericocc271e22022-06-01 15:45:02 +00001946 buildTargets = append(buildTargets, FirstTarget(targets, "lib64", "lib32")...)
Colin Cross6b4a32d2017-12-05 13:42:45 -08001947 }
Colin Cross4225f652015-09-17 14:33:42 -07001948 case "both":
Colin Cross8b74d172016-09-13 09:59:14 -07001949 if prefer32 {
1950 buildTargets = append(buildTargets, filterMultilibTargets(targets, "lib32")...)
1951 buildTargets = append(buildTargets, filterMultilibTargets(targets, "lib64")...)
1952 } else {
1953 buildTargets = append(buildTargets, filterMultilibTargets(targets, "lib64")...)
1954 buildTargets = append(buildTargets, filterMultilibTargets(targets, "lib32")...)
1955 }
Colin Cross4225f652015-09-17 14:33:42 -07001956 case "32":
Colin Cross69617d32016-09-06 10:39:07 -07001957 buildTargets = filterMultilibTargets(targets, "lib32")
Colin Cross4225f652015-09-17 14:33:42 -07001958 case "64":
Colin Cross69617d32016-09-06 10:39:07 -07001959 buildTargets = filterMultilibTargets(targets, "lib64")
Colin Cross6b4a32d2017-12-05 13:42:45 -08001960 case "first":
1961 if prefer32 {
Sam Delmericocc271e22022-06-01 15:45:02 +00001962 buildTargets = FirstTarget(targets, "lib32", "lib64")
Colin Cross6b4a32d2017-12-05 13:42:45 -08001963 } else {
Sam Delmericocc271e22022-06-01 15:45:02 +00001964 buildTargets = FirstTarget(targets, "lib64", "lib32")
Colin Cross6b4a32d2017-12-05 13:42:45 -08001965 }
Victor Chang9448e8f2020-09-14 15:34:16 +01001966 case "first_prefer32":
Sam Delmericocc271e22022-06-01 15:45:02 +00001967 buildTargets = FirstTarget(targets, "lib32", "lib64")
Colin Cross69617d32016-09-06 10:39:07 -07001968 case "prefer32":
Colin Cross3dceee32018-09-06 10:19:57 -07001969 buildTargets = filterMultilibTargets(targets, "lib32")
1970 if len(buildTargets) == 0 {
1971 buildTargets = filterMultilibTargets(targets, "lib64")
1972 }
Dan Willemsen47450072021-10-19 20:24:49 -07001973 case "darwin_universal":
1974 buildTargets = filterMultilibTargets(targets, "lib64")
1975 // Reverse the targets so that the first architecture can depend on the second
1976 // architecture module in order to merge the outputs.
Colin Crossb5e3f7d2023-07-06 15:37:53 -07001977 ReverseSliceInPlace(buildTargets)
Dan Willemsen47450072021-10-19 20:24:49 -07001978 case "darwin_universal_common_first":
1979 archTargets := filterMultilibTargets(targets, "lib64")
Colin Crossb5e3f7d2023-07-06 15:37:53 -07001980 ReverseSliceInPlace(archTargets)
Dan Willemsen47450072021-10-19 20:24:49 -07001981 buildTargets = append(getCommonTargets(targets), archTargets...)
Colin Cross4225f652015-09-17 14:33:42 -07001982 default:
Victor Chang9448e8f2020-09-14 15:34:16 +01001983 return nil, fmt.Errorf(`compile_multilib must be "both", "first", "32", "64", "prefer32" or "first_prefer32" found %q`,
Colin Cross4225f652015-09-17 14:33:42 -07001984 multilib)
Colin Cross4225f652015-09-17 14:33:42 -07001985 }
1986
Colin Crossa1ad8d12016-06-01 17:09:44 -07001987 return buildTargets, nil
Colin Cross4225f652015-09-17 14:33:42 -07001988}
Jingwen Chen5d864492021-02-24 07:20:12 -05001989
Liz Kammerb6dbc872021-05-14 15:14:40 -04001990// ArchVariantContext defines the limited context necessary to retrieve arch_variant properties.
1991type ArchVariantContext interface {
1992 ModuleErrorf(fmt string, args ...interface{})
1993 PropertyErrorf(property, fmt string, args ...interface{})
1994}