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