diff --git a/lib/compiler/Maker.zig b/lib/compiler/Maker.zig index aaa6498c001a1eb1305cfa6466d94b09825cde2f..0a7ea5cb1f5520d4c606f58049c7f1185f43ae09 100644 --- a/lib/compiler/Maker.zig +++ b/lib/compiler/Maker.zig @@ -3434,6 +3434,8 @@ fn serveBuildStepCompleted( const step = maker.stepByIndex(step_index); const error_bundle = step.result_error_bundle; + const gf_size = countGeneratedFiles(maker.generated_files, step_index, &maker.scanned_config.configuration); + const body: Server.Message.BuildStepCompleted = .{ .step_index = step_index, .status = status, @@ -3441,19 +3443,172 @@ fn serveBuildStepCompleted( .extra_len = @intCast(error_bundle.extra.len), .string_bytes_len = @intCast(error_bundle.string_bytes.len), }, + .generated_files_len = gf_size.count, }; const eb_bytes_len = @sizeOf(u32) * error_bundle.extra.len + error_bundle.string_bytes.len; - const bytes_len = @sizeOf(Server.Message.BuildStepCompleted) + eb_bytes_len; + const bytes_len = @sizeOf(Server.Message.BuildStepCompleted) + eb_bytes_len + + (gf_size.count * @sizeOf(Server.Message.GeneratedFile)) + gf_size.size; try s.serveMessageHeader(.{ .tag = .bsp_step_completed, .bytes_len = @intCast(bytes_len), }); try s.out.writeStruct(body, .little); + try s.out.writeSliceEndian(u32, error_bundle.extra, .little); try s.out.writeAll(error_bundle.string_bytes); + + try writeGeneratedFiles(maker.generated_files, step_index, &maker.scanned_config.configuration, s.out); + try writeGeneratedFilesData(maker.generated_files, step_index, &maker.scanned_config.configuration, s.out); + try s.out.flush(); } +fn walkGeneratedFiles( + step_index: Configuration.Step.Index, + conf: *const Configuration, + comptime Context: type, + context: Context, +) void { + const conf_step = step_index.ptr(conf); + switch (conf_step.extended.get(conf.extra)) { + .check_file, + .fail, + .fmt, + .install_artifact, + .install_dir, + .install_file, + .top_level, + .update_source_files, + => {}, + + .compile => |compile| { + walkGeneratedFilesOne(context, compile.emit_directory.value); + walkGeneratedFilesOne(context, compile.generated_docs.value); + walkGeneratedFilesOne(context, compile.generated_asm.value); + walkGeneratedFilesOne(context, compile.generated_bin.value); + walkGeneratedFilesOne(context, compile.generated_pdb.value); + walkGeneratedFilesOne(context, compile.generated_implib.value); + walkGeneratedFilesOne(context, compile.generated_llvm_bc.value); + walkGeneratedFilesOne(context, compile.generated_llvm_ir.value); + walkGeneratedFilesOne(context, compile.generated_h.value); + }, + .config_header => |config_header| { + walkGeneratedFilesOne(context, config_header.generated_dir); + }, + .find_program => |find_program| { + walkGeneratedFilesOne(context, find_program.found_path); + }, + .obj_copy => |obj_copy| { + walkGeneratedFilesOne(context, obj_copy.output_file); + walkGeneratedFilesOne(context, obj_copy.debug_file.value); + }, + .options => |options| { + walkGeneratedFilesOne(context, options.generated_file); + }, + .run => |run| { + if (run.captured_stdout.value) |v| walkGeneratedFilesOne(context, v.generated_file); + if (run.captured_stderr.value) |v| walkGeneratedFilesOne(context, v.generated_file); + for (run.args.slice) |arg| + walkGeneratedFilesOne(context, arg.get(conf).generated.value); + }, + .translate_c => |translate_c| { + walkGeneratedFilesOne(context, translate_c.output_file); + }, + .write_file => |write_file| { + walkGeneratedFilesOne(context, write_file.generated_directory); + }, + } +} + +fn walkGeneratedFilesOne( + context: anytype, + opt: ?Configuration.GeneratedFileIndex, +) void { + context.visit(opt orelse return); +} + +fn countGeneratedFiles( + generated_files: []const GeneratedFile, + step_index: Configuration.Step.Index, + conf: *const Configuration, +) struct { count: u32, size: u32 } { + const Visitor = struct { + generated_files: []const GeneratedFile, + count: u32, + size: u32, + + fn visit(this: *@This(), i: Configuration.GeneratedFileIndex) void { + const data = this.generated_files[@backingInt(i)].data orelse return; + this.count += 1; + this.size = @intCast(this.size + data.len); + } + }; + var v: Visitor = .{ + .generated_files = generated_files, + .count = 0, + .size = 0, + }; + walkGeneratedFiles(step_index, conf, *Visitor, &v); + return .{ + .count = v.count, + .size = v.size, + }; +} + +fn writeGeneratedFiles( + generated_files: []const GeneratedFile, + step_index: Configuration.Step.Index, + conf: *const Configuration, + writer: *Io.Writer, +) Io.Writer.Error!void { + const Visitor = struct { + generated_files: []const GeneratedFile, + writer: *Io.Writer, + result: Io.Writer.Error!void, + + fn visit(this: *@This(), i: Configuration.GeneratedFileIndex) void { + const unpacked = this.generated_files[@backingInt(i)].unpack() orelse return; + const payload: Server.Message.GeneratedFile = .{ + .index = i, + .path_len = @intCast(unpacked.sub_path.len), + }; + this.result = this.writer.writeAll(@ptrCast((&payload)[0..1])); + } + }; + var v: Visitor = .{ + .generated_files = generated_files, + .writer = writer, + .result = {}, + }; + walkGeneratedFiles(step_index, conf, *Visitor, &v); + return v.result; +} + +fn writeGeneratedFilesData( + generated_files: []const GeneratedFile, + step_index: Configuration.Step.Index, + conf: *const Configuration, + writer: *Io.Writer, +) Io.Writer.Error!void { + const Visitor = struct { + generated_files: []const GeneratedFile, + writer: *Io.Writer, + result: Io.Writer.Error!void, + + fn visit(this: *@This(), i: Configuration.GeneratedFileIndex) void { + const data = this.generated_files[@backingInt(i)].data orelse return; + this.result = this.writer.writeAll(data); + } + }; + var v: Visitor = .{ + .generated_files = generated_files, + .writer = writer, + .result = {}, + }; + walkGeneratedFiles(step_index, conf, *Visitor, &v); + return v.result; +} + fn initStdoutWriter(io: Io) *Writer { stdout_writer_allocation = Io.File.stdout().writerStreaming(io, &stdio_buffer_allocation); return &stdout_writer_allocation.interface; diff --git a/lib/std/zig/ErrorBundle.zig b/lib/std/zig/ErrorBundle.zig index 03ff0f83f22ae3184aced9a856e443f65d1273a0..d6fde276f1e9fb328d262b90a91f0112c45afb77 100644 --- a/lib/std/zig/ErrorBundle.zig +++ b/lib/std/zig/ErrorBundle.zig @@ -197,6 +197,24 @@ pub fn renderToTerminal(eb: ErrorBundle, options: RenderOptions, t: Io.Terminal) } } +pub fn readAlloc( + r: *Io.Reader, + gpa: Allocator, + extra_len: u32, + string_bytes_len: u32, +) Io.Reader.ReadAllocError!ErrorBundle { + const extra = try r.readSliceEndianAlloc(gpa, u32, extra_len, .little); + errdefer gpa.free(extra); + + const string_bytes = try r.readAlloc(gpa, string_bytes_len); + errdefer gpa.free(string_bytes); + + return .{ + .extra = extra, + .string_bytes = string_bytes, + }; +} + fn renderErrorMessage( eb: ErrorBundle, options: RenderOptions, diff --git a/lib/std/zig/Server.zig b/lib/std/zig/Server.zig index eac3555acf7074a174f333401e0f79c70c23ab7e..a96f186f4460c585bffb9fc8cd42f030675d172c 100644 --- a/lib/std/zig/Server.zig +++ b/lib/std/zig/Server.zig @@ -8,6 +8,7 @@ const OutMessage = std.zig.Server.Message; const InMessage = std.zig.Client.Message; const Reader = std.Io.Reader; const Writer = std.Io.Writer; +const Configuration = std.Build.Configuration; in: *Reader, out: *Writer, @@ -113,10 +114,15 @@ pub const Message = struct { /// Trailing: /// * error_bundle: ErrorBundle, + /// * generated_file: [generated_files_len]GeneratedFile, + /// * path_bytes: [_]u8, // for each GeneratedFile + /// - PathPrefix + /// - sub_path: [_]u8, pub const BuildStepCompleted = extern struct { - step_index: std.Build.Configuration.Step.Index, + step_index: Configuration.Step.Index, status: Status, error_bundle: ErrorBundle, + generated_files_len: u32, // TODO result_error_msgs // TODO result_stderr // TODO result_peak_rss @@ -130,6 +136,12 @@ pub const Message = struct { }; }; + pub const GeneratedFile = extern struct { + index: Configuration.GeneratedFileIndex, + /// Includes only the path bytes, not the prefix or null byte. + path_len: u32, + }; + pub const PathPrefix = enum(u8) { cwd, zig_lib, diff --git a/tools/bsp.zig b/tools/bsp.zig index b86e30c3af07b53b352602e5b480c0d785055830..e58205fd958ad569ec76fbf4703671546d0062d5 100644 --- a/tools/bsp.zig +++ b/tools/bsp.zig @@ -184,7 +184,35 @@ pub fn main(init: std.process.Init) !void { .bsp_build_started => {}, .bsp_build_completed => if (!watch) break, .bsp_step_started => {}, - .bsp_step_completed => {}, + .bsp_step_completed => { + var reader: Io.Reader = .fixed(body); + const bsc = try reader.takeStruct(Server.Message.BuildStepCompleted, .little); + log.info("step {q} {t}: ({d} generated files)", .{ + bsc.step_index.ptr(c).name.slice(c), + bsc.status, + bsc.generated_files_len, + }); + + var eb = try std.zig.ErrorBundle.readAlloc( + &reader, + gpa, + bsc.error_bundle.extra_len, + bsc.error_bundle.string_bytes_len, + ); + defer eb.deinit(gpa); + try eb.renderToStderr(io, .{}, .auto); + + const modified_files: []align(1) Server.Message.GeneratedFile = @ptrCast( + try reader.take(bsc.generated_files_len * @sizeOf(Server.Message.GeneratedFile)), + ); + for (modified_files) |modified_file| { + const prefix = try reader.takeEnum(Server.Message.PathPrefix, .little); + const sub_path = try reader.take(modified_file.path_len); + log.info("generated file: {d} {t} {q}", .{ + modified_file.index, prefix, sub_path, + }); + } + }, .bsp_configuration => @panic("TODO"), else => std.debug.panic("received unexpected message: {f}", .{fmtEnum(header.tag)}), }