at 25.11-pre 23 kB view raw
1# Define the list of system with their properties. 2# 3# See https://clang.llvm.org/docs/CrossCompilation.html and 4# http://llvm.org/docs/doxygen/html/Triple_8cpp_source.html especially 5# Triple::normalize. Parsing should essentially act as a more conservative 6# version of that last function. 7# 8# Most of the types below come in "open" and "closed" pairs. The open ones 9# specify what information we need to know about systems in general, and the 10# closed ones are sub-types representing the whitelist of systems we support in 11# practice. 12# 13# Code in the remainder of nixpkgs shouldn't rely on the closed ones in 14# e.g. exhaustive cases. Its more a sanity check to make sure nobody defines 15# systems that overlap with existing ones and won't notice something amiss. 16# 17{ lib }: 18 19let 20 inherit (lib) 21 all 22 any 23 attrValues 24 elem 25 elemAt 26 hasPrefix 27 id 28 length 29 mapAttrs 30 mergeOneOption 31 optionalString 32 splitString 33 versionAtLeast 34 ; 35 36 inherit (lib.strings) match; 37 38 inherit (lib.systems.inspect.predicates) 39 isAarch32 40 isBigEndian 41 isDarwin 42 isLinux 43 isPower64 44 isWindows 45 ; 46 47 inherit (lib.types) 48 enum 49 float 50 isType 51 mkOptionType 52 number 53 setType 54 string 55 types 56 ; 57 58 setTypes = 59 type: 60 mapAttrs ( 61 name: value: 62 assert type.check value; 63 setType type.name ({ inherit name; } // value) 64 ); 65 66 # gnu-config will ignore the portion of a triple matching the 67 # regex `e?abi.*$` when determining the validity of a triple. In 68 # other words, `i386-linuxabichickenlips` is a valid triple. 69 removeAbiSuffix = 70 x: 71 let 72 found = match "(.*)e?abi.*" x; 73 in 74 if found == null then x else elemAt found 0; 75 76in 77 78rec { 79 80 ################################################################################ 81 82 types.openSignificantByte = mkOptionType { 83 name = "significant-byte"; 84 description = "Endianness"; 85 merge = mergeOneOption; 86 }; 87 88 types.significantByte = enum (attrValues significantBytes); 89 90 significantBytes = setTypes types.openSignificantByte { 91 bigEndian = { }; 92 littleEndian = { }; 93 }; 94 95 ################################################################################ 96 97 # Reasonable power of 2 98 types.bitWidth = enum [ 99 8 100 16 101 32 102 64 103 128 104 ]; 105 106 ################################################################################ 107 108 types.openCpuType = mkOptionType { 109 name = "cpu-type"; 110 description = "instruction set architecture name and information"; 111 merge = mergeOneOption; 112 check = 113 x: 114 types.bitWidth.check x.bits 115 && (if 8 < x.bits then types.significantByte.check x.significantByte else !(x ? significantByte)); 116 }; 117 118 types.cpuType = enum (attrValues cpuTypes); 119 120 cpuTypes = 121 let 122 inherit (significantBytes) bigEndian littleEndian; 123 in 124 setTypes types.openCpuType { 125 arm = { 126 bits = 32; 127 significantByte = littleEndian; 128 family = "arm"; 129 }; 130 armv5tel = { 131 bits = 32; 132 significantByte = littleEndian; 133 family = "arm"; 134 version = "5"; 135 arch = "armv5t"; 136 }; 137 armv6m = { 138 bits = 32; 139 significantByte = littleEndian; 140 family = "arm"; 141 version = "6"; 142 arch = "armv6-m"; 143 }; 144 armv6l = { 145 bits = 32; 146 significantByte = littleEndian; 147 family = "arm"; 148 version = "6"; 149 arch = "armv6"; 150 }; 151 armv7a = { 152 bits = 32; 153 significantByte = littleEndian; 154 family = "arm"; 155 version = "7"; 156 arch = "armv7-a"; 157 }; 158 armv7r = { 159 bits = 32; 160 significantByte = littleEndian; 161 family = "arm"; 162 version = "7"; 163 arch = "armv7-r"; 164 }; 165 armv7m = { 166 bits = 32; 167 significantByte = littleEndian; 168 family = "arm"; 169 version = "7"; 170 arch = "armv7-m"; 171 }; 172 armv7l = { 173 bits = 32; 174 significantByte = littleEndian; 175 family = "arm"; 176 version = "7"; 177 arch = "armv7"; 178 }; 179 armv8a = { 180 bits = 32; 181 significantByte = littleEndian; 182 family = "arm"; 183 version = "8"; 184 arch = "armv8-a"; 185 }; 186 armv8r = { 187 bits = 32; 188 significantByte = littleEndian; 189 family = "arm"; 190 version = "8"; 191 arch = "armv8-a"; 192 }; 193 armv8m = { 194 bits = 32; 195 significantByte = littleEndian; 196 family = "arm"; 197 version = "8"; 198 arch = "armv8-m"; 199 }; 200 aarch64 = { 201 bits = 64; 202 significantByte = littleEndian; 203 family = "arm"; 204 version = "8"; 205 arch = "armv8-a"; 206 }; 207 aarch64_be = { 208 bits = 64; 209 significantByte = bigEndian; 210 family = "arm"; 211 version = "8"; 212 arch = "armv8-a"; 213 }; 214 215 i386 = { 216 bits = 32; 217 significantByte = littleEndian; 218 family = "x86"; 219 arch = "i386"; 220 }; 221 i486 = { 222 bits = 32; 223 significantByte = littleEndian; 224 family = "x86"; 225 arch = "i486"; 226 }; 227 i586 = { 228 bits = 32; 229 significantByte = littleEndian; 230 family = "x86"; 231 arch = "i586"; 232 }; 233 i686 = { 234 bits = 32; 235 significantByte = littleEndian; 236 family = "x86"; 237 arch = "i686"; 238 }; 239 x86_64 = { 240 bits = 64; 241 significantByte = littleEndian; 242 family = "x86"; 243 arch = "x86-64"; 244 }; 245 246 microblaze = { 247 bits = 32; 248 significantByte = bigEndian; 249 family = "microblaze"; 250 }; 251 microblazeel = { 252 bits = 32; 253 significantByte = littleEndian; 254 family = "microblaze"; 255 }; 256 257 mips = { 258 bits = 32; 259 significantByte = bigEndian; 260 family = "mips"; 261 }; 262 mipsel = { 263 bits = 32; 264 significantByte = littleEndian; 265 family = "mips"; 266 }; 267 mips64 = { 268 bits = 64; 269 significantByte = bigEndian; 270 family = "mips"; 271 }; 272 mips64el = { 273 bits = 64; 274 significantByte = littleEndian; 275 family = "mips"; 276 }; 277 278 mmix = { 279 bits = 64; 280 significantByte = bigEndian; 281 family = "mmix"; 282 }; 283 284 m68k = { 285 bits = 32; 286 significantByte = bigEndian; 287 family = "m68k"; 288 }; 289 290 powerpc = { 291 bits = 32; 292 significantByte = bigEndian; 293 family = "power"; 294 }; 295 powerpc64 = { 296 bits = 64; 297 significantByte = bigEndian; 298 family = "power"; 299 }; 300 powerpc64le = { 301 bits = 64; 302 significantByte = littleEndian; 303 family = "power"; 304 }; 305 powerpcle = { 306 bits = 32; 307 significantByte = littleEndian; 308 family = "power"; 309 }; 310 311 riscv32 = { 312 bits = 32; 313 significantByte = littleEndian; 314 family = "riscv"; 315 }; 316 riscv64 = { 317 bits = 64; 318 significantByte = littleEndian; 319 family = "riscv"; 320 }; 321 322 s390 = { 323 bits = 32; 324 significantByte = bigEndian; 325 family = "s390"; 326 }; 327 s390x = { 328 bits = 64; 329 significantByte = bigEndian; 330 family = "s390"; 331 }; 332 333 sparc = { 334 bits = 32; 335 significantByte = bigEndian; 336 family = "sparc"; 337 }; 338 sparc64 = { 339 bits = 64; 340 significantByte = bigEndian; 341 family = "sparc"; 342 }; 343 344 wasm32 = { 345 bits = 32; 346 significantByte = littleEndian; 347 family = "wasm"; 348 }; 349 wasm64 = { 350 bits = 64; 351 significantByte = littleEndian; 352 family = "wasm"; 353 }; 354 355 alpha = { 356 bits = 64; 357 significantByte = littleEndian; 358 family = "alpha"; 359 }; 360 361 rx = { 362 bits = 32; 363 significantByte = littleEndian; 364 family = "rx"; 365 }; 366 msp430 = { 367 bits = 16; 368 significantByte = littleEndian; 369 family = "msp430"; 370 }; 371 avr = { 372 bits = 8; 373 family = "avr"; 374 }; 375 376 vc4 = { 377 bits = 32; 378 significantByte = littleEndian; 379 family = "vc4"; 380 }; 381 382 or1k = { 383 bits = 32; 384 significantByte = bigEndian; 385 family = "or1k"; 386 }; 387 388 loongarch64 = { 389 bits = 64; 390 significantByte = littleEndian; 391 family = "loongarch"; 392 }; 393 394 javascript = { 395 bits = 32; 396 significantByte = littleEndian; 397 family = "javascript"; 398 }; 399 } 400 // { 401 # aliases 402 # Apple architecture name, as used by `darwinArch`; required by 403 # LLVM ≥ 20. 404 arm64 = cpuTypes.aarch64; 405 }; 406 407 # GNU build systems assume that older NetBSD architectures are using a.out. 408 gnuNetBSDDefaultExecFormat = 409 cpu: 410 if 411 (cpu.family == "arm" && cpu.bits == 32) 412 || (cpu.family == "sparc" && cpu.bits == 32) 413 || (cpu.family == "m68k" && cpu.bits == 32) 414 || (cpu.family == "x86" && cpu.bits == 32) 415 then 416 execFormats.aout 417 else 418 execFormats.elf; 419 420 # Determine when two CPUs are compatible with each other. That is, 421 # can code built for system B run on system A? For that to happen, 422 # the programs that system B accepts must be a subset of the 423 # programs that system A accepts. 424 # 425 # We have the following properties of the compatibility relation, 426 # which must be preserved when adding compatibility information for 427 # additional CPUs. 428 # - (reflexivity) 429 # Every CPU is compatible with itself. 430 # - (transitivity) 431 # If A is compatible with B and B is compatible with C then A is compatible with C. 432 # 433 # Note: Since 22.11 the archs of a mode switching CPU are no longer considered 434 # pairwise compatible. Mode switching implies that binaries built for A 435 # and B respectively can't be executed at the same time. 436 isCompatible = 437 with cpuTypes; 438 a: b: 439 any id [ 440 # x86 441 (b == i386 && isCompatible a i486) 442 (b == i486 && isCompatible a i586) 443 (b == i586 && isCompatible a i686) 444 445 # XXX: Not true in some cases. Like in WSL mode. 446 (b == i686 && isCompatible a x86_64) 447 448 # ARMv4 449 (b == arm && isCompatible a armv5tel) 450 451 # ARMv5 452 (b == armv5tel && isCompatible a armv6l) 453 454 # ARMv6 455 (b == armv6l && isCompatible a armv6m) 456 (b == armv6m && isCompatible a armv7l) 457 458 # ARMv7 459 (b == armv7l && isCompatible a armv7a) 460 (b == armv7l && isCompatible a armv7r) 461 (b == armv7l && isCompatible a armv7m) 462 463 # ARMv8 464 (b == aarch64 && a == armv8a) 465 (b == armv8a && isCompatible a aarch64) 466 (b == armv8r && isCompatible a armv8a) 467 (b == armv8m && isCompatible a armv8a) 468 469 # PowerPC 470 (b == powerpc && isCompatible a powerpc64) 471 (b == powerpcle && isCompatible a powerpc64le) 472 473 # MIPS 474 (b == mips && isCompatible a mips64) 475 (b == mipsel && isCompatible a mips64el) 476 477 # RISCV 478 (b == riscv32 && isCompatible a riscv64) 479 480 # SPARC 481 (b == sparc && isCompatible a sparc64) 482 483 # WASM 484 (b == wasm32 && isCompatible a wasm64) 485 486 # identity 487 (b == a) 488 ]; 489 490 ################################################################################ 491 492 types.openVendor = mkOptionType { 493 name = "vendor"; 494 description = "vendor for the platform"; 495 merge = mergeOneOption; 496 }; 497 498 types.vendor = enum (attrValues vendors); 499 500 vendors = setTypes types.openVendor { 501 apple = { }; 502 pc = { }; 503 knuth = { }; 504 505 # Actually matters, unlocking some MinGW-w64-specific options in GCC. See 506 # bottom of https://sourceforge.net/p/mingw-w64/wiki2/Unicode%20apps/ 507 w64 = { }; 508 509 none = { }; 510 unknown = { }; 511 }; 512 513 ################################################################################ 514 515 types.openExecFormat = mkOptionType { 516 name = "exec-format"; 517 description = "executable container used by the kernel"; 518 merge = mergeOneOption; 519 }; 520 521 types.execFormat = enum (attrValues execFormats); 522 523 execFormats = setTypes types.openExecFormat { 524 aout = { }; # a.out 525 elf = { }; 526 macho = { }; 527 pe = { }; 528 wasm = { }; 529 530 unknown = { }; 531 }; 532 533 ################################################################################ 534 535 types.openKernelFamily = mkOptionType { 536 name = "exec-format"; 537 description = "executable container used by the kernel"; 538 merge = mergeOneOption; 539 }; 540 541 types.kernelFamily = enum (attrValues kernelFamilies); 542 543 kernelFamilies = setTypes types.openKernelFamily { 544 bsd = { }; 545 darwin = { }; 546 }; 547 548 ################################################################################ 549 550 types.openKernel = mkOptionType { 551 name = "kernel"; 552 description = "kernel name and information"; 553 merge = mergeOneOption; 554 check = 555 x: types.execFormat.check x.execFormat && all types.kernelFamily.check (attrValues x.families); 556 }; 557 558 types.kernel = enum (attrValues kernels); 559 560 kernels = 561 let 562 inherit (execFormats) 563 elf 564 pe 565 wasm 566 unknown 567 macho 568 ; 569 inherit (kernelFamilies) bsd darwin; 570 in 571 setTypes types.openKernel { 572 # TODO(@Ericson2314): Don't want to mass-rebuild yet to keeping 'darwin' as 573 # the normalized name for macOS. 574 macos = { 575 execFormat = macho; 576 families = { inherit darwin; }; 577 name = "darwin"; 578 }; 579 ios = { 580 execFormat = macho; 581 families = { inherit darwin; }; 582 }; 583 freebsd = { 584 execFormat = elf; 585 families = { inherit bsd; }; 586 name = "freebsd"; 587 }; 588 linux = { 589 execFormat = elf; 590 families = { }; 591 }; 592 netbsd = { 593 execFormat = elf; 594 families = { inherit bsd; }; 595 }; 596 none = { 597 execFormat = unknown; 598 families = { }; 599 }; 600 openbsd = { 601 execFormat = elf; 602 families = { inherit bsd; }; 603 }; 604 solaris = { 605 execFormat = elf; 606 families = { }; 607 }; 608 wasi = { 609 execFormat = wasm; 610 families = { }; 611 }; 612 redox = { 613 execFormat = elf; 614 families = { }; 615 }; 616 windows = { 617 execFormat = pe; 618 families = { }; 619 }; 620 ghcjs = { 621 execFormat = unknown; 622 families = { }; 623 }; 624 genode = { 625 execFormat = elf; 626 families = { }; 627 }; 628 mmixware = { 629 execFormat = unknown; 630 families = { }; 631 }; 632 } 633 // { 634 # aliases 635 # 'darwin' is the kernel for all of them. We choose macOS by default. 636 darwin = kernels.macos; 637 watchos = kernels.ios; 638 tvos = kernels.ios; 639 win32 = kernels.windows; 640 }; 641 642 ################################################################################ 643 644 types.openAbi = mkOptionType { 645 name = "abi"; 646 description = "binary interface for compiled code and syscalls"; 647 merge = mergeOneOption; 648 }; 649 650 types.abi = enum (attrValues abis); 651 652 abis = setTypes types.openAbi { 653 cygnus = { }; 654 msvc = { }; 655 656 # Note: eabi is specific to ARM and PowerPC. 657 # On PowerPC, this corresponds to PPCEABI. 658 # On ARM, this corresponds to ARMEABI. 659 eabi = { 660 float = "soft"; 661 }; 662 eabihf = { 663 float = "hard"; 664 }; 665 666 # Other architectures should use ELF in embedded situations. 667 elf = { }; 668 669 androideabi = { }; 670 android = { 671 assertions = [ 672 { 673 assertion = platform: !platform.isAarch32; 674 message = '' 675 The "android" ABI is not for 32-bit ARM. Use "androideabi" instead. 676 ''; 677 } 678 ]; 679 }; 680 681 gnueabi = { 682 float = "soft"; 683 }; 684 gnueabihf = { 685 float = "hard"; 686 }; 687 gnu = { 688 assertions = [ 689 { 690 assertion = platform: !platform.isAarch32; 691 message = '' 692 The "gnu" ABI is ambiguous on 32-bit ARM. Use "gnueabi" or "gnueabihf" instead. 693 ''; 694 } 695 { 696 assertion = platform: !(platform.isPower64 && platform.isBigEndian); 697 message = '' 698 The "gnu" ABI is ambiguous on big-endian 64-bit PowerPC. Use "gnuabielfv2" or "gnuabielfv1" instead. 699 ''; 700 } 701 ]; 702 }; 703 gnuabi64 = { 704 abi = "64"; 705 }; 706 muslabi64 = { 707 abi = "64"; 708 }; 709 710 # NOTE: abi=n32 requires a 64-bit MIPS chip! That is not a typo. 711 # It is basically the 64-bit abi with 32-bit pointers. Details: 712 # https://www.linux-mips.org/pub/linux/mips/doc/ABI/MIPS-N32-ABI-Handbook.pdf 713 gnuabin32 = { 714 abi = "n32"; 715 }; 716 muslabin32 = { 717 abi = "n32"; 718 }; 719 720 gnuabielfv2 = { 721 abi = "elfv2"; 722 }; 723 gnuabielfv1 = { 724 abi = "elfv1"; 725 }; 726 727 musleabi = { 728 float = "soft"; 729 }; 730 musleabihf = { 731 float = "hard"; 732 }; 733 musl = { }; 734 735 uclibceabi = { 736 float = "soft"; 737 }; 738 uclibceabihf = { 739 float = "hard"; 740 }; 741 uclibc = { }; 742 743 unknown = { }; 744 }; 745 746 ################################################################################ 747 748 types.parsedPlatform = mkOptionType { 749 name = "system"; 750 description = "fully parsed representation of llvm- or nix-style platform tuple"; 751 merge = mergeOneOption; 752 check = 753 { 754 cpu, 755 vendor, 756 kernel, 757 abi, 758 }: 759 types.cpuType.check cpu 760 && types.vendor.check vendor 761 && types.kernel.check kernel 762 && types.abi.check abi; 763 }; 764 765 isSystem = isType "system"; 766 767 mkSystem = 768 components: 769 assert types.parsedPlatform.check components; 770 setType "system" components; 771 772 mkSkeletonFromList = 773 l: 774 { 775 "1" = 776 if elemAt l 0 == "avr" then 777 { 778 cpu = elemAt l 0; 779 kernel = "none"; 780 abi = "unknown"; 781 } 782 else 783 throw "system string '${lib.concatStringsSep "-" l}' with 1 component is ambiguous"; 784 "2" = # We only do 2-part hacks for things Nix already supports 785 if elemAt l 1 == "cygwin" then 786 { 787 cpu = elemAt l 0; 788 kernel = "windows"; 789 abi = "cygnus"; 790 } 791 # MSVC ought to be the default ABI so this case isn't needed. But then it 792 # becomes difficult to handle the gnu* variants for Aarch32 correctly for 793 # minGW. So it's easier to make gnu* the default for the MinGW, but 794 # hack-in MSVC for the non-MinGW case right here. 795 else if elemAt l 1 == "windows" then 796 { 797 cpu = elemAt l 0; 798 kernel = "windows"; 799 abi = "msvc"; 800 } 801 else if (elemAt l 1) == "elf" then 802 { 803 cpu = elemAt l 0; 804 vendor = "unknown"; 805 kernel = "none"; 806 abi = elemAt l 1; 807 } 808 else 809 { 810 cpu = elemAt l 0; 811 kernel = elemAt l 1; 812 }; 813 "3" = 814 # cpu-kernel-environment 815 if 816 elemAt l 1 == "linux" 817 || elem (elemAt l 2) [ 818 "eabi" 819 "eabihf" 820 "elf" 821 "gnu" 822 ] 823 then 824 { 825 cpu = elemAt l 0; 826 kernel = elemAt l 1; 827 abi = elemAt l 2; 828 vendor = "unknown"; 829 } 830 # cpu-vendor-os 831 else if 832 elemAt l 1 == "apple" 833 || elem (elemAt l 2) [ 834 "redox" 835 "mmixware" 836 "ghcjs" 837 "mingw32" 838 ] 839 || hasPrefix "freebsd" (elemAt l 2) 840 || hasPrefix "netbsd" (elemAt l 2) 841 || hasPrefix "openbsd" (elemAt l 2) 842 || hasPrefix "genode" (elemAt l 2) 843 || hasPrefix "wasm32" (elemAt l 0) 844 then 845 { 846 cpu = elemAt l 0; 847 vendor = elemAt l 1; 848 kernel = 849 if elemAt l 2 == "mingw32" then 850 "windows" # autotools breaks on -gnu for window 851 else 852 elemAt l 2; 853 } 854 else 855 throw "system string '${lib.concatStringsSep "-" l}' with 3 components is ambiguous"; 856 "4" = { 857 cpu = elemAt l 0; 858 vendor = elemAt l 1; 859 kernel = elemAt l 2; 860 abi = elemAt l 3; 861 }; 862 } 863 .${toString (length l)} 864 or (throw "system string '${lib.concatStringsSep "-" l}' has invalid number of hyphen-separated components"); 865 866 # This should revert the job done by config.guess from the gcc compiler. 867 mkSystemFromSkeleton = 868 { 869 cpu, 870 # Optional, but fallback too complex for here. 871 # Inferred below instead. 872 vendor ? 873 assert false; 874 null, 875 kernel, 876 # Also inferred below 877 abi ? 878 assert false; 879 null, 880 }@args: 881 let 882 getCpu = name: cpuTypes.${name} or (throw "Unknown CPU type: ${name}"); 883 getVendor = name: vendors.${name} or (throw "Unknown vendor: ${name}"); 884 getKernel = name: kernels.${name} or (throw "Unknown kernel: ${name}"); 885 getAbi = name: abis.${name} or (throw "Unknown ABI: ${name}"); 886 887 parsed = { 888 cpu = getCpu args.cpu; 889 vendor = 890 if args ? vendor then 891 getVendor args.vendor 892 else if isDarwin parsed then 893 vendors.apple 894 else if isWindows parsed then 895 vendors.pc 896 else 897 vendors.unknown; 898 kernel = 899 if hasPrefix "darwin" args.kernel then 900 getKernel "darwin" 901 else if hasPrefix "netbsd" args.kernel then 902 getKernel "netbsd" 903 else 904 getKernel (removeAbiSuffix args.kernel); 905 abi = 906 if args ? abi then 907 getAbi args.abi 908 else if isLinux parsed || isWindows parsed then 909 if isAarch32 parsed then 910 if versionAtLeast (parsed.cpu.version or "0") "6" then abis.gnueabihf else abis.gnueabi 911 # Default ppc64 BE to ELFv2 912 else if isPower64 parsed && isBigEndian parsed then 913 abis.gnuabielfv2 914 else 915 abis.gnu 916 else 917 abis.unknown; 918 }; 919 920 in 921 mkSystem parsed; 922 923 mkSystemFromString = s: mkSystemFromSkeleton (mkSkeletonFromList (splitString "-" s)); 924 925 kernelName = kernel: kernel.name + toString (kernel.version or ""); 926 927 darwinArch = cpu: if cpu.name == "aarch64" then "arm64" else cpu.name; 928 929 doubleFromSystem = 930 { 931 cpu, 932 kernel, 933 abi, 934 ... 935 }: 936 if abi == abis.cygnus then 937 "${cpu.name}-cygwin" 938 else if kernel.families ? darwin then 939 "${cpu.name}-darwin" 940 else 941 "${cpu.name}-${kernelName kernel}"; 942 943 tripleFromSystem = 944 { 945 cpu, 946 vendor, 947 kernel, 948 abi, 949 ... 950 }@sys: 951 assert isSystem sys; 952 let 953 optExecFormat = optionalString ( 954 kernel.name == "netbsd" && gnuNetBSDDefaultExecFormat cpu != kernel.execFormat 955 ) kernel.execFormat.name; 956 optAbi = optionalString (abi != abis.unknown) "-${abi.name}"; 957 cpuName = if kernel.families ? darwin then darwinArch cpu else cpu.name; 958 in 959 "${cpuName}-${vendor.name}-${kernelName kernel}${optExecFormat}${optAbi}"; 960 961 ################################################################################ 962 963}