Commit 8799f7466d
Changed files (3)
lib
compiler
resinator
lib/compiler/resinator/main.zig
@@ -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();
src/Compilation.zig
@@ -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);
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);