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 }