mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 05:44:20 +00:00
Report the progress of lazily building zig rc
jitCmd now takes a `server` option that will emit progress/errors via std.zig.Server when enabled.
This commit is contained in:
parent
dc4b05894d
commit
8799f7466d
3 changed files with 153 additions and 102 deletions
|
|
@ -46,6 +46,12 @@ pub fn main() !void {
|
|||
},
|
||||
};
|
||||
|
||||
if (zig_integration) {
|
||||
// Send progress with an empty string to indicate that the building of the
|
||||
// resinator binary is finished and we've moved on to actually compiling the .rc file
|
||||
try error_handler.server.serveStringMessage(.progress, "");
|
||||
}
|
||||
|
||||
var options = options: {
|
||||
var cli_diagnostics = cli.Diagnostics.init(allocator);
|
||||
defer cli_diagnostics.deinit();
|
||||
|
|
|
|||
|
|
@ -4841,6 +4841,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
|
|||
try argv.appendSlice(&.{
|
||||
self_exe_path,
|
||||
"rc",
|
||||
"--zig-integration",
|
||||
"/:no-preprocess",
|
||||
"/x", // ignore INCLUDE environment variable
|
||||
"/c65001", // UTF-8 codepage
|
||||
|
|
@ -4849,31 +4850,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
|
|||
});
|
||||
try argv.appendSlice(&.{ "--", in_rc_path, out_res_path });
|
||||
|
||||
var child = std.ChildProcess.init(argv.items, arena);
|
||||
child.stdin_behavior = .Ignore;
|
||||
child.stdout_behavior = .Ignore;
|
||||
child.stderr_behavior = .Pipe;
|
||||
|
||||
try child.spawn();
|
||||
|
||||
const stderr_reader = child.stderr.?.reader();
|
||||
const stderr = try stderr_reader.readAllAlloc(arena, 10 * 1024 * 1024);
|
||||
const term = child.wait() catch |err| {
|
||||
return comp.failWin32Resource(win32_resource, "unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) });
|
||||
};
|
||||
|
||||
switch (term) {
|
||||
.Exited => |code| {
|
||||
if (code != 0) {
|
||||
log.err("zig rc failed with stderr:\n{s}", .{stderr});
|
||||
return comp.failWin32Resource(win32_resource, "zig rc exited with code {d}", .{code});
|
||||
}
|
||||
},
|
||||
else => {
|
||||
log.err("zig rc terminated with stderr:\n{s}", .{stderr});
|
||||
return comp.failWin32Resource(win32_resource, "zig rc terminated unexpectedly", .{});
|
||||
},
|
||||
}
|
||||
try spawnZigRc(comp, win32_resource, src_basename, arena, argv.items, &child_progress_node);
|
||||
|
||||
break :blk digest;
|
||||
};
|
||||
|
|
@ -4941,79 +4918,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
|
|||
try argv.appendSlice(rc_src.extra_flags);
|
||||
try argv.appendSlice(&.{ "--", rc_src.src_path, out_res_path });
|
||||
|
||||
{
|
||||
var child = std.ChildProcess.init(argv.items, arena);
|
||||
child.stdin_behavior = .Ignore;
|
||||
child.stdout_behavior = .Pipe;
|
||||
child.stderr_behavior = .Pipe;
|
||||
|
||||
child.spawn() catch |err| {
|
||||
return comp.failWin32Resource(win32_resource, "unable to spawn {s} rc: {s}", .{ argv.items[0], @errorName(err) });
|
||||
};
|
||||
|
||||
var poller = std.io.poll(comp.gpa, enum { stdout }, .{
|
||||
.stdout = child.stdout.?,
|
||||
});
|
||||
defer poller.deinit();
|
||||
|
||||
const stdout = poller.fifo(.stdout);
|
||||
|
||||
poll: while (true) {
|
||||
while (stdout.readableLength() < @sizeOf(std.zig.Server.Message.Header)) {
|
||||
if (!(try poller.poll())) break :poll;
|
||||
}
|
||||
const header = stdout.reader().readStruct(std.zig.Server.Message.Header) catch unreachable;
|
||||
while (stdout.readableLength() < header.bytes_len) {
|
||||
if (!(try poller.poll())) break :poll;
|
||||
}
|
||||
const body = stdout.readableSliceOfLen(header.bytes_len);
|
||||
|
||||
switch (header.tag) {
|
||||
// We expect exactly one ErrorBundle, and if any error_bundle header is
|
||||
// sent then it's a fatal error.
|
||||
.error_bundle => {
|
||||
const EbHdr = std.zig.Server.Message.ErrorBundle;
|
||||
const eb_hdr = @as(*align(1) const EbHdr, @ptrCast(body));
|
||||
const extra_bytes =
|
||||
body[@sizeOf(EbHdr)..][0 .. @sizeOf(u32) * eb_hdr.extra_len];
|
||||
const string_bytes =
|
||||
body[@sizeOf(EbHdr) + extra_bytes.len ..][0..eb_hdr.string_bytes_len];
|
||||
const unaligned_extra = std.mem.bytesAsSlice(u32, extra_bytes);
|
||||
const extra_array = try comp.gpa.alloc(u32, unaligned_extra.len);
|
||||
@memcpy(extra_array, unaligned_extra);
|
||||
const error_bundle = .{
|
||||
.string_bytes = try comp.gpa.dupe(u8, string_bytes),
|
||||
.extra = extra_array,
|
||||
};
|
||||
return comp.failWin32ResourceWithOwnedBundle(win32_resource, error_bundle);
|
||||
},
|
||||
else => {}, // ignore other messages
|
||||
}
|
||||
|
||||
stdout.discard(body.len);
|
||||
}
|
||||
|
||||
// Just in case there's a failure that didn't send an ErrorBundle (e.g. an error return trace)
|
||||
const stderr_reader = child.stderr.?.reader();
|
||||
const stderr = try stderr_reader.readAllAlloc(arena, 10 * 1024 * 1024);
|
||||
|
||||
const term = child.wait() catch |err| {
|
||||
return comp.failWin32Resource(win32_resource, "unable to wait for {s} rc: {s}", .{ argv.items[0], @errorName(err) });
|
||||
};
|
||||
|
||||
switch (term) {
|
||||
.Exited => |code| {
|
||||
if (code != 0) {
|
||||
log.err("zig rc failed with stderr:\n{s}", .{stderr});
|
||||
return comp.failWin32Resource(win32_resource, "zig rc exited with code {d}", .{code});
|
||||
}
|
||||
},
|
||||
else => {
|
||||
log.err("zig rc terminated with stderr:\n{s}", .{stderr});
|
||||
return comp.failWin32Resource(win32_resource, "zig rc terminated unexpectedly", .{});
|
||||
},
|
||||
}
|
||||
}
|
||||
try spawnZigRc(comp, win32_resource, src_basename, arena, argv.items, &child_progress_node);
|
||||
|
||||
// Read depfile and update cache manifest
|
||||
{
|
||||
|
|
@ -5079,6 +4984,100 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
|
|||
};
|
||||
}
|
||||
|
||||
fn spawnZigRc(
|
||||
comp: *Compilation,
|
||||
win32_resource: *Win32Resource,
|
||||
src_basename: []const u8,
|
||||
arena: Allocator,
|
||||
argv: []const []const u8,
|
||||
child_progress_node: *std.Progress.Node,
|
||||
) !void {
|
||||
var node_name: std.ArrayListUnmanaged(u8) = .{};
|
||||
defer node_name.deinit(arena);
|
||||
|
||||
var child = std.ChildProcess.init(argv, arena);
|
||||
child.stdin_behavior = .Ignore;
|
||||
child.stdout_behavior = .Pipe;
|
||||
child.stderr_behavior = .Pipe;
|
||||
|
||||
child.spawn() catch |err| {
|
||||
return comp.failWin32Resource(win32_resource, "unable to spawn {s} rc: {s}", .{ argv[0], @errorName(err) });
|
||||
};
|
||||
|
||||
var poller = std.io.poll(comp.gpa, enum { stdout }, .{
|
||||
.stdout = child.stdout.?,
|
||||
});
|
||||
defer poller.deinit();
|
||||
|
||||
const stdout = poller.fifo(.stdout);
|
||||
|
||||
poll: while (true) {
|
||||
while (stdout.readableLength() < @sizeOf(std.zig.Server.Message.Header)) {
|
||||
if (!(try poller.poll())) break :poll;
|
||||
}
|
||||
const header = stdout.reader().readStruct(std.zig.Server.Message.Header) catch unreachable;
|
||||
while (stdout.readableLength() < header.bytes_len) {
|
||||
if (!(try poller.poll())) break :poll;
|
||||
}
|
||||
const body = stdout.readableSliceOfLen(header.bytes_len);
|
||||
|
||||
switch (header.tag) {
|
||||
// We expect exactly one ErrorBundle, and if any error_bundle header is
|
||||
// sent then it's a fatal error.
|
||||
.error_bundle => {
|
||||
const EbHdr = std.zig.Server.Message.ErrorBundle;
|
||||
const eb_hdr = @as(*align(1) const EbHdr, @ptrCast(body));
|
||||
const extra_bytes =
|
||||
body[@sizeOf(EbHdr)..][0 .. @sizeOf(u32) * eb_hdr.extra_len];
|
||||
const string_bytes =
|
||||
body[@sizeOf(EbHdr) + extra_bytes.len ..][0..eb_hdr.string_bytes_len];
|
||||
const unaligned_extra = std.mem.bytesAsSlice(u32, extra_bytes);
|
||||
const extra_array = try comp.gpa.alloc(u32, unaligned_extra.len);
|
||||
@memcpy(extra_array, unaligned_extra);
|
||||
const error_bundle = std.zig.ErrorBundle{
|
||||
.string_bytes = try comp.gpa.dupe(u8, string_bytes),
|
||||
.extra = extra_array,
|
||||
};
|
||||
return comp.failWin32ResourceWithOwnedBundle(win32_resource, error_bundle);
|
||||
},
|
||||
.progress => {
|
||||
node_name.clearRetainingCapacity();
|
||||
if (body.len > 0) {
|
||||
try node_name.appendSlice(arena, "build 'zig rc'... ");
|
||||
try node_name.appendSlice(arena, body);
|
||||
child_progress_node.setName(node_name.items);
|
||||
} else {
|
||||
child_progress_node.setName(src_basename);
|
||||
}
|
||||
},
|
||||
else => {}, // ignore other messages
|
||||
}
|
||||
|
||||
stdout.discard(body.len);
|
||||
}
|
||||
|
||||
// Just in case there's a failure that didn't send an ErrorBundle (e.g. an error return trace)
|
||||
const stderr_reader = child.stderr.?.reader();
|
||||
const stderr = try stderr_reader.readAllAlloc(arena, 10 * 1024 * 1024);
|
||||
|
||||
const term = child.wait() catch |err| {
|
||||
return comp.failWin32Resource(win32_resource, "unable to wait for {s} rc: {s}", .{ argv[0], @errorName(err) });
|
||||
};
|
||||
|
||||
switch (term) {
|
||||
.Exited => |code| {
|
||||
if (code != 0) {
|
||||
log.err("zig rc failed with stderr:\n{s}", .{stderr});
|
||||
return comp.failWin32Resource(win32_resource, "zig rc exited with code {d}", .{code});
|
||||
}
|
||||
},
|
||||
else => {
|
||||
log.err("zig rc terminated with stderr:\n{s}", .{stderr});
|
||||
return comp.failWin32Resource(win32_resource, "zig rc terminated unexpectedly", .{});
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tmpFilePath(comp: *Compilation, ally: Allocator, suffix: []const u8) error{OutOfMemory}![]const u8 {
|
||||
const s = std.fs.path.sep_str;
|
||||
const rand_int = std.crypto.random.int(u64);
|
||||
|
|
|
|||
54
src/main.zig
54
src/main.zig
|
|
@ -291,11 +291,13 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
|
|||
} else if (mem.eql(u8, cmd, "translate-c")) {
|
||||
return buildOutputType(gpa, arena, args, .translate_c);
|
||||
} else if (mem.eql(u8, cmd, "rc")) {
|
||||
const use_server = cmd_args.len > 0 and std.mem.eql(u8, cmd_args[0], "--zig-integration");
|
||||
return jitCmd(gpa, arena, cmd_args, .{
|
||||
.cmd_name = "resinator",
|
||||
.root_src_path = "resinator/main.zig",
|
||||
.depend_on_aro = true,
|
||||
.prepend_zig_lib_dir_path = true,
|
||||
.server = use_server,
|
||||
});
|
||||
} else if (mem.eql(u8, cmd, "fmt")) {
|
||||
return jitCmd(gpa, arena, cmd_args, .{
|
||||
|
|
@ -5304,6 +5306,8 @@ const JitCmdOptions = struct {
|
|||
prepend_zig_exe_path: bool = false,
|
||||
depend_on_aro: bool = false,
|
||||
capture: ?*[]u8 = null,
|
||||
/// Send progress and error bundles via std.zig.Server over stdout
|
||||
server: bool = false,
|
||||
};
|
||||
|
||||
fn jitCmd(
|
||||
|
|
@ -5449,10 +5453,52 @@ fn jitCmd(
|
|||
};
|
||||
defer comp.destroy();
|
||||
|
||||
updateModule(comp, color) catch |err| switch (err) {
|
||||
error.SemanticAnalyzeFail => process.exit(2),
|
||||
else => |e| return e,
|
||||
};
|
||||
if (options.server and !builtin.single_threaded) {
|
||||
var reset: std.Thread.ResetEvent = .{};
|
||||
var progress: std.Progress = .{
|
||||
.terminal = null,
|
||||
.root = .{
|
||||
.context = undefined,
|
||||
.parent = null,
|
||||
.name = "",
|
||||
.unprotected_estimated_total_items = 0,
|
||||
.unprotected_completed_items = 0,
|
||||
},
|
||||
.columns_written = 0,
|
||||
.prev_refresh_timestamp = 0,
|
||||
.timer = null,
|
||||
.done = false,
|
||||
};
|
||||
const main_progress_node = &progress.root;
|
||||
main_progress_node.context = &progress;
|
||||
var server = std.zig.Server{
|
||||
.out = std.io.getStdOut(),
|
||||
.in = undefined, // won't be receiving messages
|
||||
.receive_fifo = undefined, // won't be receiving messages
|
||||
};
|
||||
|
||||
var progress_thread = try std.Thread.spawn(.{}, progressThread, .{
|
||||
&progress, &server, &reset,
|
||||
});
|
||||
defer {
|
||||
reset.set();
|
||||
progress_thread.join();
|
||||
}
|
||||
|
||||
try comp.update(main_progress_node);
|
||||
|
||||
var error_bundle = try comp.getAllErrorsAlloc();
|
||||
defer error_bundle.deinit(comp.gpa);
|
||||
if (error_bundle.errorMessageCount() > 0) {
|
||||
try server.serveErrorBundle(error_bundle);
|
||||
process.exit(2);
|
||||
}
|
||||
} else {
|
||||
updateModule(comp, color) catch |err| switch (err) {
|
||||
error.SemanticAnalyzeFail => process.exit(2),
|
||||
else => |e| return e,
|
||||
};
|
||||
}
|
||||
|
||||
const exe_path = try global_cache_directory.join(arena, &.{comp.cache_use.whole.bin_sub_path.?});
|
||||
child_argv.appendAssumeCapacity(exe_path);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue