feature. See also
. The project being documented here (as the example) is the Zig library itself.
Maker.makeStepNames
fn makeStepNames(
maker: *Maker,
step_names: []const []const u8,
parent_progress_node: std.Progress.Node,
fuzz: ?Fuzz.Mode,
) !void
File
Code
fn makeStepNames(
maker: *Maker,
step_names: []const []const u8,
parent_progress_node: std.Progress.Node,
fuzz: ?Fuzz.Mode,
) !void {
const graph = maker.graph;
const gpa = maker.gpa;
const io = graph.io;
const step_stack = &maker.step_stack;
const top_level_steps = &maker.scanned_config.top_level_steps;
const c = &maker.scanned_config.configuration;
{
// then spawn them. The buffer is so that we don't race with `makeStep` and end up thinking
// a step is initial when it actually became ready due to an earlier initial step.
var initial_set: std.ArrayList(Configuration.Step.Index) = .empty;
defer initial_set.deinit(gpa);
try initial_set.ensureUnusedCapacity(gpa, step_stack.count());
for (step_stack.keys()) |step_index| {
const s = maker.stepByIndex(step_index);
if (s.state == .precheck_done and s.pending_deps == 0) {
initial_set.appendAssumeCapacity(step_index);
}
}
const step_prog = parent_progress_node.start("steps", step_stack.count());
defer step_prog.end();
var group: Io.Group = .init;
defer group.cancel(io);
for (initial_set.items) |step_index| try stepReady(maker, &group, step_index, step_prog);
try group.await(io);
}
assert(maker.memory_blocked_steps.items.len == 0);
var test_pass_count: usize = 0;
var test_skip_count: usize = 0;
var test_fail_count: usize = 0;
var test_crash_count: usize = 0;
var test_timeout_count: usize = 0;
var test_count: usize = 0;
var success_count: usize = 0;
var skipped_count: usize = 0;
var failure_count: usize = 0;
var pending_count: usize = 0;
var total_compile_errors: usize = 0;
var cleanup_task = io.async(cleanTmpFiles, .{ maker, step_stack.keys() });
defer cleanup_task.await(io);
for (step_stack.keys()) |step_index| {
const make_step = maker.stepByIndex(step_index);
test_pass_count += make_step.test_results.passCount();
test_skip_count += make_step.test_results.skip_count;
test_fail_count += make_step.test_results.fail_count;
test_crash_count += make_step.test_results.crash_count;
test_timeout_count += make_step.test_results.timeout_count;
test_count += make_step.test_results.test_count;
switch (make_step.state) {
.precheck_unstarted => unreachable,
.precheck_started => unreachable,
.precheck_done => unreachable,
.dependency_failure => pending_count += 1,
.success => success_count += 1,
.skipped, .skipped_oom => skipped_count += 1,
.failure => {
failure_count += 1;
const compile_errors_len = make_step.result_error_bundle.errorMessageCount();
if (compile_errors_len > 0) {
total_compile_errors += compile_errors_len;
}
},
}
}
if (fuzz) |mode| blk: {
switch (native_os) {
// * Memory-mapping to share data between the fuzzer and build runner.
// * COFF/PE support added to `std.debug.Info` (it needs a batching API for resolving
// many addresses to source locations).
.windows => fatal("--fuzz not yet implemented for {t}", .{native_os}),
else => {},
}
if (@bitSizeOf(usize) != 64) {
// being compatible with file system's u64 return value. This is not the case
// on 32-bit platforms.
// Affects or affected by issues #5185, #22523, and #22464.
fatal("--fuzz not yet implemented on {d}-bit platforms", .{@bitSizeOf(usize)});
}
switch (mode) {
.forever => break :blk,
.limit => {},
}
assert(mode == .limit);
var f = Fuzz.init(maker, step_stack.keys(), parent_progress_node, mode) catch |err|
fatal("failed to start fuzzer: {t}", .{err});
defer f.deinit();
f.start();
try f.waitAndPrintReport();
}
assert(test_pass_count + test_skip_count + test_fail_count + test_crash_count + test_timeout_count == test_count);
if (failure_count == 0) {
std.Progress.setStatus(.success);
} else {
std.Progress.setStatus(.failure);
}
summary: {
switch (maker.summary) {
.all, .new, .line => {},
.failures => if (failure_count == 0) break :summary,
.none => break :summary,
}
const stderr = try io.lockStderr(&stdio_buffer_allocation, graph.stderr_mode);
defer io.unlockStderr();
const t = stderr.terminal();
const w = &stderr.file_writer.interface;
const total_count = success_count + failure_count + pending_count + skipped_count;
t.setColor(.cyan) catch {};
t.setColor(.bold) catch {};
w.writeAll("Build Summary: ") catch {};
t.setColor(.reset) catch {};
w.print("{d}/{d} steps succeeded", .{ success_count, total_count }) catch {};
{
t.setColor(.dim) catch {};
var first = true;
if (skipped_count > 0) {
w.print("{s}{d} skipped", .{ if (first) " (" else ", ", skipped_count }) catch {};
first = false;
}
if (failure_count > 0) {
w.print("{s}{d} failed", .{ if (first) " (" else ", ", failure_count }) catch {};
first = false;
}
if (!first) w.writeByte(')') catch {};
t.setColor(.reset) catch {};
}
if (test_count > 0) {
w.print("; {d}/{d} tests passed", .{ test_pass_count, test_count }) catch {};
t.setColor(.dim) catch {};
var first = true;
if (test_skip_count > 0) {
w.print("{s}{d} skipped", .{ if (first) " (" else ", ", test_skip_count }) catch {};
first = false;
}
if (test_fail_count > 0) {
w.print("{s}{d} failed", .{ if (first) " (" else ", ", test_fail_count }) catch {};
first = false;
}
if (test_crash_count > 0) {
w.print("{s}{d} crashed", .{ if (first) " (" else ", ", test_crash_count }) catch {};
first = false;
}
if (test_timeout_count > 0) {
w.print("{s}{d} timed out", .{ if (first) " (" else ", ", test_timeout_count }) catch {};
first = false;
}
if (!first) w.writeByte(')') catch {};
t.setColor(.reset) catch {};
}
w.writeByte('\n') catch {};
if (maker.summary == .line) break :summary;
var step_stack_copy = try step_stack.clone(gpa);
defer step_stack_copy.deinit(gpa);
var print_node: PrintNode = .{ .parent = null };
if (step_names.len == 0) {
print_node.last = true;
printTreeStep(maker, c.default_step, t, &print_node, &step_stack_copy) catch |err| switch (err) {
error.Canceled => |e| return e,
else => {},
};
} else {
const last_index = if (maker.summary == .all) top_level_steps.count() else blk: {
var i: usize = step_names.len;
while (i > 0) {
i -= 1;
const step_index = top_level_steps.get(step_names[i]).?;
const step = maker.stepByIndex(step_index);
const found = switch (maker.summary) {
.all, .line, .none => unreachable,
.failures => step.state != .success,
.new => !step.result_cached,
};
if (found) break :blk i;
}
break :blk top_level_steps.count();
};
for (step_names, 0..) |step_name, i| {
const step_index = top_level_steps.get(step_name).?;
print_node.last = i + 1 == last_index;
printTreeStep(maker, step_index, t, &print_node, &step_stack_copy) catch |err| switch (err) {
error.Canceled => |e| return e,
else => {},
};
}
}
w.writeByte('\n') catch {};
}
if (maker.watch or maker.web_server != null) return;
const code: u8 = code: {
if (failure_count == 0) break :code 0;
if (maker.error_style.verboseContext()) break :code 1;
break :code 2;
};
if (code == 0) {
removePoisonedConfiguration(io, maker.scanned_config);
if (debugMakerLeaks()) return deinit(maker);
}
cleanup_task.await(io);
_ = io.lockStderr(&.{}, graph.stderr_mode) catch {};
process.exit(code);
}