master
   1const std = @import("std");
   2const builtin = @import("builtin");
   3const assert = std.debug.assert;
   4const mem = std.mem;
   5const OptimizeMode = std.builtin.OptimizeMode;
   6const Step = std.Build.Step;
   7
   8// Cases
   9const error_traces = @import("error_traces.zig");
  10const stack_traces = @import("stack_traces.zig");
  11const llvm_ir = @import("llvm_ir.zig");
  12const libc = @import("libc.zig");
  13
  14// Implementations
  15pub const ErrorTracesContext = @import("src/ErrorTrace.zig");
  16pub const StackTracesContext = @import("src/StackTrace.zig");
  17pub const DebuggerContext = @import("src/Debugger.zig");
  18pub const LlvmIrContext = @import("src/LlvmIr.zig");
  19pub const LibcContext = @import("src/Libc.zig");
  20
  21const TestTarget = struct {
  22    linkage: ?std.builtin.LinkMode = null,
  23    target: std.Target.Query = .{},
  24    optimize_mode: std.builtin.OptimizeMode = .Debug,
  25    link_libc: ?bool = null,
  26    single_threaded: ?bool = null,
  27    use_llvm: ?bool = null,
  28    use_lld: ?bool = null,
  29    pic: ?bool = null,
  30    strip: ?bool = null,
  31    skip_modules: []const []const u8 = &.{},
  32
  33    // This is intended for targets that, for any reason, shouldn't be run as part of a normal test
  34    // invocation. This could be because of a slow backend, requiring a newer LLVM version, being
  35    // too niche, etc.
  36    extra_target: bool = false,
  37};
  38
  39const test_targets = blk: {
  40    // getBaselineCpuFeatures calls populateDependencies which has a O(N ^ 2) algorithm
  41    // (where N is roughly 160, which technically makes it O(1), but it adds up to a
  42    // lot of branches)
  43    @setEvalBranchQuota(60000);
  44    break :blk [_]TestTarget{
  45        // Native Targets
  46
  47        .{}, // 0 index must be all defaults
  48        .{
  49            .link_libc = true,
  50        },
  51        .{
  52            .single_threaded = true,
  53        },
  54
  55        .{
  56            .optimize_mode = .ReleaseFast,
  57        },
  58        .{
  59            .link_libc = true,
  60            .optimize_mode = .ReleaseFast,
  61        },
  62        .{
  63            .optimize_mode = .ReleaseFast,
  64            .single_threaded = true,
  65        },
  66
  67        .{
  68            .optimize_mode = .ReleaseSafe,
  69        },
  70        .{
  71            .link_libc = true,
  72            .optimize_mode = .ReleaseSafe,
  73        },
  74        .{
  75            .optimize_mode = .ReleaseSafe,
  76            .single_threaded = true,
  77        },
  78
  79        .{
  80            .optimize_mode = .ReleaseSmall,
  81        },
  82        .{
  83            .link_libc = true,
  84            .optimize_mode = .ReleaseSmall,
  85        },
  86        .{
  87            .optimize_mode = .ReleaseSmall,
  88            .single_threaded = true,
  89        },
  90
  91        .{
  92            .target = .{
  93                .ofmt = .c,
  94            },
  95            .link_libc = true,
  96        },
  97
  98        // FreeBSD Targets
  99
 100        .{
 101            .target = .{
 102                .cpu_arch = .aarch64,
 103                .os_tag = .freebsd,
 104                .abi = .none,
 105            },
 106            .link_libc = true,
 107        },
 108
 109        .{
 110            .target = .{
 111                .cpu_arch = .arm,
 112                .os_tag = .freebsd,
 113                .abi = .eabihf,
 114            },
 115            .link_libc = true,
 116        },
 117
 118        .{
 119            .target = .{
 120                .cpu_arch = .powerpc64,
 121                .os_tag = .freebsd,
 122                .abi = .none,
 123            },
 124            .link_libc = true,
 125        },
 126
 127        .{
 128            .target = .{
 129                .cpu_arch = .powerpc64le,
 130                .os_tag = .freebsd,
 131                .abi = .none,
 132            },
 133            .link_libc = true,
 134        },
 135
 136        .{
 137            .target = .{
 138                .cpu_arch = .riscv64,
 139                .os_tag = .freebsd,
 140                .abi = .none,
 141            },
 142            .link_libc = true,
 143        },
 144
 145        .{
 146            .target = .{
 147                .cpu_arch = .x86_64,
 148                .os_tag = .freebsd,
 149                .abi = .none,
 150            },
 151            .link_libc = true,
 152        },
 153
 154        // Linux Targets
 155
 156        .{
 157            .target = .{
 158                .cpu_arch = .aarch64,
 159                .os_tag = .linux,
 160                .abi = .none,
 161            },
 162        },
 163        .{
 164            .target = .{
 165                .cpu_arch = .aarch64,
 166                .os_tag = .linux,
 167                .abi = .musl,
 168            },
 169            .link_libc = true,
 170        },
 171        .{
 172            .target = .{
 173                .cpu_arch = .aarch64,
 174                .os_tag = .linux,
 175                .abi = .musl,
 176            },
 177            .linkage = .dynamic,
 178            .link_libc = true,
 179            .extra_target = true,
 180        },
 181        .{
 182            .target = .{
 183                .cpu_arch = .aarch64,
 184                .os_tag = .linux,
 185                .abi = .gnu,
 186            },
 187            .link_libc = true,
 188        },
 189
 190        .{
 191            .target = .{
 192                .cpu_arch = .aarch64,
 193                .os_tag = .linux,
 194                .abi = .none,
 195            },
 196            .use_llvm = false,
 197            .use_lld = false,
 198            .optimize_mode = .ReleaseFast,
 199            .strip = true,
 200        },
 201        .{
 202            .target = .{
 203                .cpu_arch = .aarch64,
 204                .cpu_model = .{ .explicit = &std.Target.aarch64.cpu.neoverse_n1 },
 205                .os_tag = .linux,
 206                .abi = .none,
 207            },
 208            .use_llvm = false,
 209            .use_lld = false,
 210            .optimize_mode = .ReleaseFast,
 211            .strip = true,
 212        },
 213
 214        .{
 215            .target = .{
 216                .cpu_arch = .aarch64_be,
 217                .os_tag = .linux,
 218                .abi = .none,
 219            },
 220        },
 221        .{
 222            .target = .{
 223                .cpu_arch = .aarch64_be,
 224                .os_tag = .linux,
 225                .abi = .musl,
 226            },
 227            .link_libc = true,
 228        },
 229        .{
 230            .target = .{
 231                .cpu_arch = .aarch64_be,
 232                .os_tag = .linux,
 233                .abi = .musl,
 234            },
 235            .linkage = .dynamic,
 236            .link_libc = true,
 237            .extra_target = true,
 238        },
 239        .{
 240            .target = .{
 241                .cpu_arch = .aarch64_be,
 242                .os_tag = .linux,
 243                .abi = .gnu,
 244            },
 245            .link_libc = true,
 246        },
 247
 248        .{
 249            .target = .{
 250                .cpu_arch = .arm,
 251                .os_tag = .linux,
 252                .abi = .eabi,
 253            },
 254        },
 255        .{
 256            .target = .{
 257                .cpu_arch = .arm,
 258                .os_tag = .linux,
 259                .abi = .eabihf,
 260            },
 261        },
 262        .{
 263            .target = .{
 264                .cpu_arch = .arm,
 265                .os_tag = .linux,
 266                .abi = .musleabi,
 267            },
 268            .link_libc = true,
 269        },
 270        // Crashes in weird ways when applying relocations.
 271        // .{
 272        //     .target = .{
 273        //         .cpu_arch = .arm,
 274        //         .os_tag = .linux,
 275        //         .abi = .musleabi,
 276        //     },
 277        //     .linkage = .dynamic,
 278        //     .link_libc = true,
 279        //     .extra_target = true,
 280        // },
 281        .{
 282            .target = .{
 283                .cpu_arch = .arm,
 284                .os_tag = .linux,
 285                .abi = .musleabihf,
 286            },
 287            .link_libc = true,
 288        },
 289        // Crashes in weird ways when applying relocations.
 290        // .{
 291        //     .target = .{
 292        //         .cpu_arch = .arm,
 293        //         .os_tag = .linux,
 294        //         .abi = .musleabihf,
 295        //     },
 296        //     .linkage = .dynamic,
 297        //     .link_libc = true,
 298        //     .extra_target = true,
 299        // },
 300        .{
 301            .target = .{
 302                .cpu_arch = .arm,
 303                .os_tag = .linux,
 304                .abi = .gnueabi,
 305            },
 306            .link_libc = true,
 307        },
 308        .{
 309            .target = .{
 310                .cpu_arch = .arm,
 311                .os_tag = .linux,
 312                .abi = .gnueabihf,
 313            },
 314            .link_libc = true,
 315        },
 316
 317        .{
 318            .target = .{
 319                .cpu_arch = .armeb,
 320                .os_tag = .linux,
 321                .abi = .eabi,
 322            },
 323        },
 324        .{
 325            .target = .{
 326                .cpu_arch = .armeb,
 327                .os_tag = .linux,
 328                .abi = .eabihf,
 329            },
 330        },
 331        .{
 332            .target = .{
 333                .cpu_arch = .armeb,
 334                .os_tag = .linux,
 335                .abi = .musleabi,
 336            },
 337            .link_libc = true,
 338        },
 339        // Crashes in weird ways when applying relocations.
 340        // .{
 341        //     .target = .{
 342        //         .cpu_arch = .armeb,
 343        //         .os_tag = .linux,
 344        //         .abi = .musleabi,
 345        //     },
 346        //     .linkage = .dynamic,
 347        //     .link_libc = true,
 348        //     .extra_target = true,
 349        // },
 350        .{
 351            .target = .{
 352                .cpu_arch = .armeb,
 353                .os_tag = .linux,
 354                .abi = .musleabihf,
 355            },
 356            .link_libc = true,
 357        },
 358        // Crashes in weird ways when applying relocations.
 359        // .{
 360        //     .target = .{
 361        //         .cpu_arch = .armeb,
 362        //         .os_tag = .linux,
 363        //         .abi = .musleabihf,
 364        //     },
 365        //     .linkage = .dynamic,
 366        //     .link_libc = true,
 367        //     .extra_target = true,
 368        // },
 369        .{
 370            .target = .{
 371                .cpu_arch = .armeb,
 372                .os_tag = .linux,
 373                .abi = .gnueabi,
 374            },
 375            .link_libc = true,
 376        },
 377        .{
 378            .target = .{
 379                .cpu_arch = .armeb,
 380                .os_tag = .linux,
 381                .abi = .gnueabihf,
 382            },
 383            .link_libc = true,
 384        },
 385
 386        // Similar to Thumb, we need long calls on Hexagon due to relocation range issues.
 387        .{
 388            .target = std.Target.Query.parse(.{
 389                .arch_os_abi = "hexagon-linux-none",
 390                .cpu_features = "baseline+long_calls",
 391            }) catch unreachable,
 392        },
 393        .{
 394            .target = std.Target.Query.parse(.{
 395                .arch_os_abi = "hexagon-linux-musl",
 396                .cpu_features = "baseline+long_calls",
 397            }) catch unreachable,
 398            .link_libc = true,
 399        },
 400        .{
 401            .target = std.Target.Query.parse(.{
 402                .arch_os_abi = "hexagon-linux-musl",
 403                .cpu_features = "baseline+long_calls",
 404            }) catch unreachable,
 405            .linkage = .dynamic,
 406            .link_libc = true,
 407            .extra_target = true,
 408        },
 409
 410        .{
 411            .target = .{
 412                .cpu_arch = .loongarch64,
 413                .os_tag = .linux,
 414                .abi = .none,
 415            },
 416        },
 417        .{
 418            .target = .{
 419                .cpu_arch = .loongarch64,
 420                .os_tag = .linux,
 421                .abi = .musl,
 422            },
 423            .link_libc = true,
 424        },
 425        .{
 426            .target = .{
 427                .cpu_arch = .loongarch64,
 428                .os_tag = .linux,
 429                .abi = .musl,
 430            },
 431            .linkage = .dynamic,
 432            .link_libc = true,
 433            .extra_target = true,
 434        },
 435        .{
 436            .target = .{
 437                .cpu_arch = .loongarch64,
 438                .os_tag = .linux,
 439                .abi = .gnu,
 440            },
 441            .link_libc = true,
 442        },
 443
 444        .{
 445            .target = .{
 446                .cpu_arch = .mips,
 447                .os_tag = .linux,
 448                .abi = .eabi,
 449            },
 450        },
 451        .{
 452            .target = .{
 453                .cpu_arch = .mips,
 454                .os_tag = .linux,
 455                .abi = .eabihf,
 456            },
 457        },
 458        .{
 459            .target = .{
 460                .cpu_arch = .mips,
 461                .os_tag = .linux,
 462                .abi = .musleabi,
 463            },
 464            .link_libc = true,
 465        },
 466        .{
 467            .target = .{
 468                .cpu_arch = .mips,
 469                .os_tag = .linux,
 470                .abi = .musleabi,
 471            },
 472            .linkage = .dynamic,
 473            .link_libc = true,
 474            .extra_target = true,
 475        },
 476        .{
 477            .target = .{
 478                .cpu_arch = .mips,
 479                .os_tag = .linux,
 480                .abi = .musleabihf,
 481            },
 482            .link_libc = true,
 483        },
 484        .{
 485            .target = .{
 486                .cpu_arch = .mips,
 487                .os_tag = .linux,
 488                .abi = .musleabihf,
 489            },
 490            .linkage = .dynamic,
 491            .link_libc = true,
 492            .extra_target = true,
 493        },
 494        .{
 495            .target = .{
 496                .cpu_arch = .mips,
 497                .os_tag = .linux,
 498                .abi = .gnueabi,
 499            },
 500            .link_libc = true,
 501        },
 502        .{
 503            .target = .{
 504                .cpu_arch = .mips,
 505                .os_tag = .linux,
 506                .abi = .gnueabihf,
 507            },
 508            .link_libc = true,
 509        },
 510
 511        .{
 512            .target = .{
 513                .cpu_arch = .mipsel,
 514                .os_tag = .linux,
 515                .abi = .eabi,
 516            },
 517        },
 518        .{
 519            .target = .{
 520                .cpu_arch = .mipsel,
 521                .os_tag = .linux,
 522                .abi = .eabihf,
 523            },
 524        },
 525        .{
 526            .target = .{
 527                .cpu_arch = .mipsel,
 528                .os_tag = .linux,
 529                .abi = .musleabi,
 530            },
 531            .link_libc = true,
 532        },
 533        .{
 534            .target = .{
 535                .cpu_arch = .mipsel,
 536                .os_tag = .linux,
 537                .abi = .musleabi,
 538            },
 539            .linkage = .dynamic,
 540            .link_libc = true,
 541            .extra_target = true,
 542        },
 543        .{
 544            .target = .{
 545                .cpu_arch = .mipsel,
 546                .os_tag = .linux,
 547                .abi = .musleabihf,
 548            },
 549            .link_libc = true,
 550        },
 551        .{
 552            .target = .{
 553                .cpu_arch = .mipsel,
 554                .os_tag = .linux,
 555                .abi = .musleabihf,
 556            },
 557            .linkage = .dynamic,
 558            .link_libc = true,
 559            .extra_target = true,
 560        },
 561        .{
 562            .target = .{
 563                .cpu_arch = .mipsel,
 564                .os_tag = .linux,
 565                .abi = .gnueabi,
 566            },
 567            .link_libc = true,
 568        },
 569        .{
 570            .target = .{
 571                .cpu_arch = .mipsel,
 572                .os_tag = .linux,
 573                .abi = .gnueabihf,
 574            },
 575            .link_libc = true,
 576        },
 577
 578        .{
 579            .target = .{
 580                .cpu_arch = .mips64,
 581                .os_tag = .linux,
 582                .abi = .none,
 583            },
 584        },
 585        .{
 586            .target = .{
 587                .cpu_arch = .mips64,
 588                .os_tag = .linux,
 589                .abi = .muslabi64,
 590            },
 591            .link_libc = true,
 592        },
 593        .{
 594            .target = .{
 595                .cpu_arch = .mips64,
 596                .os_tag = .linux,
 597                .abi = .muslabi64,
 598            },
 599            .linkage = .dynamic,
 600            .link_libc = true,
 601            .extra_target = true,
 602        },
 603        .{
 604            .target = .{
 605                .cpu_arch = .mips64,
 606                .os_tag = .linux,
 607                .abi = .muslabin32,
 608            },
 609            .link_libc = true,
 610            .extra_target = true,
 611        },
 612        .{
 613            .target = .{
 614                .cpu_arch = .mips64,
 615                .os_tag = .linux,
 616                .abi = .muslabin32,
 617            },
 618            .linkage = .dynamic,
 619            .link_libc = true,
 620            .extra_target = true,
 621        },
 622        .{
 623            .target = .{
 624                .cpu_arch = .mips64,
 625                .os_tag = .linux,
 626                .abi = .gnuabi64,
 627            },
 628            .link_libc = true,
 629        },
 630        .{
 631            .target = .{
 632                .cpu_arch = .mips64,
 633                .os_tag = .linux,
 634                .abi = .gnuabin32,
 635            },
 636            .link_libc = true,
 637            .extra_target = true,
 638        },
 639
 640        .{
 641            .target = .{
 642                .cpu_arch = .mips64el,
 643                .os_tag = .linux,
 644                .abi = .none,
 645            },
 646        },
 647        .{
 648            .target = .{
 649                .cpu_arch = .mips64el,
 650                .os_tag = .linux,
 651                .abi = .muslabi64,
 652            },
 653            .link_libc = true,
 654        },
 655        .{
 656            .target = .{
 657                .cpu_arch = .mips64el,
 658                .os_tag = .linux,
 659                .abi = .muslabi64,
 660            },
 661            .linkage = .dynamic,
 662            .link_libc = true,
 663            .extra_target = true,
 664        },
 665        .{
 666            .target = .{
 667                .cpu_arch = .mips64el,
 668                .os_tag = .linux,
 669                .abi = .muslabin32,
 670            },
 671            .link_libc = true,
 672            .extra_target = true,
 673        },
 674        .{
 675            .target = .{
 676                .cpu_arch = .mips64el,
 677                .os_tag = .linux,
 678                .abi = .muslabin32,
 679            },
 680            .linkage = .dynamic,
 681            .link_libc = true,
 682            .extra_target = true,
 683        },
 684        .{
 685            .target = .{
 686                .cpu_arch = .mips64el,
 687                .os_tag = .linux,
 688                .abi = .gnuabi64,
 689            },
 690            .link_libc = true,
 691        },
 692        .{
 693            .target = .{
 694                .cpu_arch = .mips64el,
 695                .os_tag = .linux,
 696                .abi = .gnuabin32,
 697            },
 698            .link_libc = true,
 699            .extra_target = true,
 700        },
 701
 702        .{
 703            .target = .{
 704                .cpu_arch = .powerpc,
 705                .os_tag = .linux,
 706                .abi = .eabi,
 707            },
 708            .extra_target = true,
 709        },
 710        .{
 711            .target = .{
 712                .cpu_arch = .powerpc,
 713                .os_tag = .linux,
 714                .abi = .eabihf,
 715            },
 716        },
 717        .{
 718            .target = .{
 719                .cpu_arch = .powerpc,
 720                .os_tag = .linux,
 721                .abi = .musleabi,
 722            },
 723            .link_libc = true,
 724            .extra_target = true,
 725        },
 726        .{
 727            .target = .{
 728                .cpu_arch = .powerpc,
 729                .os_tag = .linux,
 730                .abi = .musleabi,
 731            },
 732            .linkage = .dynamic,
 733            .link_libc = true,
 734            // https://github.com/ziglang/zig/issues/2256
 735            .skip_modules = &.{"std"},
 736            .extra_target = true,
 737        },
 738        .{
 739            .target = .{
 740                .cpu_arch = .powerpc,
 741                .os_tag = .linux,
 742                .abi = .musleabihf,
 743            },
 744            .link_libc = true,
 745        },
 746        .{
 747            .target = .{
 748                .cpu_arch = .powerpc,
 749                .os_tag = .linux,
 750                .abi = .musleabihf,
 751            },
 752            .linkage = .dynamic,
 753            .link_libc = true,
 754            // https://github.com/ziglang/zig/issues/2256
 755            .skip_modules = &.{"std"},
 756            .extra_target = true,
 757        },
 758        .{
 759            .target = .{
 760                .cpu_arch = .powerpc,
 761                .os_tag = .linux,
 762                .abi = .gnueabi,
 763            },
 764            .link_libc = true,
 765            // https://github.com/ziglang/zig/issues/2256
 766            .skip_modules = &.{"std"},
 767            .extra_target = true,
 768        },
 769        .{
 770            .target = .{
 771                .cpu_arch = .powerpc,
 772                .os_tag = .linux,
 773                .abi = .gnueabihf,
 774            },
 775            .link_libc = true,
 776            // https://github.com/ziglang/zig/issues/2256
 777            .skip_modules = &.{"std"},
 778        },
 779
 780        .{
 781            .target = .{
 782                .cpu_arch = .powerpc64,
 783                .os_tag = .linux,
 784                .abi = .none,
 785            },
 786        },
 787        .{
 788            .target = .{
 789                .cpu_arch = .powerpc64,
 790                .os_tag = .linux,
 791                .abi = .musl,
 792            },
 793            .link_libc = true,
 794        },
 795        .{
 796            .target = .{
 797                .cpu_arch = .powerpc64,
 798                .os_tag = .linux,
 799                .abi = .musl,
 800            },
 801            .linkage = .dynamic,
 802            .link_libc = true,
 803            .extra_target = true,
 804        },
 805        // glibc's build-many-glibcs.py currently only builds this target for ELFv1.
 806        // .{
 807        //     .target = .{
 808        //         .cpu_arch = .powerpc64,
 809        //         .os_tag = .linux,
 810        //         .abi = .gnu,
 811        //     },
 812        //     .link_libc = true,
 813        // },
 814        .{
 815            .target = .{
 816                .cpu_arch = .powerpc64le,
 817                .os_tag = .linux,
 818                .abi = .none,
 819            },
 820        },
 821        .{
 822            .target = .{
 823                .cpu_arch = .powerpc64le,
 824                .os_tag = .linux,
 825                .abi = .musl,
 826            },
 827            .link_libc = true,
 828        },
 829        .{
 830            .target = .{
 831                .cpu_arch = .powerpc64le,
 832                .os_tag = .linux,
 833                .abi = .musl,
 834            },
 835            .linkage = .dynamic,
 836            .link_libc = true,
 837            .extra_target = true,
 838        },
 839        .{
 840            .target = .{
 841                .cpu_arch = .powerpc64le,
 842                .os_tag = .linux,
 843                .abi = .gnu,
 844            },
 845            .link_libc = true,
 846        },
 847
 848        .{
 849            .target = .{
 850                .cpu_arch = .riscv32,
 851                .os_tag = .linux,
 852                .abi = .none,
 853            },
 854        },
 855        .{
 856            .target = std.Target.Query.parse(.{
 857                .arch_os_abi = "riscv32-linux-none",
 858                .cpu_features = "baseline-d-f",
 859            }) catch unreachable,
 860            .extra_target = true,
 861        },
 862        .{
 863            .target = .{
 864                .cpu_arch = .riscv32,
 865                .os_tag = .linux,
 866                .abi = .musl,
 867            },
 868            .link_libc = true,
 869        },
 870        .{
 871            .target = .{
 872                .cpu_arch = .riscv32,
 873                .os_tag = .linux,
 874                .abi = .musl,
 875            },
 876            .linkage = .dynamic,
 877            .link_libc = true,
 878            .extra_target = true,
 879        },
 880        .{
 881            .target = std.Target.Query.parse(.{
 882                .arch_os_abi = "riscv32-linux-musl",
 883                .cpu_features = "baseline-d-f",
 884            }) catch unreachable,
 885            .link_libc = true,
 886            .extra_target = true,
 887        },
 888        .{
 889            .target = .{
 890                .cpu_arch = .riscv32,
 891                .os_tag = .linux,
 892                .abi = .gnu,
 893            },
 894            .link_libc = true,
 895        },
 896
 897        // TODO implement codegen airFieldParentPtr
 898        // TODO implement airMemmove for riscv64
 899        //.{
 900        //    .target = std.Target.Query.parse(.{
 901        //        .arch_os_abi = "riscv64-linux-none",
 902        //        .cpu_features = "baseline+v+zbb",
 903        //    }) catch unreachable,
 904        //    .use_llvm = false,
 905        //    .use_lld = false,
 906        //},
 907        .{
 908            .target = .{
 909                .cpu_arch = .riscv64,
 910                .os_tag = .linux,
 911                .abi = .none,
 912            },
 913        },
 914        .{
 915            .target = std.Target.Query.parse(.{
 916                .arch_os_abi = "riscv64-linux-none",
 917                .cpu_features = "baseline-d-f",
 918            }) catch unreachable,
 919            .extra_target = true,
 920        },
 921        .{
 922            .target = .{
 923                .cpu_arch = .riscv64,
 924                .os_tag = .linux,
 925                .abi = .musl,
 926            },
 927            .link_libc = true,
 928        },
 929        .{
 930            .target = .{
 931                .cpu_arch = .riscv64,
 932                .os_tag = .linux,
 933                .abi = .musl,
 934            },
 935            .linkage = .dynamic,
 936            .link_libc = true,
 937            .extra_target = true,
 938        },
 939        .{
 940            .target = std.Target.Query.parse(.{
 941                .arch_os_abi = "riscv64-linux-musl",
 942                .cpu_features = "baseline-d-f",
 943            }) catch unreachable,
 944            .link_libc = true,
 945            .extra_target = true,
 946        },
 947        .{
 948            .target = .{
 949                .cpu_arch = .riscv64,
 950                .os_tag = .linux,
 951                .abi = .gnu,
 952            },
 953            .link_libc = true,
 954        },
 955
 956        .{
 957            .target = .{
 958                .cpu_arch = .s390x,
 959                .os_tag = .linux,
 960                .abi = .none,
 961            },
 962        },
 963        .{
 964            .target = .{
 965                .cpu_arch = .s390x,
 966                .os_tag = .linux,
 967                .abi = .musl,
 968            },
 969            .link_libc = true,
 970        },
 971        // Currently hangs in qemu-s390x.
 972        // .{
 973        //     .target = .{
 974        //         .cpu_arch = .s390x,
 975        //         .os_tag = .linux,
 976        //         .abi = .musl,
 977        //     },
 978        //     .linkage = .dynamic,
 979        //     .link_libc = true,
 980        //     .extra_target = true,
 981        // },
 982        .{
 983            .target = .{
 984                .cpu_arch = .s390x,
 985                .os_tag = .linux,
 986                .abi = .gnu,
 987            },
 988            .link_libc = true,
 989        },
 990
 991        // Calls are normally lowered to branch instructions that only support +/- 16 MB range when
 992        // targeting Thumb. This easily becomes insufficient for our test binaries, so use long
 993        // calls to avoid out-of-range relocations.
 994        .{
 995            .target = std.Target.Query.parse(.{
 996                .arch_os_abi = "thumb-linux-eabi",
 997                .cpu_features = "baseline+long_calls",
 998            }) catch unreachable,
 999            .pic = false, // Long calls don't work with PIC.
1000        },
1001        .{
1002            .target = std.Target.Query.parse(.{
1003                .arch_os_abi = "thumb-linux-eabihf",
1004                .cpu_features = "baseline+long_calls",
1005            }) catch unreachable,
1006            .pic = false, // Long calls don't work with PIC.
1007        },
1008        .{
1009            .target = std.Target.Query.parse(.{
1010                .arch_os_abi = "thumb-linux-musleabi",
1011                .cpu_features = "baseline+long_calls",
1012            }) catch unreachable,
1013            .link_libc = true,
1014            .pic = false, // Long calls don't work with PIC.
1015        },
1016        .{
1017            .target = std.Target.Query.parse(.{
1018                .arch_os_abi = "thumb-linux-musleabihf",
1019                .cpu_features = "baseline+long_calls",
1020            }) catch unreachable,
1021            .link_libc = true,
1022            .pic = false, // Long calls don't work with PIC.
1023        },
1024
1025        .{
1026            .target = std.Target.Query.parse(.{
1027                .arch_os_abi = "thumbeb-linux-eabi",
1028                .cpu_features = "baseline+long_calls",
1029            }) catch unreachable,
1030            .pic = false, // Long calls don't work with PIC.
1031        },
1032        .{
1033            .target = std.Target.Query.parse(.{
1034                .arch_os_abi = "thumbeb-linux-eabihf",
1035                .cpu_features = "baseline+long_calls",
1036            }) catch unreachable,
1037            .pic = false, // Long calls don't work with PIC.
1038        },
1039        .{
1040            .target = std.Target.Query.parse(.{
1041                .arch_os_abi = "thumbeb-linux-musleabi",
1042                .cpu_features = "baseline+long_calls",
1043            }) catch unreachable,
1044            .link_libc = true,
1045            .pic = false, // Long calls don't work with PIC.
1046        },
1047        .{
1048            .target = std.Target.Query.parse(.{
1049                .arch_os_abi = "thumbeb-linux-musleabihf",
1050                .cpu_features = "baseline+long_calls",
1051            }) catch unreachable,
1052            .link_libc = true,
1053            .pic = false, // Long calls don't work with PIC.
1054        },
1055
1056        .{
1057            .target = .{
1058                .cpu_arch = .x86,
1059                .os_tag = .linux,
1060                .abi = .none,
1061            },
1062        },
1063        .{
1064            .target = .{
1065                .cpu_arch = .x86,
1066                .os_tag = .linux,
1067                .abi = .musl,
1068            },
1069            .link_libc = true,
1070        },
1071        .{
1072            .target = .{
1073                .cpu_arch = .x86,
1074                .os_tag = .linux,
1075                .abi = .musl,
1076            },
1077            .linkage = .dynamic,
1078            .link_libc = true,
1079            .extra_target = true,
1080        },
1081        .{
1082            .target = .{
1083                .cpu_arch = .x86,
1084                .os_tag = .linux,
1085                .abi = .gnu,
1086            },
1087            .link_libc = true,
1088        },
1089
1090        .{
1091            .target = .{
1092                .cpu_arch = .x86_64,
1093                .os_tag = .linux,
1094                .abi = .none,
1095            },
1096        },
1097        .{
1098            .target = .{
1099                .cpu_arch = .x86_64,
1100                .cpu_model = .{ .explicit = &std.Target.x86.cpu.x86_64_v2 },
1101                .os_tag = .linux,
1102                .abi = .none,
1103            },
1104            .pic = true,
1105        },
1106        .{
1107            .target = .{
1108                .cpu_arch = .x86_64,
1109                .cpu_model = .{ .explicit = &std.Target.x86.cpu.x86_64_v3 },
1110                .os_tag = .linux,
1111                .abi = .none,
1112            },
1113            .strip = true,
1114        },
1115        .{
1116            .target = .{
1117                .cpu_arch = .x86_64,
1118                .os_tag = .linux,
1119                .abi = .none,
1120            },
1121            .use_llvm = true,
1122            .use_lld = true,
1123        },
1124        .{
1125            .target = .{
1126                .cpu_arch = .x86_64,
1127                .os_tag = .linux,
1128                .abi = .gnu,
1129            },
1130            .link_libc = true,
1131        },
1132        .{
1133            .target = .{
1134                .cpu_arch = .x86_64,
1135                .os_tag = .linux,
1136                .abi = .gnux32,
1137            },
1138            .link_libc = true,
1139            .extra_target = true,
1140        },
1141        .{
1142            .target = .{
1143                .cpu_arch = .x86_64,
1144                .os_tag = .linux,
1145                .abi = .musl,
1146            },
1147            .link_libc = true,
1148        },
1149        .{
1150            .target = .{
1151                .cpu_arch = .x86_64,
1152                .os_tag = .linux,
1153                .abi = .musl,
1154            },
1155            .linkage = .dynamic,
1156            .link_libc = true,
1157            .extra_target = true,
1158        },
1159        .{
1160            .target = .{
1161                .cpu_arch = .x86_64,
1162                .os_tag = .linux,
1163                .abi = .muslx32,
1164            },
1165            .link_libc = true,
1166            .extra_target = true,
1167        },
1168        .{
1169            .target = .{
1170                .cpu_arch = .x86_64,
1171                .os_tag = .linux,
1172                .abi = .muslx32,
1173            },
1174            .linkage = .dynamic,
1175            .link_libc = true,
1176            .extra_target = true,
1177        },
1178        .{
1179            .target = .{
1180                .cpu_arch = .x86_64,
1181                .os_tag = .linux,
1182                .abi = .musl,
1183            },
1184            .link_libc = true,
1185            .use_llvm = true,
1186            .use_lld = false,
1187        },
1188
1189        // Darwin Targets
1190
1191        .{
1192            .target = .{
1193                .cpu_arch = .aarch64,
1194                .os_tag = .maccatalyst,
1195                .abi = .none,
1196            },
1197        },
1198
1199        .{
1200            .target = .{
1201                .cpu_arch = .aarch64,
1202                .os_tag = .macos,
1203                .abi = .none,
1204            },
1205        },
1206
1207        .{
1208            .target = .{
1209                .cpu_arch = .aarch64,
1210                .os_tag = .macos,
1211                .abi = .none,
1212            },
1213            .use_llvm = false,
1214            .use_lld = false,
1215            .optimize_mode = .ReleaseFast,
1216            .strip = true,
1217        },
1218
1219        .{
1220            .target = .{
1221                .cpu_arch = .x86_64,
1222                .os_tag = .maccatalyst,
1223                .abi = .none,
1224            },
1225        },
1226
1227        .{
1228            .target = .{
1229                .cpu_arch = .x86_64,
1230                .os_tag = .macos,
1231                .abi = .none,
1232            },
1233            .use_llvm = false,
1234        },
1235        .{
1236            .target = .{
1237                .cpu_arch = .x86_64,
1238                .os_tag = .macos,
1239                .abi = .none,
1240            },
1241        },
1242
1243        // NetBSD Targets
1244
1245        .{
1246            .target = .{
1247                .cpu_arch = .aarch64,
1248                .os_tag = .netbsd,
1249                .abi = .none,
1250            },
1251            .link_libc = true,
1252        },
1253
1254        .{
1255            .target = .{
1256                .cpu_arch = .aarch64_be,
1257                .os_tag = .netbsd,
1258                .abi = .none,
1259            },
1260            .link_libc = true,
1261        },
1262
1263        .{
1264            .target = .{
1265                .cpu_arch = .arm,
1266                .os_tag = .netbsd,
1267                .abi = .eabi,
1268            },
1269            .link_libc = true,
1270        },
1271        .{
1272            .target = .{
1273                .cpu_arch = .arm,
1274                .os_tag = .netbsd,
1275                .abi = .eabihf,
1276            },
1277            .link_libc = true,
1278        },
1279
1280        .{
1281            .target = .{
1282                .cpu_arch = .armeb,
1283                .os_tag = .netbsd,
1284                .abi = .eabi,
1285            },
1286            .link_libc = true,
1287        },
1288        .{
1289            .target = .{
1290                .cpu_arch = .armeb,
1291                .os_tag = .netbsd,
1292                .abi = .eabihf,
1293            },
1294            .link_libc = true,
1295        },
1296
1297        .{
1298            .target = .{
1299                .cpu_arch = .mips,
1300                .os_tag = .netbsd,
1301                .abi = .eabi,
1302            },
1303            .link_libc = true,
1304        },
1305        .{
1306            .target = .{
1307                .cpu_arch = .mips,
1308                .os_tag = .netbsd,
1309                .abi = .eabihf,
1310            },
1311            .link_libc = true,
1312        },
1313
1314        .{
1315            .target = .{
1316                .cpu_arch = .mipsel,
1317                .os_tag = .netbsd,
1318                .abi = .eabi,
1319            },
1320            .link_libc = true,
1321        },
1322        .{
1323            .target = .{
1324                .cpu_arch = .mipsel,
1325                .os_tag = .netbsd,
1326                .abi = .eabihf,
1327            },
1328            .link_libc = true,
1329        },
1330
1331        .{
1332            .target = .{
1333                .cpu_arch = .powerpc,
1334                .os_tag = .netbsd,
1335                .abi = .eabi,
1336            },
1337            .link_libc = true,
1338            .extra_target = true,
1339        },
1340        .{
1341            .target = .{
1342                .cpu_arch = .powerpc,
1343                .os_tag = .netbsd,
1344                .abi = .eabihf,
1345            },
1346            .link_libc = true,
1347        },
1348
1349        .{
1350            .target = .{
1351                .cpu_arch = .x86,
1352                .os_tag = .netbsd,
1353                .abi = .none,
1354            },
1355            .link_libc = true,
1356        },
1357
1358        .{
1359            .target = .{
1360                .cpu_arch = .x86_64,
1361                .os_tag = .netbsd,
1362                .abi = .none,
1363            },
1364            .link_libc = true,
1365        },
1366
1367        // SPIR-V Targets
1368
1369        // Disabled due to no active maintainer (feel free to fix the failures
1370        // and then re-enable at any time). The failures occur due to changing AIR
1371        // from the frontend, and backend being incomplete.
1372        //.{
1373        //    .target = std.Target.Query.parse(.{
1374        //        .arch_os_abi = "spirv64-vulkan",
1375        //        .cpu_features = "vulkan_v1_2+float16+float64",
1376        //    }) catch unreachable,
1377        //    .use_llvm = false,
1378        //    .use_lld = false,
1379        //    .skip_modules = &.{ "c-import", "zigc", "std" },
1380        //},
1381
1382        // WASI Targets
1383
1384        // Disabled due to no active maintainer (feel free to fix the failures
1385        // and then re-enable at any time). The failures occur due to backend
1386        // miscompilation of different AIR from the frontend.
1387        //.{
1388        //    .target = .{
1389        //        .cpu_arch = .wasm32,
1390        //        .os_tag = .wasi,
1391        //        .abi = .none,
1392        //    },
1393        //    .use_llvm = false,
1394        //    .use_lld = false,
1395        //},
1396        .{
1397            .target = .{
1398                .cpu_arch = .wasm32,
1399                .os_tag = .wasi,
1400                .abi = .none,
1401            },
1402        },
1403        .{
1404            .target = .{
1405                .cpu_arch = .wasm32,
1406                .os_tag = .wasi,
1407                .abi = .musl,
1408            },
1409            .link_libc = true,
1410        },
1411
1412        // Windows Targets
1413
1414        .{
1415            .target = .{
1416                .cpu_arch = .aarch64,
1417                .os_tag = .windows,
1418                .abi = .msvc,
1419            },
1420        },
1421        .{
1422            .target = .{
1423                .cpu_arch = .aarch64,
1424                .os_tag = .windows,
1425                .abi = .msvc,
1426            },
1427            .link_libc = true,
1428        },
1429        .{
1430            .target = .{
1431                .cpu_arch = .aarch64,
1432                .os_tag = .windows,
1433                .abi = .gnu,
1434            },
1435        },
1436        .{
1437            .target = .{
1438                .cpu_arch = .aarch64,
1439                .os_tag = .windows,
1440                .abi = .gnu,
1441            },
1442            .link_libc = true,
1443        },
1444
1445        .{
1446            .target = .{
1447                .cpu_arch = .thumb,
1448                .os_tag = .windows,
1449                .abi = .msvc,
1450            },
1451        },
1452        .{
1453            .target = .{
1454                .cpu_arch = .thumb,
1455                .os_tag = .windows,
1456                .abi = .msvc,
1457            },
1458            .link_libc = true,
1459        },
1460        // https://github.com/ziglang/zig/issues/24016
1461        // .{
1462        //     .target = .{
1463        //         .cpu_arch = .thumb,
1464        //         .os_tag = .windows,
1465        //         .abi = .gnu,
1466        //     },
1467        // },
1468        // .{
1469        //     .target = .{
1470        //         .cpu_arch = .thumb,
1471        //         .os_tag = .windows,
1472        //         .abi = .gnu,
1473        //     },
1474        //     .link_libc = true,
1475        // },
1476
1477        .{
1478            .target = .{
1479                .cpu_arch = .x86,
1480                .os_tag = .windows,
1481                .abi = .msvc,
1482            },
1483        },
1484        .{
1485            .target = .{
1486                .cpu_arch = .x86,
1487                .os_tag = .windows,
1488                .abi = .msvc,
1489            },
1490            .link_libc = true,
1491        },
1492        .{
1493            .target = .{
1494                .cpu_arch = .x86,
1495                .os_tag = .windows,
1496                .abi = .gnu,
1497            },
1498        },
1499        .{
1500            .target = .{
1501                .cpu_arch = .x86,
1502                .os_tag = .windows,
1503                .abi = .gnu,
1504            },
1505            .link_libc = true,
1506        },
1507
1508        .{
1509            .target = .{
1510                .cpu_arch = .x86_64,
1511                .os_tag = .windows,
1512                .abi = .msvc,
1513            },
1514            .use_llvm = false,
1515            .use_lld = false,
1516        },
1517        .{
1518            .target = .{
1519                .cpu_arch = .x86_64,
1520                .os_tag = .windows,
1521                .abi = .msvc,
1522            },
1523        },
1524        .{
1525            .target = .{
1526                .cpu_arch = .x86_64,
1527                .os_tag = .windows,
1528                .abi = .msvc,
1529            },
1530            .link_libc = true,
1531        },
1532        .{
1533            .target = .{
1534                .cpu_arch = .x86_64,
1535                .os_tag = .windows,
1536                .abi = .gnu,
1537            },
1538            .use_llvm = false,
1539            .use_lld = false,
1540        },
1541        .{
1542            .target = .{
1543                .cpu_arch = .x86_64,
1544                .os_tag = .windows,
1545                .abi = .gnu,
1546            },
1547        },
1548        .{
1549            .target = .{
1550                .cpu_arch = .x86_64,
1551                .os_tag = .windows,
1552                .abi = .gnu,
1553            },
1554            .link_libc = true,
1555        },
1556    };
1557};
1558
1559const CAbiTarget = struct {
1560    target: std.Target.Query = .{},
1561    use_llvm: ?bool = null,
1562    use_lld: ?bool = null,
1563    pic: ?bool = null,
1564    strip: ?bool = null,
1565    c_defines: []const []const u8 = &.{},
1566};
1567
1568const c_abi_targets = blk: {
1569    @setEvalBranchQuota(30000);
1570    break :blk [_]CAbiTarget{
1571        // Native Targets
1572
1573        .{
1574            .use_llvm = true,
1575        },
1576
1577        // Linux Targets
1578
1579        .{
1580            .target = .{
1581                .cpu_arch = .aarch64,
1582                .os_tag = .linux,
1583                .abi = .musl,
1584            },
1585        },
1586
1587        .{
1588            .target = .{
1589                .cpu_arch = .aarch64_be,
1590                .os_tag = .linux,
1591                .abi = .musl,
1592            },
1593        },
1594
1595        .{
1596            .target = .{
1597                .cpu_arch = .arm,
1598                .os_tag = .linux,
1599                .abi = .musleabi,
1600            },
1601        },
1602        .{
1603            .target = .{
1604                .cpu_arch = .arm,
1605                .os_tag = .linux,
1606                .abi = .musleabihf,
1607            },
1608        },
1609
1610        .{
1611            .target = .{
1612                .cpu_arch = .armeb,
1613                .os_tag = .linux,
1614                .abi = .musleabi,
1615            },
1616        },
1617        .{
1618            .target = .{
1619                .cpu_arch = .armeb,
1620                .os_tag = .linux,
1621                .abi = .musleabihf,
1622            },
1623        },
1624
1625        .{
1626            .target = .{
1627                .cpu_arch = .hexagon,
1628                .os_tag = .linux,
1629                .abi = .musl,
1630            },
1631        },
1632
1633        .{
1634            .target = .{
1635                .cpu_arch = .loongarch64,
1636                .os_tag = .linux,
1637                .abi = .musl,
1638            },
1639        },
1640
1641        .{
1642            .target = .{
1643                .cpu_arch = .mips,
1644                .os_tag = .linux,
1645                .abi = .musleabi,
1646            },
1647        },
1648        .{
1649            .target = .{
1650                .cpu_arch = .mips,
1651                .os_tag = .linux,
1652                .abi = .musleabihf,
1653            },
1654        },
1655
1656        .{
1657            .target = .{
1658                .cpu_arch = .mipsel,
1659                .os_tag = .linux,
1660                .abi = .musleabi,
1661            },
1662        },
1663        .{
1664            .target = .{
1665                .cpu_arch = .mipsel,
1666                .os_tag = .linux,
1667                .abi = .musleabihf,
1668            },
1669        },
1670
1671        .{
1672            .target = .{
1673                .cpu_arch = .mips64,
1674                .os_tag = .linux,
1675                .abi = .muslabi64,
1676            },
1677        },
1678        .{
1679            .target = .{
1680                .cpu_arch = .mips64,
1681                .os_tag = .linux,
1682                .abi = .muslabin32,
1683            },
1684        },
1685
1686        .{
1687            .target = .{
1688                .cpu_arch = .mips64el,
1689                .os_tag = .linux,
1690                .abi = .muslabi64,
1691            },
1692        },
1693        .{
1694            .target = .{
1695                .cpu_arch = .mips64el,
1696                .os_tag = .linux,
1697                .abi = .muslabin32,
1698            },
1699        },
1700
1701        .{
1702            .target = .{
1703                .cpu_arch = .powerpc,
1704                .os_tag = .linux,
1705                .abi = .musleabi,
1706            },
1707        },
1708        .{
1709            .target = .{
1710                .cpu_arch = .powerpc,
1711                .os_tag = .linux,
1712                .abi = .musleabihf,
1713            },
1714        },
1715
1716        .{
1717            .target = .{
1718                .cpu_arch = .powerpc64,
1719                .os_tag = .linux,
1720                .abi = .musl,
1721            },
1722        },
1723        .{
1724            .target = .{
1725                .cpu_arch = .powerpc64le,
1726                .os_tag = .linux,
1727                .abi = .musl,
1728            },
1729        },
1730
1731        .{
1732            .target = std.Target.Query.parse(.{
1733                .arch_os_abi = "riscv32-linux-musl",
1734                .cpu_features = "baseline-d-f",
1735            }) catch unreachable,
1736        },
1737        .{
1738            .target = .{
1739                .cpu_arch = .riscv32,
1740                .os_tag = .linux,
1741                .abi = .musl,
1742            },
1743        },
1744
1745        .{
1746            .target = std.Target.Query.parse(.{
1747                .arch_os_abi = "riscv64-linux-musl",
1748                .cpu_features = "baseline-d-f",
1749            }) catch unreachable,
1750        },
1751        .{
1752            .target = .{
1753                .cpu_arch = .riscv64,
1754                .os_tag = .linux,
1755                .abi = .musl,
1756            },
1757        },
1758
1759        .{
1760            .target = .{
1761                .cpu_arch = .s390x,
1762                .os_tag = .linux,
1763                .abi = .musl,
1764            },
1765        },
1766
1767        .{
1768            .target = std.Target.Query.parse(.{
1769                .arch_os_abi = "thumb-linux-musleabi",
1770                .cpu_features = "baseline+long_calls",
1771            }) catch unreachable,
1772            .pic = false, // Long calls don't work with PIC.
1773        },
1774        .{
1775            .target = std.Target.Query.parse(.{
1776                .arch_os_abi = "thumb-linux-musleabihf",
1777                .cpu_features = "baseline+long_calls",
1778            }) catch unreachable,
1779            .pic = false, // Long calls don't work with PIC.
1780        },
1781
1782        .{
1783            .target = std.Target.Query.parse(.{
1784                .arch_os_abi = "thumbeb-linux-musleabi",
1785                .cpu_features = "baseline+long_calls",
1786            }) catch unreachable,
1787            .pic = false, // Long calls don't work with PIC.
1788        },
1789        .{
1790            .target = std.Target.Query.parse(.{
1791                .arch_os_abi = "thumbeb-linux-musleabihf",
1792                .cpu_features = "baseline+long_calls",
1793            }) catch unreachable,
1794            .pic = false, // Long calls don't work with PIC.
1795        },
1796
1797        .{
1798            .target = .{
1799                .cpu_arch = .x86,
1800                .os_tag = .linux,
1801                .abi = .musl,
1802            },
1803        },
1804
1805        .{
1806            .target = .{
1807                .cpu_arch = .x86_64,
1808                .os_tag = .linux,
1809                .abi = .musl,
1810            },
1811            .use_llvm = false,
1812            .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"},
1813        },
1814        .{
1815            .target = .{
1816                .cpu_arch = .x86_64,
1817                .cpu_model = .{ .explicit = &std.Target.x86.cpu.x86_64_v2 },
1818                .os_tag = .linux,
1819                .abi = .musl,
1820            },
1821            .use_llvm = false,
1822            .strip = true,
1823            .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"},
1824        },
1825        .{
1826            .target = .{
1827                .cpu_arch = .x86_64,
1828                .cpu_model = .{ .explicit = &std.Target.x86.cpu.x86_64_v3 },
1829                .os_tag = .linux,
1830                .abi = .musl,
1831            },
1832            .use_llvm = false,
1833            .pic = true,
1834            .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"},
1835        },
1836        .{
1837            .target = .{
1838                .cpu_arch = .x86_64,
1839                .os_tag = .linux,
1840                .abi = .musl,
1841            },
1842            .use_llvm = true,
1843        },
1844        .{
1845            .target = .{
1846                .cpu_arch = .x86_64,
1847                .os_tag = .linux,
1848                .abi = .muslx32,
1849            },
1850        },
1851
1852        // WASI Targets
1853
1854        .{
1855            .target = .{
1856                .cpu_arch = .wasm32,
1857                .os_tag = .wasi,
1858                .abi = .musl,
1859            },
1860        },
1861
1862        // Windows Targets
1863
1864        .{
1865            .target = .{
1866                .cpu_arch = .x86,
1867                .os_tag = .windows,
1868                .abi = .gnu,
1869            },
1870        },
1871        .{
1872            .target = .{
1873                .cpu_arch = .x86_64,
1874                .os_tag = .windows,
1875                .abi = .gnu,
1876            },
1877        },
1878    };
1879};
1880
1881/// For stack trace tests, we only test native, because external executors are pretty unreliable at
1882/// stack tracing. However, if there's a 32-bit equivalent target which the host can trivially run,
1883/// we may as well at least test that!
1884fn nativeAndCompatible32bit(b: *std.Build, skip_non_native: bool) []const std.Build.ResolvedTarget {
1885    const host = b.graph.host.result;
1886    const only_native = (&b.graph.host)[0..1];
1887    if (skip_non_native) return only_native;
1888    const arch32: std.Target.Cpu.Arch = switch (host.os.tag) {
1889        .windows => switch (host.cpu.arch) {
1890            .x86_64 => .x86,
1891            .aarch64 => .thumb,
1892            .aarch64_be => .thumbeb,
1893            else => return only_native,
1894        },
1895        .freebsd => switch (host.cpu.arch) {
1896            .aarch64 => .arm,
1897            .aarch64_be => .armeb,
1898            else => return only_native,
1899        },
1900        .linux, .netbsd => switch (host.cpu.arch) {
1901            .x86_64 => .x86,
1902            .aarch64 => .arm,
1903            .aarch64_be => .armeb,
1904            else => return only_native,
1905        },
1906        else => return only_native,
1907    };
1908    return b.graph.arena.dupe(std.Build.ResolvedTarget, &.{
1909        b.graph.host,
1910        b.resolveTargetQuery(.{ .cpu_arch = arch32, .os_tag = host.os.tag }),
1911    }) catch @panic("OOM");
1912}
1913
1914pub fn addStackTraceTests(
1915    b: *std.Build,
1916    test_filters: []const []const u8,
1917    skip_non_native: bool,
1918) *Step {
1919    const convert_exe = b.addExecutable(.{
1920        .name = "convert-stack-trace",
1921        .root_module = b.createModule(.{
1922            .root_source_file = b.path("test/src/convert-stack-trace.zig"),
1923            .target = b.graph.host,
1924            .optimize = .Debug,
1925        }),
1926    });
1927
1928    const cases = b.allocator.create(StackTracesContext) catch @panic("OOM");
1929
1930    cases.* = .{
1931        .b = b,
1932        .step = b.step("test-stack-traces", "Run the stack trace tests"),
1933        .test_filters = test_filters,
1934        .targets = nativeAndCompatible32bit(b, skip_non_native),
1935        .convert_exe = convert_exe,
1936    };
1937
1938    stack_traces.addCases(cases);
1939
1940    return cases.step;
1941}
1942
1943pub fn addErrorTraceTests(
1944    b: *std.Build,
1945    test_filters: []const []const u8,
1946    optimize_modes: []const OptimizeMode,
1947    skip_non_native: bool,
1948) *Step {
1949    const convert_exe = b.addExecutable(.{
1950        .name = "convert-stack-trace",
1951        .root_module = b.createModule(.{
1952            .root_source_file = b.path("test/src/convert-stack-trace.zig"),
1953            .target = b.graph.host,
1954            .optimize = .Debug,
1955        }),
1956    });
1957
1958    const cases = b.allocator.create(ErrorTracesContext) catch @panic("OOM");
1959    cases.* = .{
1960        .b = b,
1961        .step = b.step("test-error-traces", "Run the error trace tests"),
1962        .test_filters = test_filters,
1963        .targets = nativeAndCompatible32bit(b, skip_non_native),
1964        .optimize_modes = optimize_modes,
1965        .convert_exe = convert_exe,
1966    };
1967
1968    error_traces.addCases(cases);
1969
1970    return cases.step;
1971}
1972
1973fn compilerHasPackageManager(b: *std.Build) bool {
1974    // We can only use dependencies if the compiler was built with support for package management.
1975    // (zig2 doesn't support it, but we still need to construct a build graph to build stage3.)
1976    return b.available_deps.len != 0;
1977}
1978
1979pub fn addStandaloneTests(
1980    b: *std.Build,
1981    optimize_modes: []const OptimizeMode,
1982    enable_macos_sdk: bool,
1983    enable_ios_sdk: bool,
1984    enable_symlinks_windows: bool,
1985) *Step {
1986    const step = b.step("test-standalone", "Run the standalone tests");
1987    if (compilerHasPackageManager(b)) {
1988        const test_cases_dep_name = "standalone_test_cases";
1989        const test_cases_dep = b.dependency(test_cases_dep_name, .{
1990            .enable_ios_sdk = enable_ios_sdk,
1991            .enable_macos_sdk = enable_macos_sdk,
1992            .enable_symlinks_windows = enable_symlinks_windows,
1993            .simple_skip_debug = mem.indexOfScalar(OptimizeMode, optimize_modes, .Debug) == null,
1994            .simple_skip_release_safe = mem.indexOfScalar(OptimizeMode, optimize_modes, .ReleaseSafe) == null,
1995            .simple_skip_release_fast = mem.indexOfScalar(OptimizeMode, optimize_modes, .ReleaseFast) == null,
1996            .simple_skip_release_small = mem.indexOfScalar(OptimizeMode, optimize_modes, .ReleaseSmall) == null,
1997        });
1998        const test_cases_dep_step = test_cases_dep.builder.default_step;
1999        test_cases_dep_step.name = b.dupe(test_cases_dep_name);
2000        step.dependOn(test_cases_dep.builder.default_step);
2001    }
2002    return step;
2003}
2004
2005pub fn addLinkTests(
2006    b: *std.Build,
2007    enable_macos_sdk: bool,
2008    enable_ios_sdk: bool,
2009    enable_symlinks_windows: bool,
2010) *Step {
2011    const step = b.step("test-link", "Run the linker tests");
2012    if (compilerHasPackageManager(b)) {
2013        const test_cases_dep_name = "link_test_cases";
2014        const test_cases_dep = b.dependency(test_cases_dep_name, .{
2015            .enable_ios_sdk = enable_ios_sdk,
2016            .enable_macos_sdk = enable_macos_sdk,
2017            .enable_symlinks_windows = enable_symlinks_windows,
2018        });
2019        const test_cases_dep_step = test_cases_dep.builder.default_step;
2020        test_cases_dep_step.name = b.dupe(test_cases_dep_name);
2021        step.dependOn(test_cases_dep.builder.default_step);
2022    }
2023    return step;
2024}
2025
2026pub fn addCliTests(b: *std.Build) *Step {
2027    const step = b.step("test-cli", "Test the command line interface");
2028    const s = std.fs.path.sep_str;
2029
2030    {
2031        // Test `zig init`.
2032        const tmp_path = b.makeTempPath();
2033        const init_exe = b.addSystemCommand(&.{ b.graph.zig_exe, "init" });
2034        init_exe.setCwd(.{ .cwd_relative = tmp_path });
2035        init_exe.setName("zig init");
2036        init_exe.expectStdOutEqual("");
2037        init_exe.expectStdErrEqual("info: created build.zig\n" ++
2038            "info: created build.zig.zon\n" ++
2039            "info: created src" ++ s ++ "main.zig\n" ++
2040            "info: created src" ++ s ++ "root.zig\n" ++
2041            "info: see `zig build --help` for a menu of options\n");
2042
2043        // Test missing output path.
2044        const bad_out_arg = "-femit-bin=does" ++ s ++ "not" ++ s ++ "exist" ++ s ++ "foo.exe";
2045        const ok_src_arg = "src" ++ s ++ "main.zig";
2046        const expected = "error: unable to open output directory 'does" ++ s ++ "not" ++ s ++ "exist': FileNotFound\n";
2047        const run_bad = b.addSystemCommand(&.{ b.graph.zig_exe, "build-exe", ok_src_arg, bad_out_arg });
2048        run_bad.setName("zig build-exe error message for bad -femit-bin arg");
2049        run_bad.expectExitCode(1);
2050        run_bad.expectStdErrEqual(expected);
2051        run_bad.expectStdOutEqual("");
2052        run_bad.step.dependOn(&init_exe.step);
2053
2054        const run_test = b.addSystemCommand(&.{ b.graph.zig_exe, "build", "test" });
2055        run_test.setCwd(.{ .cwd_relative = tmp_path });
2056        run_test.setName("zig build test");
2057        run_test.expectStdOutEqual("");
2058        run_test.step.dependOn(&init_exe.step);
2059
2060        const run_run = b.addSystemCommand(&.{ b.graph.zig_exe, "build", "run" });
2061        run_run.setCwd(.{ .cwd_relative = tmp_path });
2062        run_run.setName("zig build run");
2063        run_run.expectStdOutEqual("Run `zig build test` to run the tests.\n");
2064        run_run.expectStdErrEqual("All your codebase are belong to us.\n");
2065        run_run.step.dependOn(&init_exe.step);
2066
2067        const cleanup = b.addRemoveDirTree(.{ .cwd_relative = tmp_path });
2068        cleanup.step.dependOn(&run_test.step);
2069        cleanup.step.dependOn(&run_run.step);
2070        cleanup.step.dependOn(&run_bad.step);
2071
2072        step.dependOn(&cleanup.step);
2073    }
2074
2075    {
2076        // Test `zig init -m`.
2077        const tmp_path = b.makeTempPath();
2078        const init_exe = b.addSystemCommand(&.{ b.graph.zig_exe, "init", "-m" });
2079        init_exe.setCwd(.{ .cwd_relative = tmp_path });
2080        init_exe.setName("zig init -m");
2081        init_exe.expectStdOutEqual("");
2082        init_exe.expectStdErrEqual("info: successfully populated 'build.zig.zon' and 'build.zig'\n");
2083    }
2084
2085    // Test Godbolt API
2086    if (builtin.os.tag == .linux and builtin.cpu.arch == .x86_64) {
2087        const tmp_path = b.makeTempPath();
2088
2089        const example_zig = b.addWriteFiles().add("example.zig",
2090            \\// Type your code here, or load an example.
2091            \\export fn square(num: i32) i32 {
2092            \\    return num * num;
2093            \\}
2094            \\extern fn zig_panic() noreturn;
2095            \\pub fn panic(msg: []const u8, error_return_trace: ?*@import("std").builtin.StackTrace, _: ?usize) noreturn {
2096            \\    _ = msg;
2097            \\    _ = error_return_trace;
2098            \\    zig_panic();
2099            \\}
2100        );
2101
2102        // This is intended to be the exact CLI usage used by godbolt.org.
2103        const run = b.addSystemCommand(&.{
2104            b.graph.zig_exe, "build-obj",
2105            "--cache-dir",   tmp_path,
2106            "--name",        "example",
2107            "-fno-emit-bin", "-fno-emit-h",
2108            "-fstrip",       "-OReleaseFast",
2109        });
2110        run.addFileArg(example_zig);
2111        const example_s = run.addPrefixedOutputFileArg("-femit-asm=", "example.s");
2112
2113        const checkfile = b.addCheckFile(example_s, .{
2114            .expected_matches = &.{
2115                "square:",
2116                "mov\teax, edi",
2117                "imul\teax, edi",
2118            },
2119        });
2120        checkfile.setName("check godbolt.org CLI usage generating valid asm");
2121
2122        const cleanup = b.addRemoveDirTree(.{ .cwd_relative = tmp_path });
2123        cleanup.step.dependOn(&checkfile.step);
2124
2125        step.dependOn(&cleanup.step);
2126    }
2127
2128    {
2129        // Test `zig fmt`.
2130        // This test must use a temporary directory rather than a cache
2131        // directory because this test will be mutating the files. The cache
2132        // system relies on cache directories being mutated only by their
2133        // owners.
2134        const tmp_path = b.makeTempPath();
2135        const unformatted_code = "    // no reason for indent";
2136
2137        var dir = std.fs.cwd().openDir(tmp_path, .{}) catch @panic("unhandled");
2138        defer dir.close();
2139        dir.writeFile(.{ .sub_path = "fmt1.zig", .data = unformatted_code }) catch @panic("unhandled");
2140        dir.writeFile(.{ .sub_path = "fmt2.zig", .data = unformatted_code }) catch @panic("unhandled");
2141        dir.makeDir("subdir") catch @panic("unhandled");
2142        var subdir = dir.openDir("subdir", .{}) catch @panic("unhandled");
2143        defer subdir.close();
2144        subdir.writeFile(.{ .sub_path = "fmt3.zig", .data = unformatted_code }) catch @panic("unhandled");
2145
2146        // Test zig fmt affecting only the appropriate files.
2147        const run1 = b.addSystemCommand(&.{ b.graph.zig_exe, "fmt", "fmt1.zig" });
2148        run1.setName("run zig fmt one file");
2149        run1.setCwd(.{ .cwd_relative = tmp_path });
2150        run1.has_side_effects = true;
2151        // stdout should be file path + \n
2152        run1.expectStdOutEqual("fmt1.zig\n");
2153
2154        // Test excluding files and directories from a run
2155        const run2 = b.addSystemCommand(&.{ b.graph.zig_exe, "fmt", "--exclude", "fmt2.zig", "--exclude", "subdir", "." });
2156        run2.setName("run zig fmt on directory with exclusions");
2157        run2.setCwd(.{ .cwd_relative = tmp_path });
2158        run2.has_side_effects = true;
2159        run2.expectStdOutEqual("");
2160        run2.step.dependOn(&run1.step);
2161
2162        // Test excluding non-existent file
2163        const run3 = b.addSystemCommand(&.{ b.graph.zig_exe, "fmt", "--exclude", "fmt2.zig", "--exclude", "nonexistent.zig", "." });
2164        run3.setName("run zig fmt on directory with non-existent exclusion");
2165        run3.setCwd(.{ .cwd_relative = tmp_path });
2166        run3.has_side_effects = true;
2167        run3.expectStdOutEqual("." ++ s ++ "subdir" ++ s ++ "fmt3.zig\n");
2168        run3.step.dependOn(&run2.step);
2169
2170        // running it on the dir, only the new file should be changed
2171        const run4 = b.addSystemCommand(&.{ b.graph.zig_exe, "fmt", "." });
2172        run4.setName("run zig fmt the directory");
2173        run4.setCwd(.{ .cwd_relative = tmp_path });
2174        run4.has_side_effects = true;
2175        run4.expectStdOutEqual("." ++ s ++ "fmt2.zig\n");
2176        run4.step.dependOn(&run3.step);
2177
2178        // both files have been formatted, nothing should change now
2179        const run5 = b.addSystemCommand(&.{ b.graph.zig_exe, "fmt", "." });
2180        run5.setName("run zig fmt with nothing to do");
2181        run5.setCwd(.{ .cwd_relative = tmp_path });
2182        run5.has_side_effects = true;
2183        run5.expectStdOutEqual("");
2184        run5.step.dependOn(&run4.step);
2185
2186        const unformatted_code_utf16 = "\xff\xfe \x00 \x00 \x00 \x00/\x00/\x00 \x00n\x00o\x00 \x00r\x00e\x00a\x00s\x00o\x00n\x00";
2187        const fmt6_path = b.pathJoin(&.{ tmp_path, "fmt6.zig" });
2188        const write6 = b.addUpdateSourceFiles();
2189        write6.addBytesToSource(unformatted_code_utf16, fmt6_path);
2190        write6.step.dependOn(&run5.step);
2191
2192        // Test `zig fmt` handling UTF-16 decoding.
2193        const run6 = b.addSystemCommand(&.{ b.graph.zig_exe, "fmt", "." });
2194        run6.setName("run zig fmt convert UTF-16 to UTF-8");
2195        run6.setCwd(.{ .cwd_relative = tmp_path });
2196        run6.has_side_effects = true;
2197        run6.expectStdOutEqual("." ++ s ++ "fmt6.zig\n");
2198        run6.step.dependOn(&write6.step);
2199
2200        // TODO change this to an exact match
2201        const check6 = b.addCheckFile(.{ .cwd_relative = fmt6_path }, .{
2202            .expected_matches = &.{
2203                "// no reason",
2204            },
2205        });
2206        check6.step.dependOn(&run6.step);
2207
2208        const cleanup = b.addRemoveDirTree(.{ .cwd_relative = tmp_path });
2209        cleanup.step.dependOn(&check6.step);
2210
2211        step.dependOn(&cleanup.step);
2212    }
2213
2214    {
2215        const run_test = b.addSystemCommand(&.{
2216            b.graph.zig_exe,
2217            "build",
2218            "test",
2219            "-Dbool_true",
2220            "-Dbool_false=false",
2221            "-Dint=1234",
2222            "-De=two",
2223            "-Dstring=hello",
2224        });
2225        run_test.addArg("--build-file");
2226        run_test.addFileArg(b.path("test/cli/options/build.zig"));
2227        run_test.addArg("--cache-dir");
2228        run_test.addFileArg(.{ .cwd_relative = b.cache_root.join(b.allocator, &.{}) catch @panic("OOM") });
2229        run_test.setName("test build options");
2230
2231        step.dependOn(&run_test.step);
2232    }
2233
2234    return step;
2235}
2236
2237const ModuleTestOptions = struct {
2238    test_filters: []const []const u8,
2239    test_target_filters: []const []const u8,
2240    test_extra_targets: bool,
2241    root_src: []const u8,
2242    name: []const u8,
2243    desc: []const u8,
2244    optimize_modes: []const OptimizeMode,
2245    include_paths: []const []const u8,
2246    test_default_only: bool,
2247    skip_single_threaded: bool,
2248    skip_non_native: bool,
2249    skip_freebsd: bool,
2250    skip_netbsd: bool,
2251    skip_windows: bool,
2252    skip_darwin: bool,
2253    skip_linux: bool,
2254    skip_llvm: bool,
2255    skip_libc: bool,
2256    max_rss: usize = 0,
2257    no_builtin: bool = false,
2258    build_options: ?*Step.Options = null,
2259};
2260
2261pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
2262    const step = b.step(b.fmt("test-{s}", .{options.name}), options.desc);
2263
2264    if (options.test_default_only) {
2265        const test_target = &test_targets[0];
2266        const resolved_target = b.resolveTargetQuery(test_target.target);
2267        const triple_txt = resolved_target.query.zigTriple(b.allocator) catch @panic("OOM");
2268        addOneModuleTest(b, step, test_target, &resolved_target, triple_txt, options);
2269        return step;
2270    }
2271
2272    for_targets: for (&test_targets) |*test_target| {
2273        if (test_target.skip_modules.len > 0) {
2274            for (test_target.skip_modules) |skip_mod| {
2275                if (std.mem.eql(u8, options.name, skip_mod)) continue :for_targets;
2276            }
2277        }
2278
2279        if (!options.test_extra_targets and test_target.extra_target) continue;
2280
2281        if (options.skip_non_native and !test_target.target.isNative())
2282            continue;
2283
2284        if (options.skip_freebsd and test_target.target.os_tag == .freebsd) continue;
2285        if (options.skip_netbsd and test_target.target.os_tag == .netbsd) continue;
2286        if (options.skip_windows and test_target.target.os_tag == .windows) continue;
2287        if (options.skip_darwin and test_target.target.os_tag != null and test_target.target.os_tag.?.isDarwin()) continue;
2288        if (options.skip_linux and test_target.target.os_tag == .linux) continue;
2289
2290        const would_use_llvm = wouldUseLlvm(test_target.use_llvm, test_target.target, test_target.optimize_mode);
2291        if (options.skip_llvm and would_use_llvm) continue;
2292
2293        const resolved_target = b.resolveTargetQuery(test_target.target);
2294        const triple_txt = resolved_target.query.zigTriple(b.allocator) catch @panic("OOM");
2295        const target = &resolved_target.result;
2296
2297        if (options.test_target_filters.len > 0) {
2298            for (options.test_target_filters) |filter| {
2299                if (std.mem.indexOf(u8, triple_txt, filter) != null) break;
2300            } else continue;
2301        }
2302
2303        if (options.skip_libc and test_target.link_libc == true)
2304            continue;
2305
2306        // We can't provide MSVC libc when cross-compiling.
2307        if (target.abi == .msvc and test_target.link_libc == true and builtin.os.tag != .windows)
2308            continue;
2309
2310        if (options.skip_single_threaded and test_target.single_threaded == true)
2311            continue;
2312
2313        if (!would_use_llvm and target.cpu.arch == .aarch64) {
2314            // TODO get std tests passing for the aarch64 self-hosted backend.
2315            if (mem.eql(u8, options.name, "std")) continue;
2316            // TODO get zigc tests passing for the aarch64 self-hosted backend.
2317            if (mem.eql(u8, options.name, "zigc")) continue;
2318        }
2319
2320        const want_this_mode = for (options.optimize_modes) |m| {
2321            if (m == test_target.optimize_mode) break true;
2322        } else false;
2323        if (!want_this_mode) continue;
2324
2325        addOneModuleTest(b, step, test_target, &resolved_target, triple_txt, options);
2326    }
2327    return step;
2328}
2329
2330fn addOneModuleTest(
2331    b: *std.Build,
2332    step: *Step,
2333    test_target: *const TestTarget,
2334    resolved_target: *const std.Build.ResolvedTarget,
2335    triple_txt: []const u8,
2336    options: ModuleTestOptions,
2337) void {
2338    const target = &resolved_target.result;
2339    const libc_suffix = if (test_target.link_libc == true) "-libc" else "";
2340    const model_txt = target.cpu.model.name;
2341
2342    // wasm32-wasi builds need more RAM, idk why
2343    const max_rss = if (target.os.tag == .wasi)
2344        options.max_rss * 2
2345    else
2346        options.max_rss;
2347
2348    const these_tests = b.addTest(.{
2349        .root_module = b.createModule(.{
2350            .root_source_file = b.path(options.root_src),
2351            .optimize = test_target.optimize_mode,
2352            .target = resolved_target.*,
2353            .link_libc = test_target.link_libc,
2354            .pic = test_target.pic,
2355            .strip = test_target.strip,
2356            .single_threaded = test_target.single_threaded,
2357        }),
2358        .max_rss = max_rss,
2359        .filters = options.test_filters,
2360        .use_llvm = test_target.use_llvm,
2361        .use_lld = test_target.use_lld,
2362        .zig_lib_dir = b.path("lib"),
2363    });
2364    these_tests.linkage = test_target.linkage;
2365    if (options.no_builtin) these_tests.root_module.no_builtin = false;
2366    if (options.build_options) |build_options| {
2367        these_tests.root_module.addOptions("build_options", build_options);
2368    }
2369    const single_threaded_suffix = if (test_target.single_threaded == true) "-single" else "";
2370    const backend_suffix = if (test_target.use_llvm == true)
2371        "-llvm"
2372    else if (target.ofmt == .c)
2373        "-cbe"
2374    else if (test_target.use_llvm == false)
2375        "-selfhosted"
2376    else
2377        "";
2378    const use_lld = if (test_target.use_lld == false) "-no-lld" else "";
2379    const linkage_name = if (test_target.linkage) |linkage| switch (linkage) {
2380        inline else => |t| "-" ++ @tagName(t),
2381    } else "";
2382    const use_pic = if (test_target.pic == true) "-pic" else "";
2383
2384    for (options.include_paths) |include_path| these_tests.root_module.addIncludePath(b.path(include_path));
2385
2386    const qualified_name = b.fmt("{s}-{s}-{s}-{t}{s}{s}{s}{s}{s}{s}", .{
2387        options.name,
2388        triple_txt,
2389        model_txt,
2390        test_target.optimize_mode,
2391        libc_suffix,
2392        single_threaded_suffix,
2393        backend_suffix,
2394        use_lld,
2395        linkage_name,
2396        use_pic,
2397    });
2398
2399    if (target.ofmt == .c) {
2400        var altered_query = test_target.target;
2401        altered_query.ofmt = null;
2402
2403        const compile_c = b.createModule(.{
2404            .root_source_file = null,
2405            .link_libc = test_target.link_libc,
2406            .target = b.resolveTargetQuery(altered_query),
2407        });
2408        const compile_c_exe = b.addExecutable(.{
2409            .name = qualified_name,
2410            .root_module = compile_c,
2411            .zig_lib_dir = b.path("lib"),
2412        });
2413
2414        compile_c.addCSourceFile(.{
2415            .file = these_tests.getEmittedBin(),
2416            .flags = &.{
2417                // Tracking issue for making the C backend generate C89 compatible code:
2418                // https://github.com/ziglang/zig/issues/19468
2419                "-std=c99",
2420                "-Werror",
2421
2422                "-Wall",
2423                "-Wembedded-directive",
2424                "-Wempty-translation-unit",
2425                "-Wextra",
2426                "-Wgnu",
2427                "-Winvalid-utf8",
2428                "-Wkeyword-macro",
2429                "-Woverlength-strings",
2430
2431                // Tracking issue for making the C backend generate code
2432                // that does not trigger warnings:
2433                // https://github.com/ziglang/zig/issues/19467
2434
2435                // spotted everywhere
2436                "-Wno-builtin-requires-header",
2437
2438                // spotted on linux
2439                "-Wno-braced-scalar-init",
2440                "-Wno-excess-initializers",
2441                "-Wno-incompatible-pointer-types-discards-qualifiers",
2442                "-Wno-unused",
2443                "-Wno-unused-parameter",
2444
2445                // spotted on darwin
2446                "-Wno-incompatible-pointer-types",
2447
2448                // https://github.com/llvm/llvm-project/issues/153314
2449                "-Wno-unterminated-string-initialization",
2450
2451                // In both Zig and C it is legal to return a pointer to a
2452                // local. The C backend lowers such thing directly, so the
2453                // corresponding warning in C must be disabled.
2454                "-Wno-return-stack-address",
2455            },
2456        });
2457        compile_c.addIncludePath(b.path("lib")); // for zig.h
2458        if (target.os.tag == .windows) {
2459            if (true) {
2460                // Unfortunately this requires about 8G of RAM for clang to compile
2461                // and our Windows CI runners do not have this much.
2462                // TODO This is not an appropriate way to work around this problem.
2463                step.dependOn(&these_tests.step);
2464                return;
2465            }
2466            if (test_target.link_libc == false) {
2467                compile_c_exe.subsystem = .Console;
2468                compile_c.linkSystemLibrary("kernel32", .{});
2469                compile_c.linkSystemLibrary("ntdll", .{});
2470            }
2471            if (mem.eql(u8, options.name, "std")) {
2472                if (test_target.link_libc == false) {
2473                    compile_c.linkSystemLibrary("shell32", .{});
2474                    compile_c.linkSystemLibrary("advapi32", .{});
2475                }
2476                compile_c.linkSystemLibrary("crypt32", .{});
2477                compile_c.linkSystemLibrary("ws2_32", .{});
2478                compile_c.linkSystemLibrary("ole32", .{});
2479            }
2480        }
2481
2482        const run = b.addRunArtifact(compile_c_exe);
2483        run.skip_foreign_checks = true;
2484        run.enableTestRunnerMode();
2485        run.setName(b.fmt("run test {s}", .{qualified_name}));
2486
2487        step.dependOn(&run.step);
2488    } else if (target.cpu.arch.isSpirV()) {
2489        // Don't run spirv binaries
2490        _ = these_tests.getEmittedBin();
2491        step.dependOn(&these_tests.step);
2492    } else {
2493        const run = b.addRunArtifact(these_tests);
2494        run.skip_foreign_checks = true;
2495        run.setName(b.fmt("run test {s}", .{qualified_name}));
2496
2497        step.dependOn(&run.step);
2498    }
2499}
2500
2501pub fn wouldUseLlvm(use_llvm: ?bool, query: std.Target.Query, optimize_mode: OptimizeMode) bool {
2502    if (comptime builtin.cpu.arch.endian() == .big) return true; // https://github.com/ziglang/zig/issues/25961
2503    if (use_llvm) |x| return x;
2504    if (query.ofmt == .c) return false;
2505    switch (optimize_mode) {
2506        .Debug => {},
2507        else => return true,
2508    }
2509    const cpu_arch = query.cpu_arch orelse builtin.cpu.arch;
2510    const os_tag = query.os_tag orelse builtin.os.tag;
2511    switch (cpu_arch) {
2512        .x86_64 => if (os_tag.isBSD() or os_tag == .illumos or std.Target.ptrBitWidth_arch_abi(cpu_arch, query.abi orelse .none) != 64) return true,
2513        .spirv32, .spirv64 => return false,
2514        else => return true,
2515    }
2516    return false;
2517}
2518
2519const CAbiTestOptions = struct {
2520    test_target_filters: []const []const u8,
2521    skip_non_native: bool,
2522    skip_freebsd: bool,
2523    skip_netbsd: bool,
2524    skip_windows: bool,
2525    skip_darwin: bool,
2526    skip_linux: bool,
2527    skip_llvm: bool,
2528    skip_release: bool,
2529};
2530
2531pub fn addCAbiTests(b: *std.Build, options: CAbiTestOptions) *Step {
2532    const step = b.step("test-c-abi", "Run the C ABI tests");
2533
2534    const optimize_modes: [3]OptimizeMode = .{ .Debug, .ReleaseSafe, .ReleaseFast };
2535
2536    for (optimize_modes) |optimize_mode| {
2537        if (optimize_mode != .Debug and options.skip_release) continue;
2538
2539        for (c_abi_targets) |c_abi_target| {
2540            if (options.skip_non_native and !c_abi_target.target.isNative()) continue;
2541            if (options.skip_freebsd and c_abi_target.target.os_tag == .freebsd) continue;
2542            if (options.skip_netbsd and c_abi_target.target.os_tag == .netbsd) continue;
2543            if (options.skip_windows and c_abi_target.target.os_tag == .windows) continue;
2544            if (options.skip_darwin and c_abi_target.target.os_tag != null and c_abi_target.target.os_tag.?.isDarwin()) continue;
2545            if (options.skip_linux and c_abi_target.target.os_tag == .linux) continue;
2546
2547            const would_use_llvm = wouldUseLlvm(c_abi_target.use_llvm, c_abi_target.target, .Debug);
2548            if (options.skip_llvm and would_use_llvm) continue;
2549
2550            const resolved_target = b.resolveTargetQuery(c_abi_target.target);
2551            const triple_txt = resolved_target.query.zigTriple(b.allocator) catch @panic("OOM");
2552            const target = &resolved_target.result;
2553
2554            if (options.test_target_filters.len > 0) {
2555                for (options.test_target_filters) |filter| {
2556                    if (std.mem.indexOf(u8, triple_txt, filter) != null) break;
2557                } else continue;
2558            }
2559
2560            if (target.os.tag == .windows and target.cpu.arch == .aarch64) {
2561                // https://github.com/ziglang/zig/issues/14908
2562                continue;
2563            }
2564
2565            const test_mod = b.createModule(.{
2566                .root_source_file = b.path("test/c_abi/main.zig"),
2567                .target = resolved_target,
2568                .optimize = optimize_mode,
2569                .link_libc = true,
2570                .pic = c_abi_target.pic,
2571                .strip = c_abi_target.strip,
2572            });
2573            test_mod.addCSourceFile(.{
2574                .file = b.path("test/c_abi/cfuncs.c"),
2575                .flags = &.{"-std=c99"},
2576            });
2577            for (c_abi_target.c_defines) |define| test_mod.addCMacro(define, "1");
2578
2579            const test_step = b.addTest(.{
2580                .name = b.fmt("test-c-abi-{s}-{s}-{s}{s}{s}{s}", .{
2581                    triple_txt,
2582                    target.cpu.model.name,
2583                    @tagName(optimize_mode),
2584                    if (c_abi_target.use_llvm == true)
2585                        "-llvm"
2586                    else if (target.ofmt == .c)
2587                        "-cbe"
2588                    else if (c_abi_target.use_llvm == false)
2589                        "-selfhosted"
2590                    else
2591                        "",
2592                    if (c_abi_target.use_lld == false) "-no-lld" else "",
2593                    if (c_abi_target.pic == true) "-pic" else "",
2594                }),
2595                .root_module = test_mod,
2596                .use_llvm = c_abi_target.use_llvm,
2597                .use_lld = c_abi_target.use_lld,
2598            });
2599
2600            // This test is intentionally trying to check if the external ABI is
2601            // done properly. LTO would be a hindrance to this.
2602            test_step.lto = .none;
2603
2604            const run = b.addRunArtifact(test_step);
2605            run.skip_foreign_checks = true;
2606            step.dependOn(&run.step);
2607        }
2608    }
2609    return step;
2610}
2611
2612pub fn addCases(
2613    b: *std.Build,
2614    parent_step: *Step,
2615    case_test_options: @import("src/Cases.zig").CaseTestOptions,
2616    build_options: @import("cases.zig").BuildOptions,
2617) !void {
2618    const arena = b.allocator;
2619    const gpa = b.allocator;
2620
2621    var cases = @import("src/Cases.zig").init(gpa, arena);
2622
2623    var dir = try b.build_root.handle.openDir("test/cases", .{ .iterate = true });
2624    defer dir.close();
2625
2626    cases.addFromDir(dir, b);
2627    try @import("cases.zig").addCases(&cases, build_options, b);
2628
2629    cases.lowerToBuildSteps(
2630        b,
2631        parent_step,
2632        case_test_options,
2633    );
2634}
2635
2636pub fn addDebuggerTests(b: *std.Build, options: DebuggerContext.Options) ?*Step {
2637    const step = b.step("test-debugger", "Run the debugger tests");
2638    if (options.gdb == null and options.lldb == null) {
2639        step.dependOn(&b.addFail("test-debugger requires -Dgdb and/or -Dlldb").step);
2640        return null;
2641    }
2642
2643    var context: DebuggerContext = .{
2644        .b = b,
2645        .options = options,
2646        .root_step = step,
2647    };
2648    context.addTestsForTarget(&.{
2649        .resolved = b.resolveTargetQuery(.{
2650            .cpu_arch = .x86_64,
2651            .os_tag = .linux,
2652            .abi = .none,
2653        }),
2654        .pic = false,
2655        .test_name_suffix = "x86_64-linux",
2656    });
2657    context.addTestsForTarget(&.{
2658        .resolved = b.resolveTargetQuery(.{
2659            .cpu_arch = .x86_64,
2660            .os_tag = .linux,
2661            .abi = .none,
2662        }),
2663        .pic = true,
2664        .test_name_suffix = "x86_64-linux-pic",
2665    });
2666    return step;
2667}
2668
2669pub fn addIncrementalTests(b: *std.Build, test_step: *Step) !void {
2670    const incr_check = b.addExecutable(.{
2671        .name = "incr-check",
2672        .root_module = b.createModule(.{
2673            .root_source_file = b.path("tools/incr-check.zig"),
2674            .target = b.graph.host,
2675            .optimize = .Debug,
2676        }),
2677    });
2678
2679    var dir = try b.build_root.handle.openDir("test/incremental", .{ .iterate = true });
2680    defer dir.close();
2681
2682    var it = try dir.walk(b.graph.arena);
2683    while (try it.next()) |entry| {
2684        if (entry.kind != .file) continue;
2685
2686        const run = b.addRunArtifact(incr_check);
2687        run.setName(b.fmt("incr-check '{s}'", .{entry.basename}));
2688
2689        run.addArg(b.graph.zig_exe);
2690        run.addFileArg(b.path("test/incremental/").path(b, entry.path));
2691        run.addArgs(&.{ "--zig-lib-dir", b.fmt("{f}", .{b.graph.zig_lib_directory}) });
2692
2693        run.addCheck(.{ .expect_term = .{ .Exited = 0 } });
2694
2695        test_step.dependOn(&run.step);
2696    }
2697}
2698
2699pub fn addLlvmIrTests(b: *std.Build, options: LlvmIrContext.Options) ?*Step {
2700    const step = b.step("test-llvm-ir", "Run the LLVM IR tests");
2701
2702    if (!options.enable_llvm) {
2703        step.dependOn(&b.addFail("test-llvm-ir requires -Denable-llvm").step);
2704        return null;
2705    }
2706
2707    var context: LlvmIrContext = .{
2708        .b = b,
2709        .options = options,
2710        .root_step = step,
2711    };
2712
2713    llvm_ir.addCases(&context);
2714
2715    return step;
2716}
2717
2718const libc_targets: []const std.Target.Query = &.{
2719    .{
2720        .cpu_arch = .arm,
2721        .os_tag = .linux,
2722        .abi = .musleabi,
2723    },
2724    .{
2725        .cpu_arch = .arm,
2726        .os_tag = .linux,
2727        .abi = .musleabihf,
2728    },
2729    .{
2730        .cpu_arch = .armeb,
2731        .os_tag = .linux,
2732        .abi = .musleabi,
2733    },
2734    .{
2735        .cpu_arch = .armeb,
2736        .os_tag = .linux,
2737        .abi = .musleabihf,
2738    },
2739    .{
2740        .cpu_arch = .thumb,
2741        .os_tag = .linux,
2742        .abi = .musleabi,
2743    },
2744    .{
2745        .cpu_arch = .thumb,
2746        .os_tag = .linux,
2747        .abi = .musleabihf,
2748    },
2749    .{
2750        .cpu_arch = .thumbeb,
2751        .os_tag = .linux,
2752        .abi = .musleabi,
2753    },
2754    .{
2755        .cpu_arch = .thumbeb,
2756        .os_tag = .linux,
2757        .abi = .musleabihf,
2758    },
2759    .{
2760        .cpu_arch = .aarch64,
2761        .os_tag = .linux,
2762        .abi = .musl,
2763    },
2764    .{
2765        .cpu_arch = .aarch64_be,
2766        .os_tag = .linux,
2767        .abi = .musl,
2768    },
2769    // .{
2770    //     .cpu_arch = .hexagon,
2771    //     .os_tag = .linux,
2772    //     .abi = .musl,
2773    // },
2774    .{
2775        .cpu_arch = .loongarch64,
2776        .os_tag = .linux,
2777        .abi = .musl,
2778    },
2779    .{
2780        .cpu_arch = .loongarch64,
2781        .os_tag = .linux,
2782        .abi = .muslsf,
2783    },
2784    // .{
2785    //     .cpu_arch = .mips,
2786    //     .os_tag = .linux,
2787    //     .abi = .musleabi,
2788    // },
2789    // .{
2790    //     .cpu_arch = .mips,
2791    //     .os_tag = .linux,
2792    //     .abi = .musleabihf,
2793    // },
2794    // .{
2795    //     .cpu_arch = .mipsel,
2796    //     .os_tag = .linux,
2797    //     .abi = .musleabi,
2798    // },
2799    // .{
2800    //     .cpu_arch = .mipsel,
2801    //     .os_tag = .linux,
2802    //     .abi = .musleabihf,
2803    // },
2804    // .{
2805    //     .cpu_arch = .mips64,
2806    //     .os_tag = .linux,
2807    //     .abi = .muslabi64,
2808    // },
2809    // .{
2810    //     .cpu_arch = .mips64,
2811    //     .os_tag = .linux,
2812    //     .abi = .muslabin32,
2813    // },
2814    // .{
2815    //     .cpu_arch = .mips64el,
2816    //     .os_tag = .linux,
2817    //     .abi = .muslabi64,
2818    // },
2819    // .{
2820    //     .cpu_arch = .mips64el,
2821    //     .os_tag = .linux,
2822    //     .abi = .muslabin32,
2823    // },
2824    .{
2825        .cpu_arch = .powerpc,
2826        .os_tag = .linux,
2827        .abi = .musleabi,
2828    },
2829    .{
2830        .cpu_arch = .powerpc,
2831        .os_tag = .linux,
2832        .abi = .musleabihf,
2833    },
2834    .{
2835        .cpu_arch = .powerpc64,
2836        .os_tag = .linux,
2837        .abi = .musl,
2838    },
2839    .{
2840        .cpu_arch = .powerpc64le,
2841        .os_tag = .linux,
2842        .abi = .musl,
2843    },
2844    .{
2845        .cpu_arch = .riscv32,
2846        .os_tag = .linux,
2847        .abi = .musl,
2848    },
2849    .{
2850        .cpu_arch = .riscv64,
2851        .os_tag = .linux,
2852        .abi = .musl,
2853    },
2854    .{
2855        .cpu_arch = .s390x,
2856        .os_tag = .linux,
2857        .abi = .musl,
2858    },
2859    .{
2860        .cpu_arch = .wasm32,
2861        .os_tag = .wasi,
2862        .abi = .musl,
2863    },
2864    .{
2865        .cpu_arch = .x86,
2866        .os_tag = .linux,
2867        .abi = .musl,
2868    },
2869    .{
2870        .cpu_arch = .x86_64,
2871        .os_tag = .linux,
2872        .abi = .musl,
2873    },
2874    .{
2875        .cpu_arch = .x86_64,
2876        .os_tag = .linux,
2877        .abi = .muslx32,
2878    },
2879};
2880
2881pub fn addLibcTests(b: *std.Build, options: LibcContext.Options) ?*Step {
2882    const step = b.step("test-libc", "Run libc-test test cases");
2883    const opt_libc_test_path = b.option(std.Build.LazyPath, "libc-test-path", "path to libc-test source directory");
2884    if (opt_libc_test_path) |libc_test_path| {
2885        var context: LibcContext = .{
2886            .b = b,
2887            .options = options,
2888            .root_step = step,
2889            .libc_test_src_path = libc_test_path.path(b, "src"),
2890        };
2891
2892        libc.addCases(&context);
2893
2894        for (libc_targets) |target_query| {
2895            const target = b.resolveTargetQuery(target_query);
2896            context.addTarget(target);
2897        }
2898
2899        return step;
2900    } else {
2901        step.dependOn(&b.addFail("The -Dlibc-test-path=... option is required for this step").step);
2902        return null;
2903    }
2904}