Commit 711ed56ce3

Andrew Kelley <andrew@ziglang.org>
2024-07-24 06:17:14
build runner: extract logic to std.Build.Fuzz
1 parent 0476403
Changed files (4)
lib
lib/compiler/build_runner.zig
@@ -9,6 +9,7 @@ const ArrayList = std.ArrayList;
 const File = std.fs.File;
 const Step = std.Build.Step;
 const Watch = std.Build.Watch;
+const Fuzz = std.Build.Fuzz;
 const Allocator = std.mem.Allocator;
 const fatal = std.process.fatal;
 const runner = @This();
@@ -400,7 +401,7 @@ pub fn main() !void {
             else => return err,
         };
         if (fuzz) {
-            startFuzzing(&run.thread_pool, run.step_stack.keys(), main_progress_node);
+            Fuzz.start(&run.thread_pool, run.step_stack.keys(), main_progress_node);
         }
 
         if (!watch) return cleanExit();
@@ -439,43 +440,6 @@ pub fn main() !void {
     }
 }
 
-fn startFuzzing(thread_pool: *std.Thread.Pool, all_steps: []const *Step, prog_node: std.Progress.Node) void {
-    {
-        const rebuild_node = prog_node.start("Rebuilding Unit Tests", 0);
-        defer rebuild_node.end();
-        var count: usize = 0;
-        var wait_group: std.Thread.WaitGroup = .{};
-        defer wait_group.wait();
-        for (all_steps) |step| {
-            const run = step.cast(Step.Run) orelse continue;
-            if (run.fuzz_tests.items.len > 0 and run.producer != null) {
-                thread_pool.spawnWg(&wait_group, rebuildTestsWorkerRun, .{ run, prog_node });
-                count += 1;
-            }
-        }
-        if (count == 0) {
-            std.debug.lockStdErr();
-            std.debug.print("no fuzz tests found\n", .{});
-            process.exit(2);
-        }
-        rebuild_node.setEstimatedTotalItems(count);
-    }
-    @panic("TODO do something with the rebuilt unit tests");
-}
-
-fn rebuildTestsWorkerRun(run: *Step.Run, parent_prog_node: std.Progress.Node) void {
-    const compile_step = run.producer.?;
-    const prog_node = parent_prog_node.start(compile_step.step.name, 0);
-    defer prog_node.end();
-    const rebuilt_bin_path = compile_step.rebuildInFuzzMode(prog_node) catch |err| {
-        std.debug.print("failed to rebuild {s} in fuzz mode: {s}", .{
-            compile_step.step.name, @errorName(err),
-        });
-        return;
-    };
-    std.debug.print("rebuilt binary: '{s}'\n", .{rebuilt_bin_path});
-}
-
 fn markFailedStepsDirty(gpa: Allocator, all_steps: []const *Step) void {
     for (all_steps) |step| switch (step.state) {
         .dependency_failure, .failure, .skipped => step.recursiveReset(gpa),
lib/std/Build/Step/Run.zig
@@ -89,6 +89,9 @@ has_side_effects: bool,
 /// If this is a Zig unit test binary, this tracks the indexes of the unit
 /// tests that are also fuzz tests.
 fuzz_tests: std.ArrayListUnmanaged(u32),
+/// Populated during the fuzz phase if this run step corresponds to a unit test
+/// executable that contains fuzz tests.
+rebuilt_executable: ?[]const u8,
 
 /// If this Run step was produced by a Compile step, it is tracked here.
 producer: ?*Step.Compile,
@@ -183,6 +186,7 @@ pub fn create(owner: *std.Build, name: []const u8) *Run {
         .dep_output_file = null,
         .has_side_effects = false,
         .fuzz_tests = .{},
+        .rebuilt_executable = null,
         .producer = null,
     };
     return run;
lib/std/Build/Fuzz.zig
@@ -0,0 +1,46 @@
+const std = @import("../std.zig");
+const Fuzz = @This();
+const Step = std.Build.Step;
+const assert = std.debug.assert;
+const fatal = std.process.fatal;
+
+pub fn start(thread_pool: *std.Thread.Pool, all_steps: []const *Step, prog_node: std.Progress.Node) void {
+    {
+        const rebuild_node = prog_node.start("Rebuilding Unit Tests", 0);
+        defer rebuild_node.end();
+        var count: usize = 0;
+        var wait_group: std.Thread.WaitGroup = .{};
+        defer wait_group.wait();
+        for (all_steps) |step| {
+            const run = step.cast(Step.Run) orelse continue;
+            if (run.fuzz_tests.items.len > 0 and run.producer != null) {
+                thread_pool.spawnWg(&wait_group, rebuildTestsWorkerRun, .{ run, prog_node });
+                count += 1;
+            }
+        }
+        if (count == 0) fatal("no fuzz tests found", .{});
+        rebuild_node.setEstimatedTotalItems(count);
+    }
+
+    // Detect failure.
+    for (all_steps) |step| {
+        const run = step.cast(Step.Run) orelse continue;
+        if (run.fuzz_tests.items.len > 0 and run.rebuilt_executable == null)
+            fatal("one or more unit tests failed to be rebuilt in fuzz mode", .{});
+    }
+
+    @panic("TODO do something with the rebuilt unit tests");
+}
+
+fn rebuildTestsWorkerRun(run: *Step.Run, parent_prog_node: std.Progress.Node) void {
+    const compile_step = run.producer.?;
+    const prog_node = parent_prog_node.start(compile_step.step.name, 0);
+    defer prog_node.end();
+    const rebuilt_bin_path = compile_step.rebuildInFuzzMode(prog_node) catch |err| {
+        std.debug.print("failed to rebuild {s} in fuzz mode: {s}", .{
+            compile_step.step.name, @errorName(err),
+        });
+        return;
+    };
+    run.rebuilt_executable = rebuilt_bin_path;
+}
lib/std/Build.zig
@@ -21,6 +21,7 @@ pub const Cache = @import("Build/Cache.zig");
 pub const Step = @import("Build/Step.zig");
 pub const Module = @import("Build/Module.zig");
 pub const Watch = @import("Build/Watch.zig");
+pub const Fuzz = @import("Build/Fuzz.zig");
 
 /// Shared state among all Build instances.
 graph: *Graph,