zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

blob a9bed635 (33438B) - Raw


      1 const std = @import("std");
      2 const builtin = @import("builtin");
      3 const assert = std.debug.assert;
      4 const CrossTarget = std.zig.CrossTarget;
      5 const mem = std.mem;
      6 const OptimizeMode = std.builtin.OptimizeMode;
      7 const Step = std.Build.Step;
      8 
      9 // Cases
     10 const compare_output = @import("compare_output.zig");
     11 const standalone = @import("standalone.zig");
     12 const stack_traces = @import("stack_traces.zig");
     13 const assemble_and_link = @import("assemble_and_link.zig");
     14 const translate_c = @import("translate_c.zig");
     15 const run_translated_c = @import("run_translated_c.zig");
     16 const link = @import("link.zig");
     17 
     18 // Implementations
     19 pub const TranslateCContext = @import("src/translate_c.zig").TranslateCContext;
     20 pub const RunTranslatedCContext = @import("src/run_translated_c.zig").RunTranslatedCContext;
     21 pub const CompareOutputContext = @import("src/CompareOutput.zig");
     22 pub const StackTracesContext = @import("src/StackTrace.zig");
     23 
     24 const TestTarget = struct {
     25     target: CrossTarget = @as(CrossTarget, .{}),
     26     optimize_mode: std.builtin.OptimizeMode = .Debug,
     27     link_libc: bool = false,
     28     single_threaded: bool = false,
     29     disable_native: bool = false,
     30     backend: ?std.builtin.CompilerBackend = null,
     31 };
     32 
     33 const test_targets = blk: {
     34     // getBaselineCpuFeatures calls populateDependencies which has a O(N ^ 2) algorithm
     35     // (where N is roughly 160, which technically makes it O(1), but it adds up to a
     36     // lot of branches)
     37     @setEvalBranchQuota(50000);
     38     break :blk [_]TestTarget{
     39         .{},
     40         .{
     41             .link_libc = true,
     42         },
     43         .{
     44             .single_threaded = true,
     45         },
     46 
     47         .{
     48             .target = .{
     49                 .ofmt = .c,
     50             },
     51             .link_libc = true,
     52             .backend = .stage2_c,
     53         },
     54         .{
     55             .target = .{
     56                 .cpu_arch = .x86_64,
     57                 .os_tag = .linux,
     58                 .abi = .none,
     59             },
     60             .backend = .stage2_x86_64,
     61         },
     62         .{
     63             .target = .{
     64                 .cpu_arch = .aarch64,
     65                 .os_tag = .linux,
     66             },
     67             .backend = .stage2_aarch64,
     68         },
     69         .{
     70             .target = .{
     71                 .cpu_arch = .wasm32,
     72                 .os_tag = .wasi,
     73             },
     74             .single_threaded = true,
     75             .backend = .stage2_wasm,
     76         },
     77         // https://github.com/ziglang/zig/issues/13623
     78         //.{
     79         //    .target = .{
     80         //        .cpu_arch = .arm,
     81         //        .os_tag = .linux,
     82         //    },
     83         //    .backend = .stage2_arm,
     84         //},
     85         // https://github.com/ziglang/zig/issues/13623
     86         //.{
     87         //    .target = CrossTarget.parse(.{
     88         //        .arch_os_abi = "arm-linux-none",
     89         //        .cpu_features = "generic+v8a",
     90         //    }) catch unreachable,
     91         //    .backend = .stage2_arm,
     92         //},
     93         .{
     94             .target = .{
     95                 .cpu_arch = .aarch64,
     96                 .os_tag = .macos,
     97                 .abi = .none,
     98             },
     99             .backend = .stage2_aarch64,
    100         },
    101         .{
    102             .target = .{
    103                 .cpu_arch = .x86_64,
    104                 .os_tag = .macos,
    105                 .abi = .none,
    106             },
    107             .backend = .stage2_x86_64,
    108         },
    109         .{
    110             .target = .{
    111                 .cpu_arch = .x86_64,
    112                 .os_tag = .windows,
    113                 .abi = .gnu,
    114             },
    115             .backend = .stage2_x86_64,
    116         },
    117 
    118         .{
    119             .target = .{
    120                 .cpu_arch = .wasm32,
    121                 .os_tag = .wasi,
    122             },
    123             .link_libc = false,
    124             .single_threaded = true,
    125         },
    126         .{
    127             .target = .{
    128                 .cpu_arch = .wasm32,
    129                 .os_tag = .wasi,
    130             },
    131             .link_libc = true,
    132             .single_threaded = true,
    133         },
    134 
    135         .{
    136             .target = .{
    137                 .cpu_arch = .x86_64,
    138                 .os_tag = .linux,
    139                 .abi = .none,
    140             },
    141         },
    142         .{
    143             .target = .{
    144                 .cpu_arch = .x86_64,
    145                 .os_tag = .linux,
    146                 .abi = .gnu,
    147             },
    148             .link_libc = true,
    149         },
    150         .{
    151             .target = .{
    152                 .cpu_arch = .x86_64,
    153                 .os_tag = .linux,
    154                 .abi = .musl,
    155             },
    156             .link_libc = true,
    157         },
    158 
    159         .{
    160             .target = .{
    161                 .cpu_arch = .x86,
    162                 .os_tag = .linux,
    163                 .abi = .none,
    164             },
    165         },
    166         .{
    167             .target = .{
    168                 .cpu_arch = .x86,
    169                 .os_tag = .linux,
    170                 .abi = .musl,
    171             },
    172             .link_libc = true,
    173         },
    174         .{
    175             .target = .{
    176                 .cpu_arch = .x86,
    177                 .os_tag = .linux,
    178                 .abi = .gnu,
    179             },
    180             .link_libc = true,
    181         },
    182 
    183         .{
    184             .target = .{
    185                 .cpu_arch = .aarch64,
    186                 .os_tag = .linux,
    187                 .abi = .none,
    188             },
    189         },
    190         .{
    191             .target = .{
    192                 .cpu_arch = .aarch64,
    193                 .os_tag = .linux,
    194                 .abi = .musl,
    195             },
    196             .link_libc = true,
    197         },
    198         .{
    199             .target = .{
    200                 .cpu_arch = .aarch64,
    201                 .os_tag = .linux,
    202                 .abi = .gnu,
    203             },
    204             .link_libc = true,
    205         },
    206         .{
    207             .target = .{
    208                 .cpu_arch = .aarch64,
    209                 .os_tag = .windows,
    210                 .abi = .gnu,
    211             },
    212             .link_libc = true,
    213         },
    214 
    215         .{
    216             .target = CrossTarget.parse(.{
    217                 .arch_os_abi = "arm-linux-none",
    218                 .cpu_features = "generic+v8a",
    219             }) catch unreachable,
    220         },
    221         .{
    222             .target = CrossTarget.parse(.{
    223                 .arch_os_abi = "arm-linux-musleabihf",
    224                 .cpu_features = "generic+v8a",
    225             }) catch unreachable,
    226             .link_libc = true,
    227         },
    228         // https://github.com/ziglang/zig/issues/3287
    229         //.{
    230         //    .target = CrossTarget.parse(.{
    231         //        .arch_os_abi = "arm-linux-gnueabihf",
    232         //        .cpu_features = "generic+v8a",
    233         //    }) catch unreachable,
    234         //    .link_libc = true,
    235         //},
    236 
    237         .{
    238             .target = .{
    239                 .cpu_arch = .mips,
    240                 .os_tag = .linux,
    241                 .abi = .none,
    242             },
    243         },
    244 
    245         .{
    246             .target = .{
    247                 .cpu_arch = .mips,
    248                 .os_tag = .linux,
    249                 .abi = .musl,
    250             },
    251             .link_libc = true,
    252         },
    253 
    254         // https://github.com/ziglang/zig/issues/4927
    255         //.{
    256         //    .target = .{
    257         //        .cpu_arch = .mips,
    258         //        .os_tag = .linux,
    259         //        .abi = .gnueabihf,
    260         //    },
    261         //    .link_libc = true,
    262         //},
    263 
    264         .{
    265             .target = .{
    266                 .cpu_arch = .mipsel,
    267                 .os_tag = .linux,
    268                 .abi = .none,
    269             },
    270         },
    271 
    272         .{
    273             .target = .{
    274                 .cpu_arch = .mipsel,
    275                 .os_tag = .linux,
    276                 .abi = .musl,
    277             },
    278             .link_libc = true,
    279         },
    280 
    281         // https://github.com/ziglang/zig/issues/4927
    282         //.{
    283         //    .target = .{
    284         //        .cpu_arch = .mipsel,
    285         //        .os_tag = .linux,
    286         //        .abi = .gnueabihf,
    287         //    },
    288         //    .link_libc = true,
    289         //},
    290 
    291         .{
    292             .target = .{
    293                 .cpu_arch = .powerpc,
    294                 .os_tag = .linux,
    295                 .abi = .none,
    296             },
    297         },
    298         .{
    299             .target = .{
    300                 .cpu_arch = .powerpc,
    301                 .os_tag = .linux,
    302                 .abi = .musl,
    303             },
    304             .link_libc = true,
    305         },
    306         // https://github.com/ziglang/zig/issues/2256
    307         //.{
    308         //    .target = .{
    309         //        .cpu_arch = .powerpc,
    310         //        .os_tag = .linux,
    311         //        .abi = .gnueabihf,
    312         //    },
    313         //    .link_libc = true,
    314         //},
    315 
    316         .{
    317             .target = .{
    318                 .cpu_arch = .powerpc64le,
    319                 .os_tag = .linux,
    320                 .abi = .none,
    321             },
    322         },
    323         .{
    324             .target = .{
    325                 .cpu_arch = .powerpc64le,
    326                 .os_tag = .linux,
    327                 .abi = .musl,
    328             },
    329             .link_libc = true,
    330         },
    331         .{
    332             .target = .{
    333                 .cpu_arch = .powerpc64le,
    334                 .os_tag = .linux,
    335                 .abi = .gnu,
    336             },
    337             .link_libc = true,
    338         },
    339 
    340         .{
    341             .target = .{
    342                 .cpu_arch = .riscv64,
    343                 .os_tag = .linux,
    344                 .abi = .none,
    345             },
    346         },
    347 
    348         .{
    349             .target = .{
    350                 .cpu_arch = .riscv64,
    351                 .os_tag = .linux,
    352                 .abi = .musl,
    353             },
    354             .link_libc = true,
    355         },
    356 
    357         // https://github.com/ziglang/zig/issues/3340
    358         //.{
    359         //    .target = .{
    360         //        .cpu_arch = .riscv64,
    361         //        .os = .linux,
    362         //        .abi = .gnu,
    363         //    },
    364         //    .link_libc = true,
    365         //},
    366 
    367         .{
    368             .target = .{
    369                 .cpu_arch = .x86_64,
    370                 .os_tag = .macos,
    371                 .abi = .none,
    372             },
    373         },
    374 
    375         .{
    376             .target = .{
    377                 .cpu_arch = .aarch64,
    378                 .os_tag = .macos,
    379                 .abi = .none,
    380             },
    381         },
    382 
    383         .{
    384             .target = .{
    385                 .cpu_arch = .x86,
    386                 .os_tag = .windows,
    387                 .abi = .msvc,
    388             },
    389         },
    390 
    391         .{
    392             .target = .{
    393                 .cpu_arch = .x86_64,
    394                 .os_tag = .windows,
    395                 .abi = .msvc,
    396             },
    397         },
    398 
    399         .{
    400             .target = .{
    401                 .cpu_arch = .x86,
    402                 .os_tag = .windows,
    403                 .abi = .gnu,
    404             },
    405             .link_libc = true,
    406         },
    407 
    408         .{
    409             .target = .{
    410                 .cpu_arch = .x86_64,
    411                 .os_tag = .windows,
    412                 .abi = .gnu,
    413             },
    414             .link_libc = true,
    415         },
    416 
    417         // Do the release tests last because they take a long time
    418         .{
    419             .optimize_mode = .ReleaseFast,
    420         },
    421         .{
    422             .link_libc = true,
    423             .optimize_mode = .ReleaseFast,
    424         },
    425         .{
    426             .optimize_mode = .ReleaseFast,
    427             .single_threaded = true,
    428         },
    429 
    430         .{
    431             .optimize_mode = .ReleaseSafe,
    432         },
    433         .{
    434             .link_libc = true,
    435             .optimize_mode = .ReleaseSafe,
    436         },
    437         .{
    438             .optimize_mode = .ReleaseSafe,
    439             .single_threaded = true,
    440         },
    441 
    442         .{
    443             .optimize_mode = .ReleaseSmall,
    444         },
    445         .{
    446             .link_libc = true,
    447             .optimize_mode = .ReleaseSmall,
    448         },
    449         .{
    450             .optimize_mode = .ReleaseSmall,
    451             .single_threaded = true,
    452         },
    453     };
    454 };
    455 
    456 const c_abi_targets = [_]CrossTarget{
    457     .{},
    458     .{
    459         .cpu_arch = .x86_64,
    460         .os_tag = .linux,
    461         .abi = .musl,
    462     },
    463     .{
    464         .cpu_arch = .x86,
    465         .os_tag = .linux,
    466         .abi = .musl,
    467     },
    468     .{
    469         .cpu_arch = .aarch64,
    470         .os_tag = .linux,
    471         .abi = .musl,
    472     },
    473     .{
    474         .cpu_arch = .arm,
    475         .os_tag = .linux,
    476         .abi = .musleabihf,
    477     },
    478     .{
    479         .cpu_arch = .mips,
    480         .os_tag = .linux,
    481         .abi = .musl,
    482     },
    483     .{
    484         .cpu_arch = .riscv64,
    485         .os_tag = .linux,
    486         .abi = .musl,
    487     },
    488     .{
    489         .cpu_arch = .wasm32,
    490         .os_tag = .wasi,
    491         .abi = .musl,
    492     },
    493     .{
    494         .cpu_arch = .powerpc,
    495         .os_tag = .linux,
    496         .abi = .musl,
    497     },
    498     .{
    499         .cpu_arch = .powerpc64le,
    500         .os_tag = .linux,
    501         .abi = .musl,
    502     },
    503     .{
    504         .cpu_arch = .x86,
    505         .os_tag = .windows,
    506         .abi = .gnu,
    507     },
    508     .{
    509         .cpu_arch = .x86_64,
    510         .os_tag = .windows,
    511         .abi = .gnu,
    512     },
    513 };
    514 
    515 pub fn addCompareOutputTests(
    516     b: *std.Build,
    517     test_filter: ?[]const u8,
    518     optimize_modes: []const OptimizeMode,
    519 ) *Step {
    520     const cases = b.allocator.create(CompareOutputContext) catch @panic("OOM");
    521     cases.* = CompareOutputContext{
    522         .b = b,
    523         .step = b.step("test-compare-output", "Run the compare output tests"),
    524         .test_index = 0,
    525         .test_filter = test_filter,
    526         .optimize_modes = optimize_modes,
    527     };
    528 
    529     compare_output.addCases(cases);
    530 
    531     return cases.step;
    532 }
    533 
    534 pub fn addStackTraceTests(
    535     b: *std.Build,
    536     test_filter: ?[]const u8,
    537     optimize_modes: []const OptimizeMode,
    538 ) *Step {
    539     const check_exe = b.addExecutable(.{
    540         .name = "check-stack-trace",
    541         .root_source_file = .{ .path = "test/src/check-stack-trace.zig" },
    542         .target = .{},
    543         .optimize = .Debug,
    544     });
    545 
    546     const cases = b.allocator.create(StackTracesContext) catch @panic("OOM");
    547     cases.* = .{
    548         .b = b,
    549         .step = b.step("test-stack-traces", "Run the stack trace tests"),
    550         .test_index = 0,
    551         .test_filter = test_filter,
    552         .optimize_modes = optimize_modes,
    553         .check_exe = check_exe,
    554     };
    555 
    556     stack_traces.addCases(cases);
    557 
    558     return cases.step;
    559 }
    560 
    561 pub fn addStandaloneTests(
    562     b: *std.Build,
    563     optimize_modes: []const OptimizeMode,
    564     enable_macos_sdk: bool,
    565     omit_stage2: bool,
    566     enable_symlinks_windows: bool,
    567 ) *Step {
    568     const step = b.step("test-standalone", "Run the standalone tests");
    569     const omit_symlinks = builtin.os.tag == .windows and !enable_symlinks_windows;
    570 
    571     for (standalone.simple_cases) |case| {
    572         for (optimize_modes) |optimize| {
    573             if (!case.all_modes and optimize != .Debug) continue;
    574             if (case.os_filter) |os_tag| {
    575                 if (os_tag != builtin.os.tag) continue;
    576             }
    577 
    578             if (case.is_exe) {
    579                 const exe = b.addExecutable(.{
    580                     .name = std.fs.path.stem(case.src_path),
    581                     .root_source_file = .{ .path = case.src_path },
    582                     .optimize = optimize,
    583                     .target = case.target,
    584                 });
    585                 if (case.link_libc) exe.linkLibC();
    586 
    587                 step.dependOn(&exe.step);
    588             }
    589 
    590             if (case.is_test) {
    591                 const exe = b.addTest(.{
    592                     .name = std.fs.path.stem(case.src_path),
    593                     .root_source_file = .{ .path = case.src_path },
    594                     .optimize = optimize,
    595                     .target = case.target,
    596                 });
    597                 if (case.link_libc) exe.linkLibC();
    598 
    599                 const run = b.addRunArtifact(exe);
    600                 step.dependOn(&run.step);
    601             }
    602         }
    603     }
    604 
    605     inline for (standalone.build_cases) |case| {
    606         const requires_stage2 = @hasDecl(case.import, "requires_stage2") and
    607             case.import.requires_stage2;
    608         const requires_symlinks = @hasDecl(case.import, "requires_symlinks") and
    609             case.import.requires_symlinks;
    610         const requires_macos_sdk = @hasDecl(case.import, "requires_macos_sdk") and
    611             case.import.requires_macos_sdk;
    612         const bad =
    613             (requires_stage2 and omit_stage2) or
    614             (requires_symlinks and omit_symlinks) or
    615             (requires_macos_sdk and !enable_macos_sdk);
    616         if (!bad) {
    617             const dep = b.anonymousDependency(case.build_root, case.import, .{});
    618             const dep_step = dep.builder.default_step;
    619             assert(mem.startsWith(u8, dep.builder.dep_prefix, "test."));
    620             const dep_prefix_adjusted = dep.builder.dep_prefix["test.".len..];
    621             dep_step.name = b.fmt("{s}{s}", .{ dep_prefix_adjusted, dep_step.name });
    622             step.dependOn(dep_step);
    623         }
    624     }
    625 
    626     return step;
    627 }
    628 
    629 pub fn addLinkTests(
    630     b: *std.Build,
    631     enable_macos_sdk: bool,
    632     omit_stage2: bool,
    633     enable_symlinks_windows: bool,
    634 ) *Step {
    635     const step = b.step("test-link", "Run the linker tests");
    636     const omit_symlinks = builtin.os.tag == .windows and !enable_symlinks_windows;
    637 
    638     inline for (link.cases) |case| {
    639         const requires_stage2 = @hasDecl(case.import, "requires_stage2") and
    640             case.import.requires_stage2;
    641         const requires_symlinks = @hasDecl(case.import, "requires_symlinks") and
    642             case.import.requires_symlinks;
    643         const requires_macos_sdk = @hasDecl(case.import, "requires_macos_sdk") and
    644             case.import.requires_macos_sdk;
    645         const bad =
    646             (requires_stage2 and omit_stage2) or
    647             (requires_symlinks and omit_symlinks) or
    648             (requires_macos_sdk and !enable_macos_sdk);
    649         if (!bad) {
    650             const dep = b.anonymousDependency(case.build_root, case.import, .{});
    651             const dep_step = dep.builder.default_step;
    652             assert(mem.startsWith(u8, dep.builder.dep_prefix, "test."));
    653             const dep_prefix_adjusted = dep.builder.dep_prefix["test.".len..];
    654             dep_step.name = b.fmt("{s}{s}", .{ dep_prefix_adjusted, dep_step.name });
    655             step.dependOn(dep_step);
    656         }
    657     }
    658 
    659     return step;
    660 }
    661 
    662 pub fn addCliTests(b: *std.Build) *Step {
    663     const step = b.step("test-cli", "Test the command line interface");
    664     const s = std.fs.path.sep_str;
    665 
    666     {
    667 
    668         // Test `zig init-lib`.
    669         const tmp_path = b.makeTempPath();
    670         const init_lib = b.addSystemCommand(&.{ b.zig_exe, "init-lib" });
    671         init_lib.cwd = tmp_path;
    672         init_lib.setName("zig init-lib");
    673         init_lib.expectStdOutEqual("");
    674         init_lib.expectStdErrEqual("info: Created build.zig\n" ++
    675             "info: Created src" ++ s ++ "main.zig\n" ++
    676             "info: Next, try `zig build --help` or `zig build test`\n");
    677 
    678         const run_test = b.addSystemCommand(&.{ b.zig_exe, "build", "test" });
    679         run_test.cwd = tmp_path;
    680         run_test.setName("zig build test");
    681         run_test.expectStdOutEqual("");
    682         run_test.step.dependOn(&init_lib.step);
    683 
    684         const cleanup = b.addRemoveDirTree(tmp_path);
    685         cleanup.step.dependOn(&run_test.step);
    686 
    687         step.dependOn(&cleanup.step);
    688     }
    689 
    690     {
    691         // Test `zig init-exe`.
    692         const tmp_path = b.makeTempPath();
    693         const init_exe = b.addSystemCommand(&.{ b.zig_exe, "init-exe" });
    694         init_exe.cwd = tmp_path;
    695         init_exe.setName("zig init-exe");
    696         init_exe.expectStdOutEqual("");
    697         init_exe.expectStdErrEqual("info: Created build.zig\n" ++
    698             "info: Created src" ++ s ++ "main.zig\n" ++
    699             "info: Next, try `zig build --help` or `zig build run`\n");
    700 
    701         // Test missing output path.
    702         const bad_out_arg = "-femit-bin=does" ++ s ++ "not" ++ s ++ "exist" ++ s ++ "foo.exe";
    703         const ok_src_arg = "src" ++ s ++ "main.zig";
    704         const expected = "error: unable to open output directory 'does" ++ s ++ "not" ++ s ++ "exist': FileNotFound\n";
    705         const run_bad = b.addSystemCommand(&.{ b.zig_exe, "build-exe", ok_src_arg, bad_out_arg });
    706         run_bad.setName("zig build-exe error message for bad -femit-bin arg");
    707         run_bad.expectExitCode(1);
    708         run_bad.expectStdErrEqual(expected);
    709         run_bad.expectStdOutEqual("");
    710         run_bad.step.dependOn(&init_exe.step);
    711 
    712         const run_test = b.addSystemCommand(&.{ b.zig_exe, "build", "test" });
    713         run_test.cwd = tmp_path;
    714         run_test.setName("zig build test");
    715         run_test.expectStdOutEqual("");
    716         run_test.step.dependOn(&init_exe.step);
    717 
    718         const run_run = b.addSystemCommand(&.{ b.zig_exe, "build", "run" });
    719         run_run.cwd = tmp_path;
    720         run_run.setName("zig build run");
    721         run_run.expectStdOutEqual("Run `zig build test` to run the tests.\n");
    722         run_run.expectStdErrEqual("All your codebase are belong to us.\n");
    723         run_run.step.dependOn(&init_exe.step);
    724 
    725         const cleanup = b.addRemoveDirTree(tmp_path);
    726         cleanup.step.dependOn(&run_test.step);
    727         cleanup.step.dependOn(&run_run.step);
    728         cleanup.step.dependOn(&run_bad.step);
    729 
    730         step.dependOn(&cleanup.step);
    731     }
    732 
    733     // Test Godbolt API
    734     if (builtin.os.tag == .linux and builtin.cpu.arch == .x86_64) {
    735         const tmp_path = b.makeTempPath();
    736 
    737         const writefile = b.addWriteFile("example.zig",
    738             \\// Type your code here, or load an example.
    739             \\export fn square(num: i32) i32 {
    740             \\    return num * num;
    741             \\}
    742             \\extern fn zig_panic() noreturn;
    743             \\pub fn panic(msg: []const u8, error_return_trace: ?*@import("std").builtin.StackTrace, _: ?usize) noreturn {
    744             \\    _ = msg;
    745             \\    _ = error_return_trace;
    746             \\    zig_panic();
    747             \\}
    748         );
    749 
    750         // This is intended to be the exact CLI usage used by godbolt.org.
    751         const run = b.addSystemCommand(&.{
    752             b.zig_exe,       "build-obj",
    753             "--cache-dir",   tmp_path,
    754             "--name",        "example",
    755             "-fno-emit-bin", "-fno-emit-h",
    756             "-fstrip",       "-OReleaseFast",
    757         });
    758         run.addFileSourceArg(writefile.getFileSource("example.zig").?);
    759         const example_s = run.addPrefixedOutputFileArg("-femit-asm=", "example.s");
    760 
    761         const checkfile = b.addCheckFile(example_s, .{
    762             .expected_matches = &.{
    763                 "square:",
    764                 "mov\teax, edi",
    765                 "imul\teax, edi",
    766             },
    767         });
    768         checkfile.setName("check godbolt.org CLI usage generating valid asm");
    769 
    770         const cleanup = b.addRemoveDirTree(tmp_path);
    771         cleanup.step.dependOn(&checkfile.step);
    772 
    773         step.dependOn(&cleanup.step);
    774     }
    775 
    776     {
    777         // Test `zig fmt`.
    778         // This test must use a temporary directory rather than a cache
    779         // directory because this test will be mutating the files. The cache
    780         // system relies on cache directories being mutated only by their
    781         // owners.
    782         const tmp_path = b.makeTempPath();
    783         const unformatted_code = "    // no reason for indent";
    784 
    785         var dir = std.fs.cwd().openDir(tmp_path, .{}) catch @panic("unhandled");
    786         defer dir.close();
    787         dir.writeFile("fmt1.zig", unformatted_code) catch @panic("unhandled");
    788         dir.writeFile("fmt2.zig", unformatted_code) catch @panic("unhandled");
    789 
    790         // Test zig fmt affecting only the appropriate files.
    791         const run1 = b.addSystemCommand(&.{ b.zig_exe, "fmt", "fmt1.zig" });
    792         run1.setName("run zig fmt one file");
    793         run1.cwd = tmp_path;
    794         run1.has_side_effects = true;
    795         // stdout should be file path + \n
    796         run1.expectStdOutEqual("fmt1.zig\n");
    797 
    798         // running it on the dir, only the new file should be changed
    799         const run2 = b.addSystemCommand(&.{ b.zig_exe, "fmt", "." });
    800         run2.setName("run zig fmt the directory");
    801         run2.cwd = tmp_path;
    802         run2.has_side_effects = true;
    803         run2.expectStdOutEqual("." ++ s ++ "fmt2.zig\n");
    804         run2.step.dependOn(&run1.step);
    805 
    806         // both files have been formatted, nothing should change now
    807         const run3 = b.addSystemCommand(&.{ b.zig_exe, "fmt", "." });
    808         run3.setName("run zig fmt with nothing to do");
    809         run3.cwd = tmp_path;
    810         run3.has_side_effects = true;
    811         run3.expectStdOutEqual("");
    812         run3.step.dependOn(&run2.step);
    813 
    814         const unformatted_code_utf16 = "\xff\xfe \x00 \x00 \x00 \x00/\x00/\x00 \x00n\x00o\x00 \x00r\x00e\x00a\x00s\x00o\x00n\x00";
    815         const fmt4_path = std.fs.path.join(b.allocator, &.{ tmp_path, "fmt4.zig" }) catch @panic("OOM");
    816         const write4 = b.addWriteFiles();
    817         write4.addBytesToSource(unformatted_code_utf16, fmt4_path);
    818         write4.step.dependOn(&run3.step);
    819 
    820         // Test `zig fmt` handling UTF-16 decoding.
    821         const run4 = b.addSystemCommand(&.{ b.zig_exe, "fmt", "." });
    822         run4.setName("run zig fmt convert UTF-16 to UTF-8");
    823         run4.cwd = tmp_path;
    824         run4.has_side_effects = true;
    825         run4.expectStdOutEqual("." ++ s ++ "fmt4.zig\n");
    826         run4.step.dependOn(&write4.step);
    827 
    828         // TODO change this to an exact match
    829         const check4 = b.addCheckFile(.{ .path = fmt4_path }, .{
    830             .expected_matches = &.{
    831                 "// no reason",
    832             },
    833         });
    834         check4.step.dependOn(&run4.step);
    835 
    836         const cleanup = b.addRemoveDirTree(tmp_path);
    837         cleanup.step.dependOn(&check4.step);
    838 
    839         step.dependOn(&cleanup.step);
    840     }
    841 
    842     {
    843         // TODO this should move to become a CLI test rather than standalone
    844         //    cases.addBuildFile("test/standalone/options/build.zig", .{
    845         //        .extra_argv = &.{
    846         //            "-Dbool_true",
    847         //            "-Dbool_false=false",
    848         //            "-Dint=1234",
    849         //            "-De=two",
    850         //            "-Dstring=hello",
    851         //        },
    852         //    });
    853     }
    854 
    855     return step;
    856 }
    857 
    858 pub fn addAssembleAndLinkTests(b: *std.Build, test_filter: ?[]const u8, optimize_modes: []const OptimizeMode) *Step {
    859     const cases = b.allocator.create(CompareOutputContext) catch @panic("OOM");
    860     cases.* = CompareOutputContext{
    861         .b = b,
    862         .step = b.step("test-asm-link", "Run the assemble and link tests"),
    863         .test_index = 0,
    864         .test_filter = test_filter,
    865         .optimize_modes = optimize_modes,
    866     };
    867 
    868     assemble_and_link.addCases(cases);
    869 
    870     return cases.step;
    871 }
    872 
    873 pub fn addTranslateCTests(b: *std.Build, test_filter: ?[]const u8) *Step {
    874     const cases = b.allocator.create(TranslateCContext) catch @panic("OOM");
    875     cases.* = TranslateCContext{
    876         .b = b,
    877         .step = b.step("test-translate-c", "Run the C translation tests"),
    878         .test_index = 0,
    879         .test_filter = test_filter,
    880     };
    881 
    882     translate_c.addCases(cases);
    883 
    884     return cases.step;
    885 }
    886 
    887 pub fn addRunTranslatedCTests(
    888     b: *std.Build,
    889     test_filter: ?[]const u8,
    890     target: std.zig.CrossTarget,
    891 ) *Step {
    892     const cases = b.allocator.create(RunTranslatedCContext) catch @panic("OOM");
    893     cases.* = .{
    894         .b = b,
    895         .step = b.step("test-run-translated-c", "Run the Run-Translated-C tests"),
    896         .test_index = 0,
    897         .test_filter = test_filter,
    898         .target = target,
    899     };
    900 
    901     run_translated_c.addCases(cases);
    902 
    903     return cases.step;
    904 }
    905 
    906 const ModuleTestOptions = struct {
    907     test_filter: ?[]const u8,
    908     root_src: []const u8,
    909     name: []const u8,
    910     desc: []const u8,
    911     optimize_modes: []const OptimizeMode,
    912     skip_single_threaded: bool,
    913     skip_non_native: bool,
    914     skip_cross_glibc: bool,
    915     skip_libc: bool,
    916     skip_stage1: bool,
    917     skip_stage2: bool,
    918     max_rss: usize = 0,
    919 };
    920 
    921 pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
    922     const step = b.step(b.fmt("test-{s}", .{options.name}), options.desc);
    923 
    924     for (test_targets) |test_target| {
    925         if (options.skip_non_native and !test_target.target.isNative())
    926             continue;
    927 
    928         if (options.skip_cross_glibc and test_target.target.isGnuLibC() and test_target.link_libc)
    929             continue;
    930 
    931         if (options.skip_libc and test_target.link_libc)
    932             continue;
    933 
    934         if (test_target.link_libc and test_target.target.getOs().requiresLibC()) {
    935             // This would be a redundant test.
    936             continue;
    937         }
    938 
    939         if (options.skip_single_threaded and test_target.single_threaded)
    940             continue;
    941 
    942         if (test_target.disable_native and
    943             test_target.target.getOsTag() == builtin.os.tag and
    944             test_target.target.getCpuArch() == builtin.cpu.arch)
    945         {
    946             continue;
    947         }
    948 
    949         if (test_target.backend) |backend| switch (backend) {
    950             .stage1 => if (options.skip_stage1) continue,
    951             .stage2_llvm => {},
    952             else => if (options.skip_stage2) continue,
    953         };
    954 
    955         const want_this_mode = for (options.optimize_modes) |m| {
    956             if (m == test_target.optimize_mode) break true;
    957         } else false;
    958         if (!want_this_mode) continue;
    959 
    960         const libc_prefix = if (test_target.target.getOs().requiresLibC())
    961             ""
    962         else if (test_target.link_libc)
    963             "c"
    964         else
    965             "bare";
    966 
    967         const triple_prefix = test_target.target.zigTriple(b.allocator) catch @panic("OOM");
    968 
    969         // wasm32-wasi builds need more RAM, idk why
    970         const max_rss = if (test_target.target.getOs().tag == .wasi)
    971             options.max_rss * 2
    972         else
    973             options.max_rss;
    974 
    975         const these_tests = b.addTest(.{
    976             .root_source_file = .{ .path = options.root_src },
    977             .optimize = test_target.optimize_mode,
    978             .target = test_target.target,
    979             .max_rss = max_rss,
    980         });
    981         const single_threaded_txt = if (test_target.single_threaded) "single" else "multi";
    982         const backend_txt = if (test_target.backend) |backend| @tagName(backend) else "default";
    983         these_tests.single_threaded = test_target.single_threaded;
    984         these_tests.setFilter(options.test_filter);
    985         if (test_target.link_libc) {
    986             these_tests.linkSystemLibrary("c");
    987         }
    988         these_tests.overrideZigLibDir("lib");
    989         these_tests.addIncludePath("test");
    990         if (test_target.backend) |backend| switch (backend) {
    991             .stage1 => {
    992                 @panic("stage1 testing requested");
    993             },
    994             .stage2_llvm => {
    995                 these_tests.use_llvm = true;
    996             },
    997             .stage2_c => {
    998                 these_tests.use_llvm = false;
    999             },
   1000             else => {
   1001                 these_tests.use_llvm = false;
   1002                 // TODO: force self-hosted linkers to avoid LLD creeping in
   1003                 // until the auto-select mechanism deems them worthy
   1004                 these_tests.use_lld = false;
   1005             },
   1006         };
   1007 
   1008         const run = b.addRunArtifact(these_tests);
   1009         run.skip_foreign_checks = true;
   1010         run.setName(b.fmt("run test {s}-{s}-{s}-{s}-{s}-{s}", .{
   1011             options.name,
   1012             triple_prefix,
   1013             @tagName(test_target.optimize_mode),
   1014             libc_prefix,
   1015             single_threaded_txt,
   1016             backend_txt,
   1017         }));
   1018 
   1019         step.dependOn(&run.step);
   1020     }
   1021     return step;
   1022 }
   1023 
   1024 pub fn addCAbiTests(b: *std.Build, skip_non_native: bool, skip_release: bool) *Step {
   1025     const step = b.step("test-c-abi", "Run the C ABI tests");
   1026 
   1027     const optimize_modes: [2]OptimizeMode = .{ .Debug, .ReleaseFast };
   1028 
   1029     for (optimize_modes) |optimize_mode| {
   1030         if (optimize_mode != .Debug and skip_release) continue;
   1031 
   1032         for (c_abi_targets) |c_abi_target| {
   1033             if (skip_non_native and !c_abi_target.isNative()) continue;
   1034 
   1035             if (c_abi_target.isWindows() and c_abi_target.getCpuArch() == .aarch64) {
   1036                 // https://github.com/ziglang/zig/issues/14908
   1037                 continue;
   1038             }
   1039 
   1040             const test_step = b.addTest(.{
   1041                 .root_source_file = .{ .path = "test/c_abi/main.zig" },
   1042                 .optimize = optimize_mode,
   1043                 .target = c_abi_target,
   1044             });
   1045             if (c_abi_target.abi != null and c_abi_target.abi.?.isMusl()) {
   1046                 // TODO NativeTargetInfo insists on dynamically linking musl
   1047                 // for some reason?
   1048                 test_step.target_info.dynamic_linker.max_byte = null;
   1049             }
   1050             test_step.linkLibC();
   1051             test_step.addCSourceFile("test/c_abi/cfuncs.c", &.{"-std=c99"});
   1052 
   1053             // test-c-abi should test both with LTO on and with LTO off. Only
   1054             // some combinations are passing currently:
   1055             // https://github.com/ziglang/zig/issues/14908
   1056             if (c_abi_target.isWindows()) {
   1057                 test_step.want_lto = false;
   1058             }
   1059 
   1060             const triple_prefix = c_abi_target.zigTriple(b.allocator) catch @panic("OOM");
   1061             test_step.setName(b.fmt("test-c-abi-{s}-{s} ", .{
   1062                 triple_prefix, @tagName(optimize_mode),
   1063             }));
   1064 
   1065             const run = b.addRunArtifact(test_step);
   1066             run.skip_foreign_checks = true;
   1067             step.dependOn(&run.step);
   1068         }
   1069     }
   1070     return step;
   1071 }
   1072 
   1073 pub fn addCases(
   1074     b: *std.Build,
   1075     parent_step: *Step,
   1076     opt_test_filter: ?[]const u8,
   1077     check_case_exe: *std.Build.CompileStep,
   1078 ) !void {
   1079     const arena = b.allocator;
   1080     const gpa = b.allocator;
   1081 
   1082     var cases = @import("src/Cases.zig").init(gpa, arena);
   1083 
   1084     var dir = try b.build_root.handle.openIterableDir("test/cases", .{});
   1085     defer dir.close();
   1086 
   1087     cases.addFromDir(dir);
   1088     try @import("cases.zig").addCases(&cases);
   1089 
   1090     const cases_dir_path = try b.build_root.join(b.allocator, &.{ "test", "cases" });
   1091     cases.lowerToBuildSteps(
   1092         b,
   1093         parent_step,
   1094         opt_test_filter,
   1095         cases_dir_path,
   1096         check_case_exe,
   1097     );
   1098 }