build runner: extract logic to std.Build.Fuzz

This commit is contained in:
Andrew Kelley 2024-07-23 21:17:14 -07:00
parent 047640383e
commit 711ed56ce3
4 changed files with 53 additions and 38 deletions

View file

@ -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),

View file

@ -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,

46
lib/std/Build/Fuzz.zig Normal file
View file

@ -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;
}

View file

@ -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;