From 711ed56ce361fd9051fcf6039de48022b8dbc2d1 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 23 Jul 2024 21:17:14 -0700 Subject: [PATCH] build runner: extract logic to std.Build.Fuzz --- lib/compiler/build_runner.zig | 40 ++---------------------------- lib/std/Build.zig | 1 + lib/std/Build/Fuzz.zig | 46 +++++++++++++++++++++++++++++++++++ lib/std/Build/Step/Run.zig | 4 +++ 4 files changed, 53 insertions(+), 38 deletions(-) create mode 100644 lib/std/Build/Fuzz.zig diff --git a/lib/compiler/build_runner.zig b/lib/compiler/build_runner.zig index 5f7c12fe92..e27b4e8762 100644 --- a/lib/compiler/build_runner.zig +++ b/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), diff --git a/lib/std/Build.zig b/lib/std/Build.zig index 1ad2e0ee51..8a4f3e87dd 100644 --- a/lib/std/Build.zig +++ b/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, diff --git a/lib/std/Build/Fuzz.zig b/lib/std/Build/Fuzz.zig new file mode 100644 index 0000000000..a0e754fab1 --- /dev/null +++ b/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; +} diff --git a/lib/std/Build/Step/Run.zig b/lib/std/Build/Step/Run.zig index 7927ac9479..9b7997306f 100644 --- a/lib/std/Build/Step/Run.zig +++ b/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;