diff --git a/build.zig b/build.zig index c8d8f35..d512e25 100644 --- a/build.zig +++ b/build.zig @@ -1,6 +1,7 @@ const std = @import("std"); const builtin = @import("builtin"); const compat = @import("src/compat.zig"); +const ipc = @import("src/ipc.zig"); const tests = @import("test/tests.zig"); const Build = compat.Build; @@ -878,8 +879,8 @@ const ZiglingStep = struct { }); defer poller.deinit(); - try sendMessage(child.stdin.?, .update); - try sendMessage(child.stdin.?, .exit); + try ipc.sendMessage(child.stdin.?, .update); + try ipc.sendMessage(child.stdin.?, .exit); const Header = std.zig.Server.Message.Header; var result: ?[]const u8 = null; @@ -907,21 +908,7 @@ const ZiglingStep = struct { return error.ZigVersionMismatch; }, .error_bundle => { - const EbHdr = std.zig.Server.Message.ErrorBundle; - const eb_hdr = @ptrCast(*align(1) const EbHdr, 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]; - // TODO: use @ptrCast when the compiler supports it - const unaligned_extra = std.mem.bytesAsSlice(u32, extra_bytes); - const extra_array = try allocator.alloc(u32, unaligned_extra.len); - // TODO: use @memcpy when it supports slices - for (extra_array, unaligned_extra) |*dst, src| dst.* = src; - const error_bundle: std.zig.ErrorBundle = .{ - .string_bytes = try allocator.dupe(u8, string_bytes), - .extra = extra_array, - }; + const error_bundle = try ipc.parseErrorBundle(allocator, body); // Print the compiler error bundle now. // TODO: use the same ttyconf from the builder. @@ -939,13 +926,8 @@ const ZiglingStep = struct { sub_prog_node.setName(node_name.items); }, .emit_bin_path => { - const EbpHdr = std.zig.Server.Message.EmitBinPath; - - // TODO: add cache support? - //const ebp_hdr = @ptrCast(*align(1) const EbpHdr, body); - //s.result_cached = ebp_hdr.flags.cache_hit; - - result = try allocator.dupe(u8, body[@sizeOf(EbpHdr)..]); + const emit_bin = try ipc.parseEmitBinPath(allocator, body); + result = emit_bin.path; }, else => {}, // ignore other messages } @@ -985,14 +967,6 @@ const ZiglingStep = struct { } }; -fn sendMessage(file: std.fs.File, tag: std.zig.Client.Message.Tag) !void { - const header: std.zig.Client.Message.Header = .{ - .tag = tag, - .bytes_len = 0, - }; - try file.writeAll(std.mem.asBytes(&header)); -} - // Print a message to stderr. const PrintStep = struct { step: Step, diff --git a/src/ipc.zig b/src/ipc.zig new file mode 100644 index 0000000..9eaaa13 --- /dev/null +++ b/src/ipc.zig @@ -0,0 +1,68 @@ +/// Client side support for Zig IPC. +const std = @import("std"); +const debug = std.debug; +const fs = std.fs; +const mem = std.mem; + +const Allocator = mem.Allocator; +const Client = std.zig.Client; +const ErrorBundle = std.zig.ErrorBundle; +const Server = std.zig.Server; + +/// This data structure must be kept in sync with zig.Server.Message.EmitBinPath. +const EmitBinPath = struct { + flags: Flags, + path: []const u8, + + pub const Flags = Server.Message.EmitBinPath.Flags; + + pub fn deinit(self: *EmitBinPath, allocator: Allocator) void { + allocator.free(self.path); + self.* = undefined; + } +}; + +pub fn parseErrorBundle(allocator: Allocator, data: []const u8) !ErrorBundle { + const EbHdr = Server.Message.ErrorBundle; + const eb_hdr = @ptrCast(*align(1) const EbHdr, data); + const extra_bytes = + data[@sizeOf(EbHdr)..][0 .. @sizeOf(u32) * eb_hdr.extra_len]; + const string_bytes = + data[@sizeOf(EbHdr) + extra_bytes.len ..][0..eb_hdr.string_bytes_len]; + + // TODO: use @ptrCast when the compiler supports it + const unaligned_extra = std.mem.bytesAsSlice(u32, extra_bytes); + const extra_array = try allocator.alloc(u32, unaligned_extra.len); + // TODO: use @memcpy when it supports slices + // + // Don't use the "multi-object for loop" syntax, in + // order to avoid a syntax error with old Zig compilers. + var i: usize = 0; + while (i < extra_array.len) : (i += 1) { + extra_array[i] = unaligned_extra[i]; + } + + return .{ + .string_bytes = try allocator.dupe(u8, string_bytes), + .extra = extra_array, + }; +} + +pub fn parseEmitBinPath(allocator: Allocator, data: []const u8) !EmitBinPath { + const EbpHdr = Server.Message.EmitBinPath; + const ebp_hdr = @ptrCast(*align(1) const EbpHdr, data); + const path = try allocator.dupe(u8, data[@sizeOf(EbpHdr)..]); + + return .{ + .flags = ebp_hdr.flags, + .path = path, + }; +} + +pub fn sendMessage(file: fs.File, tag: Client.Message.Tag) !void { + const header: Client.Message.Header = .{ + .tag = tag, + .bytes_len = 0, + }; + try file.writeAll(mem.asBytes(&header)); +}