| author | |
| committer | |
| log | ede5dcffea5a3a5fc9fd14e4e180464633402fae |
| tree | dcf88812197be81cdb36b747d2b2b55c56d2192b |
| parent | ef5f8bd7c62f929b5cc210caa816ce4a8c8f8538 |
std.Build.addTest creates a CompileStep as before, however, this kind of
step no longer actually runs the unit tests. Instead it only compiles
it, and one must additionally create a RunStep from the CompileStep in
order to actually run the tests.
RunStep gains integration with the default test runner, which now
supports the standard --listen=- argument in order to communicate over
stdin and stdout. It also reports test statistics; how many passed,
failed, and leaked, as well as directly associating the relevant stderr
with the particular test name that failed.
This separation of CompileStep and RunStep means that
`CompileStep.Kind.test_exe` is no longer needed, and therefore has been
removed in this commit.
* build runner: show unit test statistics in build summary
* added Step.writeManifest since many steps want to treat it as a
warning and emit the same message if it fails.
* RunStep: fixed error message that prints the failed command printing
the original argv and not the adjusted argv in case an interpreter
was used.
* RunStep: fixed not passing the command line arguments to the
interpreter.
* move src/Server.zig to std.zig.Server so that the default test runner
can use it.
* the simpler test runner function which is used by work-in-progress
backends now no longer prints to stderr, which is necessary in order
for the build runner to not print the stderr as a warning message.30 files changed, 780 insertions(+), 373 deletions(-)
CMakeLists.txt+1-1| ... | @@ -518,6 +518,7 @@ set(ZIG_STAGE2_SOURCES | ... | @@ -518,6 +518,7 @@ set(ZIG_STAGE2_SOURCES |
| 518 | "${CMAKE_SOURCE_DIR}/lib/std/zig/c_builtins.zig" | 518 | "${CMAKE_SOURCE_DIR}/lib/std/zig/c_builtins.zig" |
| 519 | "${CMAKE_SOURCE_DIR}/lib/std/zig/Parse.zig" | 519 | "${CMAKE_SOURCE_DIR}/lib/std/zig/Parse.zig" |
| 520 | "${CMAKE_SOURCE_DIR}/lib/std/zig/render.zig" | 520 | "${CMAKE_SOURCE_DIR}/lib/std/zig/render.zig" |
| 521 | "${CMAKE_SOURCE_DIR}/lib/std/zig/Server.zig" | ||
| 521 | "${CMAKE_SOURCE_DIR}/lib/std/zig/string_literal.zig" | 522 | "${CMAKE_SOURCE_DIR}/lib/std/zig/string_literal.zig" |
| 522 | "${CMAKE_SOURCE_DIR}/lib/std/zig/system.zig" | 523 | "${CMAKE_SOURCE_DIR}/lib/std/zig/system.zig" |
| 523 | "${CMAKE_SOURCE_DIR}/lib/std/zig/system/NativePaths.zig" | 524 | "${CMAKE_SOURCE_DIR}/lib/std/zig/system/NativePaths.zig" |
| ... | @@ -623,7 +624,6 @@ set(ZIG_STAGE2_SOURCES | ... | @@ -623,7 +624,6 @@ set(ZIG_STAGE2_SOURCES |
| 623 | "${CMAKE_SOURCE_DIR}/src/print_targets.zig" | 624 | "${CMAKE_SOURCE_DIR}/src/print_targets.zig" |
| 624 | "${CMAKE_SOURCE_DIR}/src/print_zir.zig" | 625 | "${CMAKE_SOURCE_DIR}/src/print_zir.zig" |
| 625 | "${CMAKE_SOURCE_DIR}/src/register_manager.zig" | 626 | "${CMAKE_SOURCE_DIR}/src/register_manager.zig" |
| 626 | "${CMAKE_SOURCE_DIR}/src/Server.zig" | ||
| 627 | "${CMAKE_SOURCE_DIR}/src/target.zig" | 627 | "${CMAKE_SOURCE_DIR}/src/target.zig" |
| 628 | "${CMAKE_SOURCE_DIR}/src/tracy.zig" | 628 | "${CMAKE_SOURCE_DIR}/src/tracy.zig" |
| 629 | "${CMAKE_SOURCE_DIR}/src/translate_c.zig" | 629 | "${CMAKE_SOURCE_DIR}/src/translate_c.zig" |
lib/build_runner.zig+57-2| ... | @@ -416,6 +416,12 @@ fn runStepNames( | ... | @@ -416,6 +416,12 @@ fn runStepNames( |
| 416 | } | 416 | } |
| 417 | assert(run.memory_blocked_steps.items.len == 0); | 417 | assert(run.memory_blocked_steps.items.len == 0); |
| 418 | 418 | ||
| 419 | var test_skip_count: usize = 0; | ||
| 420 | var test_fail_count: usize = 0; | ||
| 421 | var test_pass_count: usize = 0; | ||
| 422 | var test_leak_count: usize = 0; | ||
| 423 | var test_count: usize = 0; | ||
| 424 | |||
| 419 | var success_count: usize = 0; | 425 | var success_count: usize = 0; |
| 420 | var skipped_count: usize = 0; | 426 | var skipped_count: usize = 0; |
| 421 | var failure_count: usize = 0; | 427 | var failure_count: usize = 0; |
| ... | @@ -425,6 +431,12 @@ fn runStepNames( | ... | @@ -425,6 +431,12 @@ fn runStepNames( |
| 425 | defer compile_error_steps.deinit(gpa); | 431 | defer compile_error_steps.deinit(gpa); |
| 426 | 432 | ||
| 427 | for (step_stack.keys()) |s| { | 433 | for (step_stack.keys()) |s| { |
| 434 | test_fail_count += s.test_results.fail_count; | ||
| 435 | test_skip_count += s.test_results.skip_count; | ||
| 436 | test_leak_count += s.test_results.leak_count; | ||
| 437 | test_pass_count += s.test_results.passCount(); | ||
| 438 | test_count += s.test_results.test_count; | ||
| 439 | |||
| 428 | switch (s.state) { | 440 | switch (s.state) { |
| 429 | .precheck_unstarted => unreachable, | 441 | .precheck_unstarted => unreachable, |
| 430 | .precheck_started => unreachable, | 442 | .precheck_started => unreachable, |
| ... | @@ -468,6 +480,11 @@ fn runStepNames( | ... | @@ -468,6 +480,11 @@ fn runStepNames( |
| 468 | if (skipped_count > 0) stderr.writer().print("; {d} skipped", .{skipped_count}) catch {}; | 480 | if (skipped_count > 0) stderr.writer().print("; {d} skipped", .{skipped_count}) catch {}; |
| 469 | if (failure_count > 0) stderr.writer().print("; {d} failed", .{failure_count}) catch {}; | 481 | if (failure_count > 0) stderr.writer().print("; {d} failed", .{failure_count}) catch {}; |
| 470 | 482 | ||
| 483 | if (test_count > 0) stderr.writer().print("; {d}/{d} tests passed", .{ test_pass_count, test_count }) catch {}; | ||
| 484 | if (test_skip_count > 0) stderr.writer().print("; {d} skipped", .{test_skip_count}) catch {}; | ||
| 485 | if (test_fail_count > 0) stderr.writer().print("; {d} failed", .{test_fail_count}) catch {}; | ||
| 486 | if (test_leak_count > 0) stderr.writer().print("; {d} leaked", .{test_leak_count}) catch {}; | ||
| 487 | |||
| 471 | if (run.enable_summary == null) { | 488 | if (run.enable_summary == null) { |
| 472 | ttyconf.setColor(stderr, .Dim) catch {}; | 489 | ttyconf.setColor(stderr, .Dim) catch {}; |
| 473 | stderr.writeAll(" (disable with -fno-summary)") catch {}; | 490 | stderr.writeAll(" (disable with -fno-summary)") catch {}; |
| ... | @@ -566,6 +583,13 @@ fn printTreeStep( | ... | @@ -566,6 +583,13 @@ fn printTreeStep( |
| 566 | try ttyconf.setColor(stderr, .Green); | 583 | try ttyconf.setColor(stderr, .Green); |
| 567 | if (s.result_cached) { | 584 | if (s.result_cached) { |
| 568 | try stderr.writeAll(" cached"); | 585 | try stderr.writeAll(" cached"); |
| 586 | } else if (s.test_results.test_count > 0) { | ||
| 587 | const pass_count = s.test_results.passCount(); | ||
| 588 | try stderr.writer().print(" {d} passed", .{pass_count}); | ||
| 589 | if (s.test_results.skip_count > 0) { | ||
| 590 | try ttyconf.setColor(stderr, .Yellow); | ||
| 591 | try stderr.writer().print(" {d} skipped", .{s.test_results.skip_count}); | ||
| 592 | } | ||
| 569 | } else { | 593 | } else { |
| 570 | try stderr.writeAll(" success"); | 594 | try stderr.writeAll(" success"); |
| 571 | } | 595 | } |
| ... | @@ -609,15 +633,46 @@ fn printTreeStep( | ... | @@ -609,15 +633,46 @@ fn printTreeStep( |
| 609 | }, | 633 | }, |
| 610 | 634 | ||
| 611 | .failure => { | 635 | .failure => { |
| 612 | try ttyconf.setColor(stderr, .Red); | ||
| 613 | if (s.result_error_bundle.errorMessageCount() > 0) { | 636 | if (s.result_error_bundle.errorMessageCount() > 0) { |
| 637 | try ttyconf.setColor(stderr, .Red); | ||
| 614 | try stderr.writer().print(" {d} errors\n", .{ | 638 | try stderr.writer().print(" {d} errors\n", .{ |
| 615 | s.result_error_bundle.errorMessageCount(), | 639 | s.result_error_bundle.errorMessageCount(), |
| 616 | }); | 640 | }); |
| 641 | try ttyconf.setColor(stderr, .Reset); | ||
| 642 | } else if (!s.test_results.isSuccess()) { | ||
| 643 | try stderr.writer().print(" {d}/{d} passed", .{ | ||
| 644 | s.test_results.passCount(), s.test_results.test_count, | ||
| 645 | }); | ||
| 646 | if (s.test_results.fail_count > 0) { | ||
| 647 | try stderr.writeAll(", "); | ||
| 648 | try ttyconf.setColor(stderr, .Red); | ||
| 649 | try stderr.writer().print("{d} failed", .{ | ||
| 650 | s.test_results.fail_count, | ||
| 651 | }); | ||
| 652 | try ttyconf.setColor(stderr, .Reset); | ||
| 653 | } | ||
| 654 | if (s.test_results.skip_count > 0) { | ||
| 655 | try stderr.writeAll(", "); | ||
| 656 | try ttyconf.setColor(stderr, .Yellow); | ||
| 657 | try stderr.writer().print("{d} skipped", .{ | ||
| 658 | s.test_results.skip_count, | ||
| 659 | }); | ||
| 660 | try ttyconf.setColor(stderr, .Reset); | ||
| 661 | } | ||
| 662 | if (s.test_results.leak_count > 0) { | ||
| 663 | try stderr.writeAll(", "); | ||
| 664 | try ttyconf.setColor(stderr, .Red); | ||
| 665 | try stderr.writer().print("{d} leaked", .{ | ||
| 666 | s.test_results.leak_count, | ||
| 667 | }); | ||
| 668 | try ttyconf.setColor(stderr, .Reset); | ||
| 669 | } | ||
| 670 | try stderr.writeAll("\n"); | ||
| 617 | } else { | 671 | } else { |
| 672 | try ttyconf.setColor(stderr, .Red); | ||
| 618 | try stderr.writeAll(" failure\n"); | 673 | try stderr.writeAll(" failure\n"); |
| 674 | try ttyconf.setColor(stderr, .Reset); | ||
| 619 | } | 675 | } |
| 620 | try ttyconf.setColor(stderr, .Reset); | ||
| 621 | }, | 676 | }, |
| 622 | } | 677 | } |
| 623 | 678 |
lib/std/Build.zig+4-6| ... | @@ -531,7 +531,6 @@ pub fn addStaticLibrary(b: *Build, options: StaticLibraryOptions) *CompileStep { | ... | @@ -531,7 +531,6 @@ pub fn addStaticLibrary(b: *Build, options: StaticLibraryOptions) *CompileStep { |
| 531 | 531 | ||
| 532 | pub const TestOptions = struct { | 532 | pub const TestOptions = struct { |
| 533 | name: []const u8 = "test", | 533 | name: []const u8 = "test", |
| 534 | kind: CompileStep.Kind = .@"test", | ||
| 535 | root_source_file: FileSource, | 534 | root_source_file: FileSource, |
| 536 | target: CrossTarget = .{}, | 535 | target: CrossTarget = .{}, |
| 537 | optimize: std.builtin.Mode = .Debug, | 536 | optimize: std.builtin.Mode = .Debug, |
| ... | @@ -542,7 +541,7 @@ pub const TestOptions = struct { | ... | @@ -542,7 +541,7 @@ pub const TestOptions = struct { |
| 542 | pub fn addTest(b: *Build, options: TestOptions) *CompileStep { | 541 | pub fn addTest(b: *Build, options: TestOptions) *CompileStep { |
| 543 | return CompileStep.create(b, .{ | 542 | return CompileStep.create(b, .{ |
| 544 | .name = options.name, | 543 | .name = options.name, |
| 545 | .kind = options.kind, | 544 | .kind = .@"test", |
| 546 | .root_source_file = options.root_source_file, | 545 | .root_source_file = options.root_source_file, |
| 547 | .target = options.target, | 546 | .target = options.target, |
| 548 | .optimize = options.optimize, | 547 | .optimize = options.optimize, |
| ... | @@ -626,16 +625,15 @@ pub fn addSystemCommand(self: *Build, argv: []const []const u8) *RunStep { | ... | @@ -626,16 +625,15 @@ pub fn addSystemCommand(self: *Build, argv: []const []const u8) *RunStep { |
| 626 | /// Creates a `RunStep` with an executable built with `addExecutable`. | 625 | /// Creates a `RunStep` with an executable built with `addExecutable`. |
| 627 | /// Add command line arguments with methods of `RunStep`. | 626 | /// Add command line arguments with methods of `RunStep`. |
| 628 | pub fn addRunArtifact(b: *Build, exe: *CompileStep) *RunStep { | 627 | pub fn addRunArtifact(b: *Build, exe: *CompileStep) *RunStep { |
| 629 | assert(exe.kind == .exe or exe.kind == .test_exe); | ||
| 630 | |||
| 631 | // It doesn't have to be native. We catch that if you actually try to run it. | 628 | // It doesn't have to be native. We catch that if you actually try to run it. |
| 632 | // Consider that this is declarative; the run step may not be run unless a user | 629 | // Consider that this is declarative; the run step may not be run unless a user |
| 633 | // option is supplied. | 630 | // option is supplied. |
| 634 | const run_step = RunStep.create(b, b.fmt("run {s}", .{exe.name})); | 631 | const run_step = RunStep.create(b, b.fmt("run {s}", .{exe.name})); |
| 635 | run_step.addArtifactArg(exe); | 632 | run_step.addArtifactArg(exe); |
| 636 | 633 | ||
| 637 | if (exe.kind == .test_exe) { | 634 | if (exe.kind == .@"test") { |
| 638 | run_step.addArg(b.zig_exe); | 635 | run_step.stdio = .zig_test; |
| 636 | run_step.addArgs(&.{"--listen=-"}); | ||
| 639 | } | 637 | } |
| 640 | 638 | ||
| 641 | if (exe.vcpkg_bin_path) |path| { | 639 | if (exe.vcpkg_bin_path) |path| { |
lib/std/Build/CompileStep.zig+7-86| ... | @@ -289,7 +289,6 @@ pub const Kind = enum { | ... | @@ -289,7 +289,6 @@ pub const Kind = enum { |
| 289 | lib, | 289 | lib, |
| 290 | obj, | 290 | obj, |
| 291 | @"test", | 291 | @"test", |
| 292 | test_exe, | ||
| 293 | }; | 292 | }; |
| 294 | 293 | ||
| 295 | pub const Linkage = enum { dynamic, static }; | 294 | pub const Linkage = enum { dynamic, static }; |
| ... | @@ -328,7 +327,7 @@ pub fn create(owner: *std.Build, options: Options) *CompileStep { | ... | @@ -328,7 +327,7 @@ pub fn create(owner: *std.Build, options: Options) *CompileStep { |
| 328 | .exe => "zig build-exe", | 327 | .exe => "zig build-exe", |
| 329 | .lib => "zig build-lib", | 328 | .lib => "zig build-lib", |
| 330 | .obj => "zig build-obj", | 329 | .obj => "zig build-obj", |
| 331 | .test_exe, .@"test" => "zig test", | 330 | .@"test" => "zig test", |
| 332 | }, | 331 | }, |
| 333 | name_adjusted, | 332 | name_adjusted, |
| 334 | @tagName(options.optimize), | 333 | @tagName(options.optimize), |
| ... | @@ -410,7 +409,7 @@ fn computeOutFileNames(self: *CompileStep) void { | ... | @@ -410,7 +409,7 @@ fn computeOutFileNames(self: *CompileStep) void { |
| 410 | .output_mode = switch (self.kind) { | 409 | .output_mode = switch (self.kind) { |
| 411 | .lib => .Lib, | 410 | .lib => .Lib, |
| 412 | .obj => .Obj, | 411 | .obj => .Obj, |
| 413 | .exe, .@"test", .test_exe => .Exe, | 412 | .exe, .@"test" => .Exe, |
| 414 | }, | 413 | }, |
| 415 | .link_mode = if (self.linkage) |some| @as(std.builtin.LinkMode, switch (some) { | 414 | .link_mode = if (self.linkage) |some| @as(std.builtin.LinkMode, switch (some) { |
| 416 | .dynamic => .Dynamic, | 415 | .dynamic => .Dynamic, |
| ... | @@ -621,7 +620,7 @@ pub fn producesPdbFile(self: *CompileStep) bool { | ... | @@ -621,7 +620,7 @@ pub fn producesPdbFile(self: *CompileStep) bool { |
| 621 | if (!self.target.isWindows() and !self.target.isUefi()) return false; | 620 | if (!self.target.isWindows() and !self.target.isUefi()) return false; |
| 622 | if (self.target.getObjectFormat() == .c) return false; | 621 | if (self.target.getObjectFormat() == .c) return false; |
| 623 | if (self.strip == true) return false; | 622 | if (self.strip == true) return false; |
| 624 | return self.isDynamicLibrary() or self.kind == .exe or self.kind == .test_exe; | 623 | return self.isDynamicLibrary() or self.kind == .exe or self.kind == .@"test"; |
| 625 | } | 624 | } |
| 626 | 625 | ||
| 627 | pub fn linkLibC(self: *CompileStep) void { | 626 | pub fn linkLibC(self: *CompileStep) void { |
| ... | @@ -850,19 +849,19 @@ fn linkSystemLibraryInner(self: *CompileStep, name: []const u8, opts: struct { | ... | @@ -850,19 +849,19 @@ fn linkSystemLibraryInner(self: *CompileStep, name: []const u8, opts: struct { |
| 850 | 849 | ||
| 851 | pub fn setNamePrefix(self: *CompileStep, text: []const u8) void { | 850 | pub fn setNamePrefix(self: *CompileStep, text: []const u8) void { |
| 852 | const b = self.step.owner; | 851 | const b = self.step.owner; |
| 853 | assert(self.kind == .@"test" or self.kind == .test_exe); | 852 | assert(self.kind == .@"test"); |
| 854 | self.name_prefix = b.dupe(text); | 853 | self.name_prefix = b.dupe(text); |
| 855 | } | 854 | } |
| 856 | 855 | ||
| 857 | pub fn setFilter(self: *CompileStep, text: ?[]const u8) void { | 856 | pub fn setFilter(self: *CompileStep, text: ?[]const u8) void { |
| 858 | const b = self.step.owner; | 857 | const b = self.step.owner; |
| 859 | assert(self.kind == .@"test" or self.kind == .test_exe); | 858 | assert(self.kind == .@"test"); |
| 860 | self.filter = if (text) |t| b.dupe(t) else null; | 859 | self.filter = if (text) |t| b.dupe(t) else null; |
| 861 | } | 860 | } |
| 862 | 861 | ||
| 863 | pub fn setTestRunner(self: *CompileStep, path: ?[]const u8) void { | 862 | pub fn setTestRunner(self: *CompileStep, path: ?[]const u8) void { |
| 864 | const b = self.step.owner; | 863 | const b = self.step.owner; |
| 865 | assert(self.kind == .@"test" or self.kind == .test_exe); | 864 | assert(self.kind == .@"test"); |
| 866 | self.test_runner = if (path) |p| b.dupePath(p) else null; | 865 | self.test_runner = if (path) |p| b.dupePath(p) else null; |
| 867 | } | 866 | } |
| 868 | 867 | ||
| ... | @@ -938,7 +937,7 @@ pub fn getOutputLibSource(self: *CompileStep) FileSource { | ... | @@ -938,7 +937,7 @@ pub fn getOutputLibSource(self: *CompileStep) FileSource { |
| 938 | /// Returns the generated header file. | 937 | /// Returns the generated header file. |
| 939 | /// This function can only be called for libraries or object files which have `emit_h` set. | 938 | /// This function can only be called for libraries or object files which have `emit_h` set. |
| 940 | pub fn getOutputHSource(self: *CompileStep) FileSource { | 939 | pub fn getOutputHSource(self: *CompileStep) FileSource { |
| 941 | assert(self.kind != .exe and self.kind != .test_exe and self.kind != .@"test"); | 940 | assert(self.kind != .exe and self.kind != .@"test"); |
| 942 | assert(self.emit_h); | 941 | assert(self.emit_h); |
| 943 | return .{ .generated = &self.output_h_path_source }; | 942 | return .{ .generated = &self.output_h_path_source }; |
| 944 | } | 943 | } |
| ... | @@ -1243,7 +1242,6 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { | ... | @@ -1243,7 +1242,6 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 1243 | .exe => "build-exe", | 1242 | .exe => "build-exe", |
| 1244 | .obj => "build-obj", | 1243 | .obj => "build-obj", |
| 1245 | .@"test" => "test", | 1244 | .@"test" => "test", |
| 1246 | .test_exe => "test", | ||
| 1247 | }; | 1245 | }; |
| 1248 | try zig_args.append(cmd); | 1246 | try zig_args.append(cmd); |
| 1249 | 1247 | ||
| ... | @@ -1293,7 +1291,6 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { | ... | @@ -1293,7 +1291,6 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 1293 | 1291 | ||
| 1294 | .other_step => |other| switch (other.kind) { | 1292 | .other_step => |other| switch (other.kind) { |
| 1295 | .exe => @panic("Cannot link with an executable build artifact"), | 1293 | .exe => @panic("Cannot link with an executable build artifact"), |
| 1296 | .test_exe => @panic("Cannot link with an executable build artifact"), | ||
| 1297 | .@"test" => @panic("Cannot link with a test"), | 1294 | .@"test" => @panic("Cannot link with a test"), |
| 1298 | .obj => { | 1295 | .obj => { |
| 1299 | try zig_args.append(other.getOutputSource().getPath(b)); | 1296 | try zig_args.append(other.getOutputSource().getPath(b)); |
| ... | @@ -1661,83 +1658,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { | ... | @@ -1661,83 +1658,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 1661 | try zig_args.append("--test-cmd-bin"); | 1658 | try zig_args.append("--test-cmd-bin"); |
| 1662 | } | 1659 | } |
| 1663 | } | 1660 | } |
| 1664 | } else { | ||
| 1665 | const need_cross_glibc = self.target.isGnuLibC() and transitive_deps.is_linking_libc; | ||
| 1666 | |||
| 1667 | switch (b.host.getExternalExecutor(self.target_info, .{ | ||
| 1668 | .qemu_fixes_dl = need_cross_glibc and b.glibc_runtimes_dir != null, | ||
| 1669 | .link_libc = transitive_deps.is_linking_libc, | ||
| 1670 | })) { | ||
| 1671 | .native => {}, | ||
| 1672 | .bad_dl, .bad_os_or_cpu => { | ||
| 1673 | try zig_args.append("--test-no-exec"); | ||
| 1674 | }, | ||
| 1675 | .rosetta => if (b.enable_rosetta) { | ||
| 1676 | try zig_args.append("--test-cmd-bin"); | ||
| 1677 | } else { | ||
| 1678 | try zig_args.append("--test-no-exec"); | ||
| 1679 | }, | ||
| 1680 | .qemu => |bin_name| ok: { | ||
| 1681 | if (b.enable_qemu) qemu: { | ||
| 1682 | const glibc_dir_arg = if (need_cross_glibc) | ||
| 1683 | b.glibc_runtimes_dir orelse break :qemu | ||
| 1684 | else | ||
| 1685 | null; | ||
| 1686 | try zig_args.append("--test-cmd"); | ||
| 1687 | try zig_args.append(bin_name); | ||
| 1688 | if (glibc_dir_arg) |dir| { | ||
| 1689 | // TODO look into making this a call to `linuxTriple`. This | ||
| 1690 | // needs the directory to be called "i686" rather than | ||
| 1691 | // "x86" which is why we do it manually here. | ||
| 1692 | const fmt_str = "{s}" ++ fs.path.sep_str ++ "{s}-{s}-{s}"; | ||
| 1693 | const cpu_arch = self.target.getCpuArch(); | ||
| 1694 | const os_tag = self.target.getOsTag(); | ||
| 1695 | const abi = self.target.getAbi(); | ||
| 1696 | const cpu_arch_name: []const u8 = if (cpu_arch == .x86) | ||
| 1697 | "i686" | ||
| 1698 | else | ||
| 1699 | @tagName(cpu_arch); | ||
| 1700 | const full_dir = try std.fmt.allocPrint(b.allocator, fmt_str, .{ | ||
| 1701 | dir, cpu_arch_name, @tagName(os_tag), @tagName(abi), | ||
| 1702 | }); | ||
| 1703 | |||
| 1704 | try zig_args.append("--test-cmd"); | ||
| 1705 | try zig_args.append("-L"); | ||
| 1706 | try zig_args.append("--test-cmd"); | ||
| 1707 | try zig_args.append(full_dir); | ||
| 1708 | } | ||
| 1709 | try zig_args.append("--test-cmd-bin"); | ||
| 1710 | break :ok; | ||
| 1711 | } | ||
| 1712 | try zig_args.append("--test-no-exec"); | ||
| 1713 | }, | ||
| 1714 | .wine => |bin_name| if (b.enable_wine) { | ||
| 1715 | try zig_args.append("--test-cmd"); | ||
| 1716 | try zig_args.append(bin_name); | ||
| 1717 | try zig_args.append("--test-cmd-bin"); | ||
| 1718 | } else { | ||
| 1719 | try zig_args.append("--test-no-exec"); | ||
| 1720 | }, | ||
| 1721 | .wasmtime => |bin_name| if (b.enable_wasmtime) { | ||
| 1722 | try zig_args.append("--test-cmd"); | ||
| 1723 | try zig_args.append(bin_name); | ||
| 1724 | try zig_args.append("--test-cmd"); | ||
| 1725 | try zig_args.append("--dir=."); | ||
| 1726 | try zig_args.append("--test-cmd-bin"); | ||
| 1727 | } else { | ||
| 1728 | try zig_args.append("--test-no-exec"); | ||
| 1729 | }, | ||
| 1730 | .darling => |bin_name| if (b.enable_darling) { | ||
| 1731 | try zig_args.append("--test-cmd"); | ||
| 1732 | try zig_args.append(bin_name); | ||
| 1733 | try zig_args.append("--test-cmd-bin"); | ||
| 1734 | } else { | ||
| 1735 | try zig_args.append("--test-no-exec"); | ||
| 1736 | }, | ||
| 1737 | } | ||
| 1738 | } | 1661 | } |
| 1739 | } else if (self.kind == .test_exe) { | ||
| 1740 | try zig_args.append("--test-no-exec"); | ||
| 1741 | } | 1662 | } |
| 1742 | 1663 | ||
| 1743 | try self.appendModuleArgs(&zig_args); | 1664 | try self.appendModuleArgs(&zig_args); |
lib/std/Build/InstallArtifactStep.zig+2-3| ... | @@ -32,12 +32,11 @@ pub fn create(owner: *std.Build, artifact: *CompileStep) *InstallArtifactStep { | ... | @@ -32,12 +32,11 @@ pub fn create(owner: *std.Build, artifact: *CompileStep) *InstallArtifactStep { |
| 32 | .artifact = artifact, | 32 | .artifact = artifact, |
| 33 | .dest_dir = artifact.override_dest_dir orelse switch (artifact.kind) { | 33 | .dest_dir = artifact.override_dest_dir orelse switch (artifact.kind) { |
| 34 | .obj => @panic("Cannot install a .obj build artifact."), | 34 | .obj => @panic("Cannot install a .obj build artifact."), |
| 35 | .@"test" => @panic("Cannot install a .test build artifact, use .test_exe instead."), | 35 | .exe, .@"test" => InstallDir{ .bin = {} }, |
| 36 | .exe, .test_exe => InstallDir{ .bin = {} }, | ||
| 37 | .lib => InstallDir{ .lib = {} }, | 36 | .lib => InstallDir{ .lib = {} }, |
| 38 | }, | 37 | }, |
| 39 | .pdb_dir = if (artifact.producesPdbFile()) blk: { | 38 | .pdb_dir = if (artifact.producesPdbFile()) blk: { |
| 40 | if (artifact.kind == .exe or artifact.kind == .test_exe) { | 39 | if (artifact.kind == .exe or artifact.kind == .@"test") { |
| 41 | break :blk InstallDir{ .bin = {} }; | 40 | break :blk InstallDir{ .bin = {} }; |
| 42 | } else { | 41 | } else { |
| 43 | break :blk InstallDir{ .lib = {} }; | 42 | break :blk InstallDir{ .lib = {} }; |
lib/std/Build/RunStep.zig+296-59| ... | @@ -92,6 +92,9 @@ pub const StdIo = union(enum) { | ... | @@ -92,6 +92,9 @@ pub const StdIo = union(enum) { |
| 92 | /// Note that an explicit check for exit code 0 needs to be added to this | 92 | /// Note that an explicit check for exit code 0 needs to be added to this |
| 93 | /// list if such a check is desireable. | 93 | /// list if such a check is desireable. |
| 94 | check: std.ArrayList(Check), | 94 | check: std.ArrayList(Check), |
| 95 | /// This RunStep is running a zig unit test binary and will communicate | ||
| 96 | /// extra metadata over the IPC protocol. | ||
| 97 | zig_test, | ||
| 95 | 98 | ||
| 96 | pub const Check = union(enum) { | 99 | pub const Check = union(enum) { |
| 97 | expect_stderr_exact: []const u8, | 100 | expect_stderr_exact: []const u8, |
| ... | @@ -324,6 +327,7 @@ fn hasSideEffects(self: RunStep) bool { | ... | @@ -324,6 +327,7 @@ fn hasSideEffects(self: RunStep) bool { |
| 324 | .infer_from_args => !self.hasAnyOutputArgs(), | 327 | .infer_from_args => !self.hasAnyOutputArgs(), |
| 325 | .inherit => true, | 328 | .inherit => true, |
| 326 | .check => false, | 329 | .check => false, |
| 330 | .zig_test => false, | ||
| 327 | }; | 331 | }; |
| 328 | } | 332 | } |
| 329 | 333 | ||
| ... | @@ -366,11 +370,6 @@ fn checksContainStderr(checks: []const StdIo.Check) bool { | ... | @@ -366,11 +370,6 @@ fn checksContainStderr(checks: []const StdIo.Check) bool { |
| 366 | } | 370 | } |
| 367 | 371 | ||
| 368 | fn make(step: *Step, prog_node: *std.Progress.Node) !void { | 372 | fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 369 | // Unfortunately we have no way to collect progress from arbitrary programs. | ||
| 370 | // Perhaps in the future Zig could offer some kind of opt-in IPC mechanism that | ||
| 371 | // processes could use to supply progress updates. | ||
| 372 | _ = prog_node; | ||
| 373 | |||
| 374 | const b = step.owner; | 373 | const b = step.owner; |
| 375 | const arena = b.allocator; | 374 | const arena = b.allocator; |
| 376 | const self = @fieldParentPtr(RunStep, "step", step); | 375 | const self = @fieldParentPtr(RunStep, "step", step); |
| ... | @@ -439,7 +438,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { | ... | @@ -439,7 +438,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 439 | hashStdIo(&man.hash, self.stdio); | 438 | hashStdIo(&man.hash, self.stdio); |
| 440 | 439 | ||
| 441 | if (has_side_effects) { | 440 | if (has_side_effects) { |
| 442 | try runCommand(self, argv_list.items, has_side_effects, null); | 441 | try runCommand(self, argv_list.items, has_side_effects, null, prog_node); |
| 443 | return; | 442 | return; |
| 444 | } | 443 | } |
| 445 | 444 | ||
| ... | @@ -492,8 +491,9 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { | ... | @@ -492,8 +491,9 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 492 | argv_list.items[placeholder.index] = cli_arg; | 491 | argv_list.items[placeholder.index] = cli_arg; |
| 493 | } | 492 | } |
| 494 | 493 | ||
| 495 | try runCommand(self, argv_list.items, has_side_effects, &digest); | 494 | try runCommand(self, argv_list.items, has_side_effects, &digest, prog_node); |
| 496 | try man.writeManifest(); | 495 | |
| 496 | try step.writeManifest(&man); | ||
| 497 | } | 497 | } |
| 498 | 498 | ||
| 499 | fn formatTerm( | 499 | fn formatTerm( |
| ... | @@ -546,6 +546,7 @@ fn runCommand( | ... | @@ -546,6 +546,7 @@ fn runCommand( |
| 546 | argv: []const []const u8, | 546 | argv: []const []const u8, |
| 547 | has_side_effects: bool, | 547 | has_side_effects: bool, |
| 548 | digest: ?*const [std.Build.Cache.hex_digest_len]u8, | 548 | digest: ?*const [std.Build.Cache.hex_digest_len]u8, |
| 549 | prog_node: *std.Progress.Node, | ||
| 549 | ) !void { | 550 | ) !void { |
| 550 | const step = &self.step; | 551 | const step = &self.step; |
| 551 | const b = step.owner; | 552 | const b = step.owner; |
| ... | @@ -554,7 +555,15 @@ fn runCommand( | ... | @@ -554,7 +555,15 @@ fn runCommand( |
| 554 | try step.handleChildProcUnsupported(self.cwd, argv); | 555 | try step.handleChildProcUnsupported(self.cwd, argv); |
| 555 | try Step.handleVerbose(step.owner, self.cwd, argv); | 556 | try Step.handleVerbose(step.owner, self.cwd, argv); |
| 556 | 557 | ||
| 557 | const result = spawnChildAndCollect(self, argv, has_side_effects) catch |err| term: { | 558 | const allow_skip = switch (self.stdio) { |
| 559 | .check, .zig_test => self.skip_foreign_checks, | ||
| 560 | else => false, | ||
| 561 | }; | ||
| 562 | |||
| 563 | var interp_argv = std.ArrayList([]const u8).init(b.allocator); | ||
| 564 | defer interp_argv.deinit(); | ||
| 565 | |||
| 566 | const result = spawnChildAndCollect(self, argv, has_side_effects, prog_node) catch |err| term: { | ||
| 558 | // InvalidExe: cpu arch mismatch | 567 | // InvalidExe: cpu arch mismatch |
| 559 | // FileNotFound: can happen with a wrong dynamic linker path | 568 | // FileNotFound: can happen with a wrong dynamic linker path |
| 560 | if (err == error.InvalidExe or err == error.FileNotFound) interpret: { | 569 | if (err == error.InvalidExe or err == error.FileNotFound) interpret: { |
| ... | @@ -566,10 +575,10 @@ fn runCommand( | ... | @@ -566,10 +575,10 @@ fn runCommand( |
| 566 | .artifact => |exe| exe, | 575 | .artifact => |exe| exe, |
| 567 | else => break :interpret, | 576 | else => break :interpret, |
| 568 | }; | 577 | }; |
| 569 | if (exe.kind != .exe) break :interpret; | 578 | switch (exe.kind) { |
| 570 | 579 | .exe, .@"test" => {}, | |
| 571 | var interp_argv = std.ArrayList([]const u8).init(b.allocator); | 580 | else => break :interpret, |
| 572 | defer interp_argv.deinit(); | 581 | } |
| 573 | 582 | ||
| 574 | const need_cross_glibc = exe.target.isGnuLibC() and exe.is_linking_libc; | 583 | const need_cross_glibc = exe.target.isGnuLibC() and exe.is_linking_libc; |
| 575 | switch (b.host.getExternalExecutor(exe.target_info, .{ | 584 | switch (b.host.getExternalExecutor(exe.target_info, .{ |
| ... | @@ -577,14 +586,13 @@ fn runCommand( | ... | @@ -577,14 +586,13 @@ fn runCommand( |
| 577 | .link_libc = exe.is_linking_libc, | 586 | .link_libc = exe.is_linking_libc, |
| 578 | })) { | 587 | })) { |
| 579 | .native, .rosetta => { | 588 | .native, .rosetta => { |
| 580 | if (self.stdio == .check and self.skip_foreign_checks) | 589 | if (allow_skip) return error.MakeSkipped; |
| 581 | return error.MakeSkipped; | ||
| 582 | |||
| 583 | break :interpret; | 590 | break :interpret; |
| 584 | }, | 591 | }, |
| 585 | .wine => |bin_name| { | 592 | .wine => |bin_name| { |
| 586 | if (b.enable_wine) { | 593 | if (b.enable_wine) { |
| 587 | try interp_argv.append(bin_name); | 594 | try interp_argv.append(bin_name); |
| 595 | try interp_argv.appendSlice(argv); | ||
| 588 | } else { | 596 | } else { |
| 589 | return failForeign(self, "-fwine", argv[0], exe); | 597 | return failForeign(self, "-fwine", argv[0], exe); |
| 590 | } | 598 | } |
| ... | @@ -617,6 +625,8 @@ fn runCommand( | ... | @@ -617,6 +625,8 @@ fn runCommand( |
| 617 | try interp_argv.append("-L"); | 625 | try interp_argv.append("-L"); |
| 618 | try interp_argv.append(full_dir); | 626 | try interp_argv.append(full_dir); |
| 619 | } | 627 | } |
| 628 | |||
| 629 | try interp_argv.appendSlice(argv); | ||
| 620 | } else { | 630 | } else { |
| 621 | return failForeign(self, "-fqemu", argv[0], exe); | 631 | return failForeign(self, "-fqemu", argv[0], exe); |
| 622 | } | 632 | } |
| ... | @@ -624,6 +634,7 @@ fn runCommand( | ... | @@ -624,6 +634,7 @@ fn runCommand( |
| 624 | .darling => |bin_name| { | 634 | .darling => |bin_name| { |
| 625 | if (b.enable_darling) { | 635 | if (b.enable_darling) { |
| 626 | try interp_argv.append(bin_name); | 636 | try interp_argv.append(bin_name); |
| 637 | try interp_argv.appendSlice(argv); | ||
| 627 | } else { | 638 | } else { |
| 628 | return failForeign(self, "-fdarling", argv[0], exe); | 639 | return failForeign(self, "-fdarling", argv[0], exe); |
| 629 | } | 640 | } |
| ... | @@ -632,13 +643,15 @@ fn runCommand( | ... | @@ -632,13 +643,15 @@ fn runCommand( |
| 632 | if (b.enable_wasmtime) { | 643 | if (b.enable_wasmtime) { |
| 633 | try interp_argv.append(bin_name); | 644 | try interp_argv.append(bin_name); |
| 634 | try interp_argv.append("--dir=."); | 645 | try interp_argv.append("--dir=."); |
| 646 | try interp_argv.append(argv[0]); | ||
| 647 | try interp_argv.append("--"); | ||
| 648 | try interp_argv.appendSlice(argv[1..]); | ||
| 635 | } else { | 649 | } else { |
| 636 | return failForeign(self, "-fwasmtime", argv[0], exe); | 650 | return failForeign(self, "-fwasmtime", argv[0], exe); |
| 637 | } | 651 | } |
| 638 | }, | 652 | }, |
| 639 | .bad_dl => |foreign_dl| { | 653 | .bad_dl => |foreign_dl| { |
| 640 | if (self.stdio == .check and self.skip_foreign_checks) | 654 | if (allow_skip) return error.MakeSkipped; |
| 641 | return error.MakeSkipped; | ||
| 642 | 655 | ||
| 643 | const host_dl = b.host.dynamic_linker.get() orelse "(none)"; | 656 | const host_dl = b.host.dynamic_linker.get() orelse "(none)"; |
| 644 | 657 | ||
| ... | @@ -650,8 +663,7 @@ fn runCommand( | ... | @@ -650,8 +663,7 @@ fn runCommand( |
| 650 | , .{ host_dl, foreign_dl }); | 663 | , .{ host_dl, foreign_dl }); |
| 651 | }, | 664 | }, |
| 652 | .bad_os_or_cpu => { | 665 | .bad_os_or_cpu => { |
| 653 | if (self.stdio == .check and self.skip_foreign_checks) | 666 | if (allow_skip) return error.MakeSkipped; |
| 654 | return error.MakeSkipped; | ||
| 655 | 667 | ||
| 656 | const host_name = try b.host.target.zigTriple(b.allocator); | 668 | const host_name = try b.host.target.zigTriple(b.allocator); |
| 657 | const foreign_name = try exe.target.zigTriple(b.allocator); | 669 | const foreign_name = try exe.target.zigTriple(b.allocator); |
| ... | @@ -667,11 +679,9 @@ fn runCommand( | ... | @@ -667,11 +679,9 @@ fn runCommand( |
| 667 | RunStep.addPathForDynLibsInternal(&self.step, b, exe); | 679 | RunStep.addPathForDynLibsInternal(&self.step, b, exe); |
| 668 | } | 680 | } |
| 669 | 681 | ||
| 670 | try interp_argv.append(argv[0]); | ||
| 671 | |||
| 672 | try Step.handleVerbose(step.owner, self.cwd, interp_argv.items); | 682 | try Step.handleVerbose(step.owner, self.cwd, interp_argv.items); |
| 673 | 683 | ||
| 674 | break :term spawnChildAndCollect(self, interp_argv.items, has_side_effects) catch |e| { | 684 | break :term spawnChildAndCollect(self, interp_argv.items, has_side_effects, prog_node) catch |e| { |
| 675 | return step.fail("unable to spawn {s}: {s}", .{ | 685 | return step.fail("unable to spawn {s}: {s}", .{ |
| 676 | interp_argv.items[0], @errorName(e), | 686 | interp_argv.items[0], @errorName(e), |
| 677 | }); | 687 | }); |
| ... | @@ -683,6 +693,7 @@ fn runCommand( | ... | @@ -683,6 +693,7 @@ fn runCommand( |
| 683 | 693 | ||
| 684 | step.result_duration_ns = result.elapsed_ns; | 694 | step.result_duration_ns = result.elapsed_ns; |
| 685 | step.result_peak_rss = result.peak_rss; | 695 | step.result_peak_rss = result.peak_rss; |
| 696 | step.test_results = result.stdio.test_results; | ||
| 686 | 697 | ||
| 687 | // Capture stdout and stderr to GeneratedFile objects. | 698 | // Capture stdout and stderr to GeneratedFile objects. |
| 688 | const Stream = struct { | 699 | const Stream = struct { |
| ... | @@ -693,13 +704,13 @@ fn runCommand( | ... | @@ -693,13 +704,13 @@ fn runCommand( |
| 693 | for ([_]Stream{ | 704 | for ([_]Stream{ |
| 694 | .{ | 705 | .{ |
| 695 | .captured = self.captured_stdout, | 706 | .captured = self.captured_stdout, |
| 696 | .is_null = result.stdout_null, | 707 | .is_null = result.stdio.stdout_null, |
| 697 | .bytes = result.stdout, | 708 | .bytes = result.stdio.stdout, |
| 698 | }, | 709 | }, |
| 699 | .{ | 710 | .{ |
| 700 | .captured = self.captured_stderr, | 711 | .captured = self.captured_stderr, |
| 701 | .is_null = result.stderr_null, | 712 | .is_null = result.stdio.stderr_null, |
| 702 | .bytes = result.stderr, | 713 | .bytes = result.stdio.stderr, |
| 703 | }, | 714 | }, |
| 704 | }) |stream| { | 715 | }) |stream| { |
| 705 | if (stream.captured) |output| { | 716 | if (stream.captured) |output| { |
| ... | @@ -724,11 +735,13 @@ fn runCommand( | ... | @@ -724,11 +735,13 @@ fn runCommand( |
| 724 | } | 735 | } |
| 725 | } | 736 | } |
| 726 | 737 | ||
| 738 | const final_argv = if (interp_argv.items.len == 0) argv else interp_argv.items; | ||
| 739 | |||
| 727 | switch (self.stdio) { | 740 | switch (self.stdio) { |
| 728 | .check => |checks| for (checks.items) |check| switch (check) { | 741 | .check => |checks| for (checks.items) |check| switch (check) { |
| 729 | .expect_stderr_exact => |expected_bytes| { | 742 | .expect_stderr_exact => |expected_bytes| { |
| 730 | assert(!result.stderr_null); | 743 | assert(!result.stdio.stderr_null); |
| 731 | if (!mem.eql(u8, expected_bytes, result.stderr)) { | 744 | if (!mem.eql(u8, expected_bytes, result.stdio.stderr)) { |
| 732 | return step.fail( | 745 | return step.fail( |
| 733 | \\ | 746 | \\ |
| 734 | \\========= expected this stderr: ========= | 747 | \\========= expected this stderr: ========= |
| ... | @@ -739,14 +752,14 @@ fn runCommand( | ... | @@ -739,14 +752,14 @@ fn runCommand( |
| 739 | \\{s} | 752 | \\{s} |
| 740 | , .{ | 753 | , .{ |
| 741 | expected_bytes, | 754 | expected_bytes, |
| 742 | result.stderr, | 755 | result.stdio.stderr, |
| 743 | try Step.allocPrintCmd(arena, self.cwd, argv), | 756 | try Step.allocPrintCmd(arena, self.cwd, final_argv), |
| 744 | }); | 757 | }); |
| 745 | } | 758 | } |
| 746 | }, | 759 | }, |
| 747 | .expect_stderr_match => |match| { | 760 | .expect_stderr_match => |match| { |
| 748 | assert(!result.stderr_null); | 761 | assert(!result.stdio.stderr_null); |
| 749 | if (mem.indexOf(u8, result.stderr, match) == null) { | 762 | if (mem.indexOf(u8, result.stdio.stderr, match) == null) { |
| 750 | return step.fail( | 763 | return step.fail( |
| 751 | \\ | 764 | \\ |
| 752 | \\========= expected to find in stderr: ========= | 765 | \\========= expected to find in stderr: ========= |
| ... | @@ -757,14 +770,14 @@ fn runCommand( | ... | @@ -757,14 +770,14 @@ fn runCommand( |
| 757 | \\{s} | 770 | \\{s} |
| 758 | , .{ | 771 | , .{ |
| 759 | match, | 772 | match, |
| 760 | result.stderr, | 773 | result.stdio.stderr, |
| 761 | try Step.allocPrintCmd(arena, self.cwd, argv), | 774 | try Step.allocPrintCmd(arena, self.cwd, final_argv), |
| 762 | }); | 775 | }); |
| 763 | } | 776 | } |
| 764 | }, | 777 | }, |
| 765 | .expect_stdout_exact => |expected_bytes| { | 778 | .expect_stdout_exact => |expected_bytes| { |
| 766 | assert(!result.stdout_null); | 779 | assert(!result.stdio.stdout_null); |
| 767 | if (!mem.eql(u8, expected_bytes, result.stdout)) { | 780 | if (!mem.eql(u8, expected_bytes, result.stdio.stdout)) { |
| 768 | return step.fail( | 781 | return step.fail( |
| 769 | \\ | 782 | \\ |
| 770 | \\========= expected this stdout: ========= | 783 | \\========= expected this stdout: ========= |
| ... | @@ -775,14 +788,14 @@ fn runCommand( | ... | @@ -775,14 +788,14 @@ fn runCommand( |
| 775 | \\{s} | 788 | \\{s} |
| 776 | , .{ | 789 | , .{ |
| 777 | expected_bytes, | 790 | expected_bytes, |
| 778 | result.stdout, | 791 | result.stdio.stdout, |
| 779 | try Step.allocPrintCmd(arena, self.cwd, argv), | 792 | try Step.allocPrintCmd(arena, self.cwd, final_argv), |
| 780 | }); | 793 | }); |
| 781 | } | 794 | } |
| 782 | }, | 795 | }, |
| 783 | .expect_stdout_match => |match| { | 796 | .expect_stdout_match => |match| { |
| 784 | assert(!result.stdout_null); | 797 | assert(!result.stdio.stdout_null); |
| 785 | if (mem.indexOf(u8, result.stdout, match) == null) { | 798 | if (mem.indexOf(u8, result.stdio.stdout, match) == null) { |
| 786 | return step.fail( | 799 | return step.fail( |
| 787 | \\ | 800 | \\ |
| 788 | \\========= expected to find in stdout: ========= | 801 | \\========= expected to find in stdout: ========= |
| ... | @@ -793,8 +806,8 @@ fn runCommand( | ... | @@ -793,8 +806,8 @@ fn runCommand( |
| 793 | \\{s} | 806 | \\{s} |
| 794 | , .{ | 807 | , .{ |
| 795 | match, | 808 | match, |
| 796 | result.stdout, | 809 | result.stdio.stdout, |
| 797 | try Step.allocPrintCmd(arena, self.cwd, argv), | 810 | try Step.allocPrintCmd(arena, self.cwd, final_argv), |
| 798 | }); | 811 | }); |
| 799 | } | 812 | } |
| 800 | }, | 813 | }, |
| ... | @@ -803,33 +816,46 @@ fn runCommand( | ... | @@ -803,33 +816,46 @@ fn runCommand( |
| 803 | return step.fail("the following command {} (expected {}):\n{s}", .{ | 816 | return step.fail("the following command {} (expected {}):\n{s}", .{ |
| 804 | fmtTerm(result.term), | 817 | fmtTerm(result.term), |
| 805 | fmtTerm(expected_term), | 818 | fmtTerm(expected_term), |
| 806 | try Step.allocPrintCmd(arena, self.cwd, argv), | 819 | try Step.allocPrintCmd(arena, self.cwd, final_argv), |
| 807 | }); | 820 | }); |
| 808 | } | 821 | } |
| 809 | }, | 822 | }, |
| 810 | }, | 823 | }, |
| 824 | .zig_test => { | ||
| 825 | const expected_term: std.process.Child.Term = .{ .Exited = 0 }; | ||
| 826 | if (!termMatches(expected_term, result.term)) { | ||
| 827 | return step.fail("the following command {} (expected {}):\n{s}", .{ | ||
| 828 | fmtTerm(result.term), | ||
| 829 | fmtTerm(expected_term), | ||
| 830 | try Step.allocPrintCmd(arena, self.cwd, final_argv), | ||
| 831 | }); | ||
| 832 | } | ||
| 833 | if (!result.stdio.test_results.isSuccess()) { | ||
| 834 | return step.fail( | ||
| 835 | "the following test command failed:\n{s}", | ||
| 836 | .{try Step.allocPrintCmd(arena, self.cwd, final_argv)}, | ||
| 837 | ); | ||
| 838 | } | ||
| 839 | }, | ||
| 811 | else => { | 840 | else => { |
| 812 | try step.handleChildProcessTerm(result.term, self.cwd, argv); | 841 | try step.handleChildProcessTerm(result.term, self.cwd, final_argv); |
| 813 | }, | 842 | }, |
| 814 | } | 843 | } |
| 815 | } | 844 | } |
| 816 | 845 | ||
| 817 | const ChildProcResult = struct { | 846 | const ChildProcResult = struct { |
| 818 | // These use boolean flags instead of optionals as a workaround for | ||
| 819 | // https://github.com/ziglang/zig/issues/14783 | ||
| 820 | stdout: []const u8, | ||
| 821 | stderr: []const u8, | ||
| 822 | stdout_null: bool, | ||
| 823 | stderr_null: bool, | ||
| 824 | term: std.process.Child.Term, | 847 | term: std.process.Child.Term, |
| 825 | elapsed_ns: u64, | 848 | elapsed_ns: u64, |
| 826 | peak_rss: usize, | 849 | peak_rss: usize, |
| 850 | |||
| 851 | stdio: StdIoResult, | ||
| 827 | }; | 852 | }; |
| 828 | 853 | ||
| 829 | fn spawnChildAndCollect( | 854 | fn spawnChildAndCollect( |
| 830 | self: *RunStep, | 855 | self: *RunStep, |
| 831 | argv: []const []const u8, | 856 | argv: []const []const u8, |
| 832 | has_side_effects: bool, | 857 | has_side_effects: bool, |
| 858 | prog_node: *std.Progress.Node, | ||
| 833 | ) !ChildProcResult { | 859 | ) !ChildProcResult { |
| 834 | const b = self.step.owner; | 860 | const b = self.step.owner; |
| 835 | const arena = b.allocator; | 861 | const arena = b.allocator; |
| ... | @@ -848,16 +874,19 @@ fn spawnChildAndCollect( | ... | @@ -848,16 +874,19 @@ fn spawnChildAndCollect( |
| 848 | .infer_from_args => if (has_side_effects) .Inherit else .Close, | 874 | .infer_from_args => if (has_side_effects) .Inherit else .Close, |
| 849 | .inherit => .Inherit, | 875 | .inherit => .Inherit, |
| 850 | .check => .Close, | 876 | .check => .Close, |
| 877 | .zig_test => .Pipe, | ||
| 851 | }; | 878 | }; |
| 852 | child.stdout_behavior = switch (self.stdio) { | 879 | child.stdout_behavior = switch (self.stdio) { |
| 853 | .infer_from_args => if (has_side_effects) .Inherit else .Ignore, | 880 | .infer_from_args => if (has_side_effects) .Inherit else .Ignore, |
| 854 | .inherit => .Inherit, | 881 | .inherit => .Inherit, |
| 855 | .check => |checks| if (checksContainStdout(checks.items)) .Pipe else .Ignore, | 882 | .check => |checks| if (checksContainStdout(checks.items)) .Pipe else .Ignore, |
| 883 | .zig_test => .Pipe, | ||
| 856 | }; | 884 | }; |
| 857 | child.stderr_behavior = switch (self.stdio) { | 885 | child.stderr_behavior = switch (self.stdio) { |
| 858 | .infer_from_args => if (has_side_effects) .Inherit else .Pipe, | 886 | .infer_from_args => if (has_side_effects) .Inherit else .Pipe, |
| 859 | .inherit => .Inherit, | 887 | .inherit => .Inherit, |
| 860 | .check => .Pipe, | 888 | .check => .Pipe, |
| 889 | .zig_test => .Pipe, | ||
| 861 | }; | 890 | }; |
| 862 | if (self.captured_stdout != null) child.stdout_behavior = .Pipe; | 891 | if (self.captured_stdout != null) child.stdout_behavior = .Pipe; |
| 863 | if (self.captured_stderr != null) child.stderr_behavior = .Pipe; | 892 | if (self.captured_stderr != null) child.stderr_behavior = .Pipe; |
| ... | @@ -871,6 +900,219 @@ fn spawnChildAndCollect( | ... | @@ -871,6 +900,219 @@ fn spawnChildAndCollect( |
| 871 | }); | 900 | }); |
| 872 | var timer = try std.time.Timer.start(); | 901 | var timer = try std.time.Timer.start(); |
| 873 | 902 | ||
| 903 | const result = if (self.stdio == .zig_test) | ||
| 904 | evalZigTest(self, &child, prog_node) | ||
| 905 | else | ||
| 906 | evalGeneric(self, &child); | ||
| 907 | |||
| 908 | const term = try child.wait(); | ||
| 909 | const elapsed_ns = timer.read(); | ||
| 910 | |||
| 911 | return .{ | ||
| 912 | .stdio = try result, | ||
| 913 | .term = term, | ||
| 914 | .elapsed_ns = elapsed_ns, | ||
| 915 | .peak_rss = child.resource_usage_statistics.getMaxRss() orelse 0, | ||
| 916 | }; | ||
| 917 | } | ||
| 918 | |||
| 919 | const StdIoResult = struct { | ||
| 920 | // These use boolean flags instead of optionals as a workaround for | ||
| 921 | // https://github.com/ziglang/zig/issues/14783 | ||
| 922 | stdout: []const u8, | ||
| 923 | stderr: []const u8, | ||
| 924 | stdout_null: bool, | ||
| 925 | stderr_null: bool, | ||
| 926 | test_results: Step.TestResults, | ||
| 927 | }; | ||
| 928 | |||
| 929 | fn evalZigTest( | ||
| 930 | self: *RunStep, | ||
| 931 | child: *std.process.Child, | ||
| 932 | prog_node: *std.Progress.Node, | ||
| 933 | ) !StdIoResult { | ||
| 934 | const gpa = self.step.owner.allocator; | ||
| 935 | const arena = self.step.owner.allocator; | ||
| 936 | |||
| 937 | var poller = std.io.poll(gpa, enum { stdout, stderr }, .{ | ||
| 938 | .stdout = child.stdout.?, | ||
| 939 | .stderr = child.stderr.?, | ||
| 940 | }); | ||
| 941 | defer poller.deinit(); | ||
| 942 | |||
| 943 | try sendMessage(child.stdin.?, .query_test_metadata); | ||
| 944 | |||
| 945 | const Header = std.zig.Server.Message.Header; | ||
| 946 | |||
| 947 | const stdout = poller.fifo(.stdout); | ||
| 948 | const stderr = poller.fifo(.stderr); | ||
| 949 | |||
| 950 | var fail_count: u32 = 0; | ||
| 951 | var skip_count: u32 = 0; | ||
| 952 | var leak_count: u32 = 0; | ||
| 953 | var test_count: u32 = 0; | ||
| 954 | |||
| 955 | var metadata: ?TestMetadata = null; | ||
| 956 | |||
| 957 | var sub_prog_node: ?std.Progress.Node = null; | ||
| 958 | defer if (sub_prog_node) |*n| n.end(); | ||
| 959 | |||
| 960 | poll: while (try poller.poll()) { | ||
| 961 | while (true) { | ||
| 962 | const buf = stdout.readableSlice(0); | ||
| 963 | assert(stdout.readableLength() == buf.len); | ||
| 964 | if (buf.len < @sizeOf(Header)) continue :poll; | ||
| 965 | const header = @ptrCast(*align(1) const Header, buf[0..@sizeOf(Header)]); | ||
| 966 | const header_and_msg_len = header.bytes_len + @sizeOf(Header); | ||
| 967 | if (buf.len < header_and_msg_len) continue :poll; | ||
| 968 | const body = buf[@sizeOf(Header)..][0..header.bytes_len]; | ||
| 969 | switch (header.tag) { | ||
| 970 | .zig_version => { | ||
| 971 | if (!std.mem.eql(u8, builtin.zig_version_string, body)) { | ||
| 972 | return self.step.fail( | ||
| 973 | "zig version mismatch build runner vs compiler: '{s}' vs '{s}'", | ||
| 974 | .{ builtin.zig_version_string, body }, | ||
| 975 | ); | ||
| 976 | } | ||
| 977 | }, | ||
| 978 | .test_metadata => { | ||
| 979 | const TmHdr = std.zig.Server.Message.TestMetadata; | ||
| 980 | const tm_hdr = @ptrCast(*align(1) const TmHdr, body); | ||
| 981 | test_count = tm_hdr.tests_len; | ||
| 982 | |||
| 983 | const names_bytes = body[@sizeOf(TmHdr)..][0 .. test_count * @sizeOf(u32)]; | ||
| 984 | const async_frame_lens_bytes = body[@sizeOf(TmHdr) + names_bytes.len ..][0 .. test_count * @sizeOf(u32)]; | ||
| 985 | const expected_panic_msgs_bytes = body[@sizeOf(TmHdr) + names_bytes.len + async_frame_lens_bytes.len ..][0 .. test_count * @sizeOf(u32)]; | ||
| 986 | const string_bytes = body[@sizeOf(TmHdr) + names_bytes.len + async_frame_lens_bytes.len + expected_panic_msgs_bytes.len ..][0..tm_hdr.string_bytes_len]; | ||
| 987 | |||
| 988 | const names = std.mem.bytesAsSlice(u32, names_bytes); | ||
| 989 | const async_frame_lens = std.mem.bytesAsSlice(u32, async_frame_lens_bytes); | ||
| 990 | const expected_panic_msgs = std.mem.bytesAsSlice(u32, expected_panic_msgs_bytes); | ||
| 991 | const names_aligned = try arena.alloc(u32, names.len); | ||
| 992 | for (names_aligned, names) |*dest, src| dest.* = src; | ||
| 993 | |||
| 994 | const async_frame_lens_aligned = try arena.alloc(u32, async_frame_lens.len); | ||
| 995 | for (async_frame_lens_aligned, async_frame_lens) |*dest, src| dest.* = src; | ||
| 996 | |||
| 997 | const expected_panic_msgs_aligned = try arena.alloc(u32, expected_panic_msgs.len); | ||
| 998 | for (expected_panic_msgs_aligned, expected_panic_msgs) |*dest, src| dest.* = src; | ||
| 999 | |||
| 1000 | prog_node.setEstimatedTotalItems(names.len); | ||
| 1001 | metadata = .{ | ||
| 1002 | .string_bytes = try arena.dupe(u8, string_bytes), | ||
| 1003 | .names = names_aligned, | ||
| 1004 | .async_frame_lens = async_frame_lens_aligned, | ||
| 1005 | .expected_panic_msgs = expected_panic_msgs_aligned, | ||
| 1006 | .next_index = 0, | ||
| 1007 | .prog_node = prog_node, | ||
| 1008 | }; | ||
| 1009 | |||
| 1010 | try requestNextTest(child.stdin.?, &metadata.?, &sub_prog_node); | ||
| 1011 | }, | ||
| 1012 | .test_results => { | ||
| 1013 | const md = metadata.?; | ||
| 1014 | |||
| 1015 | const TrHdr = std.zig.Server.Message.TestResults; | ||
| 1016 | const tr_hdr = @ptrCast(*align(1) const TrHdr, body); | ||
| 1017 | fail_count += @boolToInt(tr_hdr.flags.fail); | ||
| 1018 | skip_count += @boolToInt(tr_hdr.flags.skip); | ||
| 1019 | leak_count += @boolToInt(tr_hdr.flags.leak); | ||
| 1020 | |||
| 1021 | if (tr_hdr.flags.fail or tr_hdr.flags.leak) { | ||
| 1022 | const name = std.mem.sliceTo(md.string_bytes[md.names[tr_hdr.index]..], 0); | ||
| 1023 | const msg = std.mem.trim(u8, stderr.readableSlice(0), "\n"); | ||
| 1024 | const label = if (tr_hdr.flags.fail) "failed" else "leaked"; | ||
| 1025 | if (msg.len > 0) { | ||
| 1026 | try self.step.addError("'{s}' {s}: {s}", .{ name, label, msg }); | ||
| 1027 | } else { | ||
| 1028 | try self.step.addError("'{s}' {s}", .{ name, label }); | ||
| 1029 | } | ||
| 1030 | stderr.discard(msg.len); | ||
| 1031 | } | ||
| 1032 | |||
| 1033 | try requestNextTest(child.stdin.?, &metadata.?, &sub_prog_node); | ||
| 1034 | }, | ||
| 1035 | else => {}, // ignore other messages | ||
| 1036 | } | ||
| 1037 | stdout.discard(header_and_msg_len); | ||
| 1038 | } | ||
| 1039 | } | ||
| 1040 | |||
| 1041 | if (stderr.readableLength() > 0) { | ||
| 1042 | const msg = std.mem.trim(u8, try stderr.toOwnedSlice(), "\n"); | ||
| 1043 | if (msg.len > 0) try self.step.result_error_msgs.append(arena, msg); | ||
| 1044 | } | ||
| 1045 | |||
| 1046 | // Send EOF to stdin. | ||
| 1047 | child.stdin.?.close(); | ||
| 1048 | child.stdin = null; | ||
| 1049 | |||
| 1050 | return .{ | ||
| 1051 | .stdout = &.{}, | ||
| 1052 | .stderr = &.{}, | ||
| 1053 | .stdout_null = true, | ||
| 1054 | .stderr_null = true, | ||
| 1055 | .test_results = .{ | ||
| 1056 | .test_count = test_count, | ||
| 1057 | .fail_count = fail_count, | ||
| 1058 | .skip_count = skip_count, | ||
| 1059 | .leak_count = leak_count, | ||
| 1060 | }, | ||
| 1061 | }; | ||
| 1062 | } | ||
| 1063 | |||
| 1064 | const TestMetadata = struct { | ||
| 1065 | names: []const u32, | ||
| 1066 | async_frame_lens: []const u32, | ||
| 1067 | expected_panic_msgs: []const u32, | ||
| 1068 | string_bytes: []const u8, | ||
| 1069 | next_index: u32, | ||
| 1070 | prog_node: *std.Progress.Node, | ||
| 1071 | |||
| 1072 | fn testName(tm: TestMetadata, index: u32) []const u8 { | ||
| 1073 | return std.mem.sliceTo(tm.string_bytes[tm.names[index]..], 0); | ||
| 1074 | } | ||
| 1075 | }; | ||
| 1076 | |||
| 1077 | fn requestNextTest(in: fs.File, metadata: *TestMetadata, sub_prog_node: *?std.Progress.Node) !void { | ||
| 1078 | while (metadata.next_index < metadata.names.len) { | ||
| 1079 | const i = metadata.next_index; | ||
| 1080 | metadata.next_index += 1; | ||
| 1081 | |||
| 1082 | if (metadata.async_frame_lens[i] != 0) continue; | ||
| 1083 | if (metadata.expected_panic_msgs[i] != 0) continue; | ||
| 1084 | |||
| 1085 | const name = metadata.testName(i); | ||
| 1086 | if (sub_prog_node.*) |*n| n.end(); | ||
| 1087 | sub_prog_node.* = metadata.prog_node.start(name, 0); | ||
| 1088 | |||
| 1089 | try sendRunTestMessage(in, i); | ||
| 1090 | return; | ||
| 1091 | } else { | ||
| 1092 | try sendMessage(in, .exit); | ||
| 1093 | } | ||
| 1094 | } | ||
| 1095 | |||
| 1096 | fn sendMessage(file: std.fs.File, tag: std.zig.Client.Message.Tag) !void { | ||
| 1097 | const header: std.zig.Client.Message.Header = .{ | ||
| 1098 | .tag = tag, | ||
| 1099 | .bytes_len = 0, | ||
| 1100 | }; | ||
| 1101 | try file.writeAll(std.mem.asBytes(&header)); | ||
| 1102 | } | ||
| 1103 | |||
| 1104 | fn sendRunTestMessage(file: std.fs.File, index: u32) !void { | ||
| 1105 | const header: std.zig.Client.Message.Header = .{ | ||
| 1106 | .tag = .run_test, | ||
| 1107 | .bytes_len = 4, | ||
| 1108 | }; | ||
| 1109 | const full_msg = std.mem.asBytes(&header) ++ std.mem.asBytes(&index); | ||
| 1110 | try file.writeAll(full_msg); | ||
| 1111 | } | ||
| 1112 | |||
| 1113 | fn evalGeneric(self: *RunStep, child: *std.process.Child) !StdIoResult { | ||
| 1114 | const arena = self.step.owner.allocator; | ||
| 1115 | |||
| 874 | if (self.stdin) |stdin| { | 1116 | if (self.stdin) |stdin| { |
| 875 | child.stdin.?.writeAll(stdin) catch |err| { | 1117 | child.stdin.?.writeAll(stdin) catch |err| { |
| 876 | return self.step.fail("unable to write stdin: {s}", .{@errorName(err)}); | 1118 | return self.step.fail("unable to write stdin: {s}", .{@errorName(err)}); |
| ... | @@ -925,17 +1167,12 @@ fn spawnChildAndCollect( | ... | @@ -925,17 +1167,12 @@ fn spawnChildAndCollect( |
| 925 | } | 1167 | } |
| 926 | } | 1168 | } |
| 927 | 1169 | ||
| 928 | const term = try child.wait(); | ||
| 929 | const elapsed_ns = timer.read(); | ||
| 930 | |||
| 931 | return .{ | 1170 | return .{ |
| 932 | .stdout = stdout_bytes, | 1171 | .stdout = stdout_bytes, |
| 933 | .stderr = stderr_bytes, | 1172 | .stderr = stderr_bytes, |
| 934 | .stdout_null = stdout_null, | 1173 | .stdout_null = stdout_null, |
| 935 | .stderr_null = stderr_null, | 1174 | .stderr_null = stderr_null, |
| 936 | .term = term, | 1175 | .test_results = .{}, |
| 937 | .elapsed_ns = elapsed_ns, | ||
| 938 | .peak_rss = child.resource_usage_statistics.getMaxRss() orelse 0, | ||
| 939 | }; | 1176 | }; |
| 940 | } | 1177 | } |
| 941 | 1178 | ||
| ... | @@ -966,7 +1203,7 @@ fn failForeign( | ... | @@ -966,7 +1203,7 @@ fn failForeign( |
| 966 | exe: *CompileStep, | 1203 | exe: *CompileStep, |
| 967 | ) error{ MakeFailed, MakeSkipped, OutOfMemory } { | 1204 | ) error{ MakeFailed, MakeSkipped, OutOfMemory } { |
| 968 | switch (self.stdio) { | 1205 | switch (self.stdio) { |
| 969 | .check => { | 1206 | .check, .zig_test => { |
| 970 | if (self.skip_foreign_checks) | 1207 | if (self.skip_foreign_checks) |
| 971 | return error.MakeSkipped; | 1208 | return error.MakeSkipped; |
| 972 | 1209 | ||
| ... | @@ -987,7 +1224,7 @@ fn failForeign( | ... | @@ -987,7 +1224,7 @@ fn failForeign( |
| 987 | 1224 | ||
| 988 | fn hashStdIo(hh: *std.Build.Cache.HashHelper, stdio: StdIo) void { | 1225 | fn hashStdIo(hh: *std.Build.Cache.HashHelper, stdio: StdIo) void { |
| 989 | switch (stdio) { | 1226 | switch (stdio) { |
| 990 | .infer_from_args, .inherit => {}, | 1227 | .infer_from_args, .inherit, .zig_test => {}, |
| 991 | .check => |checks| for (checks.items) |check| { | 1228 | .check => |checks| for (checks.items) |check| { |
| 992 | hh.add(@as(std.meta.Tag(StdIo.Check), check)); | 1229 | hh.add(@as(std.meta.Tag(StdIo.Check), check)); |
| 993 | switch (check) { | 1230 | switch (check) { |
lib/std/Build/Step.zig+30-3| ... | @@ -35,11 +35,27 @@ result_cached: bool, | ... | @@ -35,11 +35,27 @@ result_cached: bool, |
| 35 | result_duration_ns: ?u64, | 35 | result_duration_ns: ?u64, |
| 36 | /// 0 means unavailable or not reported. | 36 | /// 0 means unavailable or not reported. |
| 37 | result_peak_rss: usize, | 37 | result_peak_rss: usize, |
| 38 | test_results: TestResults, | ||
| 38 | 39 | ||
| 39 | /// The return addresss associated with creation of this step that can be useful | 40 | /// The return addresss associated with creation of this step that can be useful |
| 40 | /// to print along with debugging messages. | 41 | /// to print along with debugging messages. |
| 41 | debug_stack_trace: [n_debug_stack_frames]usize, | 42 | debug_stack_trace: [n_debug_stack_frames]usize, |
| 42 | 43 | ||
| 44 | pub const TestResults = struct { | ||
| 45 | fail_count: u32 = 0, | ||
| 46 | skip_count: u32 = 0, | ||
| 47 | leak_count: u32 = 0, | ||
| 48 | test_count: u32 = 0, | ||
| 49 | |||
| 50 | pub fn isSuccess(tr: TestResults) bool { | ||
| 51 | return tr.fail_count == 0 and tr.leak_count == 0; | ||
| 52 | } | ||
| 53 | |||
| 54 | pub fn passCount(tr: TestResults) u32 { | ||
| 55 | return tr.test_count - tr.fail_count - tr.skip_count; | ||
| 56 | } | ||
| 57 | }; | ||
| 58 | |||
| 43 | pub const MakeFn = *const fn (self: *Step, prog_node: *std.Progress.Node) anyerror!void; | 59 | pub const MakeFn = *const fn (self: *Step, prog_node: *std.Progress.Node) anyerror!void; |
| 44 | 60 | ||
| 45 | const n_debug_stack_frames = 4; | 61 | const n_debug_stack_frames = 4; |
| ... | @@ -134,6 +150,7 @@ pub fn init(options: Options) Step { | ... | @@ -134,6 +150,7 @@ pub fn init(options: Options) Step { |
| 134 | .result_cached = false, | 150 | .result_cached = false, |
| 135 | .result_duration_ns = null, | 151 | .result_duration_ns = null, |
| 136 | .result_peak_rss = 0, | 152 | .result_peak_rss = 0, |
| 153 | .test_results = .{}, | ||
| 137 | }; | 154 | }; |
| 138 | } | 155 | } |
| 139 | 156 | ||
| ... | @@ -152,6 +169,10 @@ pub fn make(s: *Step, prog_node: *std.Progress.Node) error{ MakeFailed, MakeSkip | ... | @@ -152,6 +169,10 @@ pub fn make(s: *Step, prog_node: *std.Progress.Node) error{ MakeFailed, MakeSkip |
| 152 | }, | 169 | }, |
| 153 | }; | 170 | }; |
| 154 | 171 | ||
| 172 | if (!s.test_results.isSuccess()) { | ||
| 173 | return error.MakeFailed; | ||
| 174 | } | ||
| 175 | |||
| 155 | if (s.max_rss != 0 and s.result_peak_rss > s.max_rss) { | 176 | if (s.max_rss != 0 and s.result_peak_rss > s.max_rss) { |
| 156 | const msg = std.fmt.allocPrint(arena, "memory usage peaked at {d} bytes, exceeding the declared upper bound of {d}", .{ | 177 | const msg = std.fmt.allocPrint(arena, "memory usage peaked at {d} bytes, exceeding the declared upper bound of {d}", .{ |
| 157 | s.result_peak_rss, s.max_rss, | 178 | s.result_peak_rss, s.max_rss, |
| ... | @@ -346,9 +367,7 @@ pub fn evalZigProcess( | ... | @@ -346,9 +367,7 @@ pub fn evalZigProcess( |
| 346 | s.result_cached = ebp_hdr.flags.cache_hit; | 367 | s.result_cached = ebp_hdr.flags.cache_hit; |
| 347 | result = try arena.dupe(u8, body[@sizeOf(EbpHdr)..]); | 368 | result = try arena.dupe(u8, body[@sizeOf(EbpHdr)..]); |
| 348 | }, | 369 | }, |
| 349 | _ => { | 370 | else => {}, // ignore other messages |
| 350 | // Unrecognized message. | ||
| 351 | }, | ||
| 352 | } | 371 | } |
| 353 | stdout.discard(header_and_msg_len); | 372 | stdout.discard(header_and_msg_len); |
| 354 | } | 373 | } |
| ... | @@ -475,3 +494,11 @@ fn failWithCacheError(s: *Step, man: *const std.Build.Cache.Manifest, err: anyer | ... | @@ -475,3 +494,11 @@ fn failWithCacheError(s: *Step, man: *const std.Build.Cache.Manifest, err: anyer |
| 475 | const prefix = man.cache.prefixes()[pp.prefix].path orelse ""; | 494 | const prefix = man.cache.prefixes()[pp.prefix].path orelse ""; |
| 476 | return s.fail("{s}: {s}/{s}", .{ @errorName(err), prefix, pp.sub_path }); | 495 | return s.fail("{s}: {s}/{s}", .{ @errorName(err), prefix, pp.sub_path }); |
| 477 | } | 496 | } |
| 497 | |||
| 498 | pub fn writeManifest(s: *Step, man: *std.Build.Cache.Manifest) !void { | ||
| 499 | if (s.test_results.isSuccess()) { | ||
| 500 | man.writeManifest() catch |err| { | ||
| 501 | try s.addError("unable to write cache manifest: {s}", .{@errorName(err)}); | ||
| 502 | }; | ||
| 503 | } | ||
| 504 | } |
lib/std/Build/WriteFileStep.zig+1-1| ... | @@ -282,7 +282,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { | ... | @@ -282,7 +282,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 282 | }); | 282 | }); |
| 283 | } | 283 | } |
| 284 | 284 | ||
| 285 | try man.writeManifest(); | 285 | try step.writeManifest(&man); |
| 286 | } | 286 | } |
| 287 | 287 | ||
| 288 | const std = @import("../std.zig"); | 288 | const std = @import("../std.zig"); |
lib/std/zig/Client.zig+7| ... | @@ -26,6 +26,13 @@ pub const Message = struct { | ... | @@ -26,6 +26,13 @@ pub const Message = struct { |
| 26 | /// swap. | 26 | /// swap. |
| 27 | /// No body. | 27 | /// No body. |
| 28 | hot_update, | 28 | hot_update, |
| 29 | /// Ask the test runner for metadata about all the unit tests that can | ||
| 30 | /// be run. Server will respond with a `test_metadata` message. | ||
| 31 | /// No body. | ||
| 32 | query_test_metadata, | ||
| 33 | /// Ask the test runner to run a particular test. | ||
| 34 | /// The message body is a u32 test index. | ||
| 35 | run_test, | ||
| 29 | 36 | ||
| 30 | _, | 37 | _, |
| 31 | }; | 38 | }; |
lib/std/zig/Server.zig+200| ... | @@ -1,3 +1,7 @@ | ... | @@ -1,3 +1,7 @@ |
| 1 | in: std.fs.File, | ||
| 2 | out: std.fs.File, | ||
| 3 | receive_fifo: std.fifo.LinearFifo(u8, .Dynamic), | ||
| 4 | |||
| 1 | pub const Message = struct { | 5 | pub const Message = struct { |
| 2 | pub const Header = extern struct { | 6 | pub const Header = extern struct { |
| 3 | tag: Tag, | 7 | tag: Tag, |
| ... | @@ -14,6 +18,11 @@ pub const Message = struct { | ... | @@ -14,6 +18,11 @@ pub const Message = struct { |
| 14 | progress, | 18 | progress, |
| 15 | /// Body is a EmitBinPath. | 19 | /// Body is a EmitBinPath. |
| 16 | emit_bin_path, | 20 | emit_bin_path, |
| 21 | /// Body is a TestMetadata | ||
| 22 | test_metadata, | ||
| 23 | /// Body is a TestResults | ||
| 24 | test_results, | ||
| 25 | |||
| 17 | _, | 26 | _, |
| 18 | }; | 27 | }; |
| 19 | 28 | ||
| ... | @@ -26,6 +35,33 @@ pub const Message = struct { | ... | @@ -26,6 +35,33 @@ pub const Message = struct { |
| 26 | string_bytes_len: u32, | 35 | string_bytes_len: u32, |
| 27 | }; | 36 | }; |
| 28 | 37 | ||
| 38 | /// Trailing: | ||
| 39 | /// * name: [tests_len]u32 | ||
| 40 | /// - null-terminated string_bytes index | ||
| 41 | /// * async_frame_len: [tests_len]u32, | ||
| 42 | /// - 0 means not async | ||
| 43 | /// * expected_panic_msg: [tests_len]u32, | ||
| 44 | /// - null-terminated string_bytes index | ||
| 45 | /// - 0 means does not expect pani | ||
| 46 | /// * string_bytes: [string_bytes_len]u8, | ||
| 47 | pub const TestMetadata = extern struct { | ||
| 48 | string_bytes_len: u32, | ||
| 49 | tests_len: u32, | ||
| 50 | }; | ||
| 51 | |||
| 52 | pub const TestResults = extern struct { | ||
| 53 | index: u32, | ||
| 54 | flags: Flags, | ||
| 55 | |||
| 56 | pub const Flags = packed struct(u8) { | ||
| 57 | fail: bool, | ||
| 58 | skip: bool, | ||
| 59 | leak: bool, | ||
| 60 | |||
| 61 | reserved: u5 = 0, | ||
| 62 | }; | ||
| 63 | }; | ||
| 64 | |||
| 29 | /// Trailing: | 65 | /// Trailing: |
| 30 | /// * the file system path the emitted binary can be found | 66 | /// * the file system path the emitted binary can be found |
| 31 | pub const EmitBinPath = extern struct { | 67 | pub const EmitBinPath = extern struct { |
| ... | @@ -37,3 +73,167 @@ pub const Message = struct { | ... | @@ -37,3 +73,167 @@ pub const Message = struct { |
| 37 | }; | 73 | }; |
| 38 | }; | 74 | }; |
| 39 | }; | 75 | }; |
| 76 | |||
| 77 | pub const Options = struct { | ||
| 78 | gpa: Allocator, | ||
| 79 | in: std.fs.File, | ||
| 80 | out: std.fs.File, | ||
| 81 | zig_version: []const u8, | ||
| 82 | }; | ||
| 83 | |||
| 84 | pub fn init(options: Options) !Server { | ||
| 85 | var s: Server = .{ | ||
| 86 | .in = options.in, | ||
| 87 | .out = options.out, | ||
| 88 | .receive_fifo = std.fifo.LinearFifo(u8, .Dynamic).init(options.gpa), | ||
| 89 | }; | ||
| 90 | try s.serveStringMessage(.zig_version, options.zig_version); | ||
| 91 | return s; | ||
| 92 | } | ||
| 93 | |||
| 94 | pub fn deinit(s: *Server) void { | ||
| 95 | s.receive_fifo.deinit(); | ||
| 96 | s.* = undefined; | ||
| 97 | } | ||
| 98 | |||
| 99 | pub fn receiveMessage(s: *Server) !InMessage.Header { | ||
| 100 | const Header = InMessage.Header; | ||
| 101 | const fifo = &s.receive_fifo; | ||
| 102 | |||
| 103 | while (true) { | ||
| 104 | const buf = fifo.readableSlice(0); | ||
| 105 | assert(fifo.readableLength() == buf.len); | ||
| 106 | if (buf.len >= @sizeOf(Header)) { | ||
| 107 | const header = @ptrCast(*align(1) const Header, buf[0..@sizeOf(Header)]); | ||
| 108 | |||
| 109 | if (buf.len - @sizeOf(Header) >= header.bytes_len) { | ||
| 110 | const result = header.*; | ||
| 111 | fifo.discard(@sizeOf(Header)); | ||
| 112 | return result; | ||
| 113 | } else { | ||
| 114 | const needed = header.bytes_len - (buf.len - @sizeOf(Header)); | ||
| 115 | const write_buffer = try fifo.writableWithSize(needed); | ||
| 116 | const amt = try s.in.read(write_buffer); | ||
| 117 | fifo.update(amt); | ||
| 118 | continue; | ||
| 119 | } | ||
| 120 | } | ||
| 121 | |||
| 122 | const write_buffer = try fifo.writableWithSize(256); | ||
| 123 | const amt = try s.in.read(write_buffer); | ||
| 124 | fifo.update(amt); | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 128 | pub fn receiveBody_u32(s: *Server) !u32 { | ||
| 129 | const fifo = &s.receive_fifo; | ||
| 130 | const buf = fifo.readableSlice(0); | ||
| 131 | const result = @ptrCast(*align(1) const u32, buf[0..4]).*; | ||
| 132 | fifo.discard(4); | ||
| 133 | return result; | ||
| 134 | } | ||
| 135 | |||
| 136 | pub fn serveStringMessage(s: *Server, tag: OutMessage.Tag, msg: []const u8) !void { | ||
| 137 | return s.serveMessage(.{ | ||
| 138 | .tag = tag, | ||
| 139 | .bytes_len = @intCast(u32, msg.len), | ||
| 140 | }, &.{msg}); | ||
| 141 | } | ||
| 142 | |||
| 143 | pub fn serveMessage( | ||
| 144 | s: *const Server, | ||
| 145 | header: OutMessage.Header, | ||
| 146 | bufs: []const []const u8, | ||
| 147 | ) !void { | ||
| 148 | var iovecs: [10]std.os.iovec_const = undefined; | ||
| 149 | iovecs[0] = .{ | ||
| 150 | .iov_base = @ptrCast([*]const u8, &header), | ||
| 151 | .iov_len = @sizeOf(OutMessage.Header), | ||
| 152 | }; | ||
| 153 | for (bufs, iovecs[1 .. bufs.len + 1]) |buf, *iovec| { | ||
| 154 | iovec.* = .{ | ||
| 155 | .iov_base = buf.ptr, | ||
| 156 | .iov_len = buf.len, | ||
| 157 | }; | ||
| 158 | } | ||
| 159 | try s.out.writevAll(iovecs[0 .. bufs.len + 1]); | ||
| 160 | } | ||
| 161 | |||
| 162 | pub fn serveEmitBinPath( | ||
| 163 | s: *Server, | ||
| 164 | fs_path: []const u8, | ||
| 165 | header: OutMessage.EmitBinPath, | ||
| 166 | ) !void { | ||
| 167 | try s.serveMessage(.{ | ||
| 168 | .tag = .emit_bin_path, | ||
| 169 | .bytes_len = @intCast(u32, fs_path.len + @sizeOf(OutMessage.EmitBinPath)), | ||
| 170 | }, &.{ | ||
| 171 | std.mem.asBytes(&header), | ||
| 172 | fs_path, | ||
| 173 | }); | ||
| 174 | } | ||
| 175 | |||
| 176 | pub fn serveTestResults( | ||
| 177 | s: *Server, | ||
| 178 | msg: OutMessage.TestResults, | ||
| 179 | ) !void { | ||
| 180 | try s.serveMessage(.{ | ||
| 181 | .tag = .test_results, | ||
| 182 | .bytes_len = @intCast(u32, @sizeOf(OutMessage.TestResults)), | ||
| 183 | }, &.{ | ||
| 184 | std.mem.asBytes(&msg), | ||
| 185 | }); | ||
| 186 | } | ||
| 187 | |||
| 188 | pub fn serveErrorBundle(s: *Server, error_bundle: std.zig.ErrorBundle) !void { | ||
| 189 | const eb_hdr: OutMessage.ErrorBundle = .{ | ||
| 190 | .extra_len = @intCast(u32, error_bundle.extra.len), | ||
| 191 | .string_bytes_len = @intCast(u32, error_bundle.string_bytes.len), | ||
| 192 | }; | ||
| 193 | const bytes_len = @sizeOf(OutMessage.ErrorBundle) + | ||
| 194 | 4 * error_bundle.extra.len + error_bundle.string_bytes.len; | ||
| 195 | try s.serveMessage(.{ | ||
| 196 | .tag = .error_bundle, | ||
| 197 | .bytes_len = @intCast(u32, bytes_len), | ||
| 198 | }, &.{ | ||
| 199 | std.mem.asBytes(&eb_hdr), | ||
| 200 | // TODO: implement @ptrCast between slices changing the length | ||
| 201 | std.mem.sliceAsBytes(error_bundle.extra), | ||
| 202 | error_bundle.string_bytes, | ||
| 203 | }); | ||
| 204 | } | ||
| 205 | |||
| 206 | pub const TestMetadata = struct { | ||
| 207 | names: []const u32, | ||
| 208 | async_frame_sizes: []const u32, | ||
| 209 | expected_panic_msgs: []const u32, | ||
| 210 | string_bytes: []const u8, | ||
| 211 | }; | ||
| 212 | |||
| 213 | pub fn serveTestMetadata(s: *Server, test_metadata: TestMetadata) !void { | ||
| 214 | const header: OutMessage.TestMetadata = .{ | ||
| 215 | .tests_len = @intCast(u32, test_metadata.names.len), | ||
| 216 | .string_bytes_len = @intCast(u32, test_metadata.string_bytes.len), | ||
| 217 | }; | ||
| 218 | const bytes_len = @sizeOf(OutMessage.TestMetadata) + | ||
| 219 | 3 * 4 * test_metadata.names.len + test_metadata.string_bytes.len; | ||
| 220 | return s.serveMessage(.{ | ||
| 221 | .tag = .test_metadata, | ||
| 222 | .bytes_len = @intCast(u32, bytes_len), | ||
| 223 | }, &.{ | ||
| 224 | std.mem.asBytes(&header), | ||
| 225 | // TODO: implement @ptrCast between slices changing the length | ||
| 226 | std.mem.sliceAsBytes(test_metadata.names), | ||
| 227 | std.mem.sliceAsBytes(test_metadata.async_frame_sizes), | ||
| 228 | std.mem.sliceAsBytes(test_metadata.expected_panic_msgs), | ||
| 229 | test_metadata.string_bytes, | ||
| 230 | }); | ||
| 231 | } | ||
| 232 | |||
| 233 | const OutMessage = std.zig.Server.Message; | ||
| 234 | const InMessage = std.zig.Client.Message; | ||
| 235 | |||
| 236 | const Server = @This(); | ||
| 237 | const std = @import("std"); | ||
| 238 | const Allocator = std.mem.Allocator; | ||
| 239 | const assert = std.debug.assert; |
lib/test_runner.zig+127-45| ... | @@ -8,14 +8,130 @@ pub const std_options = struct { | ... | @@ -8,14 +8,130 @@ pub const std_options = struct { |
| 8 | }; | 8 | }; |
| 9 | 9 | ||
| 10 | var log_err_count: usize = 0; | 10 | var log_err_count: usize = 0; |
| 11 | var cmdline_buffer: [4096]u8 = undefined; | ||
| 12 | var fba = std.heap.FixedBufferAllocator.init(&cmdline_buffer); | ||
| 11 | 13 | ||
| 12 | pub fn main() void { | 14 | pub fn main() void { |
| 13 | if (builtin.zig_backend != .stage1 and | 15 | if (builtin.zig_backend == .stage2_wasm or |
| 14 | builtin.zig_backend != .stage2_llvm and | 16 | builtin.zig_backend == .stage2_x86_64 or |
| 15 | builtin.zig_backend != .stage2_c) | 17 | builtin.zig_backend == .stage2_aarch64) |
| 16 | { | 18 | { |
| 17 | return main2() catch @panic("test failure"); | 19 | return mainSimple() catch @panic("test failure"); |
| 20 | } | ||
| 21 | |||
| 22 | const args = std.process.argsAlloc(fba.allocator()) catch | ||
| 23 | @panic("unable to parse command line args"); | ||
| 24 | |||
| 25 | var listen = false; | ||
| 26 | |||
| 27 | for (args[1..]) |arg| { | ||
| 28 | if (std.mem.eql(u8, arg, "--listen=-")) { | ||
| 29 | listen = true; | ||
| 30 | } else { | ||
| 31 | @panic("unrecognized command line argument"); | ||
| 32 | } | ||
| 33 | } | ||
| 34 | |||
| 35 | if (listen) { | ||
| 36 | return mainServer(); | ||
| 37 | } else { | ||
| 38 | return mainTerminal(); | ||
| 39 | } | ||
| 40 | } | ||
| 41 | |||
| 42 | fn mainServer() void { | ||
| 43 | return mainServerFallible() catch @panic("internal test runner failure"); | ||
| 44 | } | ||
| 45 | |||
| 46 | fn mainServerFallible() !void { | ||
| 47 | var server = try std.zig.Server.init(.{ | ||
| 48 | .gpa = fba.allocator(), | ||
| 49 | .in = std.io.getStdIn(), | ||
| 50 | .out = std.io.getStdOut(), | ||
| 51 | .zig_version = builtin.zig_version_string, | ||
| 52 | }); | ||
| 53 | defer server.deinit(); | ||
| 54 | |||
| 55 | while (true) { | ||
| 56 | const hdr = try server.receiveMessage(); | ||
| 57 | switch (hdr.tag) { | ||
| 58 | .exit => { | ||
| 59 | return std.process.exit(0); | ||
| 60 | }, | ||
| 61 | .query_test_metadata => { | ||
| 62 | std.testing.allocator_instance = .{}; | ||
| 63 | defer if (std.testing.allocator_instance.deinit()) { | ||
| 64 | @panic("internal test runner memory leak"); | ||
| 65 | }; | ||
| 66 | |||
| 67 | var string_bytes: std.ArrayListUnmanaged(u8) = .{}; | ||
| 68 | defer string_bytes.deinit(std.testing.allocator); | ||
| 69 | try string_bytes.append(std.testing.allocator, 0); // Reserve 0 for null. | ||
| 70 | |||
| 71 | const test_fns = builtin.test_functions; | ||
| 72 | const names = try std.testing.allocator.alloc(u32, test_fns.len); | ||
| 73 | defer std.testing.allocator.free(names); | ||
| 74 | const async_frame_sizes = try std.testing.allocator.alloc(u32, test_fns.len); | ||
| 75 | defer std.testing.allocator.free(async_frame_sizes); | ||
| 76 | const expected_panic_msgs = try std.testing.allocator.alloc(u32, test_fns.len); | ||
| 77 | defer std.testing.allocator.free(expected_panic_msgs); | ||
| 78 | |||
| 79 | for (test_fns, names, async_frame_sizes, expected_panic_msgs) |test_fn, *name, *async_frame_size, *expected_panic_msg| { | ||
| 80 | name.* = @intCast(u32, string_bytes.items.len); | ||
| 81 | try string_bytes.ensureUnusedCapacity(std.testing.allocator, test_fn.name.len + 1); | ||
| 82 | string_bytes.appendSliceAssumeCapacity(test_fn.name); | ||
| 83 | string_bytes.appendAssumeCapacity(0); | ||
| 84 | |||
| 85 | async_frame_size.* = @intCast(u32, test_fn.async_frame_size orelse 0); | ||
| 86 | expected_panic_msg.* = 0; | ||
| 87 | } | ||
| 88 | |||
| 89 | try server.serveTestMetadata(.{ | ||
| 90 | .names = names, | ||
| 91 | .async_frame_sizes = async_frame_sizes, | ||
| 92 | .expected_panic_msgs = expected_panic_msgs, | ||
| 93 | .string_bytes = string_bytes.items, | ||
| 94 | }); | ||
| 95 | }, | ||
| 96 | |||
| 97 | .run_test => { | ||
| 98 | std.testing.allocator_instance = .{}; | ||
| 99 | const index = try server.receiveBody_u32(); | ||
| 100 | const test_fn = builtin.test_functions[index]; | ||
| 101 | if (test_fn.async_frame_size != null) | ||
| 102 | @panic("TODO test runner implement async tests"); | ||
| 103 | var fail = false; | ||
| 104 | var skip = false; | ||
| 105 | var leak = false; | ||
| 106 | test_fn.func() catch |err| switch (err) { | ||
| 107 | error.SkipZigTest => skip = true, | ||
| 108 | else => { | ||
| 109 | fail = true; | ||
| 110 | if (@errorReturnTrace()) |trace| { | ||
| 111 | std.debug.dumpStackTrace(trace.*); | ||
| 112 | } | ||
| 113 | }, | ||
| 114 | }; | ||
| 115 | leak = std.testing.allocator_instance.deinit(); | ||
| 116 | try server.serveTestResults(.{ | ||
| 117 | .index = index, | ||
| 118 | .flags = .{ | ||
| 119 | .fail = fail, | ||
| 120 | .skip = skip, | ||
| 121 | .leak = leak, | ||
| 122 | }, | ||
| 123 | }); | ||
| 124 | }, | ||
| 125 | |||
| 126 | else => { | ||
| 127 | std.debug.print("unsupported message: {x}", .{@enumToInt(hdr.tag)}); | ||
| 128 | std.process.exit(1); | ||
| 129 | }, | ||
| 130 | } | ||
| 18 | } | 131 | } |
| 132 | } | ||
| 133 | |||
| 134 | fn mainTerminal() void { | ||
| 19 | const test_fn_list = builtin.test_functions; | 135 | const test_fn_list = builtin.test_functions; |
| 20 | var ok_count: usize = 0; | 136 | var ok_count: usize = 0; |
| 21 | var skip_count: usize = 0; | 137 | var skip_count: usize = 0; |
| ... | @@ -118,51 +234,17 @@ pub fn log( | ... | @@ -118,51 +234,17 @@ pub fn log( |
| 118 | } | 234 | } |
| 119 | } | 235 | } |
| 120 | 236 | ||
| 121 | pub fn main2() anyerror!void { | 237 | /// Simpler main(), exercising fewer language features, so that |
| 122 | var skipped: usize = 0; | 238 | /// work-in-progress backends can handle it. |
| 123 | var failed: usize = 0; | 239 | pub fn mainSimple() anyerror!void { |
| 124 | // Simpler main(), exercising fewer language features, so that stage2 can handle it. | 240 | //const stderr = std.io.getStdErr(); |
| 125 | for (builtin.test_functions) |test_fn| { | 241 | for (builtin.test_functions) |test_fn| { |
| 126 | test_fn.func() catch |err| { | 242 | test_fn.func() catch |err| { |
| 127 | if (err != error.SkipZigTest) { | 243 | if (err != error.SkipZigTest) { |
| 128 | failed += 1; | 244 | //stderr.writeAll(test_fn.name) catch {}; |
| 129 | } else { | 245 | //stderr.writeAll("\n") catch {}; |
| 130 | skipped += 1; | 246 | return err; |
| 131 | } | 247 | } |
| 132 | }; | 248 | }; |
| 133 | } | 249 | } |
| 134 | if (builtin.zig_backend == .stage2_wasm or | ||
| 135 | builtin.zig_backend == .stage2_x86_64 or | ||
| 136 | builtin.zig_backend == .stage2_aarch64 or | ||
| 137 | builtin.zig_backend == .stage2_llvm or | ||
| 138 | builtin.zig_backend == .stage2_c) | ||
| 139 | { | ||
| 140 | const passed = builtin.test_functions.len - skipped - failed; | ||
| 141 | const stderr = std.io.getStdErr(); | ||
| 142 | writeInt(stderr, passed) catch {}; | ||
| 143 | stderr.writeAll(" passed; ") catch {}; | ||
| 144 | writeInt(stderr, skipped) catch {}; | ||
| 145 | stderr.writeAll(" skipped; ") catch {}; | ||
| 146 | writeInt(stderr, failed) catch {}; | ||
| 147 | stderr.writeAll(" failed.\n") catch {}; | ||
| 148 | } | ||
| 149 | if (failed != 0) { | ||
| 150 | return error.TestsFailed; | ||
| 151 | } | ||
| 152 | } | ||
| 153 | |||
| 154 | fn writeInt(stderr: std.fs.File, int: usize) anyerror!void { | ||
| 155 | const base = 10; | ||
| 156 | var buf: [100]u8 = undefined; | ||
| 157 | var a: usize = int; | ||
| 158 | var index: usize = buf.len; | ||
| 159 | while (true) { | ||
| 160 | const digit = a % base; | ||
| 161 | index -= 1; | ||
| 162 | buf[index] = std.fmt.digitToChar(@intCast(u8, digit), .lower); | ||
| 163 | a /= base; | ||
| 164 | if (a == 0) break; | ||
| 165 | } | ||
| 166 | const slice = buf[index..]; | ||
| 167 | try stderr.writeAll(slice); | ||
| 168 | } | 250 | } |
src/Server.zig deleted-113| ... | @@ -1,113 +0,0 @@ | ||
| 1 | in: std.fs.File, | ||
| 2 | out: std.fs.File, | ||
| 3 | receive_fifo: std.fifo.LinearFifo(u8, .Dynamic), | ||
| 4 | |||
| 5 | pub const Options = struct { | ||
| 6 | gpa: Allocator, | ||
| 7 | in: std.fs.File, | ||
| 8 | out: std.fs.File, | ||
| 9 | }; | ||
| 10 | |||
| 11 | pub fn init(options: Options) !Server { | ||
| 12 | var s: Server = .{ | ||
| 13 | .in = options.in, | ||
| 14 | .out = options.out, | ||
| 15 | .receive_fifo = std.fifo.LinearFifo(u8, .Dynamic).init(options.gpa), | ||
| 16 | }; | ||
| 17 | try s.serveStringMessage(.zig_version, build_options.version); | ||
| 18 | return s; | ||
| 19 | } | ||
| 20 | |||
| 21 | pub fn deinit(s: *Server) void { | ||
| 22 | s.receive_fifo.deinit(); | ||
| 23 | s.* = undefined; | ||
| 24 | } | ||
| 25 | |||
| 26 | pub fn receiveMessage(s: *Server) !InMessage.Header { | ||
| 27 | const Header = InMessage.Header; | ||
| 28 | const fifo = &s.receive_fifo; | ||
| 29 | |||
| 30 | while (true) { | ||
| 31 | const buf = fifo.readableSlice(0); | ||
| 32 | assert(fifo.readableLength() == buf.len); | ||
| 33 | if (buf.len >= @sizeOf(Header)) { | ||
| 34 | const header = @ptrCast(*align(1) const Header, buf[0..@sizeOf(Header)]); | ||
| 35 | if (header.bytes_len != 0) | ||
| 36 | return error.InvalidClientMessage; | ||
| 37 | const result = header.*; | ||
| 38 | fifo.discard(@sizeOf(Header)); | ||
| 39 | return result; | ||
| 40 | } | ||
| 41 | |||
| 42 | const write_buffer = try fifo.writableWithSize(256); | ||
| 43 | const amt = try s.in.read(write_buffer); | ||
| 44 | fifo.update(amt); | ||
| 45 | } | ||
| 46 | } | ||
| 47 | |||
| 48 | pub fn serveStringMessage(s: *Server, tag: OutMessage.Tag, msg: []const u8) !void { | ||
| 49 | return s.serveMessage(.{ | ||
| 50 | .tag = tag, | ||
| 51 | .bytes_len = @intCast(u32, msg.len), | ||
| 52 | }, &.{msg}); | ||
| 53 | } | ||
| 54 | |||
| 55 | pub fn serveMessage( | ||
| 56 | s: *const Server, | ||
| 57 | header: OutMessage.Header, | ||
| 58 | bufs: []const []const u8, | ||
| 59 | ) !void { | ||
| 60 | var iovecs: [10]std.os.iovec_const = undefined; | ||
| 61 | iovecs[0] = .{ | ||
| 62 | .iov_base = @ptrCast([*]const u8, &header), | ||
| 63 | .iov_len = @sizeOf(OutMessage.Header), | ||
| 64 | }; | ||
| 65 | for (bufs, iovecs[1 .. bufs.len + 1]) |buf, *iovec| { | ||
| 66 | iovec.* = .{ | ||
| 67 | .iov_base = buf.ptr, | ||
| 68 | .iov_len = buf.len, | ||
| 69 | }; | ||
| 70 | } | ||
| 71 | try s.out.writevAll(iovecs[0 .. bufs.len + 1]); | ||
| 72 | } | ||
| 73 | |||
| 74 | pub fn serveEmitBinPath( | ||
| 75 | s: *Server, | ||
| 76 | fs_path: []const u8, | ||
| 77 | header: std.zig.Server.Message.EmitBinPath, | ||
| 78 | ) !void { | ||
| 79 | try s.serveMessage(.{ | ||
| 80 | .tag = .emit_bin_path, | ||
| 81 | .bytes_len = @intCast(u32, fs_path.len + @sizeOf(std.zig.Server.Message.EmitBinPath)), | ||
| 82 | }, &.{ | ||
| 83 | std.mem.asBytes(&header), | ||
| 84 | fs_path, | ||
| 85 | }); | ||
| 86 | } | ||
| 87 | |||
| 88 | pub fn serveErrorBundle(s: *Server, error_bundle: std.zig.ErrorBundle) !void { | ||
| 89 | const eb_hdr: std.zig.Server.Message.ErrorBundle = .{ | ||
| 90 | .extra_len = @intCast(u32, error_bundle.extra.len), | ||
| 91 | .string_bytes_len = @intCast(u32, error_bundle.string_bytes.len), | ||
| 92 | }; | ||
| 93 | const bytes_len = @sizeOf(std.zig.Server.Message.ErrorBundle) + | ||
| 94 | 4 * error_bundle.extra.len + error_bundle.string_bytes.len; | ||
| 95 | try s.serveMessage(.{ | ||
| 96 | .tag = .error_bundle, | ||
| 97 | .bytes_len = @intCast(u32, bytes_len), | ||
| 98 | }, &.{ | ||
| 99 | std.mem.asBytes(&eb_hdr), | ||
| 100 | // TODO: implement @ptrCast between slices changing the length | ||
| 101 | std.mem.sliceAsBytes(error_bundle.extra), | ||
| 102 | error_bundle.string_bytes, | ||
| 103 | }); | ||
| 104 | } | ||
| 105 | |||
| 106 | const OutMessage = std.zig.Server.Message; | ||
| 107 | const InMessage = std.zig.Client.Message; | ||
| 108 | |||
| 109 | const Server = @This(); | ||
| 110 | const std = @import("std"); | ||
| 111 | const build_options = @import("build_options"); | ||
| 112 | const Allocator = std.mem.Allocator; | ||
| 113 | const assert = std.debug.assert; | ||
src/main.zig+5-16| ... | @@ -10,6 +10,7 @@ const ArrayList = std.ArrayList; | ... | @@ -10,6 +10,7 @@ const ArrayList = std.ArrayList; |
| 10 | const Ast = std.zig.Ast; | 10 | const Ast = std.zig.Ast; |
| 11 | const warn = std.log.warn; | 11 | const warn = std.log.warn; |
| 12 | const ThreadPool = std.Thread.Pool; | 12 | const ThreadPool = std.Thread.Pool; |
| 13 | const cleanExit = std.process.cleanExit; | ||
| 13 | 14 | ||
| 14 | const tracy = @import("tracy.zig"); | 15 | const tracy = @import("tracy.zig"); |
| 15 | const Compilation = @import("Compilation.zig"); | 16 | const Compilation = @import("Compilation.zig"); |
| ... | @@ -26,7 +27,7 @@ const target_util = @import("target.zig"); | ... | @@ -26,7 +27,7 @@ const target_util = @import("target.zig"); |
| 26 | const crash_report = @import("crash_report.zig"); | 27 | const crash_report = @import("crash_report.zig"); |
| 27 | const Module = @import("Module.zig"); | 28 | const Module = @import("Module.zig"); |
| 28 | const AstGen = @import("AstGen.zig"); | 29 | const AstGen = @import("AstGen.zig"); |
| 29 | const Server = @import("Server.zig"); | 30 | const Server = std.zig.Server; |
| 30 | 31 | ||
| 31 | pub const std_options = struct { | 32 | pub const std_options = struct { |
| 32 | pub const wasiCwd = wasi_cwd; | 33 | pub const wasiCwd = wasi_cwd; |
| ... | @@ -3545,6 +3546,7 @@ fn serve( | ... | @@ -3545,6 +3546,7 @@ fn serve( |
| 3545 | .gpa = gpa, | 3546 | .gpa = gpa, |
| 3546 | .in = in, | 3547 | .in = in, |
| 3547 | .out = out, | 3548 | .out = out, |
| 3549 | .zig_version = build_options.version, | ||
| 3548 | }); | 3550 | }); |
| 3549 | defer server.deinit(); | 3551 | defer server.deinit(); |
| 3550 | 3552 | ||
| ... | @@ -3656,8 +3658,8 @@ fn serve( | ... | @@ -3656,8 +3658,8 @@ fn serve( |
| 3656 | ); | 3658 | ); |
| 3657 | } | 3659 | } |
| 3658 | }, | 3660 | }, |
| 3659 | _ => { | 3661 | else => { |
| 3660 | @panic("TODO unrecognized message from client"); | 3662 | fatal("unrecognized message from client: 0x{x}", .{@enumToInt(hdr.tag)}); |
| 3661 | }, | 3663 | }, |
| 3662 | } | 3664 | } |
| 3663 | } | 3665 | } |
| ... | @@ -5624,19 +5626,6 @@ fn detectNativeTargetInfo(cross_target: std.zig.CrossTarget) !std.zig.system.Nat | ... | @@ -5624,19 +5626,6 @@ fn detectNativeTargetInfo(cross_target: std.zig.CrossTarget) !std.zig.system.Nat |
| 5624 | return std.zig.system.NativeTargetInfo.detect(cross_target); | 5626 | return std.zig.system.NativeTargetInfo.detect(cross_target); |
| 5625 | } | 5627 | } |
| 5626 | 5628 | ||
| 5627 | /// Indicate that we are now terminating with a successful exit code. | ||
| 5628 | /// In debug builds, this is a no-op, so that the calling code's | ||
| 5629 | /// cleanup mechanisms are tested and so that external tools that | ||
| 5630 | /// check for resource leaks can be accurate. In release builds, this | ||
| 5631 | /// calls exit(0), and does not return. | ||
| 5632 | pub fn cleanExit() void { | ||
| 5633 | if (builtin.mode == .Debug) { | ||
| 5634 | return; | ||
| 5635 | } else { | ||
| 5636 | process.exit(0); | ||
| 5637 | } | ||
| 5638 | } | ||
| 5639 | |||
| 5640 | const usage_ast_check = | 5629 | const usage_ast_check = |
| 5641 | \\Usage: zig ast-check [file] | 5630 | \\Usage: zig ast-check [file] |
| 5642 | \\ | 5631 | \\ |
src/objcopy.zig+5-4| ... | @@ -8,8 +8,8 @@ const assert = std.debug.assert; | ... | @@ -8,8 +8,8 @@ const assert = std.debug.assert; |
| 8 | 8 | ||
| 9 | const main = @import("main.zig"); | 9 | const main = @import("main.zig"); |
| 10 | const fatal = main.fatal; | 10 | const fatal = main.fatal; |
| 11 | const cleanExit = main.cleanExit; | 11 | const Server = std.zig.Server; |
| 12 | const Server = @import("Server.zig"); | 12 | const build_options = @import("build_options"); |
| 13 | 13 | ||
| 14 | pub fn cmdObjCopy( | 14 | pub fn cmdObjCopy( |
| 15 | gpa: Allocator, | 15 | gpa: Allocator, |
| ... | @@ -116,6 +116,7 @@ pub fn cmdObjCopy( | ... | @@ -116,6 +116,7 @@ pub fn cmdObjCopy( |
| 116 | .gpa = gpa, | 116 | .gpa = gpa, |
| 117 | .in = std.io.getStdIn(), | 117 | .in = std.io.getStdIn(), |
| 118 | .out = std.io.getStdOut(), | 118 | .out = std.io.getStdOut(), |
| 119 | .zig_version = build_options.version, | ||
| 119 | }); | 120 | }); |
| 120 | defer server.deinit(); | 121 | defer server.deinit(); |
| 121 | 122 | ||
| ... | @@ -124,7 +125,7 @@ pub fn cmdObjCopy( | ... | @@ -124,7 +125,7 @@ pub fn cmdObjCopy( |
| 124 | const hdr = try server.receiveMessage(); | 125 | const hdr = try server.receiveMessage(); |
| 125 | switch (hdr.tag) { | 126 | switch (hdr.tag) { |
| 126 | .exit => { | 127 | .exit => { |
| 127 | return cleanExit(); | 128 | return std.process.cleanExit(); |
| 128 | }, | 129 | }, |
| 129 | .update => { | 130 | .update => { |
| 130 | if (seen_update) { | 131 | if (seen_update) { |
| ... | @@ -144,7 +145,7 @@ pub fn cmdObjCopy( | ... | @@ -144,7 +145,7 @@ pub fn cmdObjCopy( |
| 144 | } | 145 | } |
| 145 | } | 146 | } |
| 146 | } | 147 | } |
| 147 | return cleanExit(); | 148 | return std.process.cleanExit(); |
| 148 | } | 149 | } |
| 149 | 150 | ||
| 150 | const usage = | 151 | const usage = |
test/link/common_symbols/build.zig+1-1| ... | @@ -24,5 +24,5 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize | ... | @@ -24,5 +24,5 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize |
| 24 | }); | 24 | }); |
| 25 | test_exe.linkLibrary(lib_a); | 25 | test_exe.linkLibrary(lib_a); |
| 26 | 26 | ||
| 27 | test_step.dependOn(&test_exe.step); | 27 | test_step.dependOn(&test_exe.run().step); |
| 28 | } | 28 | } |
test/link/common_symbols_alignment/build.zig+1-1| ... | @@ -24,5 +24,5 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize | ... | @@ -24,5 +24,5 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize |
| 24 | }); | 24 | }); |
| 25 | test_exe.linkLibrary(lib_a); | 25 | test_exe.linkLibrary(lib_a); |
| 26 | 26 | ||
| 27 | test_step.dependOn(&test_exe.step); | 27 | test_step.dependOn(&test_exe.run().step); |
| 28 | } | 28 | } |
test/link/interdependent_static_c_libs/build.zig+1-1| ... | @@ -35,5 +35,5 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize | ... | @@ -35,5 +35,5 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize |
| 35 | test_exe.linkLibrary(lib_b); | 35 | test_exe.linkLibrary(lib_b); |
| 36 | test_exe.addIncludePath("."); | 36 | test_exe.addIncludePath("."); |
| 37 | 37 | ||
| 38 | test_step.dependOn(&test_exe.step); | 38 | test_step.dependOn(&test_exe.run().step); |
| 39 | } | 39 | } |
test/link/macho/tls/build.zig+4-1| ... | @@ -32,5 +32,8 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize | ... | @@ -32,5 +32,8 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize |
| 32 | test_exe.linkLibrary(lib); | 32 | test_exe.linkLibrary(lib); |
| 33 | test_exe.linkLibC(); | 33 | test_exe.linkLibC(); |
| 34 | 34 | ||
| 35 | test_step.dependOn(&test_exe.step); | 35 | const run = test_exe.run(); |
| 36 | run.skip_foreign_checks = true; | ||
| 37 | |||
| 38 | test_step.dependOn(&run.step); | ||
| 36 | } | 39 | } |
test/src/Cases.zig+4-7| ... | @@ -547,15 +547,12 @@ pub fn lowerToBuildSteps( | ... | @@ -547,15 +547,12 @@ pub fn lowerToBuildSteps( |
| 547 | parent_step.dependOn(&artifact.step); | 547 | parent_step.dependOn(&artifact.step); |
| 548 | }, | 548 | }, |
| 549 | .Execution => |expected_stdout| { | 549 | .Execution => |expected_stdout| { |
| 550 | if (case.is_test) { | 550 | const run = b.addRunArtifact(artifact); |
| 551 | parent_step.dependOn(&artifact.step); | 551 | run.skip_foreign_checks = true; |
| 552 | } else { | 552 | if (!case.is_test) { |
| 553 | const run = b.addRunArtifact(artifact); | ||
| 554 | run.skip_foreign_checks = true; | ||
| 555 | run.expectStdOutEqual(expected_stdout); | 553 | run.expectStdOutEqual(expected_stdout); |
| 556 | |||
| 557 | parent_step.dependOn(&run.step); | ||
| 558 | } | 554 | } |
| 555 | parent_step.dependOn(&run.step); | ||
| 559 | }, | 556 | }, |
| 560 | .Header => @panic("TODO"), | 557 | .Header => @panic("TODO"), |
| 561 | } | 558 | } |
test/standalone/emit_asm_and_bin/build.zig+1-1| ... | @@ -11,5 +11,5 @@ pub fn build(b: *std.Build) void { | ... | @@ -11,5 +11,5 @@ pub fn build(b: *std.Build) void { |
| 11 | main.emit_asm = .{ .emit_to = b.pathFromRoot("main.s") }; | 11 | main.emit_asm = .{ .emit_to = b.pathFromRoot("main.s") }; |
| 12 | main.emit_bin = .{ .emit_to = b.pathFromRoot("main") }; | 12 | main.emit_bin = .{ .emit_to = b.pathFromRoot("main") }; |
| 13 | 13 | ||
| 14 | test_step.dependOn(&main.step); | 14 | test_step.dependOn(&main.run().step); |
| 15 | } | 15 | } |
test/standalone/global_linkage/build.zig+1-1| ... | @@ -28,5 +28,5 @@ pub fn build(b: *std.Build) void { | ... | @@ -28,5 +28,5 @@ pub fn build(b: *std.Build) void { |
| 28 | main.linkLibrary(obj1); | 28 | main.linkLibrary(obj1); |
| 29 | main.linkLibrary(obj2); | 29 | main.linkLibrary(obj2); |
| 30 | 30 | ||
| 31 | test_step.dependOn(&main.step); | 31 | test_step.dependOn(&main.run().step); |
| 32 | } | 32 | } |
test/standalone/issue_13970/build.zig+3-3| ... | @@ -17,7 +17,7 @@ pub fn build(b: *std.Build) void { | ... | @@ -17,7 +17,7 @@ pub fn build(b: *std.Build) void { |
| 17 | test2.setTestRunner("src/main.zig"); | 17 | test2.setTestRunner("src/main.zig"); |
| 18 | test3.setTestRunner("src/main.zig"); | 18 | test3.setTestRunner("src/main.zig"); |
| 19 | 19 | ||
| 20 | test_step.dependOn(&test1.step); | 20 | test_step.dependOn(&test1.run().step); |
| 21 | test_step.dependOn(&test2.step); | 21 | test_step.dependOn(&test2.run().step); |
| 22 | test_step.dependOn(&test3.step); | 22 | test_step.dependOn(&test3.run().step); |
| 23 | } | 23 | } |
test/standalone/main_pkg_path/build.zig+1-1| ... | @@ -9,5 +9,5 @@ pub fn build(b: *std.Build) void { | ... | @@ -9,5 +9,5 @@ pub fn build(b: *std.Build) void { |
| 9 | }); | 9 | }); |
| 10 | test_exe.setMainPkgPath("."); | 10 | test_exe.setMainPkgPath("."); |
| 11 | 11 | ||
| 12 | test_step.dependOn(&test_exe.step); | 12 | test_step.dependOn(&test_exe.run().step); |
| 13 | } | 13 | } |
test/standalone/options/build.zig+1-1| ... | @@ -20,5 +20,5 @@ pub fn build(b: *std.Build) void { | ... | @@ -20,5 +20,5 @@ pub fn build(b: *std.Build) void { |
| 20 | options.addOption([]const u8, "string", b.option([]const u8, "string", "s").?); | 20 | options.addOption([]const u8, "string", b.option([]const u8, "string", "s").?); |
| 21 | 21 | ||
| 22 | const test_step = b.step("test", "Run unit tests"); | 22 | const test_step = b.step("test", "Run unit tests"); |
| 23 | test_step.dependOn(&main.step); | 23 | test_step.dependOn(&main.run().step); |
| 24 | } | 24 | } |
test/standalone/pie/build.zig+1-1| ... | @@ -17,5 +17,5 @@ pub fn build(b: *std.Build) void { | ... | @@ -17,5 +17,5 @@ pub fn build(b: *std.Build) void { |
| 17 | }); | 17 | }); |
| 18 | main.pie = true; | 18 | main.pie = true; |
| 19 | 19 | ||
| 20 | test_step.dependOn(&main.step); | 20 | test_step.dependOn(&main.run().step); |
| 21 | } | 21 | } |
test/standalone/static_c_lib/build.zig+1-1| ... | @@ -21,5 +21,5 @@ pub fn build(b: *std.Build) void { | ... | @@ -21,5 +21,5 @@ pub fn build(b: *std.Build) void { |
| 21 | test_exe.linkLibrary(foo); | 21 | test_exe.linkLibrary(foo); |
| 22 | test_exe.addIncludePath("."); | 22 | test_exe.addIncludePath("."); |
| 23 | 23 | ||
| 24 | test_step.dependOn(&test_exe.step); | 24 | test_step.dependOn(&test_exe.run().step); |
| 25 | } | 25 | } |
test/standalone/test_runner_module_imports/build.zig+1-1| ... | @@ -15,5 +15,5 @@ pub fn build(b: *std.Build) void { | ... | @@ -15,5 +15,5 @@ pub fn build(b: *std.Build) void { |
| 15 | t.addModule("module2", module2); | 15 | t.addModule("module2", module2); |
| 16 | 16 | ||
| 17 | const test_step = b.step("test", "Run unit tests"); | 17 | const test_step = b.step("test", "Run unit tests"); |
| 18 | test_step.dependOn(&t.step); | 18 | test_step.dependOn(&t.run().step); |
| 19 | } | 19 | } |
test/standalone/test_runner_path/build.zig-1| ... | @@ -8,7 +8,6 @@ pub fn build(b: *std.Build) void { | ... | @@ -8,7 +8,6 @@ pub fn build(b: *std.Build) void { |
| 8 | 8 | ||
| 9 | const test_exe = b.addTest(.{ | 9 | const test_exe = b.addTest(.{ |
| 10 | .root_source_file = .{ .path = "test.zig" }, | 10 | .root_source_file = .{ .path = "test.zig" }, |
| 11 | .kind = .test_exe, | ||
| 12 | }); | 11 | }); |
| 13 | test_exe.test_runner = "test_runner.zig"; | 12 | test_exe.test_runner = "test_runner.zig"; |
| 14 | 13 |
test/standalone/use_alias/build.zig+1-1| ... | @@ -12,5 +12,5 @@ pub fn build(b: *std.Build) void { | ... | @@ -12,5 +12,5 @@ pub fn build(b: *std.Build) void { |
| 12 | }); | 12 | }); |
| 13 | main.addIncludePath("."); | 13 | main.addIncludePath("."); |
| 14 | 14 | ||
| 15 | test_step.dependOn(&main.step); | 15 | test_step.dependOn(&main.run().step); |
| 16 | } | 16 | } |
test/tests.zig+16-11| ... | @@ -596,7 +596,7 @@ pub fn addStandaloneTests( | ... | @@ -596,7 +596,7 @@ pub fn addStandaloneTests( |
| 596 | }); | 596 | }); |
| 597 | if (case.link_libc) exe.linkLibC(); | 597 | if (case.link_libc) exe.linkLibC(); |
| 598 | 598 | ||
| 599 | step.dependOn(&exe.step); | 599 | step.dependOn(&exe.run().step); |
| 600 | } | 600 | } |
| 601 | } | 601 | } |
| 602 | } | 602 | } |
| ... | @@ -981,14 +981,6 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step { | ... | @@ -981,14 +981,6 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step { |
| 981 | }); | 981 | }); |
| 982 | const single_threaded_txt = if (test_target.single_threaded) "single" else "multi"; | 982 | const single_threaded_txt = if (test_target.single_threaded) "single" else "multi"; |
| 983 | const backend_txt = if (test_target.backend) |backend| @tagName(backend) else "default"; | 983 | const backend_txt = if (test_target.backend) |backend| @tagName(backend) else "default"; |
| 984 | these_tests.setNamePrefix(b.fmt("{s}-{s}-{s}-{s}-{s}-{s} ", .{ | ||
| 985 | options.name, | ||
| 986 | triple_prefix, | ||
| 987 | @tagName(test_target.optimize_mode), | ||
| 988 | libc_prefix, | ||
| 989 | single_threaded_txt, | ||
| 990 | backend_txt, | ||
| 991 | })); | ||
| 992 | these_tests.single_threaded = test_target.single_threaded; | 984 | these_tests.single_threaded = test_target.single_threaded; |
| 993 | these_tests.setFilter(options.test_filter); | 985 | these_tests.setFilter(options.test_filter); |
| 994 | if (test_target.link_libc) { | 986 | if (test_target.link_libc) { |
| ... | @@ -1014,7 +1006,18 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step { | ... | @@ -1014,7 +1006,18 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step { |
| 1014 | }, | 1006 | }, |
| 1015 | }; | 1007 | }; |
| 1016 | 1008 | ||
| 1017 | step.dependOn(&these_tests.step); | 1009 | const run = these_tests.run(); |
| 1010 | run.skip_foreign_checks = true; | ||
| 1011 | run.setName(b.fmt("run test {s}-{s}-{s}-{s}-{s}-{s}", .{ | ||
| 1012 | options.name, | ||
| 1013 | triple_prefix, | ||
| 1014 | @tagName(test_target.optimize_mode), | ||
| 1015 | libc_prefix, | ||
| 1016 | single_threaded_txt, | ||
| 1017 | backend_txt, | ||
| 1018 | })); | ||
| 1019 | |||
| 1020 | step.dependOn(&run.step); | ||
| 1018 | } | 1021 | } |
| 1019 | return step; | 1022 | return step; |
| 1020 | } | 1023 | } |
| ... | @@ -1053,7 +1056,9 @@ pub fn addCAbiTests(b: *std.Build, skip_non_native: bool, skip_release: bool) *S | ... | @@ -1053,7 +1056,9 @@ pub fn addCAbiTests(b: *std.Build, skip_non_native: bool, skip_release: bool) *S |
| 1053 | @tagName(optimize_mode), | 1056 | @tagName(optimize_mode), |
| 1054 | })); | 1057 | })); |
| 1055 | 1058 | ||
| 1056 | step.dependOn(&test_step.step); | 1059 | const run = test_step.run(); |
| 1060 | run.skip_foreign_checks = true; | ||
| 1061 | step.dependOn(&run.step); | ||
| 1057 | } | 1062 | } |
| 1058 | } | 1063 | } |
| 1059 | return step; | 1064 | return step; |