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