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.

evalZigProcess

Assumes that argv contains --listen=- and that the process being spawned is the zig compiler - the same version that compiled the build runner.

Populates s.result_failed_command on failure.

Step.evalZigProcess
pub fn evalZigProcess(
    step_index: Configuration.Step.Index,
    maker: *Maker,
    argv: []const []const u8,
    prog_node: std.Progress.Node,
    watch: bool,
) (Step.ExtendedMakeError || error

File

Code

pub fn evalZigProcess(
    step_index: Configuration.Step.Index,
    maker: *Maker,
    argv: []const []const u8,
    prog_node: std.Progress.Node,
    watch: bool,
) (Step.ExtendedMakeError || error{NeedCompileErrorCheck})!?Path {
    const s = maker.stepByIndex(step_index);
    const gpa = maker.gpa;
    const graph = maker.graph;
    const io = graph.io;

    // If an error occurs, it's happened in this command:
    errdefer s.setFailedCommand(gpa, argv, .{});

    if (s.getZigProcess()) |zp| update: {
        assert(watch);
        if (zp.progress_ipc_index) |ipc_index| prog_node.setIpcIndex(ipc_index);
        zp.progress_ipc_index = null;
        var exited = false;
        defer if (exited) {
            s.extended.compile.zig_process = null;
            zp.deinit(io);
            gpa.destroy(zp);
        } else zp.saveState(prog_node);
        const result = zigProcessUpdate(step_index, maker, zp, watch) catch |err| switch (err) {
            error.BrokenPipe, error.EndOfStream => |reason| {
                // Process restart required.
                std.log.info("{s} restart required: {t}", .{ argv[0], reason });
                _ = zp.child.wait(io) catch |e| return s.fail(maker, "unable to wait for {s}: {t}", .{ argv[0], e });
                exited = true;
                break :update;
            },
            error.OutOfMemory, error.Canceled, error.MakeFailed => |e| return e,
            else => |e| return s.fail(maker, "zig child process monitoring failed: {t}", .{e}),
        };

        if (s.result_error_bundle.errorMessageCount() > 0)
            return s.fail(maker, "{d} compilation errors", .{s.result_error_bundle.errorMessageCount()});

        if (s.result_error_msgs.items.len > 0 and result == null) {
            // Crash detected.
            const term = zp.child.wait(io) catch |e| {
                return s.fail(maker, "unable to wait for {s}: {t}", .{ argv[0], e });
            };
            s.result_peak_rss = zp.child.resource_usage_statistics.getMaxRss() orelse 0;
            exited = true;
            try handleChildProcessTerm(s, maker, term);
            return error.MakeFailed;
        }

        return result;
    }
    assert(argv.len != 0);

    try handleChildProcUnsupported(s, maker);
    try graph.handleVerbose(null, null, argv);

    const zp = try gpa.create(ZigProcess);
    defer if (!watch) gpa.destroy(zp);

    zp.child = std.process.spawn(io, .{
        .argv = argv,
        .environ_map = &graph.environ_map,
        .stdin = .pipe,
        .stdout = .pipe,
        .stderr = .pipe,
        .request_resource_usage_statistics = true,
        .progress_node = prog_node,
    }) catch |err| return s.fail(maker, "failed to spawn zig compiler {s}: {t}", .{ argv[0], err });

    zp.multi_reader.init(gpa, io, zp.multi_reader_buffer.toStreams(), &.{
        zp.child.stdout.?, zp.child.stderr.?,
    });
    if (watch) s.extended.compile.zig_process = zp;
    defer if (!watch) zp.deinit(io);

    const result = result: {
        defer if (watch) zp.saveState(prog_node);
        break :result zigProcessUpdate(step_index, maker, zp, watch) catch |err| switch (err) {
            error.OutOfMemory, error.Canceled, error.MakeFailed => |e| return e,
            else => |e| return s.fail(maker, "zig child process monitoring failed: {t}", .{e}),
        };
    };

    if (!watch) {
        // Send EOF to stdin.
        zp.child.stdin.?.close(io);
        zp.child.stdin = null;

        const term = zp.child.wait(io) catch |err| {
            return s.fail(maker, "unable to wait for {s}: {t}", .{ argv[0], err });
        };
        s.result_peak_rss = zp.child.resource_usage_statistics.getMaxRss() orelse 0;

        // Special handling for compile step that is expecting compile errors.
        const conf = &maker.scanned_config.configuration;
        if (term == .exited) switch (step_index.ptr(conf).extended.get(conf.extra)) {
            .compile => |compile| if (compile.flags4.expect_errors != .none) {
                // Note that the exit code may be 0 in this case due to the
                // compiler server protocol.
                return error.NeedCompileErrorCheck;
            },
            else => {},
        };
        try handleChildProcessTerm(s, maker, term);
    }

    if (s.result_error_bundle.errorMessageCount() > 0) {
        return s.fail(maker, "{d} compilation errors", .{s.result_error_bundle.errorMessageCount()});
    }

    return result;
}