blob: 6d896e5fce8331bdfdb365273da8f14a495b733e [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 Cross617b88a2020-08-24 18:04:09 -070026 "github.com/google/blueprint/bootstrap"
Colin Crossf6566ed2015-03-24 11:13:38 -070027 "github.com/google/blueprint/proptools"
Colin Cross3f40fa42015-01-30 17:27:36 -080028)
29
Colin Cross3f40fa42015-01-30 17:27:36 -080030/*
31Example blueprints file containing all variant property groups, with comment listing what type
32of variants get properties in that group:
33
34module {
35 arch: {
36 arm: {
37 // Host or device variants with arm architecture
38 },
39 arm64: {
40 // Host or device variants with arm64 architecture
41 },
Colin Cross3f40fa42015-01-30 17:27:36 -080042 x86: {
43 // Host or device variants with x86 architecture
44 },
45 x86_64: {
46 // Host or device variants with x86_64 architecture
47 },
48 },
49 multilib: {
50 lib32: {
51 // Host or device variants for 32-bit architectures
52 },
53 lib64: {
54 // Host or device variants for 64-bit architectures
55 },
56 },
57 target: {
58 android: {
Martin Stjernholme284b482020-09-23 21:03:27 +010059 // Device variants (implies Bionic)
Colin Cross3f40fa42015-01-30 17:27:36 -080060 },
61 host: {
62 // Host variants
63 },
Martin Stjernholme284b482020-09-23 21:03:27 +010064 bionic: {
65 // Bionic (device and host) variants
66 },
67 linux_bionic: {
68 // Bionic host variants
69 },
70 linux: {
71 // Bionic (device and host) and Linux glibc variants
72 },
Dan Willemsen5746bd42017-10-02 19:42:01 -070073 linux_glibc: {
Martin Stjernholme284b482020-09-23 21:03:27 +010074 // Linux host variants (using non-Bionic libc)
Colin Cross3f40fa42015-01-30 17:27:36 -080075 },
76 darwin: {
77 // Darwin host variants
78 },
79 windows: {
80 // Windows host variants
81 },
82 not_windows: {
83 // Non-windows host variants
84 },
Martin Stjernholme284b482020-09-23 21:03:27 +010085 android_arm: {
86 // Any <os>_<arch> combination restricts to that os and arch
87 },
Colin Cross3f40fa42015-01-30 17:27:36 -080088 },
89}
90*/
Colin Cross7d5136f2015-05-11 13:39:40 -070091
Colin Cross3f40fa42015-01-30 17:27:36 -080092// An Arch indicates a single CPU architecture.
93type Arch struct {
Colin Crossa6845402020-11-16 15:08:19 -080094 // The type of the architecture (arm, arm64, x86, or x86_64).
95 ArchType ArchType
96
97 // The variant of the architecture, for example "armv7-a" or "armv7-a-neon" for arm.
98 ArchVariant string
99
100 // The variant of the CPU, for example "cortex-a53" for arm64.
101 CpuVariant string
102
103 // The list of Android app ABIs supported by the CPU architecture, for example "arm64-v8a".
104 Abi []string
105
106 // The list of arch-specific features supported by the CPU architecture, for example "neon".
Colin Crossc5c24ad2015-11-20 15:35:00 -0800107 ArchFeatures []string
Colin Cross3f40fa42015-01-30 17:27:36 -0800108}
109
Colin Crossa6845402020-11-16 15:08:19 -0800110// String returns the Arch as a string. The value is used as the name of the variant created
111// by archMutator.
Colin Cross3f40fa42015-01-30 17:27:36 -0800112func (a Arch) String() string {
Colin Crossd3ba0392015-05-07 14:11:29 -0700113 s := a.ArchType.String()
Colin Cross3f40fa42015-01-30 17:27:36 -0800114 if a.ArchVariant != "" {
115 s += "_" + a.ArchVariant
116 }
117 if a.CpuVariant != "" {
118 s += "_" + a.CpuVariant
119 }
120 return s
121}
122
Colin Crossa6845402020-11-16 15:08:19 -0800123// ArchType is used to define the 4 supported architecture types (arm, arm64, x86, x86_64), as
124// well as the "common" architecture used for modules that support multiple architectures, for
125// example Java modules.
Colin Cross3f40fa42015-01-30 17:27:36 -0800126type ArchType struct {
Colin Crossa6845402020-11-16 15:08:19 -0800127 // Name is the name of the architecture type, "arm", "arm64", "x86", or "x86_64".
128 Name string
129
130 // Field is the name of the field used in properties that refer to the architecture, e.g. "Arm64".
131 Field string
132
133 // Multilib is either "lib32" or "lib64" for 32-bit or 64-bit architectures.
Colin Crossec193632015-07-06 17:49:43 -0700134 Multilib string
Colin Cross3f40fa42015-01-30 17:27:36 -0800135}
136
Colin Crossa6845402020-11-16 15:08:19 -0800137// String returns the name of the ArchType.
138func (a ArchType) String() string {
139 return a.Name
140}
141
142const COMMON_VARIANT = "common"
143
144var (
145 archTypeList []ArchType
146
Colin Crossf05b0d32022-07-14 18:10:34 -0700147 Arm = newArch("arm", "lib32")
148 Arm64 = newArch("arm64", "lib64")
149 Riscv64 = newArch("riscv64", "lib64")
150 X86 = newArch("x86", "lib32")
151 X86_64 = newArch("x86_64", "lib64")
Colin Crossa6845402020-11-16 15:08:19 -0800152
153 Common = ArchType{
154 Name: COMMON_VARIANT,
155 }
156)
157
158var archTypeMap = map[string]ArchType{}
159
Colin Crossec193632015-07-06 17:49:43 -0700160func newArch(name, multilib string) ArchType {
Dan Willemsenb1957a52016-06-23 23:44:54 -0700161 archType := ArchType{
Colin Crossec193632015-07-06 17:49:43 -0700162 Name: name,
Dan Willemsenb1957a52016-06-23 23:44:54 -0700163 Field: proptools.FieldNameForProperty(name),
Colin Crossec193632015-07-06 17:49:43 -0700164 Multilib: multilib,
Colin Cross3f40fa42015-01-30 17:27:36 -0800165 }
Dan Willemsenb1957a52016-06-23 23:44:54 -0700166 archTypeList = append(archTypeList, archType)
Colin Crossa6845402020-11-16 15:08:19 -0800167 archTypeMap[name] = archType
Dan Willemsenb1957a52016-06-23 23:44:54 -0700168 return archType
Colin Cross3f40fa42015-01-30 17:27:36 -0800169}
170
Ustaeabf0f32021-12-06 15:17:23 -0500171// ArchTypeList returns a slice copy of the 4 supported ArchTypes for arm,
Jingwen Chen2f6a21e2021-04-05 07:33:05 +0000172// arm64, x86 and x86_64.
Jaewoong Jung1ce9ac62019-08-13 14:11:33 -0700173func ArchTypeList() []ArchType {
174 return append([]ArchType(nil), archTypeList...)
175}
176
Colin Crossa6845402020-11-16 15:08:19 -0800177// MarshalText allows an ArchType to be serialized through any encoder that supports
178// encoding.TextMarshaler.
Colin Cross74ba9622019-02-11 15:11:14 -0800179func (a ArchType) MarshalText() ([]byte, error) {
Jeongik Chabec4d032021-04-15 08:55:38 +0900180 return []byte(a.String()), nil
Colin Cross74ba9622019-02-11 15:11:14 -0800181}
182
Colin Crossa6845402020-11-16 15:08:19 -0800183var _ encoding.TextMarshaler = ArchType{}
Colin Cross74ba9622019-02-11 15:11:14 -0800184
Colin Crossa6845402020-11-16 15:08:19 -0800185// UnmarshalText allows an ArchType to be deserialized through any decoder that supports
186// encoding.TextUnmarshaler.
Colin Cross74ba9622019-02-11 15:11:14 -0800187func (a *ArchType) UnmarshalText(text []byte) error {
188 if u, ok := archTypeMap[string(text)]; ok {
189 *a = u
190 return nil
191 }
192
193 return fmt.Errorf("unknown ArchType %q", text)
194}
195
Colin Crossa6845402020-11-16 15:08:19 -0800196var _ encoding.TextUnmarshaler = &ArchType{}
Colin Crossa1ad8d12016-06-01 17:09:44 -0700197
Colin Crossa6845402020-11-16 15:08:19 -0800198// OsClass is an enum that describes whether a variant of a module runs on the host, on the device,
199// or is generic.
Colin Crossa1ad8d12016-06-01 17:09:44 -0700200type OsClass int
201
202const (
Colin Crossa6845402020-11-16 15:08:19 -0800203 // Generic is used for variants of modules that are not OS-specific.
Dan Willemsen0e2d97b2016-11-28 17:50:06 -0800204 Generic OsClass = iota
Colin Crossa6845402020-11-16 15:08:19 -0800205 // Device is used for variants of modules that run on the device.
Dan Willemsen0e2d97b2016-11-28 17:50:06 -0800206 Device
Colin Crossa6845402020-11-16 15:08:19 -0800207 // Host is used for variants of modules that run on the host.
Colin Crossa1ad8d12016-06-01 17:09:44 -0700208 Host
Colin Crossa1ad8d12016-06-01 17:09:44 -0700209)
210
Colin Crossa6845402020-11-16 15:08:19 -0800211// String returns the OsClass as a string.
Colin Cross67a5c132017-05-09 13:45:28 -0700212func (class OsClass) String() string {
213 switch class {
214 case Generic:
215 return "generic"
216 case Device:
217 return "device"
218 case Host:
219 return "host"
Colin Cross67a5c132017-05-09 13:45:28 -0700220 default:
221 panic(fmt.Errorf("unknown class %d", class))
222 }
223}
224
Colin Crossa6845402020-11-16 15:08:19 -0800225// OsType describes an OS variant of a module.
226type OsType struct {
227 // Name is the name of the OS. It is also used as the name of the property in Android.bp
228 // files.
229 Name string
230
231 // Field is the name of the OS converted to an exported field name, i.e. with the first
232 // character capitalized.
233 Field string
234
235 // Class is the OsClass of the OS.
236 Class OsClass
237
238 // DefaultDisabled is set when the module variants for the OS should not be created unless
239 // the module explicitly requests them. This is used to limit Windows cross compilation to
240 // only modules that need it.
241 DefaultDisabled bool
242}
243
244// String returns the name of the OsType.
Colin Crossa1ad8d12016-06-01 17:09:44 -0700245func (os OsType) String() string {
246 return os.Name
Colin Cross54c71122016-06-01 17:09:44 -0700247}
248
Colin Crossa6845402020-11-16 15:08:19 -0800249// Bionic returns true if the OS uses the Bionic libc runtime, i.e. if the OS is Android or
250// is Linux with Bionic.
Dan Willemsen866b5632017-09-22 12:28:24 -0700251func (os OsType) Bionic() bool {
252 return os == Android || os == LinuxBionic
253}
254
Colin Crossa6845402020-11-16 15:08:19 -0800255// Linux returns true if the OS uses the Linux kernel, i.e. if the OS is Android or is Linux
256// with or without the Bionic libc runtime.
Dan Willemsen866b5632017-09-22 12:28:24 -0700257func (os OsType) Linux() bool {
Colin Cross528d67e2021-07-23 22:23:07 +0000258 return os == Android || os == Linux || os == LinuxBionic || os == LinuxMusl
Dan Willemsen866b5632017-09-22 12:28:24 -0700259}
260
Colin Crossa6845402020-11-16 15:08:19 -0800261// newOsType constructs an OsType and adds it to the global lists.
262func newOsType(name string, class OsClass, defDisabled bool, archTypes ...ArchType) OsType {
263 checkCalledFromInit()
Colin Crossa1ad8d12016-06-01 17:09:44 -0700264 os := OsType{
265 Name: name,
Colin Crossa6845402020-11-16 15:08:19 -0800266 Field: proptools.FieldNameForProperty(name),
Colin Crossa1ad8d12016-06-01 17:09:44 -0700267 Class: class,
Dan Willemsen0a37a2a2016-11-13 10:16:05 -0800268
269 DefaultDisabled: defDisabled,
Colin Cross54c71122016-06-01 17:09:44 -0700270 }
Jingwen Chen2f6a21e2021-04-05 07:33:05 +0000271 osTypeList = append(osTypeList, os)
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800272
273 if _, found := commonTargetMap[name]; found {
274 panic(fmt.Errorf("Found Os type duplicate during OsType registration: %q", name))
275 } else {
Colin Crosse9fe2942020-11-10 18:12:15 -0800276 commonTargetMap[name] = Target{Os: os, Arch: CommonArch}
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800277 }
Colin Crossa6845402020-11-16 15:08:19 -0800278 osArchTypeMap[os] = archTypes
Nan Zhangdb0b9a32017-02-27 10:12:13 -0800279
Colin Crossa1ad8d12016-06-01 17:09:44 -0700280 return os
281}
282
Colin Crossa6845402020-11-16 15:08:19 -0800283// osByName returns the OsType that has the given name, or NoOsType if none match.
Colin Crossa1ad8d12016-06-01 17:09:44 -0700284func osByName(name string) OsType {
Jingwen Chen2f6a21e2021-04-05 07:33:05 +0000285 for _, os := range osTypeList {
Colin Crossa1ad8d12016-06-01 17:09:44 -0700286 if os.Name == name {
287 return os
288 }
289 }
290
291 return NoOsType
Dan Willemsen490fd492015-11-24 17:53:15 -0800292}
293
Colin Crossa6845402020-11-16 15:08:19 -0800294var (
Jingwen Chen2f6a21e2021-04-05 07:33:05 +0000295 // osTypeList contains a list of all the supported OsTypes, including ones not supported
Colin Crossa6845402020-11-16 15:08:19 -0800296 // by the current build host or the target device.
Jingwen Chen2f6a21e2021-04-05 07:33:05 +0000297 osTypeList []OsType
Colin Crossa6845402020-11-16 15:08:19 -0800298 // commonTargetMap maps names of OsTypes to the corresponding common Target, i.e. the
299 // Target with the same OsType and the common ArchType.
300 commonTargetMap = make(map[string]Target)
301 // osArchTypeMap maps OsTypes to the list of supported ArchTypes for that OS.
302 osArchTypeMap = map[OsType][]ArchType{}
303
304 // NoOsType is a placeholder for when no OS is needed.
305 NoOsType OsType
306 // Linux is the OS for the Linux kernel plus the glibc runtime.
307 Linux = newOsType("linux_glibc", Host, false, X86, X86_64)
Colin Cross528d67e2021-07-23 22:23:07 +0000308 // LinuxMusl is the OS for the Linux kernel plus the musl runtime.
Colin Crossa9b2aac2022-06-15 17:25:51 -0700309 LinuxMusl = newOsType("linux_musl", Host, false, X86, X86_64, Arm64, Arm)
Colin Crossa6845402020-11-16 15:08:19 -0800310 // Darwin is the OS for MacOS/Darwin host machines.
Dan Willemsen8528f4e2021-10-19 00:22:06 -0700311 Darwin = newOsType("darwin", Host, false, Arm64, X86_64)
Colin Crossa6845402020-11-16 15:08:19 -0800312 // LinuxBionic is the OS for the Linux kernel plus the Bionic libc runtime, but without the
313 // rest of Android.
314 LinuxBionic = newOsType("linux_bionic", Host, false, Arm64, X86_64)
315 // Windows the OS for Windows host machines.
316 Windows = newOsType("windows", Host, true, X86, X86_64)
317 // Android is the OS for target devices that run all of Android, including the Linux kernel
318 // and the Bionic libc runtime.
Colin Crossf05b0d32022-07-14 18:10:34 -0700319 Android = newOsType("android", Device, false, Arm, Arm64, Riscv64, X86, X86_64)
Colin Crossa6845402020-11-16 15:08:19 -0800320
321 // CommonOS is a pseudo OSType for a common OS variant, which is OsType agnostic and which
322 // has dependencies on all the OS variants.
323 CommonOS = newOsType("common_os", Generic, false)
Colin Crosse9fe2942020-11-10 18:12:15 -0800324
325 // CommonArch is the Arch for all modules that are os-specific but not arch specific,
326 // for example most Java modules.
327 CommonArch = Arch{ArchType: Common}
dimitry1f33e402019-03-26 12:39:31 +0100328)
329
Jingwen Chen2f6a21e2021-04-05 07:33:05 +0000330// OsTypeList returns a slice copy of the supported OsTypes.
331func OsTypeList() []OsType {
332 return append([]OsType(nil), osTypeList...)
333}
334
Colin Crossa6845402020-11-16 15:08:19 -0800335// Target specifies the OS and architecture that a module is being compiled for.
Colin Crossa1ad8d12016-06-01 17:09:44 -0700336type Target struct {
Colin Crossa6845402020-11-16 15:08:19 -0800337 // Os the OS that the module is being compiled for (e.g. "linux_glibc", "android").
338 Os OsType
339 // Arch is the architecture that the module is being compiled for.
340 Arch Arch
341 // NativeBridge is NativeBridgeEnabled if the architecture is supported using NativeBridge
342 // (i.e. arm on x86) for this device.
343 NativeBridge NativeBridgeSupport
344 // NativeBridgeHostArchName is the name of the real architecture that is used to implement
345 // the NativeBridge architecture. For example, for arm on x86 this would be "x86".
dimitry8d6dde82019-07-11 10:23:53 +0200346 NativeBridgeHostArchName string
Colin Crossa6845402020-11-16 15:08:19 -0800347 // NativeBridgeRelativePath is the name of the subdirectory that will contain NativeBridge
348 // libraries and binaries.
dimitry8d6dde82019-07-11 10:23:53 +0200349 NativeBridgeRelativePath string
Jiyong Park1613e552020-09-14 19:43:17 +0900350
351 // HostCross is true when the target cannot run natively on the current build host.
352 // For example, linux_glibc_x86 returns true on a regular x86/i686/Linux machines, but returns false
353 // on Mac (different OS), or on 64-bit only i686/Linux machines (unsupported arch).
354 HostCross bool
Colin Crossd3ba0392015-05-07 14:11:29 -0700355}
356
Colin Crossa6845402020-11-16 15:08:19 -0800357// NativeBridgeSupport is an enum that specifies if a Target supports NativeBridge.
358type NativeBridgeSupport bool
359
360const (
361 NativeBridgeDisabled NativeBridgeSupport = false
362 NativeBridgeEnabled NativeBridgeSupport = true
363)
364
365// String returns the OS and arch variations used for the Target.
Colin Crossa1ad8d12016-06-01 17:09:44 -0700366func (target Target) String() string {
Colin Crossa195f912019-10-16 11:07:20 -0700367 return target.OsVariation() + "_" + target.ArchVariation()
368}
369
Colin Crossa6845402020-11-16 15:08:19 -0800370// OsVariation returns the name of the variation used by the osMutator for the Target.
Colin Crossa195f912019-10-16 11:07:20 -0700371func (target Target) OsVariation() string {
372 return target.Os.String()
Colin Cross0f7d2ef2019-10-16 11:03:10 -0700373}
374
Colin Crossa6845402020-11-16 15:08:19 -0800375// ArchVariation returns the name of the variation used by the archMutator for the Target.
Colin Cross0f7d2ef2019-10-16 11:03:10 -0700376func (target Target) ArchVariation() string {
377 var variation string
dimitry1f33e402019-03-26 12:39:31 +0100378 if target.NativeBridge {
Colin Cross0f7d2ef2019-10-16 11:03:10 -0700379 variation = "native_bridge_"
dimitry1f33e402019-03-26 12:39:31 +0100380 }
Colin Cross0f7d2ef2019-10-16 11:03:10 -0700381 variation += target.Arch.String()
382
Colin Crossa195f912019-10-16 11:07:20 -0700383 return variation
Colin Cross0f7d2ef2019-10-16 11:03:10 -0700384}
385
Colin Crossa6845402020-11-16 15:08:19 -0800386// Variations returns a list of blueprint.Variations for the osMutator and archMutator for the
387// Target.
Colin Cross0f7d2ef2019-10-16 11:03:10 -0700388func (target Target) Variations() []blueprint.Variation {
389 return []blueprint.Variation{
Colin Crossa195f912019-10-16 11:07:20 -0700390 {Mutator: "os", Variation: target.OsVariation()},
Colin Cross0f7d2ef2019-10-16 11:03:10 -0700391 {Mutator: "arch", Variation: target.ArchVariation()},
392 }
Dan Willemsen490fd492015-11-24 17:53:15 -0800393}
394
Colin Crossa6845402020-11-16 15:08:19 -0800395// osMutator splits an arch-specific module into a variant for each OS that is enabled for the
396// module. It uses the HostOrDevice value passed to InitAndroidArchModule and the
397// device_supported and host_supported properties to determine which OsTypes are enabled for this
398// module, then searches through the Targets to determine which have enabled Targets for this
399// module.
Colin Cross617b88a2020-08-24 18:04:09 -0700400func osMutator(bpctx blueprint.BottomUpMutatorContext) {
Colin Crossa195f912019-10-16 11:07:20 -0700401 var module Module
402 var ok bool
Colin Cross617b88a2020-08-24 18:04:09 -0700403 if module, ok = bpctx.Module().(Module); !ok {
Colin Crossa6845402020-11-16 15:08:19 -0800404 // The module is not a Soong module, it is a Blueprint module.
Colin Cross617b88a2020-08-24 18:04:09 -0700405 if bootstrap.IsBootstrapModule(bpctx.Module()) {
406 // Bootstrap Go modules are always the build OS or linux bionic.
407 config := bpctx.Config().(Config)
408 osNames := []string{config.BuildOSTarget.OsVariation()}
409 for _, hostCrossTarget := range config.Targets[LinuxBionic] {
410 if hostCrossTarget.Arch.ArchType == config.BuildOSTarget.Arch.ArchType {
411 osNames = append(osNames, hostCrossTarget.OsVariation())
412 }
413 }
414 osNames = FirstUniqueStrings(osNames)
415 bpctx.CreateVariations(osNames...)
416 }
Colin Crossa195f912019-10-16 11:07:20 -0700417 return
418 }
419
Colin Cross617b88a2020-08-24 18:04:09 -0700420 // Bootstrap Go module support above requires this mutator to be a
421 // blueprint.BottomUpMutatorContext because android.BottomUpMutatorContext
422 // filters out non-Soong modules. Now that we've handled them, create a
423 // normal android.BottomUpMutatorContext.
Colin Crossb63d7b32023-12-07 16:54:51 -0800424 mctx := bottomUpMutatorContextFactory(bpctx, module, false)
Colin Cross984223f2024-02-01 17:10:23 -0800425 defer bottomUpMutatorContextPool.Put(mctx)
Colin Cross617b88a2020-08-24 18:04:09 -0700426
Colin Crossa195f912019-10-16 11:07:20 -0700427 base := module.base()
428
Colin Crossa6845402020-11-16 15:08:19 -0800429 // Nothing to do for modules that are not architecture specific (e.g. a genrule).
Colin Crossa195f912019-10-16 11:07:20 -0700430 if !base.ArchSpecific() {
431 return
432 }
433
Colin Crossa6845402020-11-16 15:08:19 -0800434 // Collect a list of OSTypes supported by this module based on the HostOrDevice value
435 // passed to InitAndroidArchModule and the device_supported and host_supported properties.
Colin Crossa195f912019-10-16 11:07:20 -0700436 var moduleOSList []OsType
Jingwen Chen2f6a21e2021-04-05 07:33:05 +0000437 for _, os := range osTypeList {
Jiyong Park1613e552020-09-14 19:43:17 +0900438 for _, t := range mctx.Config().Targets[os] {
Colin Cross08d6f8f2020-11-19 02:33:19 +0000439 if base.supportsTarget(t) {
Jiyong Park1613e552020-09-14 19:43:17 +0900440 moduleOSList = append(moduleOSList, os)
441 break
Colin Crossa195f912019-10-16 11:07:20 -0700442 }
443 }
Colin Crossa195f912019-10-16 11:07:20 -0700444 }
445
Cole Faust8fc38f32023-12-12 17:14:22 -0800446 createCommonOSVariant := base.commonProperties.CreateCommonOSVariant
447
Colin Crossa6845402020-11-16 15:08:19 -0800448 // If there are no supported OSes then disable the module.
Cole Faust8fc38f32023-12-12 17:14:22 -0800449 if len(moduleOSList) == 0 && !createCommonOSVariant {
Inseob Kimeec88e12020-01-22 11:11:29 +0900450 base.Disable()
Colin Crossa195f912019-10-16 11:07:20 -0700451 return
452 }
453
Colin Crossa6845402020-11-16 15:08:19 -0800454 // Convert the list of supported OsTypes to the variation names.
Colin Crossa195f912019-10-16 11:07:20 -0700455 osNames := make([]string, len(moduleOSList))
Colin Crossa195f912019-10-16 11:07:20 -0700456 for i, os := range moduleOSList {
457 osNames[i] = os.String()
458 }
459
Paul Duffin1356d8c2020-02-25 19:26:33 +0000460 if createCommonOSVariant {
Colin Crossa6845402020-11-16 15:08:19 -0800461 // A CommonOS variant was requested so add it to the list of OS variants to
Paul Duffin1356d8c2020-02-25 19:26:33 +0000462 // create. It needs to be added to the end because it needs to depend on the
463 // the other variants in the list returned by CreateVariations(...) and inter
464 // variant dependencies can only be created from a later variant in that list to
465 // an earlier one. That is because variants are always processed in the order in
466 // which they are returned from CreateVariations(...).
467 osNames = append(osNames, CommonOS.Name)
468 moduleOSList = append(moduleOSList, CommonOS)
Colin Crossa195f912019-10-16 11:07:20 -0700469 }
470
Colin Crossa6845402020-11-16 15:08:19 -0800471 // Create the variations, annotate each one with which OS it was created for, and
472 // squash the appropriate OS-specific properties into the top level properties.
Paul Duffin1356d8c2020-02-25 19:26:33 +0000473 modules := mctx.CreateVariations(osNames...)
474 for i, m := range modules {
475 m.base().commonProperties.CompileOS = moduleOSList[i]
476 m.base().setOSProperties(mctx)
477 }
478
479 if createCommonOSVariant {
480 // A CommonOS variant was requested so add dependencies from it (the last one in
481 // the list) to the OS type specific variants.
482 last := len(modules) - 1
483 commonOSVariant := modules[last]
484 commonOSVariant.base().commonProperties.CommonOSVariant = true
485 for _, module := range modules[0:last] {
486 // Ignore modules that are enabled. Note, this will only avoid adding
487 // dependencies on OsType variants that are explicitly disabled in their
488 // properties. The CommonOS variant will still depend on disabled variants
489 // if they are disabled afterwards, e.g. in archMutator if
Cole Fausta963b942024-04-11 17:43:00 -0700490 if module.Enabled(mctx) {
Paul Duffin1356d8c2020-02-25 19:26:33 +0000491 mctx.AddInterVariantDependency(commonOsToOsSpecificVariantTag, commonOSVariant, module)
492 }
493 }
494 }
495}
496
Colin Crossc179ea62020-10-09 10:54:15 -0700497type archDepTag struct {
498 blueprint.BaseDependencyTag
499 name string
500}
Paul Duffin1356d8c2020-02-25 19:26:33 +0000501
Colin Crossc179ea62020-10-09 10:54:15 -0700502// Identifies the dependency from CommonOS variant to the os specific variants.
503var commonOsToOsSpecificVariantTag = archDepTag{name: "common os to os specific"}
504
Paul Duffin1356d8c2020-02-25 19:26:33 +0000505// Get the OsType specific variants for the current CommonOS variant.
506//
507// The returned list will only contain enabled OsType specific variants of the
508// module referenced in the supplied context. An empty list is returned if there
509// are no enabled variants or the supplied context is not for an CommonOS
510// variant.
511func GetOsSpecificVariantsOfCommonOSVariant(mctx BaseModuleContext) []Module {
512 var variants []Module
513 mctx.VisitDirectDeps(func(m Module) {
514 if mctx.OtherModuleDependencyTag(m) == commonOsToOsSpecificVariantTag {
Cole Fausta963b942024-04-11 17:43:00 -0700515 if m.Enabled(mctx) {
Paul Duffin1356d8c2020-02-25 19:26:33 +0000516 variants = append(variants, m)
517 }
518 }
519 })
Paul Duffin1356d8c2020-02-25 19:26:33 +0000520 return variants
Colin Crossa195f912019-10-16 11:07:20 -0700521}
522
Dan Willemsen47450072021-10-19 20:24:49 -0700523var DarwinUniversalVariantTag = archDepTag{name: "darwin universal binary"}
524
Colin Crossee0bc3b2018-10-02 22:01:37 -0700525// archMutator splits a module into a variant for each Target requested by the module. Target selection
Colin Crossa6845402020-11-16 15:08:19 -0800526// for a module is in three levels, OsClass, multilib, and then Target.
Colin Crossee0bc3b2018-10-02 22:01:37 -0700527// OsClass selection is determined by:
Colin Crossd079e0b2022-08-16 10:27:33 -0700528// - The HostOrDeviceSupported value passed in to InitAndroidArchModule by the module type factory, which selects
529// whether the module type can compile for host, device or both.
530// - The host_supported and device_supported properties on the module.
531//
Roland Levillainf5b635d2019-06-05 14:42:57 +0100532// 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 -0700533// for the module, the Device OsClass is selected.
534// Within each selected OsClass, the multilib selection is determined by:
Colin Crossd079e0b2022-08-16 10:27:33 -0700535// - The compile_multilib property if it set (which may be overridden by target.android.compile_multilib or
536// target.host.compile_multilib).
537// - The default multilib passed to InitAndroidArchModule if compile_multilib was not set.
538//
Colin Crossee0bc3b2018-10-02 22:01:37 -0700539// Valid multilib values include:
Colin Crossd079e0b2022-08-16 10:27:33 -0700540//
541// "both": compile for all Targets supported by the OsClass (generally x86_64 and x86, or arm64 and arm).
542// "first": compile for only a single preferred Target supported by the OsClass. This is generally x86_64 or arm64,
543// but may be arm for a 32-bit only build.
544// "32": compile for only a single 32-bit Target supported by the OsClass.
545// "64": compile for only a single 64-bit Target supported by the OsClass.
546// "common": compile a for a single Target that will work on all Targets supported by the OsClass (for example Java).
547// "common_first": compile a for a Target that will work on all Targets supported by the OsClass
548// (same as "common"), plus a second Target for the preferred Target supported by the OsClass
549// (same as "first"). This is used for java_binary that produces a common .jar and a wrapper
550// executable script.
Colin Crossee0bc3b2018-10-02 22:01:37 -0700551//
552// Once the list of Targets is determined, the module is split into a variant for each Target.
553//
554// Modules can be initialized with InitAndroidMultiTargetsArchModule, in which case they will be split by OsClass,
555// but will have a common Target that is expected to handle all other selected Targets via ctx.MultiTargets().
Colin Cross617b88a2020-08-24 18:04:09 -0700556func archMutator(bpctx blueprint.BottomUpMutatorContext) {
Colin Cross635c3b02016-05-18 15:37:25 -0700557 var module Module
Colin Cross3f40fa42015-01-30 17:27:36 -0800558 var ok bool
Colin Cross617b88a2020-08-24 18:04:09 -0700559 if module, ok = bpctx.Module().(Module); !ok {
560 if bootstrap.IsBootstrapModule(bpctx.Module()) {
561 // Bootstrap Go modules are always the build architecture.
562 bpctx.CreateVariations(bpctx.Config().(Config).BuildOSTarget.ArchVariation())
563 }
Colin Cross3f40fa42015-01-30 17:27:36 -0800564 return
565 }
566
Colin Cross617b88a2020-08-24 18:04:09 -0700567 // Bootstrap Go module support above requires this mutator to be a
568 // blueprint.BottomUpMutatorContext because android.BottomUpMutatorContext
569 // filters out non-Soong modules. Now that we've handled them, create a
570 // normal android.BottomUpMutatorContext.
Colin Crossb63d7b32023-12-07 16:54:51 -0800571 mctx := bottomUpMutatorContextFactory(bpctx, module, false)
Colin Cross984223f2024-02-01 17:10:23 -0800572 defer bottomUpMutatorContextPool.Put(mctx)
Colin Cross617b88a2020-08-24 18:04:09 -0700573
Colin Cross5eca7cb2018-10-02 14:02:10 -0700574 base := module.base()
575
576 if !base.ArchSpecific() {
Colin Crossb9db4802016-06-03 01:50:47 +0000577 return
578 }
579
Colin Crossa195f912019-10-16 11:07:20 -0700580 os := base.commonProperties.CompileOS
Paul Duffin1356d8c2020-02-25 19:26:33 +0000581 if os == CommonOS {
582 // Make sure that the target related properties are initialized for the
583 // CommonOS variant.
584 addTargetProperties(module, commonTargetMap[os.Name], nil, true)
585
586 // Do not create arch specific variants for the CommonOS variant.
587 return
588 }
589
Colin Crossa195f912019-10-16 11:07:20 -0700590 osTargets := mctx.Config().Targets[os]
Ivan Lozanoc7eafa72024-07-16 17:55:33 +0000591
Colin Crossfb0c16e2019-11-20 17:12:35 -0800592 image := base.commonProperties.ImageVariation
Colin Crossa6845402020-11-16 15:08:19 -0800593 // Filter NativeBridge targets unless they are explicitly supported.
594 // Skip creating native bridge variants for non-core modules.
Paul Duffine3d1ae42021-09-03 17:47:17 +0100595 if os == Android && !(base.IsNativeBridgeSupported() && image == CoreVariation) {
Ivan Lozano03b717d2024-07-18 15:13:50 +0000596 osTargets = slices.DeleteFunc(slices.Clone(osTargets), func(t Target) bool {
597 return bool(t.NativeBridge)
598 })
Colin Crossa195f912019-10-16 11:07:20 -0700599 }
Colin Crossee0bc3b2018-10-02 22:01:37 -0700600
Ivan Lozanoc7eafa72024-07-16 17:55:33 +0000601 // Filter HostCross targets if disabled.
602 if base.HostSupported() && !base.HostCrossSupported() {
Ivan Lozano03b717d2024-07-18 15:13:50 +0000603 osTargets = slices.DeleteFunc(slices.Clone(osTargets), func(t Target) bool {
604 return t.HostCross
605 })
Ivan Lozanoc7eafa72024-07-16 17:55:33 +0000606 }
607
Yifan Hong60e0cfb2020-10-21 15:17:56 -0700608 // only the primary arch in the ramdisk / vendor_ramdisk / recovery partition
Inseob Kim08758f02021-04-08 21:13:22 +0900609 if os == Android && (module.InstallInRecovery() || module.InstallInRamdisk() || module.InstallInVendorRamdisk() || module.InstallInDebugRamdisk()) {
Colin Crossa195f912019-10-16 11:07:20 -0700610 osTargets = []Target{osTargets[0]}
611 }
dimitry1f33e402019-03-26 12:39:31 +0100612
Jaewoong Jung003d8082021-02-24 17:39:54 -0800613 // Windows builds always prefer 32-bit
614 prefer32 := os == Windows
dimitry1f33e402019-03-26 12:39:31 +0100615
Colin Crossa6845402020-11-16 15:08:19 -0800616 // Determine the multilib selection for this module.
Christopher Ferris98f10222022-07-13 23:16:52 -0700617 ignorePrefer32OnDevice := mctx.Config().IgnorePrefer32OnDevice()
618 multilib, extraMultilib := decodeMultilib(base, os, ignorePrefer32OnDevice)
Colin Crossa6845402020-11-16 15:08:19 -0800619
620 // Convert the multilib selection into a list of Targets.
Colin Crossa195f912019-10-16 11:07:20 -0700621 targets, err := decodeMultilibTargets(multilib, osTargets, prefer32)
622 if err != nil {
623 mctx.ModuleErrorf("%s", err.Error())
624 }
Colin Cross5eca7cb2018-10-02 14:02:10 -0700625
Colin Crossc0f0eb82022-07-19 14:41:11 -0700626 // If there are no supported targets disable the module.
627 if len(targets) == 0 {
628 base.Disable()
629 return
630 }
631
Colin Crossa6845402020-11-16 15:08:19 -0800632 // If the module is using extraMultilib, decode the extraMultilib selection into
633 // a separate list of Targets.
Colin Crossa195f912019-10-16 11:07:20 -0700634 var multiTargets []Target
635 if extraMultilib != "" {
636 multiTargets, err = decodeMultilibTargets(extraMultilib, osTargets, prefer32)
Colin Crossa1ad8d12016-06-01 17:09:44 -0700637 if err != nil {
638 mctx.ModuleErrorf("%s", err.Error())
639 }
Colin Crossc0f0eb82022-07-19 14:41:11 -0700640 multiTargets = filterHostCross(multiTargets, targets[0].HostCross)
Colin Crossb9db4802016-06-03 01:50:47 +0000641 }
642
Colin Crossa6845402020-11-16 15:08:19 -0800643 // Recovery is always the primary architecture, filter out any other architectures.
Inseob Kim20fb5d42021-02-02 20:07:58 +0900644 // Common arch is also allowed
Colin Crossfb0c16e2019-11-20 17:12:35 -0800645 if image == RecoveryVariation {
646 primaryArch := mctx.Config().DevicePrimaryArchType()
Inseob Kim20fb5d42021-02-02 20:07:58 +0900647 targets = filterToArch(targets, primaryArch, Common)
648 multiTargets = filterToArch(multiTargets, primaryArch, Common)
Colin Crossfb0c16e2019-11-20 17:12:35 -0800649 }
650
Colin Crossa6845402020-11-16 15:08:19 -0800651 // If there are no supported targets disable the module.
Colin Crossa195f912019-10-16 11:07:20 -0700652 if len(targets) == 0 {
Inseob Kimeec88e12020-01-22 11:11:29 +0900653 base.Disable()
Dan Willemsen3f32f032016-07-11 14:36:48 -0700654 return
655 }
656
Colin Crossa6845402020-11-16 15:08:19 -0800657 // Convert the targets into a list of arch variation names.
Colin Crossa195f912019-10-16 11:07:20 -0700658 targetNames := make([]string, len(targets))
Colin Crossa195f912019-10-16 11:07:20 -0700659 for i, target := range targets {
660 targetNames[i] = target.ArchVariation()
Colin Crossa1ad8d12016-06-01 17:09:44 -0700661 }
662
Colin Crossa6845402020-11-16 15:08:19 -0800663 // Create the variations, annotate each one with which Target it was created for, and
664 // squash the appropriate arch-specific properties into the top level properties.
Colin Crossa1ad8d12016-06-01 17:09:44 -0700665 modules := mctx.CreateVariations(targetNames...)
Colin Cross3f40fa42015-01-30 17:27:36 -0800666 for i, m := range modules {
Paul Duffin1356d8c2020-02-25 19:26:33 +0000667 addTargetProperties(m, targets[i], multiTargets, i == 0)
Colin Cross617b88a2020-08-24 18:04:09 -0700668 m.base().setArchProperties(mctx)
Dan Willemsen8528f4e2021-10-19 00:22:06 -0700669
670 // Install support doesn't understand Darwin+Arm64
671 if os == Darwin && targets[i].HostCross {
672 m.base().commonProperties.SkipInstall = true
673 }
Colin Cross3f40fa42015-01-30 17:27:36 -0800674 }
Dan Willemsen47450072021-10-19 20:24:49 -0700675
676 // Create a dependency for Darwin Universal binaries from the primary to secondary
677 // architecture. The module itself will be responsible for calling lipo to merge the outputs.
678 if os == Darwin {
679 if multilib == "darwin_universal" && len(modules) == 2 {
680 mctx.AddInterVariantDependency(DarwinUniversalVariantTag, modules[1], modules[0])
681 } else if multilib == "darwin_universal_common_first" && len(modules) == 3 {
682 mctx.AddInterVariantDependency(DarwinUniversalVariantTag, modules[2], modules[1])
683 }
684 }
Colin Cross3f40fa42015-01-30 17:27:36 -0800685}
686
Colin Crossa6845402020-11-16 15:08:19 -0800687// addTargetProperties annotates a variant with the Target is is being compiled for, the list
688// of additional Targets it is supporting (if any), and whether it is the primary Target for
689// the module.
Paul Duffin1356d8c2020-02-25 19:26:33 +0000690func addTargetProperties(m Module, target Target, multiTargets []Target, primaryTarget bool) {
691 m.base().commonProperties.CompileTarget = target
692 m.base().commonProperties.CompileMultiTargets = multiTargets
693 m.base().commonProperties.CompilePrimary = primaryTarget
Cole Faust0aa21cc2024-03-20 12:28:03 -0700694 m.base().commonProperties.ArchReady = true
Paul Duffin1356d8c2020-02-25 19:26:33 +0000695}
696
Colin Crossa6845402020-11-16 15:08:19 -0800697// decodeMultilib returns the appropriate compile_multilib property for the module, or the default
698// multilib from the factory's call to InitAndroidArchModule if none was set. For modules that
699// called InitAndroidMultiTargetsArchModule it always returns "common" for multilib, and returns
700// the actual multilib in extraMultilib.
Christopher Ferris98f10222022-07-13 23:16:52 -0700701func decodeMultilib(base *ModuleBase, os OsType, ignorePrefer32OnDevice bool) (multilib, extraMultilib string) {
Colin Crossa6845402020-11-16 15:08:19 -0800702 // First check the "android.compile_multilib" or "host.compile_multilib" properties.
Dan Willemsen47450072021-10-19 20:24:49 -0700703 switch os.Class {
Colin Crossee0bc3b2018-10-02 22:01:37 -0700704 case Device:
705 multilib = String(base.commonProperties.Target.Android.Compile_multilib)
Jiyong Park1613e552020-09-14 19:43:17 +0900706 case Host:
Colin Crossee0bc3b2018-10-02 22:01:37 -0700707 multilib = String(base.commonProperties.Target.Host.Compile_multilib)
708 }
Colin Crossa6845402020-11-16 15:08:19 -0800709
710 // If those aren't set, try the "compile_multilib" property.
Colin Crossee0bc3b2018-10-02 22:01:37 -0700711 if multilib == "" {
712 multilib = String(base.commonProperties.Compile_multilib)
713 }
Colin Crossa6845402020-11-16 15:08:19 -0800714
715 // If that wasn't set, use the default multilib set by the factory.
Colin Crossee0bc3b2018-10-02 22:01:37 -0700716 if multilib == "" {
717 multilib = base.commonProperties.Default_multilib
718 }
719
Christopher Ferris98f10222022-07-13 23:16:52 -0700720 // If a device is configured with multiple targets, this option
721 // force all device targets that prefer32 to be compiled only as
722 // the first target.
723 if ignorePrefer32OnDevice && os.Class == Device && (multilib == "prefer32" || multilib == "first_prefer32") {
724 multilib = "first"
725 }
726
Colin Crossee0bc3b2018-10-02 22:01:37 -0700727 if base.commonProperties.UseTargetVariants {
Dan Willemsen47450072021-10-19 20:24:49 -0700728 // Darwin has the concept of "universal binaries" which is implemented in Soong by
729 // building both x86_64 and arm64 variants, and having select module types know how to
730 // merge the outputs of their corresponding variants together into a final binary. Most
731 // module types don't need to understand this logic, as we only build a small portion
732 // of the tree for Darwin, and only module types writing macho files need to do the
733 // merging.
734 //
735 // This logic is not enabled for:
736 // "common", as it's not an arch-specific variant
737 // "32", as Darwin never has a 32-bit variant
738 // !UseTargetVariants, as the module has opted into handling the arch-specific logic on
739 // its own.
740 if os == Darwin && multilib != "common" && multilib != "32" {
741 if multilib == "common_first" {
742 multilib = "darwin_universal_common_first"
743 } else {
744 multilib = "darwin_universal"
745 }
746 }
747
Colin Crossee0bc3b2018-10-02 22:01:37 -0700748 return multilib, ""
749 } else {
750 // For app modules a single arch variant will be created per OS class which is expected to handle all the
751 // selected arches. Return the common-type as multilib and any Android.bp provided multilib as extraMultilib
752 if multilib == base.commonProperties.Default_multilib {
753 multilib = "first"
754 }
755 return base.commonProperties.Default_multilib, multilib
756 }
757}
758
Colin Crossa6845402020-11-16 15:08:19 -0800759// filterToArch takes a list of Targets and an ArchType, and returns a modified list that contains
Inseob Kim20fb5d42021-02-02 20:07:58 +0900760// only Targets that have the specified ArchTypes.
761func filterToArch(targets []Target, archs ...ArchType) []Target {
Colin Crossfb0c16e2019-11-20 17:12:35 -0800762 for i := 0; i < len(targets); i++ {
Inseob Kim20fb5d42021-02-02 20:07:58 +0900763 found := false
764 for _, arch := range archs {
765 if targets[i].Arch.ArchType == arch {
766 found = true
767 break
768 }
769 }
770 if !found {
Colin Crossfb0c16e2019-11-20 17:12:35 -0800771 targets = append(targets[:i], targets[i+1:]...)
772 i--
773 }
774 }
775 return targets
776}
777
Colin Crossc0f0eb82022-07-19 14:41:11 -0700778// filterHostCross takes a list of Targets and a hostCross value, and returns a modified list
779// that contains only Targets that have the specified HostCross.
780func filterHostCross(targets []Target, hostCross bool) []Target {
781 for i := 0; i < len(targets); i++ {
782 if targets[i].HostCross != hostCross {
783 targets = append(targets[:i], targets[i+1:]...)
784 i--
785 }
786 }
787 return targets
788}
789
Colin Crossa6845402020-11-16 15:08:19 -0800790// archPropRoot is a struct type used as the top level of the arch-specific properties. It
791// contains the "arch", "multilib", and "target" property structs. It is used to split up the
792// property structs to limit how much is allocated when a single arch-specific property group is
793// used. The types are interface{} because they will hold instances of runtime-created types.
Colin Crosscbbd13f2020-01-17 14:08:22 -0800794type archPropRoot struct {
795 Arch, Multilib, Target interface{}
796}
797
Colin Crossa6845402020-11-16 15:08:19 -0800798// archPropTypeDesc holds the runtime-created types for the property structs to instantiate to
799// create an archPropRoot property struct.
800type archPropTypeDesc struct {
801 arch, multilib, target reflect.Type
802}
803
Colin Crosscbbd13f2020-01-17 14:08:22 -0800804// createArchPropTypeDesc takes a reflect.Type that is either a struct or a pointer to a struct, and
805// returns lists of reflect.Types that contains the arch-variant properties inside structs for each
806// arch, multilib and target property.
Colin Crossa6845402020-11-16 15:08:19 -0800807//
808// This is a relatively expensive operation, so the results are cached in the global
809// archPropTypeMap. It is constructed entirely based on compile-time data, so there is no need
810// to isolate the results between multiple tests running in parallel.
Colin Crosscbbd13f2020-01-17 14:08:22 -0800811func createArchPropTypeDesc(props reflect.Type) []archPropTypeDesc {
Colin Crossb1d8c992020-01-21 11:43:29 -0800812 // Each property struct shard will be nested many times under the runtime generated arch struct,
813 // which can hit the limit of 64kB for the name of runtime generated structs. They are nested
814 // 97 times now, which may grow in the future, plus there is some overhead for the containing
815 // type. This number may need to be reduced if too many are added, but reducing it too far
816 // could cause problems if a single deeply nested property no longer fits in the name.
817 const maxArchTypeNameSize = 500
818
Colin Crossa6845402020-11-16 15:08:19 -0800819 // Convert the type to a new set of types that contains only the arch-specific properties
Usta Shrestha0b52d832022-02-04 21:37:39 -0500820 // (those that are tagged with `android:"arch_variant"`), and sharded into multiple types
Colin Crossa6845402020-11-16 15:08:19 -0800821 // to keep the runtime-generated names under the limit.
Colin Crossb1d8c992020-01-21 11:43:29 -0800822 propShards, _ := proptools.FilterPropertyStructSharded(props, maxArchTypeNameSize, filterArchStruct)
Colin Crossa6845402020-11-16 15:08:19 -0800823
824 // If the type has no arch-specific properties there is nothing to do.
Colin Crosscb988072019-01-24 14:58:11 -0800825 if len(propShards) == 0 {
Dan Willemsenb1957a52016-06-23 23:44:54 -0700826 return nil
827 }
828
Colin Crosscbbd13f2020-01-17 14:08:22 -0800829 var ret []archPropTypeDesc
Colin Crossc17727d2018-10-24 12:42:09 -0700830 for _, props := range propShards {
Dan Willemsenb1957a52016-06-23 23:44:54 -0700831
Colin Crossa6845402020-11-16 15:08:19 -0800832 // variantFields takes a list of variant property field names and returns a list the
833 // StructFields with the names and the type of the current shard.
Colin Crossc17727d2018-10-24 12:42:09 -0700834 variantFields := func(names []string) []reflect.StructField {
835 ret := make([]reflect.StructField, len(names))
Dan Willemsenb1957a52016-06-23 23:44:54 -0700836
Colin Crossc17727d2018-10-24 12:42:09 -0700837 for i, name := range names {
838 ret[i].Name = name
839 ret[i].Type = props
Dan Willemsen866b5632017-09-22 12:28:24 -0700840 }
Colin Crossc17727d2018-10-24 12:42:09 -0700841
842 return ret
843 }
844
Colin Crossa6845402020-11-16 15:08:19 -0800845 // Create a type that contains the properties in this shard repeated for each
846 // architecture, architecture variant, and architecture feature.
Colin Crossc17727d2018-10-24 12:42:09 -0700847 archFields := make([]reflect.StructField, len(archTypeList))
848 for i, arch := range archTypeList {
Colin Crossa6845402020-11-16 15:08:19 -0800849 var variants []string
Colin Crossc17727d2018-10-24 12:42:09 -0700850
851 for _, archVariant := range archVariants[arch] {
852 archVariant := variantReplacer.Replace(archVariant)
853 variants = append(variants, proptools.FieldNameForProperty(archVariant))
854 }
Liz Kammer2c2afe22022-02-11 11:35:03 -0500855 for _, cpuVariant := range cpuVariants[arch] {
856 cpuVariant := variantReplacer.Replace(cpuVariant)
857 variants = append(variants, proptools.FieldNameForProperty(cpuVariant))
858 }
Colin Crossc17727d2018-10-24 12:42:09 -0700859 for _, feature := range archFeatures[arch] {
860 feature := variantReplacer.Replace(feature)
861 variants = append(variants, proptools.FieldNameForProperty(feature))
862 }
863
Colin Crossa6845402020-11-16 15:08:19 -0800864 // Create the StructFields for each architecture variant architecture feature
865 // (e.g. "arch.arm.cortex-a53" or "arch.arm.neon").
Colin Crossc17727d2018-10-24 12:42:09 -0700866 fields := variantFields(variants)
867
Colin Crossa6845402020-11-16 15:08:19 -0800868 // Create the StructField for the architecture itself (e.g. "arch.arm"). The special
869 // "BlueprintEmbed" name is used by Blueprint to put the properties in the
870 // parent struct.
Colin Crossc17727d2018-10-24 12:42:09 -0700871 fields = append([]reflect.StructField{{
872 Name: "BlueprintEmbed",
873 Type: props,
874 Anonymous: true,
875 }}, fields...)
876
877 archFields[i] = reflect.StructField{
878 Name: arch.Field,
879 Type: reflect.StructOf(fields),
880 }
881 }
Colin Crossa6845402020-11-16 15:08:19 -0800882
883 // Create the type of the "arch" property struct for this shard.
Colin Crossc17727d2018-10-24 12:42:09 -0700884 archType := reflect.StructOf(archFields)
885
Colin Crossa6845402020-11-16 15:08:19 -0800886 // Create the type for the "multilib" property struct for this shard, containing the
887 // "multilib.lib32" and "multilib.lib64" property structs.
Colin Crossc17727d2018-10-24 12:42:09 -0700888 multilibType := reflect.StructOf(variantFields([]string{"Lib32", "Lib64"}))
889
Colin Crossa6845402020-11-16 15:08:19 -0800890 // Start with a list of the special targets
Colin Crossc17727d2018-10-24 12:42:09 -0700891 targets := []string{
892 "Host",
893 "Android64",
894 "Android32",
895 "Bionic",
Colin Cross528d67e2021-07-23 22:23:07 +0000896 "Glibc",
897 "Musl",
Colin Crossc17727d2018-10-24 12:42:09 -0700898 "Linux",
Colin Crossa98d36d2022-03-07 14:39:49 -0800899 "Host_linux",
Colin Crossc17727d2018-10-24 12:42:09 -0700900 "Not_windows",
901 "Arm_on_x86",
902 "Arm_on_x86_64",
Victor Khimenkoc26fcf42020-05-07 22:16:33 +0200903 "Native_bridge",
Colin Crossc17727d2018-10-24 12:42:09 -0700904 }
Jingwen Chen2f6a21e2021-04-05 07:33:05 +0000905 for _, os := range osTypeList {
Colin Crossa6845402020-11-16 15:08:19 -0800906 // Add all the OSes.
Colin Crossc17727d2018-10-24 12:42:09 -0700907 targets = append(targets, os.Field)
908
Colin Crossa6845402020-11-16 15:08:19 -0800909 // Add the OS/Arch combinations, e.g. "android_arm64".
Colin Crossc17727d2018-10-24 12:42:09 -0700910 for _, archType := range osArchTypeMap[os] {
Liz Kammer9abd62d2021-05-21 08:37:59 -0400911 targets = append(targets, GetCompoundTargetField(os, archType))
Colin Crossc17727d2018-10-24 12:42:09 -0700912
Colin Cross1aa45b02022-02-10 10:33:10 -0800913 // Also add the special "linux_<arch>", "bionic_<arch>" , "glibc_<arch>", and
914 // "musl_<arch>" property structs.
Colin Crossc17727d2018-10-24 12:42:09 -0700915 if os.Linux() {
916 target := "Linux_" + archType.Name
917 if !InList(target, targets) {
918 targets = append(targets, target)
919 }
920 }
Colin Crossa98d36d2022-03-07 14:39:49 -0800921 if os.Linux() && os.Class == Host {
922 target := "Host_linux_" + archType.Name
923 if !InList(target, targets) {
924 targets = append(targets, target)
925 }
926 }
Colin Crossc17727d2018-10-24 12:42:09 -0700927 if os.Bionic() {
928 target := "Bionic_" + archType.Name
929 if !InList(target, targets) {
930 targets = append(targets, target)
931 }
Dan Willemsen866b5632017-09-22 12:28:24 -0700932 }
Colin Cross1aa45b02022-02-10 10:33:10 -0800933 if os == Linux {
934 target := "Glibc_" + archType.Name
935 if !InList(target, targets) {
936 targets = append(targets, target)
937 }
938 }
939 if os == LinuxMusl {
940 target := "Musl_" + archType.Name
941 if !InList(target, targets) {
942 targets = append(targets, target)
943 }
944 }
Dan Willemsen866b5632017-09-22 12:28:24 -0700945 }
Dan Willemsenb1957a52016-06-23 23:44:54 -0700946 }
Dan Willemsenb1957a52016-06-23 23:44:54 -0700947
Colin Crossa6845402020-11-16 15:08:19 -0800948 // Create the type for the "target" property struct for this shard.
Colin Crossc17727d2018-10-24 12:42:09 -0700949 targetType := reflect.StructOf(variantFields(targets))
Colin Crosscbbd13f2020-01-17 14:08:22 -0800950
Colin Crossa6845402020-11-16 15:08:19 -0800951 // Return a descriptor of the 3 runtime-created types.
Colin Crosscbbd13f2020-01-17 14:08:22 -0800952 ret = append(ret, archPropTypeDesc{
953 arch: reflect.PtrTo(archType),
954 multilib: reflect.PtrTo(multilibType),
955 target: reflect.PtrTo(targetType),
956 })
Colin Crossc17727d2018-10-24 12:42:09 -0700957 }
958 return ret
Dan Willemsenb1957a52016-06-23 23:44:54 -0700959}
960
Colin Crossa6845402020-11-16 15:08:19 -0800961// variantReplacer converts architecture variant or architecture feature names into names that
962// are valid for an Android.bp file.
963var variantReplacer = strings.NewReplacer("-", "_", ".", "_")
964
965// filterArchStruct returns true if the given field is an architecture specific property.
Colin Cross74449102019-09-25 11:26:40 -0700966func filterArchStruct(field reflect.StructField, prefix string) (bool, reflect.StructField) {
967 if proptools.HasTag(field, "android", "arch_variant") {
968 // The arch_variant field isn't necessary past this point
969 // Instead of wasting space, just remove it. Go also has a
970 // 16-bit limit on structure name length. The name is constructed
971 // based on the Go source representation of the structure, so
972 // the tag names count towards that length.
Colin Crossb4fecbf2020-01-21 11:38:47 -0800973
974 androidTag := field.Tag.Get("android")
975 values := strings.Split(androidTag, ",")
976
977 if string(field.Tag) != `android:"`+strings.Join(values, ",")+`"` {
978 panic(fmt.Errorf("unexpected tag format %q", field.Tag))
Colin Cross74449102019-09-25 11:26:40 -0700979 }
Colin Crossb4fecbf2020-01-21 11:38:47 -0800980 // these tags don't need to be present in the runtime generated struct type.
Cole Faust5fda87b2024-04-24 11:21:14 -0700981 // However replace_instead_of_append does, because it's read by the blueprint
982 // property extending util functions, which can operate on these generated arch
983 // property structs.
984 values = RemoveListFromList(values, []string{"arch_variant", "variant_prepend", "path"})
Liz Kammerff966b12022-07-29 10:49:16 -0400985 if len(values) > 0 {
Cole Faust5fda87b2024-04-24 11:21:14 -0700986 if values[0] != "replace_instead_of_append" || len(values) > 1 {
987 panic(fmt.Errorf("unknown tags %q in field %q", values, prefix+field.Name))
988 }
989 field.Tag = `android:"replace_instead_of_append"`
990 } else {
991 field.Tag = ``
Colin Crossb4fecbf2020-01-21 11:38:47 -0800992 }
Colin Cross74449102019-09-25 11:26:40 -0700993 return true, field
994 }
995 return false, field
996}
997
Colin Crossa6845402020-11-16 15:08:19 -0800998// archPropTypeMap contains a cache of the results of createArchPropTypeDesc for each type. It is
999// shared across all Contexts, but is constructed based only on compile-time information so there
1000// is no risk of contaminating one Context with data from another.
Dan Willemsenb1957a52016-06-23 23:44:54 -07001001var archPropTypeMap OncePer
1002
Colin Crossa6845402020-11-16 15:08:19 -08001003// initArchModule adds the architecture-specific property structs to a Module.
1004func initArchModule(m Module) {
Colin Cross3f40fa42015-01-30 17:27:36 -08001005
1006 base := m.base()
1007
Ustaeabf0f32021-12-06 15:17:23 -05001008 if len(base.archProperties) != 0 {
1009 panic(fmt.Errorf("module %s already has archProperties", m.Name()))
1010 }
Colin Cross3f40fa42015-01-30 17:27:36 -08001011
Ustaeabf0f32021-12-06 15:17:23 -05001012 getStructType := func(properties interface{}) reflect.Type {
Colin Cross3f40fa42015-01-30 17:27:36 -08001013 propertiesValue := reflect.ValueOf(properties)
Colin Cross62496a02016-08-08 15:49:17 -07001014 t := propertiesValue.Type()
Colin Cross3f40fa42015-01-30 17:27:36 -08001015 if propertiesValue.Kind() != reflect.Ptr {
Colin Crossca860ac2016-01-04 14:34:37 -08001016 panic(fmt.Errorf("properties must be a pointer to a struct, got %T",
1017 propertiesValue.Interface()))
Colin Cross3f40fa42015-01-30 17:27:36 -08001018 }
1019
1020 propertiesValue = propertiesValue.Elem()
1021 if propertiesValue.Kind() != reflect.Struct {
Ustaeabf0f32021-12-06 15:17:23 -05001022 panic(fmt.Errorf("properties must be a pointer to a struct, got a pointer to %T",
Colin Crossca860ac2016-01-04 14:34:37 -08001023 propertiesValue.Interface()))
Colin Cross3f40fa42015-01-30 17:27:36 -08001024 }
Ustaeabf0f32021-12-06 15:17:23 -05001025 return t
1026 }
Colin Cross3f40fa42015-01-30 17:27:36 -08001027
Usta851a3272022-01-05 23:42:33 -05001028 for _, properties := range m.GetProperties() {
Ustaeabf0f32021-12-06 15:17:23 -05001029 t := getStructType(properties)
Colin Crossa6845402020-11-16 15:08:19 -08001030 // Get or create the arch-specific property struct types for this property struct type.
Colin Cross571cccf2019-02-04 11:22:08 -08001031 archPropTypes := archPropTypeMap.Once(NewCustomOnceKey(t), func() interface{} {
Colin Crosscbbd13f2020-01-17 14:08:22 -08001032 return createArchPropTypeDesc(t)
1033 }).([]archPropTypeDesc)
Colin Cross3f40fa42015-01-30 17:27:36 -08001034
Colin Crossa6845402020-11-16 15:08:19 -08001035 // Instantiate one of each arch-specific property struct type and add it to the
1036 // properties for the Module.
Colin Crossc17727d2018-10-24 12:42:09 -07001037 var archProperties []interface{}
1038 for _, t := range archPropTypes {
Colin Crosscbbd13f2020-01-17 14:08:22 -08001039 archProperties = append(archProperties, &archPropRoot{
1040 Arch: reflect.Zero(t.arch).Interface(),
1041 Multilib: reflect.Zero(t.multilib).Interface(),
1042 Target: reflect.Zero(t.target).Interface(),
1043 })
Dan Willemsenb1957a52016-06-23 23:44:54 -07001044 }
Colin Crossc17727d2018-10-24 12:42:09 -07001045 base.archProperties = append(base.archProperties, archProperties)
1046 m.AddProperties(archProperties...)
Colin Cross3f40fa42015-01-30 17:27:36 -08001047 }
1048
Colin Cross3f40fa42015-01-30 17:27:36 -08001049}
1050
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001051func maybeBlueprintEmbed(src reflect.Value) reflect.Value {
Colin Crossa6845402020-11-16 15:08:19 -08001052 // If the value of the field is a struct (as opposed to a pointer to a struct) then step
1053 // into the BlueprintEmbed field.
Dan Willemsenb1957a52016-06-23 23:44:54 -07001054 if src.Kind() == reflect.Struct {
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001055 return src.FieldByName("BlueprintEmbed")
1056 } else {
1057 return src
Colin Cross06a931b2015-10-28 17:23:31 -07001058 }
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001059}
1060
1061// Merges the property struct in srcValue into dst.
Liz Kammerb6dbc872021-05-14 15:14:40 -04001062func mergePropertyStruct(ctx ArchVariantContext, dst interface{}, srcValue reflect.Value) {
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001063 src := maybeBlueprintEmbed(srcValue).Interface()
Colin Cross06a931b2015-10-28 17:23:31 -07001064
Colin Crossa6845402020-11-16 15:08:19 -08001065 // order checks the `android:"variant_prepend"` tag to handle properties where the
1066 // arch-specific value needs to come before the generic value, for example for lists of
1067 // include directories.
Colin Cross1e7e0432024-02-02 10:59:50 -08001068 order := func(dstField, srcField reflect.StructField) (proptools.Order, error) {
Colin Cross6ee75b62016-05-05 15:57:15 -07001069 if proptools.HasTag(dstField, "android", "variant_prepend") {
1070 return proptools.Prepend, nil
1071 } else {
1072 return proptools.Append, nil
1073 }
1074 }
1075
Colin Crossa6845402020-11-16 15:08:19 -08001076 // Squash the located property struct into the destination property struct.
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001077 err := proptools.ExtendMatchingProperties([]interface{}{dst}, src, nil, order)
Colin Cross06a931b2015-10-28 17:23:31 -07001078 if err != nil {
1079 if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
1080 ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
1081 } else {
1082 panic(err)
1083 }
1084 }
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001085}
Colin Cross85a88972015-11-23 13:29:51 -08001086
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001087// Returns the immediate child of the input property struct that corresponds to
1088// the sub-property "field".
Liz Kammerb6dbc872021-05-14 15:14:40 -04001089func getChildPropertyStruct(ctx ArchVariantContext,
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001090 src reflect.Value, field, userFriendlyField string) (reflect.Value, bool) {
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001091
1092 // Step into non-nil pointers to structs in the src value.
1093 if src.Kind() == reflect.Ptr {
1094 if src.IsNil() {
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001095 return reflect.Value{}, false
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001096 }
1097 src = src.Elem()
1098 }
1099
1100 // Find the requested field in the src struct.
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001101 child := src.FieldByName(proptools.FieldNameForProperty(field))
1102 if !child.IsValid() {
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001103 ctx.ModuleErrorf("field %q does not exist", userFriendlyField)
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001104 return reflect.Value{}, false
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001105 }
1106
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001107 if child.IsZero() {
1108 return reflect.Value{}, false
1109 }
1110
1111 return child, true
Colin Cross06a931b2015-10-28 17:23:31 -07001112}
1113
Colin Crossa6845402020-11-16 15:08:19 -08001114// Squash the appropriate OS-specific property structs into the matching top level property structs
1115// based on the CompileOS value that was annotated on the variant.
Colin Crossa195f912019-10-16 11:07:20 -07001116func (m *ModuleBase) setOSProperties(ctx BottomUpMutatorContext) {
1117 os := m.commonProperties.CompileOS
1118
Ustadca02192021-12-20 12:56:46 -05001119 for i := range m.archProperties {
Usta851a3272022-01-05 23:42:33 -05001120 genProps := m.GetProperties()[i]
Colin Crossa195f912019-10-16 11:07:20 -07001121 if m.archProperties[i] == nil {
1122 continue
1123 }
1124 for _, archProperties := range m.archProperties[i] {
1125 archPropValues := reflect.ValueOf(archProperties).Elem()
1126
Colin Crosscbbd13f2020-01-17 14:08:22 -08001127 targetProp := archPropValues.FieldByName("Target").Elem()
Colin Crossa195f912019-10-16 11:07:20 -07001128
1129 // Handle host-specific properties in the form:
1130 // target: {
1131 // host: {
1132 // key: value,
1133 // },
1134 // },
Jiyong Park1613e552020-09-14 19:43:17 +09001135 if os.Class == Host {
Colin Crossa195f912019-10-16 11:07:20 -07001136 field := "Host"
1137 prefix := "target.host"
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001138 if hostProperties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
1139 mergePropertyStruct(ctx, genProps, hostProperties)
1140 }
Colin Crossa195f912019-10-16 11:07:20 -07001141 }
1142
1143 // Handle target OS generalities of the form:
1144 // target: {
1145 // bionic: {
1146 // key: value,
1147 // },
1148 // }
1149 if os.Linux() {
1150 field := "Linux"
1151 prefix := "target.linux"
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001152 if linuxProperties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
1153 mergePropertyStruct(ctx, genProps, linuxProperties)
1154 }
Colin Crossa195f912019-10-16 11:07:20 -07001155 }
1156
Colin Crossa98d36d2022-03-07 14:39:49 -08001157 if os.Linux() && os.Class == Host {
1158 field := "Host_linux"
1159 prefix := "target.host_linux"
1160 if linuxProperties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
1161 mergePropertyStruct(ctx, genProps, linuxProperties)
1162 }
1163 }
1164
Colin Crossa195f912019-10-16 11:07:20 -07001165 if os.Bionic() {
1166 field := "Bionic"
1167 prefix := "target.bionic"
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001168 if bionicProperties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
1169 mergePropertyStruct(ctx, genProps, bionicProperties)
1170 }
Colin Crossa195f912019-10-16 11:07:20 -07001171 }
1172
Colin Cross528d67e2021-07-23 22:23:07 +00001173 if os == Linux {
1174 field := "Glibc"
1175 prefix := "target.glibc"
1176 if bionicProperties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
1177 mergePropertyStruct(ctx, genProps, bionicProperties)
1178 }
1179 }
1180
1181 if os == LinuxMusl {
1182 field := "Musl"
1183 prefix := "target.musl"
1184 if bionicProperties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
1185 mergePropertyStruct(ctx, genProps, bionicProperties)
1186 }
Colin Cross528d67e2021-07-23 22:23:07 +00001187 }
1188
Colin Crossa195f912019-10-16 11:07:20 -07001189 // Handle target OS properties in the form:
1190 // target: {
1191 // linux_glibc: {
1192 // key: value,
1193 // },
1194 // not_windows: {
1195 // key: value,
1196 // },
1197 // android {
1198 // key: value,
1199 // },
1200 // },
1201 field := os.Field
1202 prefix := "target." + os.Name
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001203 if osProperties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
1204 mergePropertyStruct(ctx, genProps, osProperties)
1205 }
Colin Crossa195f912019-10-16 11:07:20 -07001206
Jiyong Park1613e552020-09-14 19:43:17 +09001207 if os.Class == Host && os != Windows {
Colin Crossa195f912019-10-16 11:07:20 -07001208 field := "Not_windows"
1209 prefix := "target.not_windows"
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001210 if notWindowsProperties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
1211 mergePropertyStruct(ctx, genProps, notWindowsProperties)
1212 }
Colin Crossa195f912019-10-16 11:07:20 -07001213 }
1214
1215 // Handle 64-bit device properties in the form:
1216 // target {
1217 // android64 {
1218 // key: value,
1219 // },
1220 // android32 {
1221 // key: value,
1222 // },
1223 // },
1224 // WARNING: this is probably not what you want to use in your blueprints file, it selects
1225 // options for all targets on a device that supports 64-bit binaries, not just the targets
1226 // that are being compiled for 64-bit. Its expected use case is binaries like linker and
1227 // debuggerd that need to know when they are a 32-bit process running on a 64-bit device
1228 if os.Class == Device {
1229 if ctx.Config().Android64() {
1230 field := "Android64"
1231 prefix := "target.android64"
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001232 if android64Properties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
1233 mergePropertyStruct(ctx, genProps, android64Properties)
1234 }
Colin Crossa195f912019-10-16 11:07:20 -07001235 } else {
1236 field := "Android32"
1237 prefix := "target.android32"
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001238 if android32Properties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
1239 mergePropertyStruct(ctx, genProps, android32Properties)
1240 }
Colin Crossa195f912019-10-16 11:07:20 -07001241 }
1242 }
1243 }
1244 }
1245}
1246
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001247// Returns the struct containing the properties specific to the given
1248// architecture type. These look like this in Blueprint files:
Colin Crossd079e0b2022-08-16 10:27:33 -07001249//
1250// arch: {
1251// arm64: {
1252// key: value,
1253// },
1254// },
1255//
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001256// This struct will also contain sub-structs containing to the architecture/CPU
1257// variants and features that themselves contain properties specific to those.
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001258func getArchTypeStruct(ctx ArchVariantContext, archProperties interface{}, archType ArchType) (reflect.Value, bool) {
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001259 archPropValues := reflect.ValueOf(archProperties).Elem()
1260 archProp := archPropValues.FieldByName("Arch").Elem()
1261 prefix := "arch." + archType.Name
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001262 return getChildPropertyStruct(ctx, archProp, archType.Name, prefix)
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001263}
1264
1265// Returns the struct containing the properties specific to a given multilib
1266// value. These look like this in the Blueprint file:
Colin Crossd079e0b2022-08-16 10:27:33 -07001267//
1268// multilib: {
1269// lib32: {
1270// key: value,
1271// },
1272// },
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001273func getMultilibStruct(ctx ArchVariantContext, archProperties interface{}, archType ArchType) (reflect.Value, bool) {
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001274 archPropValues := reflect.ValueOf(archProperties).Elem()
1275 multilibProp := archPropValues.FieldByName("Multilib").Elem()
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001276 return getChildPropertyStruct(ctx, multilibProp, archType.Multilib, "multilib."+archType.Multilib)
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001277}
1278
Liz Kammer9abd62d2021-05-21 08:37:59 -04001279func GetCompoundTargetField(os OsType, arch ArchType) string {
Rupert Shuttleworthc194ffb2021-05-19 06:49:02 -04001280 return os.Field + "_" + arch.Name
1281}
1282
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001283// Returns the structs corresponding to the properties specific to the given
1284// architecture and OS in archProperties.
1285func getArchProperties(ctx BaseMutatorContext, archProperties interface{}, arch Arch, os OsType, nativeBridgeEnabled bool) []reflect.Value {
1286 result := make([]reflect.Value, 0)
1287 archPropValues := reflect.ValueOf(archProperties).Elem()
1288
1289 targetProp := archPropValues.FieldByName("Target").Elem()
1290
1291 archType := arch.ArchType
1292
1293 if arch.ArchType != Common {
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001294 archStruct, ok := getArchTypeStruct(ctx, archProperties, arch.ArchType)
1295 if ok {
1296 result = append(result, archStruct)
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001297
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001298 // Handle arch-variant-specific properties in the form:
1299 // arch: {
1300 // arm: {
1301 // variant: {
1302 // key: value,
1303 // },
1304 // },
1305 // },
1306 v := variantReplacer.Replace(arch.ArchVariant)
1307 if v != "" {
1308 prefix := "arch." + archType.Name + "." + v
1309 if variantProperties, ok := getChildPropertyStruct(ctx, archStruct, v, prefix); ok {
1310 result = append(result, variantProperties)
1311 }
1312 }
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001313
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001314 // Handle cpu-variant-specific properties in the form:
1315 // arch: {
1316 // arm: {
1317 // variant: {
1318 // key: value,
1319 // },
1320 // },
1321 // },
1322 if arch.CpuVariant != arch.ArchVariant {
1323 c := variantReplacer.Replace(arch.CpuVariant)
1324 if c != "" {
1325 prefix := "arch." + archType.Name + "." + c
1326 if cpuVariantProperties, ok := getChildPropertyStruct(ctx, archStruct, c, prefix); ok {
1327 result = append(result, cpuVariantProperties)
1328 }
1329 }
1330 }
1331
1332 // Handle arch-feature-specific properties in the form:
1333 // arch: {
1334 // arm: {
1335 // feature: {
1336 // key: value,
1337 // },
1338 // },
1339 // },
1340 for _, feature := range arch.ArchFeatures {
1341 prefix := "arch." + archType.Name + "." + feature
1342 if featureProperties, ok := getChildPropertyStruct(ctx, archStruct, feature, prefix); ok {
1343 result = append(result, featureProperties)
1344 }
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001345 }
1346 }
1347
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001348 if multilibProperties, ok := getMultilibStruct(ctx, archProperties, archType); ok {
1349 result = append(result, multilibProperties)
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001350 }
1351
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001352 // Handle combined OS-feature and arch specific properties in the form:
1353 // target: {
1354 // bionic_x86: {
1355 // key: value,
1356 // },
1357 // }
1358 if os.Linux() {
1359 field := "Linux_" + arch.ArchType.Name
1360 userFriendlyField := "target.linux_" + arch.ArchType.Name
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001361 if linuxProperties, ok := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField); ok {
1362 result = append(result, linuxProperties)
1363 }
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001364 }
1365
1366 if os.Bionic() {
1367 field := "Bionic_" + archType.Name
1368 userFriendlyField := "target.bionic_" + archType.Name
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001369 if bionicProperties, ok := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField); ok {
1370 result = append(result, bionicProperties)
1371 }
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001372 }
1373
1374 // Handle combined OS and arch specific properties in the form:
1375 // target: {
1376 // linux_glibc_x86: {
1377 // key: value,
1378 // },
1379 // linux_glibc_arm: {
1380 // key: value,
1381 // },
1382 // android_arm {
1383 // key: value,
1384 // },
1385 // android_x86 {
1386 // key: value,
1387 // },
1388 // },
Liz Kammer9abd62d2021-05-21 08:37:59 -04001389 field := GetCompoundTargetField(os, archType)
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001390 userFriendlyField := "target." + os.Name + "_" + archType.Name
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001391 if osArchProperties, ok := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField); ok {
1392 result = append(result, osArchProperties)
1393 }
Colin Cross528d67e2021-07-23 22:23:07 +00001394
Colin Cross1aa45b02022-02-10 10:33:10 -08001395 if os == Linux {
1396 field := "Glibc_" + archType.Name
1397 userFriendlyField := "target.glibc_" + "_" + archType.Name
1398 if osArchProperties, ok := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField); ok {
1399 result = append(result, osArchProperties)
1400 }
1401 }
1402
Colin Cross528d67e2021-07-23 22:23:07 +00001403 if os == LinuxMusl {
Colin Cross1aa45b02022-02-10 10:33:10 -08001404 field := "Musl_" + archType.Name
1405 userFriendlyField := "target.musl_" + "_" + archType.Name
1406 if osArchProperties, ok := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField); ok {
1407 result = append(result, osArchProperties)
1408 }
Colin Cross528d67e2021-07-23 22:23:07 +00001409 }
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001410 }
1411
1412 // Handle arm on x86 properties in the form:
1413 // target {
1414 // arm_on_x86 {
1415 // key: value,
1416 // },
1417 // arm_on_x86_64 {
1418 // key: value,
1419 // },
1420 // },
1421 if os.Class == Device {
1422 if arch.ArchType == X86 && (hasArmAbi(arch) ||
1423 hasArmAndroidArch(ctx.Config().Targets[Android])) {
1424 field := "Arm_on_x86"
1425 userFriendlyField := "target.arm_on_x86"
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001426 if armOnX86Properties, ok := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField); ok {
1427 result = append(result, armOnX86Properties)
1428 }
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001429 }
1430 if arch.ArchType == X86_64 && (hasArmAbi(arch) ||
1431 hasArmAndroidArch(ctx.Config().Targets[Android])) {
1432 field := "Arm_on_x86_64"
1433 userFriendlyField := "target.arm_on_x86_64"
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001434 if armOnX8664Properties, ok := getChildPropertyStruct(ctx, targetProp, field, userFriendlyField); ok {
1435 result = append(result, armOnX8664Properties)
1436 }
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001437 }
1438 if os == Android && nativeBridgeEnabled {
1439 userFriendlyField := "Native_bridge"
1440 prefix := "target.native_bridge"
Lukacs T. Berki5f518392021-05-17 11:44:58 +02001441 if nativeBridgeProperties, ok := getChildPropertyStruct(ctx, targetProp, userFriendlyField, prefix); ok {
1442 result = append(result, nativeBridgeProperties)
1443 }
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001444 }
1445 }
1446
1447 return result
1448}
1449
Colin Crossa6845402020-11-16 15:08:19 -08001450// Squash the appropriate arch-specific property structs into the matching top level property
1451// structs based on the CompileTarget value that was annotated on the variant.
Colin Cross4157e882019-06-06 16:57:04 -07001452func (m *ModuleBase) setArchProperties(ctx BottomUpMutatorContext) {
1453 arch := m.Arch()
1454 os := m.Os()
Colin Crossd3ba0392015-05-07 14:11:29 -07001455
Ustadca02192021-12-20 12:56:46 -05001456 for i := range m.archProperties {
Usta851a3272022-01-05 23:42:33 -05001457 genProps := m.GetProperties()[i]
Colin Cross4157e882019-06-06 16:57:04 -07001458 if m.archProperties[i] == nil {
Dan Willemsenb1957a52016-06-23 23:44:54 -07001459 continue
1460 }
Dan Willemsenb1957a52016-06-23 23:44:54 -07001461
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001462 propStructs := make([]reflect.Value, 0)
1463 for _, archProperty := range m.archProperties[i] {
1464 propStructShard := getArchProperties(ctx, archProperty, arch, os, m.Target().NativeBridge == NativeBridgeEnabled)
1465 propStructs = append(propStructs, propStructShard...)
1466 }
Dan Willemsenb1957a52016-06-23 23:44:54 -07001467
Lukacs T. Berki598dd002021-05-05 09:00:01 +02001468 for _, propStruct := range propStructs {
1469 mergePropertyStruct(ctx, genProps, propStruct)
Colin Crossbb2e2b72016-12-08 17:23:53 -08001470 }
Colin Cross3f40fa42015-01-30 17:27:36 -08001471 }
1472}
1473
Colin Cross0c66bc62021-07-20 09:47:41 -07001474// determineBuildOS stores the OS and architecture used for host targets used during the build into
Colin Cross528d67e2021-07-23 22:23:07 +00001475// config based on the runtime OS and architecture determined by Go and the product configuration.
Colin Cross0c66bc62021-07-20 09:47:41 -07001476func determineBuildOS(config *config) {
1477 config.BuildOS = func() OsType {
1478 switch runtime.GOOS {
1479 case "linux":
Colin Cross528d67e2021-07-23 22:23:07 +00001480 if Bool(config.productVariables.HostMusl) {
1481 return LinuxMusl
1482 }
Colin Cross0c66bc62021-07-20 09:47:41 -07001483 return Linux
1484 case "darwin":
1485 return Darwin
1486 default:
1487 panic(fmt.Sprintf("unsupported OS: %s", runtime.GOOS))
1488 }
1489 }()
1490
1491 config.BuildArch = func() ArchType {
1492 switch runtime.GOARCH {
1493 case "amd64":
1494 return X86_64
1495 default:
1496 panic(fmt.Sprintf("unsupported Arch: %s", runtime.GOARCH))
1497 }
1498 }()
1499
1500}
1501
Colin Crossa6845402020-11-16 15:08:19 -08001502// Convert the arch product variables into a list of targets for each OsType.
Dan Willemsen0ef639b2018-10-10 17:02:29 -07001503func decodeTargetProductVariables(config *config) (map[OsType][]Target, error) {
Dan Willemsen45133ac2018-03-09 21:22:06 -08001504 variables := config.productVariables
Dan Willemsen490fd492015-11-24 17:53:15 -08001505
Dan Willemsen0ef639b2018-10-10 17:02:29 -07001506 targets := make(map[OsType][]Target)
Colin Crossa1ad8d12016-06-01 17:09:44 -07001507 var targetErr error
1508
Liz Kammerb7f33662022-02-28 14:16:16 -05001509 type targetConfig struct {
1510 os OsType
1511 archName string
1512 archVariant *string
1513 cpuVariant *string
1514 abi []string
1515 nativeBridgeEnabled NativeBridgeSupport
1516 nativeBridgeHostArchName *string
1517 nativeBridgeRelativePath *string
1518 }
1519
1520 addTarget := func(target targetConfig) {
Colin Crossa1ad8d12016-06-01 17:09:44 -07001521 if targetErr != nil {
1522 return
Dan Willemsen490fd492015-11-24 17:53:15 -08001523 }
Colin Crossa1ad8d12016-06-01 17:09:44 -07001524
Liz Kammerb7f33662022-02-28 14:16:16 -05001525 arch, err := decodeArch(target.os, target.archName, target.archVariant, target.cpuVariant, target.abi)
Colin Crossa1ad8d12016-06-01 17:09:44 -07001526 if err != nil {
1527 targetErr = err
1528 return
1529 }
Liz Kammerb7f33662022-02-28 14:16:16 -05001530 nativeBridgeRelativePathStr := String(target.nativeBridgeRelativePath)
1531 nativeBridgeHostArchNameStr := String(target.nativeBridgeHostArchName)
dimitry8d6dde82019-07-11 10:23:53 +02001532
1533 // Use guest arch as relative install path by default
Liz Kammerb7f33662022-02-28 14:16:16 -05001534 if target.nativeBridgeEnabled && nativeBridgeRelativePathStr == "" {
dimitry8d6dde82019-07-11 10:23:53 +02001535 nativeBridgeRelativePathStr = arch.ArchType.String()
1536 }
Colin Crossa1ad8d12016-06-01 17:09:44 -07001537
Jiyong Park1613e552020-09-14 19:43:17 +09001538 // A target is considered as HostCross if it's a host target which can't run natively on
1539 // the currently configured build machine (either because the OS is different or because of
1540 // the unsupported arch)
1541 hostCross := false
Liz Kammerb7f33662022-02-28 14:16:16 -05001542 if target.os.Class == Host {
Jiyong Park1613e552020-09-14 19:43:17 +09001543 var osSupported bool
Liz Kammerb7f33662022-02-28 14:16:16 -05001544 if target.os == config.BuildOS {
Jiyong Park1613e552020-09-14 19:43:17 +09001545 osSupported = true
Liz Kammerb7f33662022-02-28 14:16:16 -05001546 } else if config.BuildOS.Linux() && target.os.Linux() {
Jiyong Park1613e552020-09-14 19:43:17 +09001547 // LinuxBionic and Linux are compatible
1548 osSupported = true
1549 } else {
1550 osSupported = false
1551 }
1552
1553 var archSupported bool
1554 if arch.ArchType == Common {
1555 archSupported = true
1556 } else if arch.ArchType.Name == *variables.HostArch {
1557 archSupported = true
1558 } else if variables.HostSecondaryArch != nil && arch.ArchType.Name == *variables.HostSecondaryArch {
1559 archSupported = true
1560 } else {
1561 archSupported = false
1562 }
1563 if !osSupported || !archSupported {
1564 hostCross = true
1565 }
1566 }
1567
Liz Kammerb7f33662022-02-28 14:16:16 -05001568 targets[target.os] = append(targets[target.os],
Colin Crossa1ad8d12016-06-01 17:09:44 -07001569 Target{
Liz Kammerb7f33662022-02-28 14:16:16 -05001570 Os: target.os,
dimitry8d6dde82019-07-11 10:23:53 +02001571 Arch: arch,
Liz Kammerb7f33662022-02-28 14:16:16 -05001572 NativeBridge: target.nativeBridgeEnabled,
dimitry8d6dde82019-07-11 10:23:53 +02001573 NativeBridgeHostArchName: nativeBridgeHostArchNameStr,
1574 NativeBridgeRelativePath: nativeBridgeRelativePathStr,
Jiyong Park1613e552020-09-14 19:43:17 +09001575 HostCross: hostCross,
Colin Crossa1ad8d12016-06-01 17:09:44 -07001576 })
Dan Willemsen490fd492015-11-24 17:53:15 -08001577 }
1578
Colin Cross4225f652015-09-17 14:33:42 -07001579 if variables.HostArch == nil {
Colin Crossa1ad8d12016-06-01 17:09:44 -07001580 return nil, fmt.Errorf("No host primary architecture set")
Colin Cross4225f652015-09-17 14:33:42 -07001581 }
1582
Colin Crossa6845402020-11-16 15:08:19 -08001583 // The primary host target, which must always exist.
Liz Kammerb7f33662022-02-28 14:16:16 -05001584 addTarget(targetConfig{os: config.BuildOS, archName: *variables.HostArch, nativeBridgeEnabled: NativeBridgeDisabled})
Colin Cross4225f652015-09-17 14:33:42 -07001585
Colin Crossa6845402020-11-16 15:08:19 -08001586 // An optional secondary host target.
Colin Crosseeabb892015-11-20 13:07:51 -08001587 if variables.HostSecondaryArch != nil && *variables.HostSecondaryArch != "" {
Liz Kammerb7f33662022-02-28 14:16:16 -05001588 addTarget(targetConfig{os: config.BuildOS, archName: *variables.HostSecondaryArch, nativeBridgeEnabled: NativeBridgeDisabled})
Dan Willemsen490fd492015-11-24 17:53:15 -08001589 }
1590
Colin Crossa6845402020-11-16 15:08:19 -08001591 // Optional cross-compiled host targets, generally Windows.
Colin Crossff3ae9d2018-04-10 16:15:18 -07001592 if String(variables.CrossHost) != "" {
Colin Crossa1ad8d12016-06-01 17:09:44 -07001593 crossHostOs := osByName(*variables.CrossHost)
1594 if crossHostOs == NoOsType {
1595 return nil, fmt.Errorf("Unknown cross host OS %q", *variables.CrossHost)
1596 }
1597
Colin Crossff3ae9d2018-04-10 16:15:18 -07001598 if String(variables.CrossHostArch) == "" {
Colin Crossa1ad8d12016-06-01 17:09:44 -07001599 return nil, fmt.Errorf("No cross-host primary architecture set")
Dan Willemsen490fd492015-11-24 17:53:15 -08001600 }
1601
Colin Crossa6845402020-11-16 15:08:19 -08001602 // The primary cross-compiled host target.
Liz Kammerb7f33662022-02-28 14:16:16 -05001603 addTarget(targetConfig{os: crossHostOs, archName: *variables.CrossHostArch, nativeBridgeEnabled: NativeBridgeDisabled})
Dan Willemsen490fd492015-11-24 17:53:15 -08001604
Colin Crossa6845402020-11-16 15:08:19 -08001605 // An optional secondary cross-compiled host target.
Dan Willemsen490fd492015-11-24 17:53:15 -08001606 if variables.CrossHostSecondaryArch != nil && *variables.CrossHostSecondaryArch != "" {
Liz Kammerb7f33662022-02-28 14:16:16 -05001607 addTarget(targetConfig{os: crossHostOs, archName: *variables.CrossHostSecondaryArch, nativeBridgeEnabled: NativeBridgeDisabled})
Dan Willemsen490fd492015-11-24 17:53:15 -08001608 }
1609 }
1610
Colin Crossa6845402020-11-16 15:08:19 -08001611 // Optional device targets
Dan Willemsen3f32f032016-07-11 14:36:48 -07001612 if variables.DeviceArch != nil && *variables.DeviceArch != "" {
Colin Crossa6845402020-11-16 15:08:19 -08001613 // The primary device target.
Liz Kammerb7f33662022-02-28 14:16:16 -05001614 addTarget(targetConfig{
1615 os: Android,
1616 archName: *variables.DeviceArch,
1617 archVariant: variables.DeviceArchVariant,
1618 cpuVariant: variables.DeviceCpuVariant,
1619 abi: variables.DeviceAbi,
1620 nativeBridgeEnabled: NativeBridgeDisabled,
1621 })
Colin Cross4225f652015-09-17 14:33:42 -07001622
Colin Crossa6845402020-11-16 15:08:19 -08001623 // An optional secondary device target.
Dan Willemsen3f32f032016-07-11 14:36:48 -07001624 if variables.DeviceSecondaryArch != nil && *variables.DeviceSecondaryArch != "" {
Liz Kammerb7f33662022-02-28 14:16:16 -05001625 addTarget(targetConfig{
1626 os: Android,
1627 archName: *variables.DeviceSecondaryArch,
1628 archVariant: variables.DeviceSecondaryArchVariant,
1629 cpuVariant: variables.DeviceSecondaryCpuVariant,
1630 abi: variables.DeviceSecondaryAbi,
1631 nativeBridgeEnabled: NativeBridgeDisabled,
1632 })
Colin Cross4225f652015-09-17 14:33:42 -07001633 }
dimitry1f33e402019-03-26 12:39:31 +01001634
Colin Crossa6845402020-11-16 15:08:19 -08001635 // An optional NativeBridge device target.
dimitry1f33e402019-03-26 12:39:31 +01001636 if variables.NativeBridgeArch != nil && *variables.NativeBridgeArch != "" {
Liz Kammerb7f33662022-02-28 14:16:16 -05001637 addTarget(targetConfig{
1638 os: Android,
1639 archName: *variables.NativeBridgeArch,
1640 archVariant: variables.NativeBridgeArchVariant,
1641 cpuVariant: variables.NativeBridgeCpuVariant,
1642 abi: variables.NativeBridgeAbi,
1643 nativeBridgeEnabled: NativeBridgeEnabled,
1644 nativeBridgeHostArchName: variables.DeviceArch,
1645 nativeBridgeRelativePath: variables.NativeBridgeRelativePath,
1646 })
dimitry1f33e402019-03-26 12:39:31 +01001647 }
1648
Colin Crossa6845402020-11-16 15:08:19 -08001649 // An optional secondary NativeBridge device target.
dimitry1f33e402019-03-26 12:39:31 +01001650 if variables.DeviceSecondaryArch != nil && *variables.DeviceSecondaryArch != "" &&
1651 variables.NativeBridgeSecondaryArch != nil && *variables.NativeBridgeSecondaryArch != "" {
Liz Kammerb7f33662022-02-28 14:16:16 -05001652 addTarget(targetConfig{
1653 os: Android,
1654 archName: *variables.NativeBridgeSecondaryArch,
1655 archVariant: variables.NativeBridgeSecondaryArchVariant,
1656 cpuVariant: variables.NativeBridgeSecondaryCpuVariant,
1657 abi: variables.NativeBridgeSecondaryAbi,
1658 nativeBridgeEnabled: NativeBridgeEnabled,
1659 nativeBridgeHostArchName: variables.DeviceSecondaryArch,
1660 nativeBridgeRelativePath: variables.NativeBridgeSecondaryRelativePath,
1661 })
dimitry1f33e402019-03-26 12:39:31 +01001662 }
Colin Cross4225f652015-09-17 14:33:42 -07001663 }
1664
Colin Crossa1ad8d12016-06-01 17:09:44 -07001665 if targetErr != nil {
1666 return nil, targetErr
1667 }
1668
1669 return targets, nil
Colin Cross4225f652015-09-17 14:33:42 -07001670}
1671
Colin Crossbb2e2b72016-12-08 17:23:53 -08001672// hasArmAbi returns true if arch has at least one arm ABI
1673func hasArmAbi(arch Arch) bool {
Jaewoong Jung3aff5782020-02-11 07:54:35 -08001674 return PrefixInList(arch.Abi, "arm")
Colin Crossbb2e2b72016-12-08 17:23:53 -08001675}
1676
Lev Rumyantsev34581212021-10-13 09:47:59 -07001677// hasArmAndroidArch returns true if targets has at least
1678// one arm Android arch (possibly native bridged)
Colin Cross4247f0d2017-04-13 16:56:14 -07001679func hasArmAndroidArch(targets []Target) bool {
1680 for _, target := range targets {
Lev Rumyantsev34581212021-10-13 09:47:59 -07001681 if target.Os == Android &&
1682 (target.Arch.ArchType == Arm || target.Arch.ArchType == Arm64) {
Victor Khimenko5eb8ec12018-03-21 20:30:54 +01001683 return true
1684 }
1685 }
1686 return false
1687}
1688
Colin Crossa6845402020-11-16 15:08:19 -08001689// archConfig describes a built-in configuration.
Dan Albert4098deb2016-10-19 14:04:41 -07001690type archConfig struct {
Liz Kammer992918d2022-11-11 10:37:54 -05001691 Arch string `json:"arch"`
1692 ArchVariant string `json:"arch_variant"`
1693 CpuVariant string `json:"cpu_variant"`
1694 Abi []string `json:"abis"`
Dan Albert4098deb2016-10-19 14:04:41 -07001695}
1696
Elliott Hughesc55b5862022-10-27 23:46:22 +00001697// getNdkAbisConfig returns the list of archConfigs that are used for building
1698// the API stubs and static libraries that are included in the NDK.
Dan Albert4098deb2016-10-19 14:04:41 -07001699func getNdkAbisConfig() []archConfig {
1700 return []archConfig{
Tamas Petzbca786d2021-01-20 18:56:33 +01001701 {"arm64", "armv8-a-branchprot", "", []string{"arm64-v8a"}},
Elliott Hughesc55b5862022-10-27 23:46:22 +00001702 {"arm", "armv7-a-neon", "", []string{"armeabi-v7a"}},
Elliott Hughesf7d31092023-03-14 23:11:57 +00001703 {"riscv64", "", "", []string{"riscv64"}},
Dan Albert4098deb2016-10-19 14:04:41 -07001704 {"x86_64", "", "", []string{"x86_64"}},
Inseob Kim5219c0e2021-06-17 00:33:00 +09001705 {"x86", "", "", []string{"x86"}},
Dan Albert4098deb2016-10-19 14:04:41 -07001706 }
1707}
1708
Colin Crossa6845402020-11-16 15:08:19 -08001709// getAmlAbisConfig returns a list of archConfigs for the ABIs supported by mainline modules.
Martin Stjernholmc1ecc432019-11-15 15:00:31 +00001710func getAmlAbisConfig() []archConfig {
1711 return []archConfig{
Martin Stjernholmc1ecc432019-11-15 15:00:31 +00001712 {"arm64", "armv8-a", "", []string{"arm64-v8a"}},
Inseob Kim5219c0e2021-06-17 00:33:00 +09001713 {"arm", "armv7-a-neon", "", []string{"armeabi-v7a"}},
Martin Stjernholmc1ecc432019-11-15 15:00:31 +00001714 {"x86_64", "", "", []string{"x86_64"}},
Inseob Kim5219c0e2021-06-17 00:33:00 +09001715 {"x86", "", "", []string{"x86"}},
Martin Stjernholmc1ecc432019-11-15 15:00:31 +00001716 }
1717}
1718
Colin Crossa6845402020-11-16 15:08:19 -08001719// decodeArchSettings converts a list of archConfigs into a list of Targets for the given OsType.
Liz Kammerb7f33662022-02-28 14:16:16 -05001720func decodeAndroidArchSettings(archConfigs []archConfig) ([]Target, error) {
Colin Crossa1ad8d12016-06-01 17:09:44 -07001721 var ret []Target
Dan Willemsen322acaf2016-01-12 23:07:05 -08001722
Dan Albert4098deb2016-10-19 14:04:41 -07001723 for _, config := range archConfigs {
Liz Kammer992918d2022-11-11 10:37:54 -05001724 arch, err := decodeArch(Android, config.Arch, &config.ArchVariant,
1725 &config.CpuVariant, config.Abi)
Dan Willemsen322acaf2016-01-12 23:07:05 -08001726 if err != nil {
1727 return nil, err
1728 }
Colin Cross3b19f5d2019-09-17 14:45:31 -07001729
Colin Crossa1ad8d12016-06-01 17:09:44 -07001730 ret = append(ret, Target{
1731 Os: Android,
1732 Arch: arch,
1733 })
Dan Willemsen322acaf2016-01-12 23:07:05 -08001734 }
1735
1736 return ret, nil
1737}
1738
Colin Crossa6845402020-11-16 15:08:19 -08001739// decodeArch converts a set of strings from product variables into an Arch struct.
Colin Crossa74ca042019-01-31 14:31:51 -08001740func decodeArch(os OsType, arch string, archVariant, cpuVariant *string, abi []string) (Arch, error) {
Colin Crossa6845402020-11-16 15:08:19 -08001741 // Verify the arch is valid
Colin Crosseeabb892015-11-20 13:07:51 -08001742 archType, ok := archTypeMap[arch]
1743 if !ok {
1744 return Arch{}, fmt.Errorf("unknown arch %q", arch)
1745 }
Colin Cross4225f652015-09-17 14:33:42 -07001746
Colin Crosseeabb892015-11-20 13:07:51 -08001747 a := Arch{
Colin Cross4225f652015-09-17 14:33:42 -07001748 ArchType: archType,
Colin Crossa6845402020-11-16 15:08:19 -08001749 ArchVariant: String(archVariant),
1750 CpuVariant: String(cpuVariant),
Colin Crossa74ca042019-01-31 14:31:51 -08001751 Abi: abi,
Colin Crosseeabb892015-11-20 13:07:51 -08001752 }
1753
Colin Crossa6845402020-11-16 15:08:19 -08001754 // Convert generic arch variants into the empty string.
Colin Crosseeabb892015-11-20 13:07:51 -08001755 if a.ArchVariant == a.ArchType.Name || a.ArchVariant == "generic" {
1756 a.ArchVariant = ""
1757 }
1758
Colin Crossa6845402020-11-16 15:08:19 -08001759 // Convert generic CPU variants into the empty string.
Colin Crosseeabb892015-11-20 13:07:51 -08001760 if a.CpuVariant == a.ArchType.Name || a.CpuVariant == "generic" {
1761 a.CpuVariant = ""
1762 }
1763
Liz Kammer2c2afe22022-02-11 11:35:03 -05001764 if a.ArchVariant != "" {
1765 if validArchVariants := archVariants[archType]; !InList(a.ArchVariant, validArchVariants) {
1766 return Arch{}, fmt.Errorf("[%q] unknown arch variant %q, support variants: %q", archType, a.ArchVariant, validArchVariants)
1767 }
1768 }
1769
1770 if a.CpuVariant != "" {
1771 if validCpuVariants := cpuVariants[archType]; !InList(a.CpuVariant, validCpuVariants) {
1772 return Arch{}, fmt.Errorf("[%q] unknown cpu variant %q, support variants: %q", archType, a.CpuVariant, validCpuVariants)
1773 }
1774 }
1775
Colin Crossa6845402020-11-16 15:08:19 -08001776 // Filter empty ABIs out of the list.
Colin Crosseeabb892015-11-20 13:07:51 -08001777 for i := 0; i < len(a.Abi); i++ {
1778 if a.Abi[i] == "" {
1779 a.Abi = append(a.Abi[:i], a.Abi[i+1:]...)
1780 i--
1781 }
1782 }
1783
Liz Kammere8303bd2022-02-16 09:02:48 -05001784 // Set ArchFeatures from the arch type. for Android OS, other os-es do not specify features
1785 if os == Android {
1786 if featureMap, ok := androidArchFeatureMap[archType]; ok {
Dan Willemsen01a3c252019-01-11 19:02:16 -08001787 a.ArchFeatures = featureMap[a.ArchVariant]
1788 }
Colin Crossc5c24ad2015-11-20 15:35:00 -08001789 }
1790
Colin Crosseeabb892015-11-20 13:07:51 -08001791 return a, nil
Colin Cross4225f652015-09-17 14:33:42 -07001792}
1793
Colin Crossa6845402020-11-16 15:08:19 -08001794// filterMultilibTargets takes a list of Targets and a multilib value and returns a new list of
1795// Targets containing only those that have the given multilib value.
Colin Cross69617d32016-09-06 10:39:07 -07001796func filterMultilibTargets(targets []Target, multilib string) []Target {
1797 var ret []Target
1798 for _, t := range targets {
1799 if t.Arch.ArchType.Multilib == multilib {
1800 ret = append(ret, t)
1801 }
1802 }
1803 return ret
1804}
1805
Colin Crossa6845402020-11-16 15:08:19 -08001806// getCommonTargets returns the set of Os specific common architecture targets for each Os in a list
1807// of targets.
Nan Zhangdb0b9a32017-02-27 10:12:13 -08001808func getCommonTargets(targets []Target) []Target {
1809 var ret []Target
1810 set := make(map[string]bool)
1811
1812 for _, t := range targets {
1813 if _, found := set[t.Os.String()]; !found {
1814 set[t.Os.String()] = true
Colin Cross39a18142022-06-24 18:43:40 -07001815 common := commonTargetMap[t.Os.String()]
1816 common.HostCross = t.HostCross
1817 ret = append(ret, common)
Nan Zhangdb0b9a32017-02-27 10:12:13 -08001818 }
1819 }
1820
1821 return ret
1822}
1823
Sam Delmericocc271e22022-06-01 15:45:02 +00001824// 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 -07001825// that contains zero or one Target for each OsType and HostCross, selecting the one that matches
1826// the earliest filter.
Sam Delmericocc271e22022-06-01 15:45:02 +00001827func FirstTarget(targets []Target, filters ...string) []Target {
Jiyong Park22101982020-09-17 19:09:58 +09001828 // find the first target from each OS
1829 var ret []Target
Colin Crossc0f0eb82022-07-19 14:41:11 -07001830 type osHostCross struct {
1831 os OsType
1832 hostCross bool
1833 }
1834 set := make(map[osHostCross]bool)
Jiyong Park22101982020-09-17 19:09:58 +09001835
Colin Cross6b4a32d2017-12-05 13:42:45 -08001836 for _, filter := range filters {
1837 buildTargets := filterMultilibTargets(targets, filter)
Jiyong Park22101982020-09-17 19:09:58 +09001838 for _, t := range buildTargets {
Colin Crossc0f0eb82022-07-19 14:41:11 -07001839 key := osHostCross{t.Os, t.HostCross}
1840 if _, found := set[key]; !found {
1841 set[key] = true
Jiyong Park22101982020-09-17 19:09:58 +09001842 ret = append(ret, t)
1843 }
Colin Cross6b4a32d2017-12-05 13:42:45 -08001844 }
1845 }
Jiyong Park22101982020-09-17 19:09:58 +09001846 return ret
Colin Cross6b4a32d2017-12-05 13:42:45 -08001847}
1848
Colin Crossa6845402020-11-16 15:08:19 -08001849// decodeMultilibTargets uses the module's multilib setting to select one or more targets from a
1850// list of Targets.
Colin Crossee0bc3b2018-10-02 22:01:37 -07001851func decodeMultilibTargets(multilib string, targets []Target, prefer32 bool) ([]Target, error) {
Colin Crossa6845402020-11-16 15:08:19 -08001852 var buildTargets []Target
Colin Cross6b4a32d2017-12-05 13:42:45 -08001853
Colin Cross4225f652015-09-17 14:33:42 -07001854 switch multilib {
1855 case "common":
Colin Cross6b4a32d2017-12-05 13:42:45 -08001856 buildTargets = getCommonTargets(targets)
1857 case "common_first":
1858 buildTargets = getCommonTargets(targets)
1859 if prefer32 {
Sam Delmericocc271e22022-06-01 15:45:02 +00001860 buildTargets = append(buildTargets, FirstTarget(targets, "lib32", "lib64")...)
Colin Cross6b4a32d2017-12-05 13:42:45 -08001861 } else {
Sam Delmericocc271e22022-06-01 15:45:02 +00001862 buildTargets = append(buildTargets, FirstTarget(targets, "lib64", "lib32")...)
Colin Cross6b4a32d2017-12-05 13:42:45 -08001863 }
Colin Cross4225f652015-09-17 14:33:42 -07001864 case "both":
Colin Cross8b74d172016-09-13 09:59:14 -07001865 if prefer32 {
1866 buildTargets = append(buildTargets, filterMultilibTargets(targets, "lib32")...)
1867 buildTargets = append(buildTargets, filterMultilibTargets(targets, "lib64")...)
1868 } else {
1869 buildTargets = append(buildTargets, filterMultilibTargets(targets, "lib64")...)
1870 buildTargets = append(buildTargets, filterMultilibTargets(targets, "lib32")...)
1871 }
Colin Cross4225f652015-09-17 14:33:42 -07001872 case "32":
Colin Cross69617d32016-09-06 10:39:07 -07001873 buildTargets = filterMultilibTargets(targets, "lib32")
Colin Cross4225f652015-09-17 14:33:42 -07001874 case "64":
Colin Cross69617d32016-09-06 10:39:07 -07001875 buildTargets = filterMultilibTargets(targets, "lib64")
Colin Cross6b4a32d2017-12-05 13:42:45 -08001876 case "first":
1877 if prefer32 {
Sam Delmericocc271e22022-06-01 15:45:02 +00001878 buildTargets = FirstTarget(targets, "lib32", "lib64")
Colin Cross6b4a32d2017-12-05 13:42:45 -08001879 } else {
Sam Delmericocc271e22022-06-01 15:45:02 +00001880 buildTargets = FirstTarget(targets, "lib64", "lib32")
Colin Cross6b4a32d2017-12-05 13:42:45 -08001881 }
Victor Chang9448e8f2020-09-14 15:34:16 +01001882 case "first_prefer32":
Sam Delmericocc271e22022-06-01 15:45:02 +00001883 buildTargets = FirstTarget(targets, "lib32", "lib64")
Colin Cross69617d32016-09-06 10:39:07 -07001884 case "prefer32":
Colin Cross3dceee32018-09-06 10:19:57 -07001885 buildTargets = filterMultilibTargets(targets, "lib32")
1886 if len(buildTargets) == 0 {
1887 buildTargets = filterMultilibTargets(targets, "lib64")
1888 }
Dan Willemsen47450072021-10-19 20:24:49 -07001889 case "darwin_universal":
1890 buildTargets = filterMultilibTargets(targets, "lib64")
1891 // Reverse the targets so that the first architecture can depend on the second
1892 // architecture module in order to merge the outputs.
Colin Crossb5e3f7d2023-07-06 15:37:53 -07001893 ReverseSliceInPlace(buildTargets)
Dan Willemsen47450072021-10-19 20:24:49 -07001894 case "darwin_universal_common_first":
1895 archTargets := filterMultilibTargets(targets, "lib64")
Colin Crossb5e3f7d2023-07-06 15:37:53 -07001896 ReverseSliceInPlace(archTargets)
Dan Willemsen47450072021-10-19 20:24:49 -07001897 buildTargets = append(getCommonTargets(targets), archTargets...)
Colin Cross4225f652015-09-17 14:33:42 -07001898 default:
Victor Chang9448e8f2020-09-14 15:34:16 +01001899 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 -07001900 multilib)
Colin Cross4225f652015-09-17 14:33:42 -07001901 }
1902
Colin Crossa1ad8d12016-06-01 17:09:44 -07001903 return buildTargets, nil
Colin Cross4225f652015-09-17 14:33:42 -07001904}
Jingwen Chen5d864492021-02-24 07:20:12 -05001905
Liz Kammerb6dbc872021-05-14 15:14:40 -04001906// ArchVariantContext defines the limited context necessary to retrieve arch_variant properties.
1907type ArchVariantContext interface {
1908 ModuleErrorf(fmt string, args ...interface{})
1909 PropertyErrorf(property, fmt string, args ...interface{})
1910}