DoxigAlpha

evalZigProcess

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

Function parameters

Parameters

#
s:*Step
argv:[]const []const u8
prog_node:std.Progress.Node
watch:bool
web_server:?*Build.WebServer

Type definitions in this namespace

Types

#

Functions in this namespace

Functions

#
make
If the Step's `make` function reports `error.MakeFailed`, it indicates they
dump
For debugging purposes, prints identifying information about this Step.
evalZigProcess
Assumes that argv contains `--listen=-` and that the process being spawned
installFile
Wrapper around `std.fs.Dir.updateFile` that handles verbose and error output.
installDir
Wrapper around `std.fs.Dir.makePathStatus` that handles verbose and error output.
cacheHit
Prefer `cacheHitAndWatch` unless you already added watch inputs
cacheHitAndWatch
Clears previous watch inputs, if any, and then populates watch inputs from
writeManifest
Prefer `writeManifestAndWatch` unless you already added watch inputs
writeManifestAndWatch
Clears previous watch inputs, if any, and then populates watch inputs from
singleUnchangingWatchInput
For steps that have a single input that never changes when re-running `make`.
addWatchInput
Places a *file* dependency on the path.
addDirectoryWatchInput
Any changes inside the directory will trigger invalidation.
addDirectoryWatchInputFromPath
Any changes inside the directory will trigger invalidation.
reset
Implementation detail of file watching and forced rebuilds.
recursiveReset
Implementation detail of file watching.

Source

Implementation

#
pub fn evalZigProcess(
    s: *Step,
    argv: []const []const u8,
    prog_node: std.Progress.Node,
    watch: bool,
    web_server: ?*Build.WebServer,
    gpa: Allocator,
) !?Path {
    if (s.getZigProcess()) |zp| update: {
        assert(watch);
        if (std.Progress.have_ipc) if (zp.progress_ipc_fd) |fd| prog_node.setIpcFd(fd);
        const result = zigProcessUpdate(s, zp, watch, web_server, gpa) catch |err| switch (err) {
            error.BrokenPipe => {
                // Process restart required.
                const term = zp.child.wait() catch |e| {
                    return s.fail("unable to wait for {s}: {s}", .{ argv[0], @errorName(e) });
                };
                _ = term;
                s.clearZigProcess(gpa);
                break :update;
            },
            else => |e| return e,
        };

        if (s.result_error_bundle.errorMessageCount() > 0)
            return s.fail("{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() catch |e| {
                return s.fail("unable to wait for {s}: {s}", .{ argv[0], @errorName(e) });
            };
            s.result_peak_rss = zp.child.resource_usage_statistics.getMaxRss() orelse 0;
            s.clearZigProcess(gpa);
            try handleChildProcessTerm(s, term, null, argv);
            return error.MakeFailed;
        }

        return result;
    }
    assert(argv.len != 0);
    const b = s.owner;
    const arena = b.allocator;

    try handleChildProcUnsupported(s, null, argv);
    try handleVerbose(s.owner, null, argv);

    var child = std.process.Child.init(argv, arena);
    child.env_map = &b.graph.env_map;
    child.stdin_behavior = .Pipe;
    child.stdout_behavior = .Pipe;
    child.stderr_behavior = .Pipe;
    child.request_resource_usage_statistics = true;
    child.progress_node = prog_node;

    child.spawn() catch |err| return s.fail("failed to spawn zig compiler {s}: {s}", .{
        argv[0], @errorName(err),
    });

    const zp = try gpa.create(ZigProcess);
    zp.* = .{
        .child = child,
        .poller = std.Io.poll(gpa, ZigProcess.StreamEnum, .{
            .stdout = child.stdout.?,
            .stderr = child.stderr.?,
        }),
        .progress_ipc_fd = if (std.Progress.have_ipc) child.progress_node.getIpcFd() else {},
    };
    if (watch) s.setZigProcess(zp);
    defer if (!watch) {
        zp.poller.deinit();
        gpa.destroy(zp);
    };

    const result = try zigProcessUpdate(s, zp, watch, web_server, gpa);

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

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

        // Special handling for Compile step that is expecting compile errors.
        if (s.cast(Compile)) |compile| switch (term) {
            .Exited => {
                // Note that the exit code may be 0 in this case due to the
                // compiler server protocol.
                if (compile.expect_errors != null) {
                    return error.NeedCompileErrorCheck;
                }
            },
            else => {},
        };

        try handleChildProcessTerm(s, term, null, argv);
    }

    // This is intentionally printed for failure on the first build but not for
    // subsequent rebuilds.
    if (s.result_error_bundle.errorMessageCount() > 0) {
        return s.fail("the following command failed with {d} compilation errors:\n{s}", .{
            s.result_error_bundle.errorMessageCount(),
            try allocPrintCmd(arena, null, argv),
        });
    }

    return result;
}