Zig 0.17.0-dev (Split by item)

This is an example of documentation generated by ZigDoc, an alternative to Zig's built-in Auto Doc feature. See also examples in other modes/formats. The project being documented here (as the example) is the Zig library itself.

makeStepNames

Maker.makeStepNames
fn makeStepNames(
    maker: *Maker,
    step_names: []const []const u8,
    parent_progress_node: std.Progress.Node,
    fuzz: ?Fuzz.Mode,
) !void

File

lib/compiler/Maker.zig:2096

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;

    {
        // Collect the initial set of tasks (those with no outstanding dependencies) into a buffer,
        // 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);
        // Start working on all of the initial steps...
        for (initial_set.items) |step_index| try stepReady(maker, &group, step_index, step_prog);
        // ...and `makeStep` will trigger every other step when their last dependency finishes.
        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) {
            // Current implementation depends on two things that need to be ported to Windows:
            // * 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) {
            // Current implementation depends on posix.mmap()'s second parameter, `length: usize`,
            // 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();
    }

    // Every test has a state
    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;

        // Print a fancy tree with build results.
        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; // success
        if (maker.error_style.verboseContext()) break :code 1; // failure; print build command
        break :code 2; // failure; do not print build command
    };
    if (code == 0) {
        removePoisonedConfiguration(io, maker.scanned_config);
        if (debugMakerLeaks()) return deinit(maker);
    }
    cleanup_task.await(io); // There is a defer above but an exit below.
    _ = io.lockStderr(&.{}, graph.stderr_mode) catch {};
    process.exit(code);
}