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 "strconv" 23 "strings" 24 25 "github.com/google/blueprint/proptools" 26) 27 28var ( 29 archTypeList []ArchType 30 31 Arm = newArch("arm", "lib32") 32 Arm64 = newArch("arm64", "lib64") 33 Mips = newArch("mips", "lib32") 34 Mips64 = newArch("mips64", "lib64") 35 X86 = newArch("x86", "lib32") 36 X86_64 = newArch("x86_64", "lib64") 37 38 Common = ArchType{ 39 Name: "common", 40 } 41) 42 43var archTypeMap = map[string]ArchType{ 44 "arm": Arm, 45 "arm64": Arm64, 46 "mips": Mips, 47 "mips64": Mips64, 48 "x86": X86, 49 "x86_64": X86_64, 50} 51 52/* 53Example blueprints file containing all variant property groups, with comment listing what type 54of variants get properties in that group: 55 56module { 57 arch: { 58 arm: { 59 // Host or device variants with arm architecture 60 }, 61 arm64: { 62 // Host or device variants with arm64 architecture 63 }, 64 mips: { 65 // Host or device variants with mips architecture 66 }, 67 mips64: { 68 // Host or device variants with mips64 architecture 69 }, 70 x86: { 71 // Host or device variants with x86 architecture 72 }, 73 x86_64: { 74 // Host or device variants with x86_64 architecture 75 }, 76 }, 77 multilib: { 78 lib32: { 79 // Host or device variants for 32-bit architectures 80 }, 81 lib64: { 82 // Host or device variants for 64-bit architectures 83 }, 84 }, 85 target: { 86 android: { 87 // Device variants 88 }, 89 host: { 90 // Host variants 91 }, 92 linux_glibc: { 93 // Linux host variants 94 }, 95 darwin: { 96 // Darwin host variants 97 }, 98 windows: { 99 // Windows host variants 100 }, 101 not_windows: { 102 // Non-windows host variants 103 }, 104 }, 105} 106*/ 107 108var archVariants = map[ArchType][]string{ 109 Arm: { 110 "armv7-a", 111 "armv7-a-neon", 112 "armv8-a", 113 "armv8-2a", 114 "cortex-a7", 115 "cortex-a8", 116 "cortex-a9", 117 "cortex-a15", 118 "cortex-a53", 119 "cortex-a53-a57", 120 "cortex-a55", 121 "cortex-a72", 122 "cortex-a73", 123 "cortex-a75", 124 "cortex-a76", 125 "krait", 126 "kryo", 127 "kryo385", 128 "exynos-m1", 129 "exynos-m2", 130 }, 131 Arm64: { 132 "armv8_a", 133 "armv8_2a", 134 "cortex-a53", 135 "cortex-a55", 136 "cortex-a72", 137 "cortex-a73", 138 "cortex-a75", 139 "cortex-a76", 140 "kryo", 141 "kryo385", 142 "exynos-m1", 143 "exynos-m2", 144 }, 145 Mips: { 146 "mips32_fp", 147 "mips32r2_fp", 148 "mips32r2_fp_xburst", 149 "mips32r2dsp_fp", 150 "mips32r2dspr2_fp", 151 "mips32r6", 152 }, 153 Mips64: { 154 "mips64r2", 155 "mips64r6", 156 }, 157 X86: { 158 "amberlake", 159 "atom", 160 "broadwell", 161 "haswell", 162 "icelake", 163 "ivybridge", 164 "kabylake", 165 "sandybridge", 166 "silvermont", 167 "skylake", 168 "stoneyridge", 169 "tigerlake", 170 "whiskeylake", 171 "x86_64", 172 }, 173 X86_64: { 174 "amberlake", 175 "broadwell", 176 "haswell", 177 "icelake", 178 "ivybridge", 179 "kabylake", 180 "sandybridge", 181 "silvermont", 182 "skylake", 183 "stoneyridge", 184 "tigerlake", 185 "whiskeylake", 186 }, 187} 188 189var archFeatures = map[ArchType][]string{ 190 Arm: { 191 "neon", 192 }, 193 Mips: { 194 "dspr2", 195 "rev6", 196 "msa", 197 }, 198 Mips64: { 199 "rev6", 200 "msa", 201 }, 202 X86: { 203 "ssse3", 204 "sse4", 205 "sse4_1", 206 "sse4_2", 207 "aes_ni", 208 "avx", 209 "avx2", 210 "avx512", 211 "popcnt", 212 "movbe", 213 }, 214 X86_64: { 215 "ssse3", 216 "sse4", 217 "sse4_1", 218 "sse4_2", 219 "aes_ni", 220 "avx", 221 "avx2", 222 "avx512", 223 "popcnt", 224 }, 225} 226 227var archFeatureMap = map[ArchType]map[string][]string{ 228 Arm: { 229 "armv7-a-neon": { 230 "neon", 231 }, 232 "armv8-a": { 233 "neon", 234 }, 235 "armv8-2a": { 236 "neon", 237 }, 238 }, 239 Mips: { 240 "mips32r2dspr2_fp": { 241 "dspr2", 242 }, 243 "mips32r6": { 244 "rev6", 245 }, 246 }, 247 Mips64: { 248 "mips64r6": { 249 "rev6", 250 }, 251 }, 252 X86: { 253 "amberlake": { 254 "ssse3", 255 "sse4", 256 "sse4_1", 257 "sse4_2", 258 "avx", 259 "avx2", 260 "aes_ni", 261 "popcnt", 262 }, 263 "atom": { 264 "ssse3", 265 "movbe", 266 }, 267 "broadwell": { 268 "ssse3", 269 "sse4", 270 "sse4_1", 271 "sse4_2", 272 "avx", 273 "avx2", 274 "aes_ni", 275 "popcnt", 276 }, 277 "haswell": { 278 "ssse3", 279 "sse4", 280 "sse4_1", 281 "sse4_2", 282 "aes_ni", 283 "avx", 284 "popcnt", 285 "movbe", 286 }, 287 "icelake": { 288 "ssse3", 289 "sse4", 290 "sse4_1", 291 "sse4_2", 292 "avx", 293 "avx2", 294 "avx512", 295 "aes_ni", 296 "popcnt", 297 }, 298 "ivybridge": { 299 "ssse3", 300 "sse4", 301 "sse4_1", 302 "sse4_2", 303 "aes_ni", 304 "avx", 305 "popcnt", 306 }, 307 "kabylake": { 308 "ssse3", 309 "sse4", 310 "sse4_1", 311 "sse4_2", 312 "avx", 313 "avx2", 314 "aes_ni", 315 "popcnt", 316 }, 317 "sandybridge": { 318 "ssse3", 319 "sse4", 320 "sse4_1", 321 "sse4_2", 322 "popcnt", 323 }, 324 "silvermont": { 325 "ssse3", 326 "sse4", 327 "sse4_1", 328 "sse4_2", 329 "aes_ni", 330 "popcnt", 331 "movbe", 332 }, 333 "skylake": { 334 "ssse3", 335 "sse4", 336 "sse4_1", 337 "sse4_2", 338 "avx", 339 "avx2", 340 "avx512", 341 "aes_ni", 342 "popcnt", 343 }, 344 "stoneyridge": { 345 "ssse3", 346 "sse4", 347 "sse4_1", 348 "sse4_2", 349 "aes_ni", 350 "avx", 351 "avx2", 352 "popcnt", 353 "movbe", 354 }, 355 "tigerlake": { 356 "ssse3", 357 "sse4", 358 "sse4_1", 359 "sse4_2", 360 "avx", 361 "avx2", 362 "avx512", 363 "aes_ni", 364 "popcnt", 365 }, 366 "whiskeylake": { 367 "ssse3", 368 "sse4", 369 "sse4_1", 370 "sse4_2", 371 "avx", 372 "avx2", 373 "avx512", 374 "aes_ni", 375 "popcnt", 376 }, 377 "x86_64": { 378 "ssse3", 379 "sse4", 380 "sse4_1", 381 "sse4_2", 382 "popcnt", 383 }, 384 }, 385 X86_64: { 386 "amberlake": { 387 "ssse3", 388 "sse4", 389 "sse4_1", 390 "sse4_2", 391 "avx", 392 "avx2", 393 "aes_ni", 394 "popcnt", 395 }, 396 "broadwell": { 397 "ssse3", 398 "sse4", 399 "sse4_1", 400 "sse4_2", 401 "avx", 402 "avx2", 403 "aes_ni", 404 "popcnt", 405 }, 406 "haswell": { 407 "ssse3", 408 "sse4", 409 "sse4_1", 410 "sse4_2", 411 "aes_ni", 412 "avx", 413 "popcnt", 414 }, 415 "icelake": { 416 "ssse3", 417 "sse4", 418 "sse4_1", 419 "sse4_2", 420 "avx", 421 "avx2", 422 "avx512", 423 "aes_ni", 424 "popcnt", 425 }, 426 "ivybridge": { 427 "ssse3", 428 "sse4", 429 "sse4_1", 430 "sse4_2", 431 "aes_ni", 432 "avx", 433 "popcnt", 434 }, 435 "kabylake": { 436 "ssse3", 437 "sse4", 438 "sse4_1", 439 "sse4_2", 440 "avx", 441 "avx2", 442 "aes_ni", 443 "popcnt", 444 }, 445 "sandybridge": { 446 "ssse3", 447 "sse4", 448 "sse4_1", 449 "sse4_2", 450 "popcnt", 451 }, 452 "silvermont": { 453 "ssse3", 454 "sse4", 455 "sse4_1", 456 "sse4_2", 457 "aes_ni", 458 "popcnt", 459 }, 460 "skylake": { 461 "ssse3", 462 "sse4", 463 "sse4_1", 464 "sse4_2", 465 "avx", 466 "avx2", 467 "avx512", 468 "aes_ni", 469 "popcnt", 470 }, 471 "stoneyridge": { 472 "ssse3", 473 "sse4", 474 "sse4_1", 475 "sse4_2", 476 "aes_ni", 477 "avx", 478 "avx2", 479 "popcnt", 480 }, 481 "tigerlake": { 482 "ssse3", 483 "sse4", 484 "sse4_1", 485 "sse4_2", 486 "avx", 487 "avx2", 488 "avx512", 489 "aes_ni", 490 "popcnt", 491 }, 492 "whiskeylake": { 493 "ssse3", 494 "sse4", 495 "sse4_1", 496 "sse4_2", 497 "avx", 498 "avx2", 499 "avx512", 500 "aes_ni", 501 "popcnt", 502 }, 503 }, 504} 505 506var defaultArchFeatureMap = map[OsType]map[ArchType][]string{} 507 508func RegisterDefaultArchVariantFeatures(os OsType, arch ArchType, features ...string) { 509 checkCalledFromInit() 510 511 for _, feature := range features { 512 if !InList(feature, archFeatures[arch]) { 513 panic(fmt.Errorf("Invalid feature %q for arch %q variant \"\"", feature, arch)) 514 } 515 } 516 517 if defaultArchFeatureMap[os] == nil { 518 defaultArchFeatureMap[os] = make(map[ArchType][]string) 519 } 520 defaultArchFeatureMap[os][arch] = features 521} 522 523// An Arch indicates a single CPU architecture. 524type Arch struct { 525 ArchType ArchType 526 ArchVariant string 527 CpuVariant string 528 Abi []string 529 ArchFeatures []string 530 Native bool 531} 532 533func (a Arch) String() string { 534 s := a.ArchType.String() 535 if a.ArchVariant != "" { 536 s += "_" + a.ArchVariant 537 } 538 if a.CpuVariant != "" { 539 s += "_" + a.CpuVariant 540 } 541 return s 542} 543 544type ArchType struct { 545 Name string 546 Field string 547 Multilib string 548} 549 550func newArch(name, multilib string) ArchType { 551 archType := ArchType{ 552 Name: name, 553 Field: proptools.FieldNameForProperty(name), 554 Multilib: multilib, 555 } 556 archTypeList = append(archTypeList, archType) 557 return archType 558} 559 560func (a ArchType) String() string { 561 return a.Name 562} 563 564var _ encoding.TextMarshaler = ArchType{} 565 566func (a ArchType) MarshalText() ([]byte, error) { 567 return []byte(strconv.Quote(a.String())), nil 568} 569 570var _ encoding.TextUnmarshaler = &ArchType{} 571 572func (a *ArchType) UnmarshalText(text []byte) error { 573 if u, ok := archTypeMap[string(text)]; ok { 574 *a = u 575 return nil 576 } 577 578 return fmt.Errorf("unknown ArchType %q", text) 579} 580 581var BuildOs = func() OsType { 582 switch runtime.GOOS { 583 case "linux": 584 return Linux 585 case "darwin": 586 return Darwin 587 default: 588 panic(fmt.Sprintf("unsupported OS: %s", runtime.GOOS)) 589 } 590}() 591 592var ( 593 osTypeList []OsType 594 commonTargetMap = make(map[string]Target) 595 596 NoOsType OsType 597 Linux = NewOsType("linux_glibc", Host, false) 598 Darwin = NewOsType("darwin", Host, false) 599 LinuxBionic = NewOsType("linux_bionic", Host, false) 600 Windows = NewOsType("windows", HostCross, true) 601 Android = NewOsType("android", Device, false) 602 Fuchsia = NewOsType("fuchsia", Device, false) 603 604 osArchTypeMap = map[OsType][]ArchType{ 605 Linux: []ArchType{X86, X86_64}, 606 LinuxBionic: []ArchType{X86_64}, 607 Darwin: []ArchType{X86_64}, 608 Windows: []ArchType{X86, X86_64}, 609 Android: []ArchType{Arm, Arm64, Mips, Mips64, X86, X86_64}, 610 Fuchsia: []ArchType{Arm64, X86_64}, 611 } 612) 613 614type OsType struct { 615 Name, Field string 616 Class OsClass 617 618 DefaultDisabled bool 619} 620 621type OsClass int 622 623const ( 624 Generic OsClass = iota 625 Device 626 Host 627 HostCross 628) 629 630func (class OsClass) String() string { 631 switch class { 632 case Generic: 633 return "generic" 634 case Device: 635 return "device" 636 case Host: 637 return "host" 638 case HostCross: 639 return "host cross" 640 default: 641 panic(fmt.Errorf("unknown class %d", class)) 642 } 643} 644 645func (os OsType) String() string { 646 return os.Name 647} 648 649func (os OsType) Bionic() bool { 650 return os == Android || os == LinuxBionic 651} 652 653func (os OsType) Linux() bool { 654 return os == Android || os == Linux || os == LinuxBionic 655} 656 657func NewOsType(name string, class OsClass, defDisabled bool) OsType { 658 os := OsType{ 659 Name: name, 660 Field: strings.Title(name), 661 Class: class, 662 663 DefaultDisabled: defDisabled, 664 } 665 osTypeList = append(osTypeList, os) 666 667 if _, found := commonTargetMap[name]; found { 668 panic(fmt.Errorf("Found Os type duplicate during OsType registration: %q", name)) 669 } else { 670 commonTargetMap[name] = Target{Os: os, Arch: Arch{ArchType: Common}} 671 } 672 673 return os 674} 675 676func osByName(name string) OsType { 677 for _, os := range osTypeList { 678 if os.Name == name { 679 return os 680 } 681 } 682 683 return NoOsType 684} 685 686type Target struct { 687 Os OsType 688 Arch Arch 689} 690 691func (target Target) String() string { 692 return target.Os.String() + "_" + target.Arch.String() 693} 694 695// archMutator splits a module into a variant for each Target requested by the module. Target selection 696// for a module is in three levels, OsClass, mulitlib, and then Target. 697// OsClass selection is determined by: 698// - The HostOrDeviceSupported value passed in to InitAndroidArchModule by the module type factory, which selects 699// whether the module type can compile for host, device or both. 700// - The host_supported and device_supported properties on the module. 701// If host is supported for the module, the Host and HostCross OsClasses are are selected. If device is supported 702// for the module, the Device OsClass is selected. 703// Within each selected OsClass, the multilib selection is determined by: 704// - The compile_multilib property if it set (which may be overriden by target.android.compile_multlib or 705// target.host.compile_multilib). 706// - The default multilib passed to InitAndroidArchModule if compile_multilib was not set. 707// Valid multilib values include: 708// "both": compile for all Targets supported by the OsClass (generally x86_64 and x86, or arm64 and arm). 709// "first": compile for only a single preferred Target supported by the OsClass. This is generally x86_64 or arm64, 710// but may be arm for a 32-bit only build or a build with TARGET_PREFER_32_BIT=true set. 711// "32": compile for only a single 32-bit Target supported by the OsClass. 712// "64": compile for only a single 64-bit Target supported by the OsClass. 713// "common": compile a for a single Target that will work on all Targets suported by the OsClass (for example Java). 714// 715// Once the list of Targets is determined, the module is split into a variant for each Target. 716// 717// Modules can be initialized with InitAndroidMultiTargetsArchModule, in which case they will be split by OsClass, 718// but will have a common Target that is expected to handle all other selected Targets via ctx.MultiTargets(). 719func archMutator(mctx BottomUpMutatorContext) { 720 var module Module 721 var ok bool 722 if module, ok = mctx.Module().(Module); !ok { 723 return 724 } 725 726 base := module.base() 727 728 if !base.ArchSpecific() { 729 return 730 } 731 732 var moduleTargets []Target 733 moduleMultiTargets := make(map[int][]Target) 734 primaryModules := make(map[int]bool) 735 osClasses := base.OsClassSupported() 736 737 for _, os := range osTypeList { 738 supportedClass := false 739 for _, osClass := range osClasses { 740 if os.Class == osClass { 741 supportedClass = true 742 } 743 } 744 if !supportedClass { 745 continue 746 } 747 748 osTargets := mctx.Config().Targets[os] 749 if len(osTargets) == 0 { 750 continue 751 } 752 753 // only the primary arch in the recovery partition 754 if os == Android && module.InstallInRecovery() { 755 osTargets = []Target{osTargets[0]} 756 } 757 758 prefer32 := false 759 if base.prefer32 != nil { 760 prefer32 = base.prefer32(mctx, base, os.Class) 761 } 762 763 multilib, extraMultilib := decodeMultilib(base, os.Class) 764 targets, err := decodeMultilibTargets(multilib, osTargets, prefer32) 765 if err != nil { 766 mctx.ModuleErrorf("%s", err.Error()) 767 } 768 769 var multiTargets []Target 770 if extraMultilib != "" { 771 multiTargets, err = decodeMultilibTargets(extraMultilib, osTargets, prefer32) 772 if err != nil { 773 mctx.ModuleErrorf("%s", err.Error()) 774 } 775 } 776 777 if len(targets) > 0 { 778 primaryModules[len(moduleTargets)] = true 779 moduleMultiTargets[len(moduleTargets)] = multiTargets 780 moduleTargets = append(moduleTargets, targets...) 781 } 782 } 783 784 if len(moduleTargets) == 0 { 785 base.commonProperties.Enabled = boolPtr(false) 786 return 787 } 788 789 targetNames := make([]string, len(moduleTargets)) 790 791 for i, target := range moduleTargets { 792 targetNames[i] = target.String() 793 } 794 795 modules := mctx.CreateVariations(targetNames...) 796 for i, m := range modules { 797 m.(Module).base().SetTarget(moduleTargets[i], moduleMultiTargets[i], primaryModules[i]) 798 m.(Module).base().setArchProperties(mctx) 799 } 800} 801 802func decodeMultilib(base *ModuleBase, class OsClass) (multilib, extraMultilib string) { 803 switch class { 804 case Device: 805 multilib = String(base.commonProperties.Target.Android.Compile_multilib) 806 case Host, HostCross: 807 multilib = String(base.commonProperties.Target.Host.Compile_multilib) 808 } 809 if multilib == "" { 810 multilib = String(base.commonProperties.Compile_multilib) 811 } 812 if multilib == "" { 813 multilib = base.commonProperties.Default_multilib 814 } 815 816 if base.commonProperties.UseTargetVariants { 817 return multilib, "" 818 } else { 819 // For app modules a single arch variant will be created per OS class which is expected to handle all the 820 // selected arches. Return the common-type as multilib and any Android.bp provided multilib as extraMultilib 821 if multilib == base.commonProperties.Default_multilib { 822 multilib = "first" 823 } 824 return base.commonProperties.Default_multilib, multilib 825 } 826} 827 828func filterArchStructFields(fields []reflect.StructField) (filteredFields []reflect.StructField, filtered bool) { 829 for _, field := range fields { 830 if !proptools.HasTag(field, "android", "arch_variant") { 831 filtered = true 832 continue 833 } 834 835 // The arch_variant field isn't necessary past this point 836 // Instead of wasting space, just remove it. Go also has a 837 // 16-bit limit on structure name length. The name is constructed 838 // based on the Go source representation of the structure, so 839 // the tag names count towards that length. 840 // 841 // TODO: handle the uncommon case of other tags being involved 842 if field.Tag == `android:"arch_variant"` { 843 field.Tag = "" 844 } 845 846 // Recurse into structs 847 switch field.Type.Kind() { 848 case reflect.Struct: 849 var subFiltered bool 850 field.Type, subFiltered = filterArchStruct(field.Type) 851 filtered = filtered || subFiltered 852 if field.Type == nil { 853 continue 854 } 855 case reflect.Ptr: 856 if field.Type.Elem().Kind() == reflect.Struct { 857 nestedType, subFiltered := filterArchStruct(field.Type.Elem()) 858 filtered = filtered || subFiltered 859 if nestedType == nil { 860 continue 861 } 862 field.Type = reflect.PtrTo(nestedType) 863 } 864 case reflect.Interface: 865 panic("Interfaces are not supported in arch_variant properties") 866 } 867 868 filteredFields = append(filteredFields, field) 869 } 870 871 return filteredFields, filtered 872} 873 874// filterArchStruct takes a reflect.Type that is either a sturct or a pointer to a struct, and returns a reflect.Type 875// that only contains the fields in the original type that have an `android:"arch_variant"` struct tag, and a bool 876// that is true if the new struct type has fewer fields than the original type. If there are no fields in the 877// original type with the struct tag it returns nil and true. 878func filterArchStruct(prop reflect.Type) (filteredProp reflect.Type, filtered bool) { 879 var fields []reflect.StructField 880 881 ptr := prop.Kind() == reflect.Ptr 882 if ptr { 883 prop = prop.Elem() 884 } 885 886 for i := 0; i < prop.NumField(); i++ { 887 fields = append(fields, prop.Field(i)) 888 } 889 890 filteredFields, filtered := filterArchStructFields(fields) 891 892 if len(filteredFields) == 0 { 893 return nil, true 894 } 895 896 if !filtered { 897 if ptr { 898 return reflect.PtrTo(prop), false 899 } 900 return prop, false 901 } 902 903 ret := reflect.StructOf(filteredFields) 904 if ptr { 905 ret = reflect.PtrTo(ret) 906 } 907 908 return ret, true 909} 910 911// filterArchStruct takes a reflect.Type that is either a sturct or a pointer to a struct, and returns a list of 912// reflect.Type that only contains the fields in the original type that have an `android:"arch_variant"` struct tag, 913// and a bool that is true if the new struct type has fewer fields than the original type. If there are no fields in 914// the original type with the struct tag it returns nil and true. Each returned struct type will have a maximum of 915// 10 top level fields in it to attempt to avoid hitting the reflect.StructOf name length limit, although the limit 916// can still be reached with a single struct field with many fields in it. 917func filterArchStructSharded(prop reflect.Type) (filteredProp []reflect.Type, filtered bool) { 918 var fields []reflect.StructField 919 920 ptr := prop.Kind() == reflect.Ptr 921 if ptr { 922 prop = prop.Elem() 923 } 924 925 for i := 0; i < prop.NumField(); i++ { 926 fields = append(fields, prop.Field(i)) 927 } 928 929 fields, filtered = filterArchStructFields(fields) 930 if !filtered { 931 if ptr { 932 return []reflect.Type{reflect.PtrTo(prop)}, false 933 } 934 return []reflect.Type{prop}, false 935 } 936 937 if len(fields) == 0 { 938 return nil, true 939 } 940 941 shards := shardFields(fields, 10) 942 943 for _, shard := range shards { 944 s := reflect.StructOf(shard) 945 if ptr { 946 s = reflect.PtrTo(s) 947 } 948 filteredProp = append(filteredProp, s) 949 } 950 951 return filteredProp, true 952} 953 954func shardFields(fields []reflect.StructField, shardSize int) [][]reflect.StructField { 955 ret := make([][]reflect.StructField, 0, (len(fields)+shardSize-1)/shardSize) 956 for len(fields) > shardSize { 957 ret = append(ret, fields[0:shardSize]) 958 fields = fields[shardSize:] 959 } 960 if len(fields) > 0 { 961 ret = append(ret, fields) 962 } 963 return ret 964} 965 966// createArchType takes a reflect.Type that is either a struct or a pointer to a struct, and returns a list of 967// reflect.Type that contains the arch-variant properties inside structs for each architecture, os, target, multilib, 968// etc. 969func createArchType(props reflect.Type) []reflect.Type { 970 propShards, _ := filterArchStructSharded(props) 971 if len(propShards) == 0 { 972 return nil 973 } 974 975 var ret []reflect.Type 976 for _, props := range propShards { 977 978 variantFields := func(names []string) []reflect.StructField { 979 ret := make([]reflect.StructField, len(names)) 980 981 for i, name := range names { 982 ret[i].Name = name 983 ret[i].Type = props 984 } 985 986 return ret 987 } 988 989 archFields := make([]reflect.StructField, len(archTypeList)) 990 for i, arch := range archTypeList { 991 variants := []string{} 992 993 for _, archVariant := range archVariants[arch] { 994 archVariant := variantReplacer.Replace(archVariant) 995 variants = append(variants, proptools.FieldNameForProperty(archVariant)) 996 } 997 for _, feature := range archFeatures[arch] { 998 feature := variantReplacer.Replace(feature) 999 variants = append(variants, proptools.FieldNameForProperty(feature)) 1000 } 1001 1002 fields := variantFields(variants) 1003 1004 fields = append([]reflect.StructField{{ 1005 Name: "BlueprintEmbed", 1006 Type: props, 1007 Anonymous: true, 1008 }}, fields...) 1009 1010 archFields[i] = reflect.StructField{ 1011 Name: arch.Field, 1012 Type: reflect.StructOf(fields), 1013 } 1014 } 1015 archType := reflect.StructOf(archFields) 1016 1017 multilibType := reflect.StructOf(variantFields([]string{"Lib32", "Lib64"})) 1018 1019 targets := []string{ 1020 "Host", 1021 "Android64", 1022 "Android32", 1023 "Bionic", 1024 "Linux", 1025 "Not_windows", 1026 "Arm_on_x86", 1027 "Arm_on_x86_64", 1028 } 1029 for _, os := range osTypeList { 1030 targets = append(targets, os.Field) 1031 1032 for _, archType := range osArchTypeMap[os] { 1033 targets = append(targets, os.Field+"_"+archType.Name) 1034 1035 if os.Linux() { 1036 target := "Linux_" + archType.Name 1037 if !InList(target, targets) { 1038 targets = append(targets, target) 1039 } 1040 } 1041 if os.Bionic() { 1042 target := "Bionic_" + archType.Name 1043 if !InList(target, targets) { 1044 targets = append(targets, target) 1045 } 1046 } 1047 } 1048 } 1049 1050 targetType := reflect.StructOf(variantFields(targets)) 1051 ret = append(ret, reflect.StructOf([]reflect.StructField{ 1052 { 1053 Name: "Arch", 1054 Type: archType, 1055 }, 1056 { 1057 Name: "Multilib", 1058 Type: multilibType, 1059 }, 1060 { 1061 Name: "Target", 1062 Type: targetType, 1063 }, 1064 })) 1065 } 1066 return ret 1067} 1068 1069var archPropTypeMap OncePer 1070 1071func InitArchModule(m Module) { 1072 1073 base := m.base() 1074 1075 base.generalProperties = m.GetProperties() 1076 1077 for _, properties := range base.generalProperties { 1078 propertiesValue := reflect.ValueOf(properties) 1079 t := propertiesValue.Type() 1080 if propertiesValue.Kind() != reflect.Ptr { 1081 panic(fmt.Errorf("properties must be a pointer to a struct, got %T", 1082 propertiesValue.Interface())) 1083 } 1084 1085 propertiesValue = propertiesValue.Elem() 1086 if propertiesValue.Kind() != reflect.Struct { 1087 panic(fmt.Errorf("properties must be a pointer to a struct, got %T", 1088 propertiesValue.Interface())) 1089 } 1090 1091 archPropTypes := archPropTypeMap.Once(NewCustomOnceKey(t), func() interface{} { 1092 return createArchType(t) 1093 }).([]reflect.Type) 1094 1095 var archProperties []interface{} 1096 for _, t := range archPropTypes { 1097 archProperties = append(archProperties, reflect.New(t).Interface()) 1098 } 1099 base.archProperties = append(base.archProperties, archProperties) 1100 m.AddProperties(archProperties...) 1101 } 1102 1103 base.customizableProperties = m.GetProperties() 1104} 1105 1106var variantReplacer = strings.NewReplacer("-", "_", ".", "_") 1107 1108func (a *ModuleBase) appendProperties(ctx BottomUpMutatorContext, 1109 dst interface{}, src reflect.Value, field, srcPrefix string) reflect.Value { 1110 1111 src = src.FieldByName(field) 1112 if !src.IsValid() { 1113 ctx.ModuleErrorf("field %q does not exist", srcPrefix) 1114 return src 1115 } 1116 1117 ret := src 1118 1119 if src.Kind() == reflect.Struct { 1120 src = src.FieldByName("BlueprintEmbed") 1121 } 1122 1123 order := func(property string, 1124 dstField, srcField reflect.StructField, 1125 dstValue, srcValue interface{}) (proptools.Order, error) { 1126 if proptools.HasTag(dstField, "android", "variant_prepend") { 1127 return proptools.Prepend, nil 1128 } else { 1129 return proptools.Append, nil 1130 } 1131 } 1132 1133 err := proptools.ExtendMatchingProperties([]interface{}{dst}, src.Interface(), nil, order) 1134 if err != nil { 1135 if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok { 1136 ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error()) 1137 } else { 1138 panic(err) 1139 } 1140 } 1141 1142 return ret 1143} 1144 1145// Rewrite the module's properties structs to contain arch-specific values. 1146func (a *ModuleBase) setArchProperties(ctx BottomUpMutatorContext) { 1147 arch := a.Arch() 1148 os := a.Os() 1149 1150 for i := range a.generalProperties { 1151 genProps := a.generalProperties[i] 1152 if a.archProperties[i] == nil { 1153 continue 1154 } 1155 for _, archProperties := range a.archProperties[i] { 1156 archPropValues := reflect.ValueOf(archProperties).Elem() 1157 1158 archProp := archPropValues.FieldByName("Arch") 1159 multilibProp := archPropValues.FieldByName("Multilib") 1160 targetProp := archPropValues.FieldByName("Target") 1161 1162 var field string 1163 var prefix string 1164 1165 // Handle arch-specific properties in the form: 1166 // arch: { 1167 // arm64: { 1168 // key: value, 1169 // }, 1170 // }, 1171 t := arch.ArchType 1172 1173 if arch.ArchType != Common { 1174 field := proptools.FieldNameForProperty(t.Name) 1175 prefix := "arch." + t.Name 1176 archStruct := a.appendProperties(ctx, genProps, archProp, field, prefix) 1177 1178 // Handle arch-variant-specific properties in the form: 1179 // arch: { 1180 // variant: { 1181 // key: value, 1182 // }, 1183 // }, 1184 v := variantReplacer.Replace(arch.ArchVariant) 1185 if v != "" { 1186 field := proptools.FieldNameForProperty(v) 1187 prefix := "arch." + t.Name + "." + v 1188 a.appendProperties(ctx, genProps, archStruct, field, prefix) 1189 } 1190 1191 // Handle cpu-variant-specific properties in the form: 1192 // arch: { 1193 // variant: { 1194 // key: value, 1195 // }, 1196 // }, 1197 if arch.CpuVariant != arch.ArchVariant { 1198 c := variantReplacer.Replace(arch.CpuVariant) 1199 if c != "" { 1200 field := proptools.FieldNameForProperty(c) 1201 prefix := "arch." + t.Name + "." + c 1202 a.appendProperties(ctx, genProps, archStruct, field, prefix) 1203 } 1204 } 1205 1206 // Handle arch-feature-specific properties in the form: 1207 // arch: { 1208 // feature: { 1209 // key: value, 1210 // }, 1211 // }, 1212 for _, feature := range arch.ArchFeatures { 1213 field := proptools.FieldNameForProperty(feature) 1214 prefix := "arch." + t.Name + "." + feature 1215 a.appendProperties(ctx, genProps, archStruct, field, prefix) 1216 } 1217 1218 // Handle multilib-specific properties in the form: 1219 // multilib: { 1220 // lib32: { 1221 // key: value, 1222 // }, 1223 // }, 1224 field = proptools.FieldNameForProperty(t.Multilib) 1225 prefix = "multilib." + t.Multilib 1226 a.appendProperties(ctx, genProps, multilibProp, field, prefix) 1227 } 1228 1229 // Handle host-specific properties in the form: 1230 // target: { 1231 // host: { 1232 // key: value, 1233 // }, 1234 // }, 1235 if os.Class == Host || os.Class == HostCross { 1236 field = "Host" 1237 prefix = "target.host" 1238 a.appendProperties(ctx, genProps, targetProp, field, prefix) 1239 } 1240 1241 // Handle target OS generalities of the form: 1242 // target: { 1243 // bionic: { 1244 // key: value, 1245 // }, 1246 // bionic_x86: { 1247 // key: value, 1248 // }, 1249 // } 1250 if os.Linux() { 1251 field = "Linux" 1252 prefix = "target.linux" 1253 a.appendProperties(ctx, genProps, targetProp, field, prefix) 1254 1255 if arch.ArchType != Common { 1256 field = "Linux_" + arch.ArchType.Name 1257 prefix = "target.linux_" + arch.ArchType.Name 1258 a.appendProperties(ctx, genProps, targetProp, field, prefix) 1259 } 1260 } 1261 1262 if os.Bionic() { 1263 field = "Bionic" 1264 prefix = "target.bionic" 1265 a.appendProperties(ctx, genProps, targetProp, field, prefix) 1266 1267 if arch.ArchType != Common { 1268 field = "Bionic_" + t.Name 1269 prefix = "target.bionic_" + t.Name 1270 a.appendProperties(ctx, genProps, targetProp, field, prefix) 1271 } 1272 } 1273 1274 // Handle target OS properties in the form: 1275 // target: { 1276 // linux_glibc: { 1277 // key: value, 1278 // }, 1279 // not_windows: { 1280 // key: value, 1281 // }, 1282 // linux_glibc_x86: { 1283 // key: value, 1284 // }, 1285 // linux_glibc_arm: { 1286 // key: value, 1287 // }, 1288 // android { 1289 // key: value, 1290 // }, 1291 // android_arm { 1292 // key: value, 1293 // }, 1294 // android_x86 { 1295 // key: value, 1296 // }, 1297 // }, 1298 field = os.Field 1299 prefix = "target." + os.Name 1300 a.appendProperties(ctx, genProps, targetProp, field, prefix) 1301 1302 if arch.ArchType != Common { 1303 field = os.Field + "_" + t.Name 1304 prefix = "target." + os.Name + "_" + t.Name 1305 a.appendProperties(ctx, genProps, targetProp, field, prefix) 1306 } 1307 1308 if (os.Class == Host || os.Class == HostCross) && os != Windows { 1309 field := "Not_windows" 1310 prefix := "target.not_windows" 1311 a.appendProperties(ctx, genProps, targetProp, field, prefix) 1312 } 1313 1314 // Handle 64-bit device properties in the form: 1315 // target { 1316 // android64 { 1317 // key: value, 1318 // }, 1319 // android32 { 1320 // key: value, 1321 // }, 1322 // }, 1323 // WARNING: this is probably not what you want to use in your blueprints file, it selects 1324 // options for all targets on a device that supports 64-bit binaries, not just the targets 1325 // that are being compiled for 64-bit. Its expected use case is binaries like linker and 1326 // debuggerd that need to know when they are a 32-bit process running on a 64-bit device 1327 if os.Class == Device { 1328 if ctx.Config().Android64() { 1329 field := "Android64" 1330 prefix := "target.android64" 1331 a.appendProperties(ctx, genProps, targetProp, field, prefix) 1332 } else { 1333 field := "Android32" 1334 prefix := "target.android32" 1335 a.appendProperties(ctx, genProps, targetProp, field, prefix) 1336 } 1337 1338 if (arch.ArchType == X86 && (hasArmAbi(arch) || 1339 hasArmAndroidArch(ctx.Config().Targets[Android]))) || 1340 (arch.ArchType == Arm && 1341 hasX86AndroidArch(ctx.Config().Targets[Android])) { 1342 field := "Arm_on_x86" 1343 prefix := "target.arm_on_x86" 1344 a.appendProperties(ctx, genProps, targetProp, field, prefix) 1345 } 1346 if (arch.ArchType == X86_64 && (hasArmAbi(arch) || 1347 hasArmAndroidArch(ctx.Config().Targets[Android]))) || 1348 (arch.ArchType == Arm && 1349 hasX8664AndroidArch(ctx.Config().Targets[Android])) { 1350 field := "Arm_on_x86_64" 1351 prefix := "target.arm_on_x86_64" 1352 a.appendProperties(ctx, genProps, targetProp, field, prefix) 1353 } 1354 } 1355 } 1356 } 1357} 1358 1359func forEachInterface(v reflect.Value, f func(reflect.Value)) { 1360 switch v.Kind() { 1361 case reflect.Interface: 1362 f(v) 1363 case reflect.Struct: 1364 for i := 0; i < v.NumField(); i++ { 1365 forEachInterface(v.Field(i), f) 1366 } 1367 case reflect.Ptr: 1368 forEachInterface(v.Elem(), f) 1369 default: 1370 panic(fmt.Errorf("Unsupported kind %s", v.Kind())) 1371 } 1372} 1373 1374// Convert the arch product variables into a list of targets for each os class structs 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 if targetErr != nil { 1383 return 1384 } 1385 1386 arch, err := decodeArch(os, archName, archVariant, cpuVariant, abi) 1387 if err != nil { 1388 targetErr = err 1389 return 1390 } 1391 1392 targets[os] = append(targets[os], 1393 Target{ 1394 Os: os, 1395 Arch: arch, 1396 }) 1397 } 1398 1399 if variables.HostArch == nil { 1400 return nil, fmt.Errorf("No host primary architecture set") 1401 } 1402 1403 addTarget(BuildOs, *variables.HostArch, nil, nil, nil) 1404 1405 if variables.HostSecondaryArch != nil && *variables.HostSecondaryArch != "" { 1406 addTarget(BuildOs, *variables.HostSecondaryArch, nil, nil, nil) 1407 } 1408 1409 if Bool(config.Host_bionic) { 1410 addTarget(LinuxBionic, "x86_64", nil, nil, nil) 1411 } 1412 1413 if String(variables.CrossHost) != "" { 1414 crossHostOs := osByName(*variables.CrossHost) 1415 if crossHostOs == NoOsType { 1416 return nil, fmt.Errorf("Unknown cross host OS %q", *variables.CrossHost) 1417 } 1418 1419 if String(variables.CrossHostArch) == "" { 1420 return nil, fmt.Errorf("No cross-host primary architecture set") 1421 } 1422 1423 addTarget(crossHostOs, *variables.CrossHostArch, nil, nil, nil) 1424 1425 if variables.CrossHostSecondaryArch != nil && *variables.CrossHostSecondaryArch != "" { 1426 addTarget(crossHostOs, *variables.CrossHostSecondaryArch, nil, nil, nil) 1427 } 1428 } 1429 1430 if variables.DeviceArch != nil && *variables.DeviceArch != "" { 1431 var target = Android 1432 if Bool(variables.Fuchsia) { 1433 target = Fuchsia 1434 } 1435 1436 addTarget(target, *variables.DeviceArch, variables.DeviceArchVariant, 1437 variables.DeviceCpuVariant, variables.DeviceAbi) 1438 1439 if variables.DeviceSecondaryArch != nil && *variables.DeviceSecondaryArch != "" { 1440 addTarget(Android, *variables.DeviceSecondaryArch, 1441 variables.DeviceSecondaryArchVariant, variables.DeviceSecondaryCpuVariant, 1442 variables.DeviceSecondaryAbi) 1443 1444 deviceArches := targets[Android] 1445 if deviceArches[0].Arch.ArchType.Multilib == deviceArches[1].Arch.ArchType.Multilib { 1446 deviceArches[1].Arch.Native = false 1447 } 1448 } 1449 } 1450 1451 if targetErr != nil { 1452 return nil, targetErr 1453 } 1454 1455 return targets, nil 1456} 1457 1458// hasArmAbi returns true if arch has at least one arm ABI 1459func hasArmAbi(arch Arch) bool { 1460 for _, abi := range arch.Abi { 1461 if strings.HasPrefix(abi, "arm") { 1462 return true 1463 } 1464 } 1465 return false 1466} 1467 1468// hasArmArch returns true if targets has at least arm Android arch 1469func hasArmAndroidArch(targets []Target) bool { 1470 for _, target := range targets { 1471 if target.Os == Android && target.Arch.ArchType == Arm { 1472 return true 1473 } 1474 } 1475 return false 1476} 1477 1478// hasX86Arch returns true if targets has at least x86 Android arch 1479func hasX86AndroidArch(targets []Target) bool { 1480 for _, target := range targets { 1481 if target.Os == Android && target.Arch.ArchType == X86 { 1482 return true 1483 } 1484 } 1485 return false 1486} 1487 1488// hasX8664Arch returns true if targets has at least x86_64 Android arch 1489func hasX8664AndroidArch(targets []Target) bool { 1490 for _, target := range targets { 1491 if target.Os == Android && target.Arch.ArchType == X86_64 { 1492 return true 1493 } 1494 } 1495 return false 1496} 1497 1498type archConfig struct { 1499 arch string 1500 archVariant string 1501 cpuVariant string 1502 abi []string 1503} 1504 1505func getMegaDeviceConfig() []archConfig { 1506 return []archConfig{ 1507 {"arm", "armv7-a", "generic", []string{"armeabi-v7a"}}, 1508 {"arm", "armv7-a-neon", "generic", []string{"armeabi-v7a"}}, 1509 {"arm", "armv7-a-neon", "cortex-a7", []string{"armeabi-v7a"}}, 1510 {"arm", "armv7-a-neon", "cortex-a8", []string{"armeabi-v7a"}}, 1511 {"arm", "armv7-a-neon", "cortex-a9", []string{"armeabi-v7a"}}, 1512 {"arm", "armv7-a-neon", "cortex-a15", []string{"armeabi-v7a"}}, 1513 {"arm", "armv7-a-neon", "cortex-a53", []string{"armeabi-v7a"}}, 1514 {"arm", "armv7-a-neon", "cortex-a53.a57", []string{"armeabi-v7a"}}, 1515 {"arm", "armv7-a-neon", "cortex-a72", []string{"armeabi-v7a"}}, 1516 {"arm", "armv7-a-neon", "cortex-a73", []string{"armeabi-v7a"}}, 1517 {"arm", "armv7-a-neon", "cortex-a75", []string{"armeabi-v7a"}}, 1518 {"arm", "armv7-a-neon", "cortex-a76", []string{"armeabi-v7a"}}, 1519 {"arm", "armv7-a-neon", "krait", []string{"armeabi-v7a"}}, 1520 {"arm", "armv7-a-neon", "kryo", []string{"armeabi-v7a"}}, 1521 {"arm", "armv7-a-neon", "kryo385", []string{"armeabi-v7a"}}, 1522 {"arm", "armv7-a-neon", "exynos-m1", []string{"armeabi-v7a"}}, 1523 {"arm", "armv7-a-neon", "exynos-m2", []string{"armeabi-v7a"}}, 1524 {"arm64", "armv8-a", "cortex-a53", []string{"arm64-v8a"}}, 1525 {"arm64", "armv8-a", "cortex-a72", []string{"arm64-v8a"}}, 1526 {"arm64", "armv8-a", "cortex-a73", []string{"arm64-v8a"}}, 1527 {"arm64", "armv8-a", "kryo", []string{"arm64-v8a"}}, 1528 {"arm64", "armv8-a", "exynos-m1", []string{"arm64-v8a"}}, 1529 {"arm64", "armv8-a", "exynos-m2", []string{"arm64-v8a"}}, 1530 {"arm64", "armv8-2a", "cortex-a75", []string{"arm64-v8a"}}, 1531 {"arm64", "armv8-2a", "cortex-a76", []string{"arm64-v8a"}}, 1532 {"arm64", "armv8-2a", "kryo385", []string{"arm64-v8a"}}, 1533 {"mips", "mips32-fp", "", []string{"mips"}}, 1534 {"mips", "mips32r2-fp", "", []string{"mips"}}, 1535 {"mips", "mips32r2-fp-xburst", "", []string{"mips"}}, 1536 //{"mips", "mips32r6", "", []string{"mips"}}, 1537 {"mips", "mips32r2dsp-fp", "", []string{"mips"}}, 1538 {"mips", "mips32r2dspr2-fp", "", []string{"mips"}}, 1539 // mips64r2 is mismatching 64r2 and 64r6 libraries during linking to libgcc 1540 //{"mips64", "mips64r2", "", []string{"mips64"}}, 1541 {"mips64", "mips64r6", "", []string{"mips64"}}, 1542 {"x86", "", "", []string{"x86"}}, 1543 {"x86", "atom", "", []string{"x86"}}, 1544 {"x86", "haswell", "", []string{"x86"}}, 1545 {"x86", "ivybridge", "", []string{"x86"}}, 1546 {"x86", "sandybridge", "", []string{"x86"}}, 1547 {"x86", "silvermont", "", []string{"x86"}}, 1548 {"x86", "stoneyridge", "", []string{"x86"}}, 1549 {"x86", "x86_64", "", []string{"x86"}}, 1550 {"x86_64", "", "", []string{"x86_64"}}, 1551 {"x86_64", "haswell", "", []string{"x86_64"}}, 1552 {"x86_64", "ivybridge", "", []string{"x86_64"}}, 1553 {"x86_64", "sandybridge", "", []string{"x86_64"}}, 1554 {"x86_64", "silvermont", "", []string{"x86_64"}}, 1555 {"x86_64", "stoneyridge", "", []string{"x86_64"}}, 1556 } 1557} 1558 1559func getNdkAbisConfig() []archConfig { 1560 return []archConfig{ 1561 {"arm", "armv7-a", "", []string{"armeabi"}}, 1562 {"arm64", "armv8-a", "", []string{"arm64-v8a"}}, 1563 {"x86", "", "", []string{"x86"}}, 1564 {"x86_64", "", "", []string{"x86_64"}}, 1565 } 1566} 1567 1568func decodeArchSettings(os OsType, archConfigs []archConfig) ([]Target, error) { 1569 var ret []Target 1570 1571 for _, config := range archConfigs { 1572 arch, err := decodeArch(os, config.arch, &config.archVariant, 1573 &config.cpuVariant, config.abi) 1574 if err != nil { 1575 return nil, err 1576 } 1577 arch.Native = false 1578 ret = append(ret, Target{ 1579 Os: Android, 1580 Arch: arch, 1581 }) 1582 } 1583 1584 return ret, nil 1585} 1586 1587// Convert a set of strings from product variables into a single Arch struct 1588func decodeArch(os OsType, arch string, archVariant, cpuVariant *string, abi []string) (Arch, error) { 1589 stringPtr := func(p *string) string { 1590 if p != nil { 1591 return *p 1592 } 1593 return "" 1594 } 1595 1596 archType, ok := archTypeMap[arch] 1597 if !ok { 1598 return Arch{}, fmt.Errorf("unknown arch %q", arch) 1599 } 1600 1601 a := Arch{ 1602 ArchType: archType, 1603 ArchVariant: stringPtr(archVariant), 1604 CpuVariant: stringPtr(cpuVariant), 1605 Abi: abi, 1606 Native: true, 1607 } 1608 1609 if a.ArchVariant == a.ArchType.Name || a.ArchVariant == "generic" { 1610 a.ArchVariant = "" 1611 } 1612 1613 if a.CpuVariant == a.ArchType.Name || a.CpuVariant == "generic" { 1614 a.CpuVariant = "" 1615 } 1616 1617 for i := 0; i < len(a.Abi); i++ { 1618 if a.Abi[i] == "" { 1619 a.Abi = append(a.Abi[:i], a.Abi[i+1:]...) 1620 i-- 1621 } 1622 } 1623 1624 if a.ArchVariant == "" { 1625 if featureMap, ok := defaultArchFeatureMap[os]; ok { 1626 a.ArchFeatures = featureMap[archType] 1627 } 1628 } else { 1629 if featureMap, ok := archFeatureMap[archType]; ok { 1630 a.ArchFeatures = featureMap[a.ArchVariant] 1631 } 1632 } 1633 1634 return a, nil 1635} 1636 1637func filterMultilibTargets(targets []Target, multilib string) []Target { 1638 var ret []Target 1639 for _, t := range targets { 1640 if t.Arch.ArchType.Multilib == multilib { 1641 ret = append(ret, t) 1642 } 1643 } 1644 return ret 1645} 1646 1647func getCommonTargets(targets []Target) []Target { 1648 var ret []Target 1649 set := make(map[string]bool) 1650 1651 for _, t := range targets { 1652 if _, found := set[t.Os.String()]; !found { 1653 set[t.Os.String()] = true 1654 ret = append(ret, commonTargetMap[t.Os.String()]) 1655 } 1656 } 1657 1658 return ret 1659} 1660 1661func firstTarget(targets []Target, filters ...string) []Target { 1662 for _, filter := range filters { 1663 buildTargets := filterMultilibTargets(targets, filter) 1664 if len(buildTargets) > 0 { 1665 return buildTargets[:1] 1666 } 1667 } 1668 return nil 1669} 1670 1671// Use the module multilib setting to select one or more targets from a target list 1672func decodeMultilibTargets(multilib string, targets []Target, prefer32 bool) ([]Target, error) { 1673 buildTargets := []Target{} 1674 1675 switch multilib { 1676 case "common": 1677 buildTargets = getCommonTargets(targets) 1678 case "common_first": 1679 buildTargets = getCommonTargets(targets) 1680 if prefer32 { 1681 buildTargets = append(buildTargets, firstTarget(targets, "lib32", "lib64")...) 1682 } else { 1683 buildTargets = append(buildTargets, firstTarget(targets, "lib64", "lib32")...) 1684 } 1685 case "both": 1686 if prefer32 { 1687 buildTargets = append(buildTargets, filterMultilibTargets(targets, "lib32")...) 1688 buildTargets = append(buildTargets, filterMultilibTargets(targets, "lib64")...) 1689 } else { 1690 buildTargets = append(buildTargets, filterMultilibTargets(targets, "lib64")...) 1691 buildTargets = append(buildTargets, filterMultilibTargets(targets, "lib32")...) 1692 } 1693 case "32": 1694 buildTargets = filterMultilibTargets(targets, "lib32") 1695 case "64": 1696 buildTargets = filterMultilibTargets(targets, "lib64") 1697 case "first": 1698 if prefer32 { 1699 buildTargets = firstTarget(targets, "lib32", "lib64") 1700 } else { 1701 buildTargets = firstTarget(targets, "lib64", "lib32") 1702 } 1703 case "prefer32": 1704 buildTargets = filterMultilibTargets(targets, "lib32") 1705 if len(buildTargets) == 0 { 1706 buildTargets = filterMultilibTargets(targets, "lib64") 1707 } 1708 default: 1709 return nil, fmt.Errorf(`compile_multilib must be "both", "first", "32", "64", or "prefer32" found %q`, 1710 multilib) 1711 } 1712 1713 return buildTargets, nil 1714} 1715