authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-09-25 20:04:07+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-09-25 20:04:07+02:00
log7cef4755c33ca77137fb7e4d83146e27b5703685
treed64ebc4cf10a4728a631649dc78266dc95e10f10
parent5b9147ed59b22edf7f891cf30e8b77223121da4f
parent480e3f89b227c6c1d5daeb8ae8f7af46c9301637

Merge pull request 'Maker: send generated file paths over build server protocol' (#36947) from bsp-generated-files into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/36947

15 files changed, 434 insertions(+), 168 deletions(-)

lib/compiler/Maker.zig+274-14
...@@ -49,7 +49,13 @@ scanned_config: *const ScannedConfig,...@@ -49,7 +49,13 @@ scanned_config: *const ScannedConfig,
49/// system watching does not need to make any special cases, and to avoid more49/// system watching does not need to make any special cases, and to avoid more
50/// OS-specific logic in file system watching implementation.50/// OS-specific logic in file system watching implementation.
51steps: []Step,51steps: []Step,
52generated_files: []Path,52/// Reserved space for all the file paths that are determined at runtime when the associated Step logic runs.
53/// Each element is individually allocated so that steps can access the data without synchronization, and so
54/// that steps can be arbitrarily re-run independently from each other.
55/// Each element is optional because a step might populate any number of generated file paths before ultimately
56/// failing. An element being non-null does not imply that the generated file was successfully generated. Only
57/// the Step success state indicates that information.
58generated_files: []GeneratedFile,
53run_args: ?[]const []const u8,59run_args: ?[]const []const u8,
5460
55available_rss: u64,61available_rss: u64,
...@@ -121,6 +127,38 @@ const MultilineErrors = enum { indent, newline, none };...@@ -121,6 +127,38 @@ const MultilineErrors = enum { indent, newline, none };
121const Summary = enum { all, new, failures, line, none };127const Summary = enum { all, new, failures, line, none };
122const PrintConfiguration = enum { none, zon, path };128const PrintConfiguration = enum { none, zon, path };
123129
130const GeneratedFile = struct {
131 data: ?[]const u8,
132
133 const Unpacked = struct {
134 prefix: Server.Message.PathPrefix,
135 sub_path: []const u8,
136 };
137
138 fn unpack(gf: GeneratedFile) ?Unpacked {
139 const slice = gf.data orelse return null;
140 return .{
141 .prefix = @fromBackingInt(slice[0]),
142 .sub_path = slice[1..],
143 };
144 }
145
146 fn toPath(gf: GeneratedFile, graph: *const Graph) ?Path {
147 const unpacked = unpack(gf) orelse return null;
148 return .{
149 .root_dir = prefixToDirectory(graph, unpacked.prefix),
150 .sub_path = unpacked.sub_path,
151 };
152 }
153
154 fn clear(gf: *GeneratedFile, gpa: Allocator) void {
155 if (gf.data) |data| {
156 gpa.free(data);
157 gf.data = null;
158 }
159 }
160};
161
124/// Used to build the -M flags to pass to build-exe.162/// Used to build the -M flags to pass to build-exe.
125pub const CliModule = struct {163pub const CliModule = struct {
126 name: []const u8,164 name: []const u8,
...@@ -2344,7 +2382,8 @@ fn prepare(...@@ -2344,7 +2382,8 @@ fn prepare(
2344 // Extra step at the end which is the autogenerated placeholder2382 // Extra step at the end which is the autogenerated placeholder
2345 // step which indicates that we need to reconfigure.2383 // step which indicates that we need to reconfigure.
2346 maker.steps = try arena.alloc(Step, c.steps.len + 1);2384 maker.steps = try arena.alloc(Step, c.steps.len + 1);
2347 maker.generated_files = try arena.alloc(Path, c.generated_files_len);2385 maker.generated_files = try arena.alloc(GeneratedFile, c.generated_files_len);
2386 @memset(maker.generated_files, .{ .data = null });
23482387
2349 // The last element is a reserved special pseudostep which contains the2388 // The last element is a reserved special pseudostep which contains the
2350 // watch inputs for the configurer executable.2389 // watch inputs for the configurer executable.
...@@ -2676,6 +2715,7 @@ fn deinit(maker: *Maker) void {...@@ -2676,6 +2715,7 @@ fn deinit(maker: *Maker) void {
2676 const gpa = maker.gpa;2715 const gpa = maker.gpa;
2677 const io = maker.graph.io;2716 const io = maker.graph.io;
2678 for (maker.steps) |*step| step.deinit(gpa, io);2717 for (maker.steps) |*step| step.deinit(gpa, io);
2718 for (maker.generated_files) |*gf| gf.clear(gpa);
2679 maker.memory_blocked_steps.deinit(gpa);2719 maker.memory_blocked_steps.deinit(gpa);
2680 maker.initial_steps.deinit(gpa);2720 maker.initial_steps.deinit(gpa);
2681 maker.step_stack.deinit(gpa);2721 maker.step_stack.deinit(gpa);
...@@ -2787,7 +2827,8 @@ fn makeStep(...@@ -2787,7 +2827,8 @@ fn makeStep(
2787 if (maker.web_server) |ws| {2827 if (maker.web_server) |ws| {
2788 ws.updateStepStatus(step_index, if (success) .success else .failure);2828 ws.updateStepStatus(step_index, if (success) .success else .failure);
2789 }2829 }
2790 if (maker.protocol_server != null) {2830 if (maker.protocol_server) |s| {
2831 // https://codeberg.org/ziglang/zig/issues/36938
2791 maker.protocol_server_mutex.lockUncancelable(io);2832 maker.protocol_server_mutex.lockUncancelable(io);
2792 defer maker.protocol_server_mutex.unlock(io);2833 defer maker.protocol_server_mutex.unlock(io);
27932834
...@@ -2800,11 +2841,8 @@ fn makeStep(...@@ -2800,11 +2841,8 @@ fn makeStep(
2800 .dependency_skipped, .skipped => .skipped,2841 .dependency_skipped, .skipped => .skipped,
2801 .skipped_oom => .skipped_oom,2842 .skipped_oom => .skipped_oom,
2802 };2843 };
2803 serveBuildStepCompleted(2844 serveBuildStepCompleted(maker, step_index, status, s) catch |err|
2804 maker,2845 std.debug.panic("TODO propagate error when failing to send protocol message: {t}", .{err});
2805 step_index,
2806 status,
2807 ) catch |err| std.debug.panic("TODO propagate error when failing to send protocol message: {t}", .{err});
2808 }2846 }
28092847
2810 if (!success) std.Progress.setStatus(.failure_working);2848 if (!success) std.Progress.setStatus(.failure_working);
...@@ -3366,7 +3404,7 @@ fn cleanTmpFiles(maker: *Maker, steps: []const Configuration.Step.Index) void {...@@ -3366,7 +3404,7 @@ fn cleanTmpFiles(maker: *Maker, steps: []const Configuration.Step.Index) void {
3366 if (wf.flags.mode != .tmp) continue;3404 if (wf.flags.mode != .tmp) continue;
3367 const step = maker.stepByIndex(step_index);3405 const step = maker.stepByIndex(step_index);
3368 if (step.state != .success) continue;3406 if (step.state != .success) continue;
3369 const tmp_path = generatedPath(maker, wf.generated_directory).*;3407 const tmp_path = generatedPath(maker, wf.generated_directory);
3370 tmp_path.root_dir.handle.deleteTree(io, tmp_path.subPathOrDot()) catch |err|3408 tmp_path.root_dir.handle.deleteTree(io, tmp_path.subPathOrDot()) catch |err|
3371 log.warn("failed to delete temporary path {f}: {t}", .{ tmp_path, err });3409 log.warn("failed to delete temporary path {f}: {t}", .{ tmp_path, err });
3372 }3410 }
...@@ -3391,11 +3429,13 @@ fn serveBuildStepCompleted(...@@ -3391,11 +3429,13 @@ fn serveBuildStepCompleted(
3391 maker: *Maker,3429 maker: *Maker,
3392 step_index: Configuration.Step.Index,3430 step_index: Configuration.Step.Index,
3393 status: Server.Message.BuildStepCompleted.Status,3431 status: Server.Message.BuildStepCompleted.Status,
3432 s: *Server,
3394) !void {3433) !void {
3395 const s: *Server = maker.protocol_server.?;
3396 const step = maker.stepByIndex(step_index);3434 const step = maker.stepByIndex(step_index);
3397 const error_bundle = step.result_error_bundle;3435 const error_bundle = step.result_error_bundle;
33983436
3437 const gf_size = countGeneratedFiles(maker.generated_files, step_index, &maker.scanned_config.configuration);
3438
3399 const body: Server.Message.BuildStepCompleted = .{3439 const body: Server.Message.BuildStepCompleted = .{
3400 .step_index = step_index,3440 .step_index = step_index,
3401 .status = status,3441 .status = status,
...@@ -3403,19 +3443,172 @@ fn serveBuildStepCompleted(...@@ -3403,19 +3443,172 @@ fn serveBuildStepCompleted(
3403 .extra_len = @intCast(error_bundle.extra.len),3443 .extra_len = @intCast(error_bundle.extra.len),
3404 .string_bytes_len = @intCast(error_bundle.string_bytes.len),3444 .string_bytes_len = @intCast(error_bundle.string_bytes.len),
3405 },3445 },
3446 .generated_files_len = gf_size.count,
3406 };3447 };
3407 const eb_bytes_len = @sizeOf(u32) * error_bundle.extra.len + error_bundle.string_bytes.len;3448 const eb_bytes_len = @sizeOf(u32) * error_bundle.extra.len + error_bundle.string_bytes.len;
3408 const bytes_len = @sizeOf(Server.Message.BuildStepCompleted) + eb_bytes_len;3449 const bytes_len = @sizeOf(Server.Message.BuildStepCompleted) + eb_bytes_len +
3450 (gf_size.count * @sizeOf(Server.Message.GeneratedFile)) + gf_size.size;
3409 try s.serveMessageHeader(.{3451 try s.serveMessageHeader(.{
3410 .tag = .bsp_step_completed,3452 .tag = .bsp_step_completed,
3411 .bytes_len = @intCast(bytes_len),3453 .bytes_len = @intCast(bytes_len),
3412 });3454 });
3413 try s.out.writeStruct(body, .little);3455 try s.out.writeStruct(body, .little);
3456
3414 try s.out.writeSliceEndian(u32, error_bundle.extra, .little);3457 try s.out.writeSliceEndian(u32, error_bundle.extra, .little);
3415 try s.out.writeAll(error_bundle.string_bytes);3458 try s.out.writeAll(error_bundle.string_bytes);
3459
3460 try writeGeneratedFiles(maker.generated_files, step_index, &maker.scanned_config.configuration, s.out);
3461 try writeGeneratedFilesData(maker.generated_files, step_index, &maker.scanned_config.configuration, s.out);
3462
3416 try s.out.flush();3463 try s.out.flush();
3417}3464}
34183465
3466fn walkGeneratedFiles(
3467 step_index: Configuration.Step.Index,
3468 conf: *const Configuration,
3469 comptime Context: type,
3470 context: Context,
3471) void {
3472 const conf_step = step_index.ptr(conf);
3473 switch (conf_step.extended.get(conf.extra)) {
3474 .check_file,
3475 .fail,
3476 .fmt,
3477 .install_artifact,
3478 .install_dir,
3479 .install_file,
3480 .top_level,
3481 .update_source_files,
3482 => {},
3483
3484 .compile => |compile| {
3485 walkGeneratedFilesOne(context, compile.emit_directory.value);
3486 walkGeneratedFilesOne(context, compile.generated_docs.value);
3487 walkGeneratedFilesOne(context, compile.generated_asm.value);
3488 walkGeneratedFilesOne(context, compile.generated_bin.value);
3489 walkGeneratedFilesOne(context, compile.generated_pdb.value);
3490 walkGeneratedFilesOne(context, compile.generated_implib.value);
3491 walkGeneratedFilesOne(context, compile.generated_llvm_bc.value);
3492 walkGeneratedFilesOne(context, compile.generated_llvm_ir.value);
3493 walkGeneratedFilesOne(context, compile.generated_h.value);
3494 },
3495 .config_header => |config_header| {
3496 walkGeneratedFilesOne(context, config_header.generated_dir);
3497 },
3498 .find_program => |find_program| {
3499 walkGeneratedFilesOne(context, find_program.found_path);
3500 },
3501 .obj_copy => |obj_copy| {
3502 walkGeneratedFilesOne(context, obj_copy.output_file);
3503 walkGeneratedFilesOne(context, obj_copy.debug_file.value);
3504 },
3505 .options => |options| {
3506 walkGeneratedFilesOne(context, options.generated_file);
3507 },
3508 .run => |run| {
3509 if (run.captured_stdout.value) |v| walkGeneratedFilesOne(context, v.generated_file);
3510 if (run.captured_stderr.value) |v| walkGeneratedFilesOne(context, v.generated_file);
3511 for (run.args.slice) |arg|
3512 walkGeneratedFilesOne(context, arg.get(conf).generated.value);
3513 },
3514 .translate_c => |translate_c| {
3515 walkGeneratedFilesOne(context, translate_c.output_file);
3516 },
3517 .write_file => |write_file| {
3518 walkGeneratedFilesOne(context, write_file.generated_directory);
3519 },
3520 }
3521}
3522
3523fn walkGeneratedFilesOne(
3524 context: anytype,
3525 opt: ?Configuration.GeneratedFileIndex,
3526) void {
3527 context.visit(opt orelse return);
3528}
3529
3530fn countGeneratedFiles(
3531 generated_files: []const GeneratedFile,
3532 step_index: Configuration.Step.Index,
3533 conf: *const Configuration,
3534) struct { count: u32, size: u32 } {
3535 const Visitor = struct {
3536 generated_files: []const GeneratedFile,
3537 count: u32,
3538 size: u32,
3539
3540 fn visit(this: *@This(), i: Configuration.GeneratedFileIndex) void {
3541 const data = this.generated_files[@backingInt(i)].data orelse return;
3542 this.count += 1;
3543 this.size = @intCast(this.size + data.len);
3544 }
3545 };
3546 var v: Visitor = .{
3547 .generated_files = generated_files,
3548 .count = 0,
3549 .size = 0,
3550 };
3551 walkGeneratedFiles(step_index, conf, *Visitor, &v);
3552 return .{
3553 .count = v.count,
3554 .size = v.size,
3555 };
3556}
3557
3558fn writeGeneratedFiles(
3559 generated_files: []const GeneratedFile,
3560 step_index: Configuration.Step.Index,
3561 conf: *const Configuration,
3562 writer: *Io.Writer,
3563) Io.Writer.Error!void {
3564 const Visitor = struct {
3565 generated_files: []const GeneratedFile,
3566 writer: *Io.Writer,
3567 result: Io.Writer.Error!void,
3568
3569 fn visit(this: *@This(), i: Configuration.GeneratedFileIndex) void {
3570 const unpacked = this.generated_files[@backingInt(i)].unpack() orelse return;
3571 const payload: Server.Message.GeneratedFile = .{
3572 .index = i,
3573 .path_len = @intCast(unpacked.sub_path.len),
3574 };
3575 this.result = this.writer.writeAll(@ptrCast((&payload)[0..1]));
3576 }
3577 };
3578 var v: Visitor = .{
3579 .generated_files = generated_files,
3580 .writer = writer,
3581 .result = {},
3582 };
3583 walkGeneratedFiles(step_index, conf, *Visitor, &v);
3584 return v.result;
3585}
3586
3587fn writeGeneratedFilesData(
3588 generated_files: []const GeneratedFile,
3589 step_index: Configuration.Step.Index,
3590 conf: *const Configuration,
3591 writer: *Io.Writer,
3592) Io.Writer.Error!void {
3593 const Visitor = struct {
3594 generated_files: []const GeneratedFile,
3595 writer: *Io.Writer,
3596 result: Io.Writer.Error!void,
3597
3598 fn visit(this: *@This(), i: Configuration.GeneratedFileIndex) void {
3599 const data = this.generated_files[@backingInt(i)].data orelse return;
3600 this.result = this.writer.writeAll(data);
3601 }
3602 };
3603 var v: Visitor = .{
3604 .generated_files = generated_files,
3605 .writer = writer,
3606 .result = {},
3607 };
3608 walkGeneratedFiles(step_index, conf, *Visitor, &v);
3609 return v.result;
3610}
3611
3419fn initStdoutWriter(io: Io) *Writer {3612fn initStdoutWriter(io: Io) *Writer {
3420 stdout_writer_allocation = Io.File.stdout().writerStreaming(io, &stdio_buffer_allocation);3613 stdout_writer_allocation = Io.File.stdout().writerStreaming(io, &stdio_buffer_allocation);
3421 return &stdout_writer_allocation.interface;3614 return &stdout_writer_allocation.interface;
...@@ -3434,7 +3627,7 @@ pub fn resolveLazyPath(...@@ -3434,7 +3627,7 @@ pub fn resolveLazyPath(
3434 .source_path => |sp| try packagePath(maker, arena, sp.owner, sp.sub_path.slice(c)),3627 .source_path => |sp| try packagePath(maker, arena, sp.owner, sp.sub_path.slice(c)),
3435 .relative => |relative| relativePath(maker, arena, relative),3628 .relative => |relative| relativePath(maker, arena, relative),
3436 .generated => |gen| {3629 .generated => |gen| {
3437 const base = generatedPath(maker, gen.index).*;3630 const base = generatedPath(maker, gen.index);
3438 var file_path = base;3631 var file_path = base;
3439 for (0..gen.flags.up) |_| {3632 for (0..gen.flags.up) |_| {
3440 file_path.sub_path = Dir.path.dirname(file_path.sub_path) orelse {3633 file_path.sub_path = Dir.path.dirname(file_path.sub_path) orelse {
...@@ -3485,10 +3678,67 @@ pub fn resolveLazyPathIndexAbs(...@@ -3485,10 +3678,67 @@ pub fn resolveLazyPathIndexAbs(
3485 return resolveLazyPathAbs(maker, arena, lazy_path_index.get(c), asking_step_index);3678 return resolveLazyPathAbs(maker, arena, lazy_path_index.get(c), asking_step_index);
3486}3679}
34873680
3488pub fn generatedPath(maker: *const Maker, index: Configuration.GeneratedFileIndex) *Path {3681pub fn generatedFile(maker: *const Maker, index: Configuration.GeneratedFileIndex) *GeneratedFile {
3489 return &maker.generated_files[@backingInt(index)];3682 return &maker.generated_files[@backingInt(index)];
3490}3683}
34913684
3685pub fn generatedPath(maker: *const Maker, index: Configuration.GeneratedFileIndex) Path {
3686 return generatedFile(maker, index).toPath(maker.graph).?;
3687}
3688
3689pub fn setGeneratedPath(
3690 maker: *Maker,
3691 index: Configuration.GeneratedFileIndex,
3692 prefix: Server.Message.PathPrefix,
3693 sub_paths: []const []const u8,
3694) Allocator.Error!Path {
3695 const gpa = maker.gpa;
3696 const graph = maker.graph;
3697 assert(sub_paths.len != 0);
3698
3699 var buffer: std.ArrayList(u8) = .empty;
3700 defer buffer.deinit(gpa);
3701 try buffer.append(gpa, @backingInt(prefix));
3702 for (sub_paths) |sub_path| {
3703 try buffer.ensureUnusedCapacity(gpa, sub_path.len + 1);
3704 buffer.appendSliceAssumeCapacity(sub_path);
3705 while (Dir.path.isSep(buffer.items[buffer.items.len - 1]))
3706 buffer.items.len -= 1;
3707 buffer.appendAssumeCapacity(Dir.path.sep);
3708 }
3709 assert(buffer.pop().? == Dir.path.sep);
3710 try buffer.shrinkToLen(gpa);
3711
3712 const sub_path = buffer.toOwnedSliceAssert();
3713 const ptr = generatedFile(maker, index);
3714 ptr.clear(gpa);
3715 ptr.* = .{ .data = sub_path };
3716 return .{
3717 .root_dir = prefixToDirectory(graph, prefix),
3718 .sub_path = sub_path[1..],
3719 };
3720}
3721
3722/// Prefer to use `setGeneratedPath` where possible to keep parent directory information intact.
3723pub fn setGeneratedPathPath(
3724 maker: *Maker,
3725 index: Configuration.GeneratedFileIndex,
3726 path: Path,
3727) Allocator.Error!Path {
3728 const graph = maker.graph;
3729 if (path.root_dir.eql(graph.local_cache_root)) {
3730 return setGeneratedPath(maker, index, .local_cache, &.{path.sub_path});
3731 } else if (path.root_dir.eql(graph.global_cache_root)) {
3732 return setGeneratedPath(maker, index, .global_cache, &.{path.sub_path});
3733 } else if (path.root_dir.eql(graph.zig_lib_directory)) {
3734 return setGeneratedPath(maker, index, .zig_lib, &.{path.sub_path});
3735 } else if (path.root_dir.eql(graph.build_root_directory)) {
3736 return setGeneratedPath(maker, index, .build_root, &.{path.sub_path});
3737 } else {
3738 return setGeneratedPath(maker, index, .cwd, &.{path.sub_path});
3739 }
3740}
3741
3492pub fn packagePath(3742pub fn packagePath(
3493 maker: *const Maker,3743 maker: *const Maker,
3494 arena: Allocator,3744 arena: Allocator,
...@@ -3600,7 +3850,7 @@ pub fn installGenerated(...@@ -3600,7 +3850,7 @@ pub fn installGenerated(
3600 dest_dir: Configuration.InstallDestDir,3850 dest_dir: Configuration.InstallDestDir,
3601 asking_step_index: Configuration.Step.Index,3851 asking_step_index: Configuration.Step.Index,
3602) !Dir.PrevStatus {3852) !Dir.PrevStatus {
3603 const src_path = generatedPath(maker, source).*;3853 const src_path = generatedPath(maker, source);
3604 const dest_dir_path = try resolveInstallDir(maker, arena, dest_dir);3854 const dest_dir_path = try resolveInstallDir(maker, arena, dest_dir);
3605 const dest_path = try dest_dir_path.join(arena, src_path.basename());3855 const dest_path = try dest_dir_path.join(arena, src_path.basename());
3606 return installPath(maker, arena, src_path, dest_path, asking_step_index);3856 return installPath(maker, arena, src_path, dest_path, asking_step_index);
...@@ -4170,3 +4420,13 @@ fn nextEnumArg(args: []const []const u8, i: *usize, comptime E: type) E {...@@ -4170,3 +4420,13 @@ fn nextEnumArg(args: []const []const u8, i: *usize, comptime E: type) E {
4170 const next_arg = nextArg(args, i) orelse fatalEnumHint(E, arg, null);4420 const next_arg = nextArg(args, i) orelse fatalEnumHint(E, arg, null);
4171 return stringToEnum(E, next_arg) orelse fatalEnumHint(E, arg, next_arg);4421 return stringToEnum(E, next_arg) orelse fatalEnumHint(E, arg, next_arg);
4172}4422}
4423
4424fn prefixToDirectory(graph: *const Graph, prefix: Server.Message.PathPrefix) Cache.Directory {
4425 return switch (prefix) {
4426 .cwd => .cwd(),
4427 .zig_lib => graph.zig_lib_directory,
4428 .local_cache => graph.local_cache_root,
4429 .global_cache => graph.global_cache_root,
4430 .build_root => graph.build_root_directory,
4431 };
4432}
lib/compiler/Maker/Fuzz.zig+8-2
...@@ -161,6 +161,7 @@ pub fn deinit(fuzz: *Fuzz) void {...@@ -161,6 +161,7 @@ pub fn deinit(fuzz: *Fuzz) void {
161 fuzz.group.cancel(io);161 fuzz.group.cancel(io);
162 fuzz.prog_node.end();162 fuzz.prog_node.end();
163 gpa.free(fuzz.run_steps);163 gpa.free(fuzz.run_steps);
164 fuzz.msg_queue.deinit(gpa);
164}165}
165166
166fn rebuildTestsWorkerRun(167fn rebuildTestsWorkerRun(
...@@ -212,7 +213,7 @@ fn rebuildTestsWorkerRunFallible(...@@ -212,7 +213,7 @@ fn rebuildTestsWorkerRunFallible(
212 maker.printErrorMessages(comp_index, .{}, stderr.terminal(), .verbose, .indent) catch {};213 maker.printErrorMessages(comp_index, .{}, stderr.terminal(), .verbose, .indent) catch {};
213 }214 }
214215
215 const rebuilt_bin_path = result catch |err| switch (err) {216 const rebuilt_digest = result catch |err| switch (err) {
216 error.MakeFailed => return,217 error.MakeFailed => return,
217 else => |other| return other,218 else => |other| return other,
218 };219 };
...@@ -235,7 +236,12 @@ fn rebuildTestsWorkerRunFallible(...@@ -235,7 +236,12 @@ fn rebuildTestsWorkerRunFallible(
235 });236 });
236 defer gpa.free(compile_filename);237 defer gpa.free(compile_filename);
237238
238 run.rebuilt_executable = try rebuilt_bin_path.join(gpa, compile_filename);239 const o_hex_digest = rebuilt_digest.toHex().?;
240
241 run.rebuilt_executable = .{
242 .root_dir = graph.local_cache_root,
243 .sub_path = try std.fs.path.join(gpa, &.{ "o", &o_hex_digest, compile_filename }),
244 };
239}245}
240246
241fn fuzzWorkerRun(fuzz: *Fuzz, run_index: Configuration.Step.Index) void {247fn fuzzWorkerRun(fuzz: *Fuzz, run_index: Configuration.Step.Index) void {
lib/compiler/Maker/Step.zig+14-9
...@@ -460,6 +460,15 @@ pub const ZigProcess = struct {...@@ -460,6 +460,15 @@ pub const ZigProcess = struct {
460 }460 }
461};461};
462462
463pub const OptCacheDigest = struct {
464 bin: ?Cache.BinDigest,
465
466 pub fn toHex(ocd: *const OptCacheDigest) ?Cache.HexDigest {
467 const bin = ocd.bin orelse return null;
468 return Cache.binToHex(bin);
469 }
470};
471
463/// Assumes that argv contains `--listen=-` and that the process being spawned472/// Assumes that argv contains `--listen=-` and that the process being spawned
464/// is the zig compiler - the same version that compiled the build runner.473/// is the zig compiler - the same version that compiled the build runner.
465///474///
...@@ -470,7 +479,7 @@ pub fn evalZigProcess(...@@ -470,7 +479,7 @@ pub fn evalZigProcess(
470 argv: []const []const u8,479 argv: []const []const u8,
471 prog_node: std.Progress.Node,480 prog_node: std.Progress.Node,
472 watch: bool,481 watch: bool,
473) (Step.ExtendedMakeError || error{NeedCompileErrorCheck})!?Path {482) (Step.ExtendedMakeError || error{NeedCompileErrorCheck})!OptCacheDigest {
474 const s = maker.stepByIndex(step_index);483 const s = maker.stepByIndex(step_index);
475 const gpa = maker.gpa;484 const gpa = maker.gpa;
476 const graph = maker.graph;485 const graph = maker.graph;
...@@ -503,7 +512,7 @@ pub fn evalZigProcess(...@@ -503,7 +512,7 @@ pub fn evalZigProcess(
503 if (s.result_error_bundle.errorMessageCount() > 0)512 if (s.result_error_bundle.errorMessageCount() > 0)
504 return s.fail(maker, "{d} compilation errors", .{s.result_error_bundle.errorMessageCount()});513 return s.fail(maker, "{d} compilation errors", .{s.result_error_bundle.errorMessageCount()});
505514
506 if (s.result_error_msgs.items.len > 0 and result == null) {515 if (s.result_error_msgs.items.len > 0 and result.bin == null) {
507 // Crash detected.516 // Crash detected.
508 const term = zp.child.wait(io) catch |e| {517 const term = zp.child.wait(io) catch |e| {
509 return s.fail(maker, "unable to wait for {s}: {t}", .{ argv[0], e });518 return s.fail(maker, "unable to wait for {s}: {t}", .{ argv[0], e });
...@@ -578,7 +587,7 @@ pub fn evalZigProcess(...@@ -578,7 +587,7 @@ pub fn evalZigProcess(
578 return result;587 return result;
579}588}
580589
581fn zigProcessUpdate(step_index: Configuration.Step.Index, maker: *Maker, zp: *ZigProcess, watch: bool) !?Path {590fn zigProcessUpdate(step_index: Configuration.Step.Index, maker: *Maker, zp: *ZigProcess, watch: bool) !OptCacheDigest {
582 const s = maker.stepByIndex(step_index);591 const s = maker.stepByIndex(step_index);
583 const gpa = maker.gpa;592 const gpa = maker.gpa;
584 const graph = maker.graph;593 const graph = maker.graph;
...@@ -590,7 +599,7 @@ fn zigProcessUpdate(step_index: Configuration.Step.Index, maker: *Maker, zp: *Zi...@@ -590,7 +599,7 @@ fn zigProcessUpdate(step_index: Configuration.Step.Index, maker: *Maker, zp: *Zi
590 try sendMessage(io, zp.child.stdin.?, .update);599 try sendMessage(io, zp.child.stdin.?, .update);
591 if (!watch) try sendMessage(io, zp.child.stdin.?, .exit);600 if (!watch) try sendMessage(io, zp.child.stdin.?, .exit);
592601
593 var result: ?Path = null;602 var result: OptCacheDigest = .{ .bin = null };
594 var eos_err: error{EndOfStream}!void = {};603 var eos_err: error{EndOfStream}!void = {};
595604
596 var client: std.zig.Client = .{605 var client: std.zig.Client = .{
...@@ -632,11 +641,7 @@ fn zigProcessUpdate(step_index: Configuration.Step.Index, maker: *Maker, zp: *Zi...@@ -632,11 +641,7 @@ fn zigProcessUpdate(step_index: Configuration.Step.Index, maker: *Maker, zp: *Zi
632 const EmitDigest = std.zig.Server.Message.EmitDigest;641 const EmitDigest = std.zig.Server.Message.EmitDigest;
633 const emit_digest: *align(1) const EmitDigest = @ptrCast(body);642 const emit_digest: *align(1) const EmitDigest = @ptrCast(body);
634 s.result_cached = emit_digest.flags.cache_hit;643 s.result_cached = emit_digest.flags.cache_hit;
635 const digest = body[@sizeOf(EmitDigest)..][0..Cache.bin_digest_len];644 result = .{ .bin = body[@sizeOf(EmitDigest)..][0..Cache.bin_digest_len].* };
636 result = .{
637 .root_dir = graph.local_cache_root,
638 .sub_path = try arena.dupe(u8, "o" ++ Dir.path.sep_str ++ Cache.binToHex(digest.*)),
639 };
640 },645 },
641 .file_system_inputs => {646 .file_system_inputs => {
642 clearWatchInputs(s, maker);647 clearWatchInputs(s, maker);
lib/compiler/Maker/Step/Compile.zig+19-20
...@@ -46,7 +46,7 @@ pub fn make(...@@ -46,7 +46,7 @@ pub fn make(
4646
47 const incremental = conf_comp.flags4.incremental.toBool() orelse graph.incremental == true;47 const incremental = conf_comp.flags4.incremental.toBool() orelse graph.incremental == true;
4848
49 const maybe_output_dir = Step.evalZigProcess(49 const opt_cache_digest = Step.evalZigProcess(
50 compile_index,50 compile_index,
51 maker,51 maker,
52 argv.items,52 argv.items,
...@@ -63,24 +63,25 @@ pub fn make(...@@ -63,24 +63,25 @@ pub fn make(
63 const root_module = conf_comp.root_module.get(conf);63 const root_module = conf_comp.root_module.get(conf);
64 const target = root_module.resolved_target.get(conf).?.result.get(conf);64 const target = root_module.resolved_target.get(conf).?.result.get(conf);
6565
66 // Update generated files66 if (opt_cache_digest.toHex()) |o_hex_digest| {
67 if (maybe_output_dir) |output_dir| {67 if (conf_comp.emit_directory.value) |gf| {
68 if (conf_comp.emit_directory.value) |gf| maker.generatedPath(gf).* = output_dir;68 _ = try maker.setGeneratedPath(gf, .local_cache, &.{ "o", &o_hex_digest });
69 try updateGeneratedFile(maker, arena, &conf_comp, output_dir, &target, conf_comp.generated_bin.value, .bin);69 }
70 try updateGeneratedFile(maker, arena, &conf_comp, output_dir, &target, conf_comp.generated_pdb.value, .pdb);70 try updateGeneratedFile(maker, arena, &conf_comp, &o_hex_digest, &target, conf_comp.generated_bin.value, .bin);
71 try updateGeneratedFile(maker, arena, &conf_comp, output_dir, &target, conf_comp.generated_implib.value, .implib);71 try updateGeneratedFile(maker, arena, &conf_comp, &o_hex_digest, &target, conf_comp.generated_pdb.value, .pdb);
72 try updateGeneratedFile(maker, arena, &conf_comp, output_dir, &target, conf_comp.generated_h.value, .h);72 try updateGeneratedFile(maker, arena, &conf_comp, &o_hex_digest, &target, conf_comp.generated_implib.value, .implib);
73 try updateGeneratedFile(maker, arena, &conf_comp, output_dir, &target, conf_comp.generated_docs.value, .docs);73 try updateGeneratedFile(maker, arena, &conf_comp, &o_hex_digest, &target, conf_comp.generated_h.value, .h);
74 try updateGeneratedFile(maker, arena, &conf_comp, output_dir, &target, conf_comp.generated_asm.value, .@"asm");74 try updateGeneratedFile(maker, arena, &conf_comp, &o_hex_digest, &target, conf_comp.generated_docs.value, .docs);
75 try updateGeneratedFile(maker, arena, &conf_comp, output_dir, &target, conf_comp.generated_llvm_ir.value, .llvm_ir);75 try updateGeneratedFile(maker, arena, &conf_comp, &o_hex_digest, &target, conf_comp.generated_asm.value, .@"asm");
76 try updateGeneratedFile(maker, arena, &conf_comp, output_dir, &target, conf_comp.generated_llvm_bc.value, .llvm_bc);76 try updateGeneratedFile(maker, arena, &conf_comp, &o_hex_digest, &target, conf_comp.generated_llvm_ir.value, .llvm_ir);
77 try updateGeneratedFile(maker, arena, &conf_comp, &o_hex_digest, &target, conf_comp.generated_llvm_bc.value, .llvm_bc);
77 }78 }
7879
79 if (conf_comp.flags3.kind == .lib and conf_comp.flags2.linkage == .dynamic and80 if (conf_comp.flags3.kind == .lib and conf_comp.flags2.linkage == .dynamic and
80 conf_comp.version.value != null and target.flags.os_tag != .windows)81 conf_comp.version.value != null and target.flags.os_tag != .windows)
81 {82 {
82 if (conf_comp.generated_bin.value) |generated_bin| {83 if (conf_comp.generated_bin.value) |generated_bin| {
83 const full_dest_path = maker.generatedPath(generated_bin).*;84 const full_dest_path = maker.generatedPath(generated_bin);
84 try maker.installSymLinks(arena, full_dest_path, compile_index, compile_index);85 try maker.installSymLinks(arena, full_dest_path, compile_index, compile_index);
85 }86 }
86 }87 }
...@@ -97,13 +98,12 @@ fn updateGeneratedFile(...@@ -97,13 +98,12 @@ fn updateGeneratedFile(
97 maker: *Maker,98 maker: *Maker,
98 arena: Allocator,99 arena: Allocator,
99 conf_comp: *const Configuration.Step.Compile,100 conf_comp: *const Configuration.Step.Compile,
100 out_path: std.Build.Cache.Path,101 o_hex_digest: *const std.Build.Cache.HexDigest,
101 target: *const Configuration.TargetQuery,102 target: *const Configuration.TargetQuery,
102 opt_gf: ?Configuration.GeneratedFileIndex,103 opt_gf: ?Configuration.GeneratedFileIndex,
103 ea: std.zig.EmitArtifact,104 ea: std.zig.EmitArtifact,
104) Allocator.Error!void {105) Allocator.Error!void {
105 const gf = opt_gf orelse return;106 const gf = opt_gf orelse return;
106 const graph = maker.graph;
107 const conf = &maker.scanned_config.configuration;107 const conf = &maker.scanned_config.configuration;
108 const name = try ea.cacheName(arena, .{108 const name = try ea.cacheName(arena, .{
109 .root_name = conf_comp.root_name.slice(conf),109 .root_name = conf_comp.root_name.slice(conf),
...@@ -122,7 +122,7 @@ fn updateGeneratedFile(...@@ -122,7 +122,7 @@ fn updateGeneratedFile(
122 else122 else
123 null,123 null,
124 });124 });
125 maker.generatedPath(gf).* = try out_path.join(graph.arena, name);125 _ = try maker.setGeneratedPath(gf, .local_cache, &.{ "o", o_hex_digest, name });
126}126}
127127
128/// List of importable modules in a compilation's module graph, including128/// List of importable modules in a compilation's module graph, including
...@@ -943,7 +943,7 @@ pub fn rebuildInFuzzMode(...@@ -943,7 +943,7 @@ pub fn rebuildInFuzzMode(
943 maker: *Maker,943 maker: *Maker,
944 compile_index: Configuration.Step.Index,944 compile_index: Configuration.Step.Index,
945 progress_node: std.Progress.Node,945 progress_node: std.Progress.Node,
946) !Path {946) !Step.OptCacheDigest {
947 const gpa = maker.gpa;947 const gpa = maker.gpa;
948 const step = maker.stepByIndex(compile_index);948 const step = maker.stepByIndex(compile_index);
949949
...@@ -963,8 +963,7 @@ pub fn rebuildInFuzzMode(...@@ -963,8 +963,7 @@ pub fn rebuildInFuzzMode(
963 defer argv.deinit(gpa);963 defer argv.deinit(gpa);
964964
965 try lowerZigArgs(arena, compile, compile_index, maker, progress_node, &argv, true);965 try lowerZigArgs(arena, compile, compile_index, maker, progress_node, &argv, true);
966 const maybe_output_bin_path = try Step.evalZigProcess(compile_index, maker, argv.items, progress_node, false);966 return Step.evalZigProcess(compile_index, maker, argv.items, progress_node, false);
967 return maybe_output_bin_path.?;
968}967}
969968
970fn addBool(gpa: Allocator, args: *std.ArrayList([]const u8), arg: []const u8, opt: bool) !void {969fn addBool(gpa: Allocator, args: *std.ArrayList([]const u8), arg: []const u8, opt: bool) !void {
...@@ -1380,7 +1379,7 @@ pub fn appendIncludeDirFlags(...@@ -1380,7 +1379,7 @@ pub fn appendIncludeDirFlags(
1380 },1379 },
1381 .config_header_step => |ch_index| {1380 .config_header_step => |ch_index| {
1382 const conf_ch = ch_index.ptr(conf).extended.get(conf.extra).config_header;1381 const conf_ch = ch_index.ptr(conf).extended.get(conf.extra).config_header;
1383 const path = maker.generatedPath(conf_ch.generated_dir).*;1382 const path = maker.generatedPath(conf_ch.generated_dir);
1384 zig_args.appendAssumeCapacity("-I");1383 zig_args.appendAssumeCapacity("-I");
1385 zig_args.appendAssumeCapacity(try path.toString(arena));1384 zig_args.appendAssumeCapacity(try path.toString(arena));
1386 },1385 },
lib/compiler/Maker/Step/ConfigHeader.zig+6-16
...@@ -34,7 +34,6 @@ pub fn make(...@@ -34,7 +34,6 @@ pub fn make(
34 const conf = &maker.scanned_config.configuration;34 const conf = &maker.scanned_config.configuration;
35 const conf_step = step_index.ptr(conf);35 const conf_step = step_index.ptr(conf);
36 const conf_ch = conf_step.extended.get(conf.extra).config_header;36 const conf_ch = conf_step.extended.get(conf.extra).config_header;
37 const cache_root = graph.local_cache_root;
3837
39 const input_size_limit: Io.Limit = if (conf_ch.input_size_limit.value) |x| .limited64(x) else .unlimited;38 const input_size_limit: Io.Limit = if (conf_ch.input_size_limit.value) |x| .limited64(x) else .unlimited;
40 const include_guard_override: ?[]const u8 = if (conf_ch.include_guard.value) |s| s.slice(conf) else null;39 const include_guard_override: ?[]const u8 = if (conf_ch.include_guard.value) |s| s.slice(conf) else null;
...@@ -138,10 +137,7 @@ pub fn make(...@@ -138,10 +137,7 @@ pub fn make(
138137
139 if (try step.cacheHit(maker, &man, progress_node)) {138 if (try step.cacheHit(maker, &man, progress_node)) {
140 const digest = man.hitDigestHex();139 const digest = man.hitDigestHex();
141 maker.generatedPath(conf_ch.generated_dir).* = .{140 _ = try maker.setGeneratedPath(conf_ch.generated_dir, .local_cache, &.{ "o", &digest });
142 .root_dir = cache_root,
143 .sub_path = try Io.Dir.path.join(arena, &.{ "o", &digest }),
144 };
145 return;141 return;
146 }142 }
147143
...@@ -152,22 +148,16 @@ pub fn make(...@@ -152,22 +148,16 @@ pub fn make(
152 // output_path is libavutil/avconfig.h148 // output_path is libavutil/avconfig.h
153 // We want to open directory zig-cache/o/HASH/libavutil/149 // We want to open directory zig-cache/o/HASH/libavutil/
154 // but keep output_dir as zig-cache/o/HASH for -I include150 // but keep output_dir as zig-cache/o/HASH for -I include
155 const out_path: Path = .{151
156 .root_dir = cache_root,152 const artifact_path = try maker.setGeneratedPath(conf_ch.generated_dir, .local_cache, &.{ "o", &digest });
157 .sub_path = try Io.Dir.path.join(arena, &.{ "o", &digest, conf_ch.include_path.slice(conf) }),153 const out_path = try artifact_path.join(arena, conf_ch.include_path.slice(conf));
158 };
159 const out_path_dirname = out_path.dirname().?;154 const out_path_dirname = out_path.dirname().?;
160155
161 out_path_dirname.root_dir.handle.createDirPath(io, out_path_dirname.sub_path) catch |err|156 out_path_dirname.root_dir.handle.createDirPath(io, out_path_dirname.sub_path) catch |err|
162 return step.fail(maker, "unable to make path {f}: {t}", .{ out_path_dirname, err });157 return step.fail(maker, "failed to make path {qf}: {t}", .{ out_path_dirname, err });
163158
164 out_path.root_dir.handle.writeFile(io, .{ .sub_path = out_path.sub_path, .data = output }) catch |err|159 out_path.root_dir.handle.writeFile(io, .{ .sub_path = out_path.sub_path, .data = output }) catch |err|
165 return step.fail(maker, "unable to write file {f}: {t}", .{ out_path, err });160 return step.fail(maker, "failed to write file {qf}: {t}", .{ out_path, err });
166
167 maker.generatedPath(conf_ch.generated_dir).* = .{
168 .root_dir = cache_root,
169 .sub_path = try Io.Dir.path.join(arena, &.{ "o", &digest }),
170 };
171161
172 try step.finalizeManifest(maker, &man);162 try step.finalizeManifest(maker, &man);
173}163}
lib/compiler/Maker/Step/FindProgram.zig+2-2
...@@ -77,7 +77,7 @@ fn checkCandidate(...@@ -77,7 +77,7 @@ fn checkCandidate(
77 const io = graph.io;77 const io = graph.io;
7878
79 if (Io.Dir.cwd().access(io, full_path, .{ .execute = true })) |_| {79 if (Io.Dir.cwd().access(io, full_path, .{ .execute = true })) |_| {
80 maker.generatedPath(found_path).* = .initCwd(full_path);80 _ = try maker.setGeneratedPath(found_path, .cwd, &.{full_path});
81 return true;81 return true;
82 } else |err| switch (err) {82 } else |err| switch (err) {
83 error.Canceled => |e| return e,83 error.Canceled => |e| return e,
...@@ -96,7 +96,7 @@ fn checkCandidate(...@@ -96,7 +96,7 @@ fn checkCandidate(
96 const extended_path = try std.mem.concat(arena, u8, &.{ full_path, ext });96 const extended_path = try std.mem.concat(arena, u8, &.{ full_path, ext });
9797
98 if (Io.Dir.cwd().access(io, extended_path, .{ .execute = true })) |_| {98 if (Io.Dir.cwd().access(io, extended_path, .{ .execute = true })) |_| {
99 maker.generatedPath(found_path).* = .initCwd(extended_path);99 _ = try maker.setGeneratedPath(found_path, .cwd, &.{extended_path});
100 return true;100 return true;
101 } else |err| switch (err) {101 } else |err| switch (err) {
102 error.Canceled => |e| return e,102 error.Canceled => |e| return e,
lib/compiler/Maker/Step/InstallArtifact.zig+1-1
...@@ -50,7 +50,7 @@ pub fn make(...@@ -50,7 +50,7 @@ pub fn make(
50 });50 });
51 const dest_dir = try maker.resolveInstallDir(arena, bin_dir);51 const dest_dir = try maker.resolveInstallDir(arena, bin_dir);
52 const dest_path = try dest_dir.join(arena, bin_sub_path);52 const dest_path = try dest_dir.join(arena, bin_sub_path);
53 const src_path = maker.generatedPath(generated_bin).*;53 const src_path = maker.generatedPath(generated_bin);
54 const p = try maker.installPath(arena, src_path, dest_path, step_index);54 const p = try maker.installPath(arena, src_path, dest_path, step_index);
55 all_cached = all_cached and p == .fresh;55 all_cached = all_cached and p == .fresh;
5656
lib/compiler/Maker/Step/ObjCopy.zig+7-20
...@@ -22,7 +22,6 @@ pub fn make(...@@ -22,7 +22,6 @@ pub fn make(
22 const conf = &maker.scanned_config.configuration;22 const conf = &maker.scanned_config.configuration;
23 const conf_step = step_index.ptr(conf);23 const conf_step = step_index.ptr(conf);
24 const conf_oc = conf_step.extended.get(conf.extra).obj_copy;24 const conf_oc = conf_step.extended.get(conf.extra).obj_copy;
25 const cache_root = graph.local_cache_root;
26 const input_lazy_path = conf_oc.input_file.get(conf);25 const input_lazy_path = conf_oc.input_file.get(conf);
27 const only_section: ?[]const u8 = if (conf_oc.only_section.value) |s| s.slice(conf) else null;26 const only_section: ?[]const u8 = if (conf_oc.only_section.value) |s| s.slice(conf) else null;
28 const opt_basename: ?[]const u8 = if (conf_oc.basename.value) |s| s.slice(conf) else null;27 const opt_basename: ?[]const u8 = if (conf_oc.basename.value) |s| s.slice(conf) else null;
...@@ -49,18 +48,12 @@ pub fn make(...@@ -49,18 +48,12 @@ pub fn make(
49 if (try step.cacheHit(maker, &man, progress_node)) {48 if (try step.cacheHit(maker, &man, progress_node)) {
50 // Cache hit, skip subprocess execution.49 // Cache hit, skip subprocess execution.
51 const digest = man.hitDigestHex();50 const digest = man.hitDigestHex();
52 maker.generatedPath(conf_oc.output_file).* = .{51 _ = try maker.setGeneratedPath(conf_oc.output_file, .local_cache, &.{ "o", &digest, basename });
53 .root_dir = cache_root,
54 .sub_path = try Io.Dir.path.join(arena, &.{ "o", &digest, basename }),
55 };
56 if (conf_oc.debug_file.value) |debug_file| {52 if (conf_oc.debug_file.value) |debug_file| {
57 const debug_basename = opt_debug_basename orelse try arena.print("{s}.debug", .{53 const debug_basename = opt_debug_basename orelse try arena.print("{s}.debug", .{
58 Io.Dir.path.basename(input_path.sub_path),54 Io.Dir.path.basename(input_path.sub_path),
59 });55 });
60 maker.generatedPath(debug_file).* = .{56 _ = try maker.setGeneratedPath(debug_file, .local_cache, &.{ "o", &digest, debug_basename });
61 .root_dir = cache_root,
62 .sub_path = try Io.Dir.path.join(arena, &.{ "o", &digest, debug_basename }),
63 };
64 }57 }
65 return;58 return;
66 }59 }
...@@ -68,10 +61,8 @@ pub fn make(...@@ -68,10 +61,8 @@ pub fn make(
68 // We don't find out more input files while executing objcopy so we can61 // We don't find out more input files while executing objcopy so we can
69 // already obtain the digest and use it directly as the output path.62 // already obtain the digest and use it directly as the output path.
70 const digest = man.missDigestHex();63 const digest = man.missDigestHex();
71 const dest_path: Path = .{64 const dest_path = try maker.setGeneratedPath(conf_oc.output_file, .local_cache, &.{ "o", &digest, basename });
72 .root_dir = cache_root,65
73 .sub_path = try Io.Dir.path.join(arena, &.{ "o", &digest, basename }),
74 };
75 const dest_dirname = dest_path.dirname().?;66 const dest_dirname = dest_path.dirname().?;
76 dest_dirname.root_dir.handle.createDirPath(io, dest_dirname.sub_path) catch |err|67 dest_dirname.root_dir.handle.createDirPath(io, dest_dirname.sub_path) catch |err|
77 return step.fail(maker, "failed to create path {f}: {t}", .{ dest_dirname, err });68 return step.fail(maker, "failed to create path {f}: {t}", .{ dest_dirname, err });
...@@ -107,12 +98,10 @@ pub fn make(...@@ -107,12 +98,10 @@ pub fn make(
107 const debug_basename = opt_debug_basename orelse try arena.print("{s}.debug", .{98 const debug_basename = opt_debug_basename orelse try arena.print("{s}.debug", .{
108 Io.Dir.path.basename(input_path.sub_path),99 Io.Dir.path.basename(input_path.sub_path),
109 });100 });
110 const debug_dest_path: Path = .{101 const debug_dest_path = try maker.setGeneratedPath(debug_file, .local_cache, &.{
111 .root_dir = cache_root,102 "o", &digest, debug_basename,
112 .sub_path = try Io.Dir.path.join(arena, &.{ "o", &digest, debug_basename }),103 });
113 };
114 argv.appendAssumeCapacity(try arena.print("--extract-to={f}", .{debug_dest_path}));104 argv.appendAssumeCapacity(try arena.print("--extract-to={f}", .{debug_dest_path}));
115 maker.generatedPath(debug_file).* = debug_dest_path;
116 }105 }
117106
118 try argv.ensureUnusedCapacity(arena, conf_oc.add_section.slice.len * 2);107 try argv.ensureUnusedCapacity(arena, conf_oc.add_section.slice.len * 2);
...@@ -163,8 +152,6 @@ pub fn make(...@@ -163,8 +152,6 @@ pub fn make(
163 else => |e| return e,152 else => |e| return e,
164 };153 };
165154
166 maker.generatedPath(conf_oc.output_file).* = dest_path;
167
168 step.finalizeManifest(maker, &man) catch |err| switch (err) {155 step.finalizeManifest(maker, &man) catch |err| switch (err) {
169 error.Canceled => |e| return e,156 error.Canceled => |e| return e,
170 else => |e| try step.addError(maker, "failed writing cache manifest: {t}", .{e}),157 else => |e| try step.addError(maker, "failed writing cache manifest: {t}", .{e}),
lib/compiler/Maker/Step/Options.zig+4-11
...@@ -19,7 +19,6 @@ pub fn make(...@@ -19,7 +19,6 @@ pub fn make(
19 const graph = maker.graph;19 const graph = maker.graph;
20 const step = maker.stepByIndex(step_index);20 const step = maker.stepByIndex(step_index);
21 const io = graph.io;21 const io = graph.io;
22 const cache_root = graph.local_cache_root;
23 const arena = graph.arena; // TODO don't leak into the process arena22 const arena = graph.arena; // TODO don't leak into the process arena
24 const conf = &maker.scanned_config.configuration;23 const conf = &maker.scanned_config.configuration;
25 const conf_step = step_index.ptr(conf);24 const conf_step = step_index.ptr(conf);
...@@ -80,19 +79,15 @@ pub fn make(...@@ -80,19 +79,15 @@ pub fn make(
8079
81 if (try step.cacheHitWatched(maker, &man, progress_node)) {80 if (try step.cacheHitWatched(maker, &man, progress_node)) {
82 const digest = man.hitDigestHex();81 const digest = man.hitDigestHex();
83 maker.generatedPath(conf_options.generated_file).* = .{82 _ = try maker.setGeneratedPath(conf_options.generated_file, .local_cache, &.{ "o", &digest, basename });
84 .root_dir = cache_root,
85 .sub_path = try Io.Dir.path.join(arena, &.{ "o", &digest, basename }),
86 };
87 step.result_cached = true;83 step.result_cached = true;
88 return;84 return;
89 }85 }
9086
91 const digest = man.missDigestHex();87 const digest = man.missDigestHex();
92 const out_path: Cache.Path = .{88 const out_path = try maker.setGeneratedPath(conf_options.generated_file, .local_cache, &.{
93 .root_dir = cache_root,89 "o", &digest, basename,
94 .sub_path = try Io.Dir.path.join(arena, &.{ "o", &digest, basename }),90 });
95 };
9691
97 var file: Io.File = out_path.root_dir.handle.createFile(io, out_path.sub_path, .{}) catch |err| switch (err) {92 var file: Io.File = out_path.root_dir.handle.createFile(io, out_path.sub_path, .{}) catch |err| switch (err) {
98 error.Canceled => |e| return e,93 error.Canceled => |e| return e,
...@@ -121,6 +116,4 @@ pub fn make(...@@ -121,6 +116,4 @@ pub fn make(
121 };116 };
122117
123 try step.finalizeManifestAndWatch(maker, &man);118 try step.finalizeManifestAndWatch(maker, &man);
124
125 maker.generatedPath(conf_options.generated_file).* = out_path;
126}119}
lib/compiler/Maker/Step/Run.zig+29-50
...@@ -18,14 +18,13 @@ const Step = @import("../Step.zig");...@@ -18,14 +18,13 @@ const Step = @import("../Step.zig");
18const Maker = @import("../../Maker.zig");18const Maker = @import("../../Maker.zig");
19const Fuzz = @import("../../Maker/Fuzz.zig");19const Fuzz = @import("../../Maker/Fuzz.zig");
2020
21/// If this is a Zig unit test binary, this tracks the names of the unit21/// If this is a Zig unit test binary, this tracks the names of the unit tests that are also fuzz tests.
22/// tests that are also fuzz tests. Indexes cannot be used as they may22/// Indexes cannot be used as they may change between reruns. Memory owned by `Maker.gpa`.
23/// change between reruns.
24fuzz_tests: std.ArrayList([]const u8) = .empty,23fuzz_tests: std.ArrayList([]const u8) = .empty,
25cached_test_metadata: ?CachedTestMetadata = null,24cached_test_metadata: ?CachedTestMetadata = null,
2625
27/// Populated during the fuzz phase if this run step corresponds to a unit test26/// Populated during the fuzz phase if this run step corresponds to a unit test executable that contains fuzz
28/// executable that contains fuzz tests.27/// tests. `Path.sub_path` owned by `Maker.gpa`.
29rebuilt_executable: ?Path = null,28rebuilt_executable: ?Path = null,
3029
31pub fn make(30pub fn make(
...@@ -146,7 +145,8 @@ pub fn make(...@@ -146,7 +145,8 @@ pub fn make(
146 const producer_make_comp_step = maker.stepByIndex(producer_index);145 const producer_make_comp_step = maker.stepByIndex(producer_index);
147 const producer_make_comp = &producer_make_comp_step.extended.compile;146 const producer_make_comp = &producer_make_comp_step.extended.compile;
148147
149 const file_path = producer_make_comp.installed_path orelse maker.generatedPath(producer.generated_bin.value.?).*;148 const file_path = producer_make_comp.installed_path orelse
149 maker.generatedPath(producer.generated_bin.value.?);
150150
151 argv_list.appendAssumeCapacity(try mem.concat(arena, u8, &.{151 argv_list.appendAssumeCapacity(try mem.concat(arena, u8, &.{
152 prefix, try convertPathArg(arena, run_index, maker, file_path, arg.flags.make_absolute), suffix,152 prefix, try convertPathArg(arena, run_index, maker, file_path, arg.flags.make_absolute), suffix,
...@@ -262,8 +262,8 @@ pub fn make(...@@ -262,8 +262,8 @@ pub fn make(
262 if (!has_side_effects and try step.cacheHitWatched(maker, &man, progress_node)) {262 if (!has_side_effects and try step.cacheHitWatched(maker, &man, progress_node)) {
263 // Cache hit; skip running command.263 // Cache hit; skip running command.
264 const digest = man.hitDigestHex();264 const digest = man.hitDigestHex();
265 try populateGeneratedStdIo(maker, &conf_run, cache_root, &digest);265 try populateGeneratedStdIo(maker, &conf_run, &digest);
266 try populateGeneratedPaths(maker, output_placeholders.items, cache_root, &digest);266 try populateGeneratedPaths(maker, output_placeholders.items, &digest);
267 step.result_cached = true;267 step.result_cached = true;
268 return;268 return;
269 }269 }
...@@ -272,7 +272,7 @@ pub fn make(...@@ -272,7 +272,7 @@ pub fn make(
272 // We already know the final output paths; use them directly.272 // We already know the final output paths; use them directly.
273 const digest = if (has_side_effects) man.hash.final() else man.missDigestHex();273 const digest = if (has_side_effects) man.hash.final() else man.missDigestHex();
274 const output_dir_path = "o" ++ Dir.path.sep_str ++ &digest;274 const output_dir_path = "o" ++ Dir.path.sep_str ++ &digest;
275 try populateGeneratedStdIo(maker, &conf_run, cache_root, &digest);275 try populateGeneratedStdIo(maker, &conf_run, &digest);
276 try populateGeneratedPathsCreateDirs(arena, run_index, maker, output_dir_path, output_placeholders.items, argv_list.items);276 try populateGeneratedPathsCreateDirs(arena, run_index, maker, output_dir_path, output_placeholders.items, argv_list.items);
277 try runCommand(arena, run, run_index, maker, progress_node, argv_list.items, has_side_effects, output_dir_path, null);277 try runCommand(arena, run, run_index, maker, progress_node, argv_list.items, has_side_effects, output_dir_path, null);
278 if (!has_side_effects) try step.finalizeManifestAndWatch(maker, &man);278 if (!has_side_effects) try step.finalizeManifestAndWatch(maker, &man);
...@@ -291,7 +291,7 @@ pub fn make(...@@ -291,7 +291,7 @@ pub fn make(
291 const arg = placeholder.arg_index.get(conf);291 const arg = placeholder.arg_index.get(conf);
292 switch (arg.flags.tag) {292 switch (arg.flags.tag) {
293 .output_file => if (arg.flags.dep_file) {293 .output_file => if (arg.flags.dep_file) {
294 const generated_path = maker.generatedPath(arg.generated.value.?).*;294 const generated_path = maker.generatedPath(arg.generated.value.?);
295 if (has_side_effects) {295 if (has_side_effects) {
296 var diagnostic: Cache.DepTokenizer.Token = undefined;296 var diagnostic: Cache.DepTokenizer.Token = undefined;
297 man.addInputDepFile(generated_path, &diagnostic) catch |err| switch (err) {297 man.addInputDepFile(generated_path, &diagnostic) catch |err| switch (err) {
...@@ -362,8 +362,8 @@ pub fn make(...@@ -362,8 +362,8 @@ pub fn make(
362362
363 if (!has_side_effects) try step.finalizeManifestAndWatch(maker, &man);363 if (!has_side_effects) try step.finalizeManifestAndWatch(maker, &man);
364364
365 try populateGeneratedStdIo(maker, &conf_run, cache_root, &digest);365 try populateGeneratedStdIo(maker, &conf_run, &digest);
366 try populateGeneratedPaths(maker, output_placeholders.items, cache_root, &digest);366 try populateGeneratedPaths(maker, output_placeholders.items, &digest);
367367
368 // The utility functions that spawn the child process must unconditionally allocate368 // The utility functions that spawn the child process must unconditionally allocate
369 // the failed command because at that point it is not known whether the step will369 // the failed command because at that point it is not known whether the step will
...@@ -375,6 +375,7 @@ pub fn make(...@@ -375,6 +375,7 @@ pub fn make(
375pub fn deinit(run: *Run, gpa: Allocator, io: Io) void {375pub fn deinit(run: *Run, gpa: Allocator, io: Io) void {
376 _ = io;376 _ = io;
377 run.fuzz_tests.deinit(gpa);377 run.fuzz_tests.deinit(gpa);
378 if (run.rebuilt_executable) |p| gpa.free(p.sub_path);
378}379}
379380
380fn thirdPartyToggle(381fn thirdPartyToggle(
...@@ -1575,8 +1576,7 @@ pub fn rerunInFuzzMode(...@@ -1575,8 +1576,7 @@ pub fn rerunInFuzzMode(
1575 const file_path: Path = if (producer_index == conf_run.producer.value.?)1576 const file_path: Path = if (producer_index == conf_run.producer.value.?)
1576 run.rebuilt_executable.?1577 run.rebuilt_executable.?
1577 else1578 else
1578 producer_make_comp.installed_path orelse1579 producer_make_comp.installed_path orelse maker.generatedPath(producer.generated_bin.value.?);
1579 maker.generatedPath(producer.generated_bin.value.?).*;
1580 argv_list.appendAssumeCapacity(try mem.concat(arena, u8, &.{1580 argv_list.appendAssumeCapacity(try mem.concat(arena, u8, &.{
1581 prefix, try convertPathArg(arena, run_index, maker, file_path, arg.flags.make_absolute), suffix,1581 prefix, try convertPathArg(arena, run_index, maker, file_path, arg.flags.make_absolute), suffix,
1582 }));1582 }));
...@@ -1615,20 +1615,15 @@ pub fn rerunInFuzzMode(...@@ -1615,20 +1615,15 @@ pub fn rerunInFuzzMode(
1615fn populateGeneratedPaths(1615fn populateGeneratedPaths(
1616 maker: *Maker,1616 maker: *Maker,
1617 output_placeholders: []const IndexedOutput,1617 output_placeholders: []const IndexedOutput,
1618 cache_root: Cache.Directory,
1619 digest: *const Cache.HexDigest,1618 digest: *const Cache.HexDigest,
1620) !void {1619) !void {
1621 const conf = &maker.scanned_config.configuration;1620 const conf = &maker.scanned_config.configuration;
1622 const graph = maker.graph;
16231621
1624 for (output_placeholders) |placeholder| {1622 for (output_placeholders) |placeholder| {
1625 const arg = placeholder.arg_index.get(conf);1623 const arg = placeholder.arg_index.get(conf);
1626 maker.generatedPath(arg.generated.value.?).* = .{1624 _ = try maker.setGeneratedPath(arg.generated.value.?, .local_cache, &.{
1627 .root_dir = cache_root,1625 "o", digest, arg.basename.value.?.slice(conf),
1628 .sub_path = try Dir.path.join(graph.arena, &.{1626 });
1629 "o", digest, arg.basename.value.?.slice(conf),
1630 }),
1631 };
1632 }1627 }
1633}1628}
16341629
...@@ -1652,10 +1647,9 @@ fn populateGeneratedPathsCreateDirs(...@@ -1652,10 +1647,9 @@ fn populateGeneratedPathsCreateDirs(
1652 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";1647 const suffix = if (arg.suffix.value) |p| p.slice(conf) else "";
1653 const basename = arg.basename.value.?.slice(conf);1648 const basename = arg.basename.value.?.slice(conf);
16541649
1655 const generated_path: Path = .{1650 const generated_path = try maker.setGeneratedPath(arg.generated.value.?, .local_cache, &.{
1656 .root_dir = cache_root,1651 output_dir_path, basename,
1657 .sub_path = try Dir.path.join(graph.arena, &.{ output_dir_path, basename }),1652 });
1658 };
1659 const create_path: Path = .{1653 const create_path: Path = .{
1660 .root_dir = cache_root,1654 .root_dir = cache_root,
1661 .sub_path = switch (arg.flags.tag) {1655 .sub_path = switch (arg.flags.tag) {
...@@ -1667,8 +1661,6 @@ fn populateGeneratedPathsCreateDirs(...@@ -1667,8 +1661,6 @@ fn populateGeneratedPathsCreateDirs(
1667 create_path.root_dir.handle.createDirPath(io, create_path.sub_path) catch |err|1661 create_path.root_dir.handle.createDirPath(io, create_path.sub_path) catch |err|
1668 return step.fail(maker, "unable to make path {f}: {t}", .{ create_path, err });1662 return step.fail(maker, "unable to make path {f}: {t}", .{ create_path, err });
16691663
1670 maker.generatedPath(arg.generated.value.?).* = generated_path;
1671
1672 const arg_output_path = try convertPathArg(arena, run_index, maker, generated_path, arg.flags.make_absolute);1664 const arg_output_path = try convertPathArg(arena, run_index, maker, generated_path, arg.flags.make_absolute);
1673 argv[placeholder.index] = try mem.concat(arena, u8, &.{ prefix, arg_output_path, suffix });1665 argv[placeholder.index] = try mem.concat(arena, u8, &.{ prefix, arg_output_path, suffix });
1674 }1666 }
...@@ -1677,28 +1669,20 @@ fn populateGeneratedPathsCreateDirs(...@@ -1677,28 +1669,20 @@ fn populateGeneratedPathsCreateDirs(
1677fn populateGeneratedStdIo(1669fn populateGeneratedStdIo(
1678 maker: *Maker,1670 maker: *Maker,
1679 conf_run: *const Configuration.Step.Run,1671 conf_run: *const Configuration.Step.Run,
1680 cache_root: Cache.Directory,
1681 digest: *const Cache.HexDigest,1672 digest: *const Cache.HexDigest,
1682) !void {1673) !void {
1683 const conf = &maker.scanned_config.configuration;1674 const conf = &maker.scanned_config.configuration;
1684 const graph = maker.graph;
16851675
1686 if (conf_run.captured_stdout.value) |captured| {1676 if (conf_run.captured_stdout.value) |captured| {
1687 maker.generatedPath(captured.generated_file).* = .{1677 _ = try maker.setGeneratedPath(captured.generated_file, .local_cache, &.{
1688 .root_dir = cache_root,1678 "o", digest, captured.basename.slice(conf),
1689 .sub_path = try Dir.path.join(graph.arena, &.{1679 });
1690 "o", digest, captured.basename.slice(conf),
1691 }),
1692 };
1693 }1680 }
16941681
1695 if (conf_run.captured_stderr.value) |captured| {1682 if (conf_run.captured_stderr.value) |captured| {
1696 maker.generatedPath(captured.generated_file).* = .{1683 _ = try maker.setGeneratedPath(captured.generated_file, .local_cache, &.{
1697 .root_dir = cache_root,1684 "o", digest, captured.basename.slice(conf),
1698 .sub_path = try Dir.path.join(graph.arena, &.{1685 });
1699 "o", digest, captured.basename.slice(conf),
1700 }),
1701 };
1702 }1686 }
1703}1687}
17041688
...@@ -1735,7 +1719,6 @@ fn runCommand(...@@ -1735,7 +1719,6 @@ fn runCommand(
1735 const gpa = maker.gpa;1719 const gpa = maker.gpa;
1736 const step = maker.stepByIndex(run_index);1720 const step = maker.stepByIndex(run_index);
1737 const io = graph.io;1721 const io = graph.io;
1738 const cache_root = graph.local_cache_root;
1739 const conf = &maker.scanned_config.configuration;1722 const conf = &maker.scanned_config.configuration;
1740 const conf_step = run_index.ptr(conf);1723 const conf_step = run_index.ptr(conf);
1741 const conf_run = conf_step.extended.get(conf.extra).run;1724 const conf_run = conf_step.extended.get(conf.extra).run;
...@@ -1989,13 +1972,9 @@ fn runCommand(...@@ -1989,13 +1972,9 @@ fn runCommand(
1989 },1972 },
1990 }) |*stream| {1973 }) |*stream| {
1991 if (stream.captured) |captured| {1974 if (stream.captured) |captured| {
1992 const output_path: Path = .{1975 const output_path = try maker.setGeneratedPath(captured.generated_file, .local_cache, &.{
1993 .root_dir = cache_root,1976 output_dir_path, captured.basename.slice(conf),
1994 .sub_path = try Dir.path.join(graph.arena, &.{1977 });
1995 output_dir_path, captured.basename.slice(conf),
1996 }),
1997 };
1998 maker.generatedPath(captured.generated_file).* = output_path;
19991978
2000 const sub_path_parent = output_path.dirname().?;1979 const sub_path_parent = output_path.dirname().?;
2001 sub_path_parent.root_dir.handle.createDirPath(io, sub_path_parent.sub_path) catch |err|1980 sub_path_parent.root_dir.handle.createDirPath(io, sub_path_parent.sub_path) catch |err|
lib/compiler/Maker/Step/TranslateC.zig+4-3
...@@ -143,13 +143,14 @@ pub fn make(...@@ -143,13 +143,14 @@ pub fn make(
143 argv.appendAssumeCapacity(c_source_path);143 argv.appendAssumeCapacity(c_source_path);
144144
145 argv.appendAssumeCapacity("--listen=-");145 argv.appendAssumeCapacity("--listen=-");
146 const output_dir_path = (Step.evalZigProcess(step_index, maker, argv.items, progress_node, false) catch |err| switch (err) {146 const opt_cache_digest = Step.evalZigProcess(step_index, maker, argv.items, progress_node, false) catch |err| switch (err) {
147 error.NeedCompileErrorCheck => unreachable,147 error.NeedCompileErrorCheck => unreachable,
148 else => |e| return e,148 else => |e| return e,
149 }).?;149 };
150 const o_hex_digest = opt_cache_digest.toHex().?;
150151
151 const stem = Io.Dir.path.stem(Io.Dir.path.basename(c_source_path));152 const stem = Io.Dir.path.stem(Io.Dir.path.basename(c_source_path));
152 const out_basename = try arena.print("{s}.zig", .{stem});153 const out_basename = try arena.print("{s}.zig", .{stem});
153154
154 maker.generatedPath(conf_tc.output_file).* = try output_dir_path.join(arena, out_basename);155 _ = try maker.setGeneratedPath(conf_tc.output_file, .local_cache, &.{ "o", &o_hex_digest, out_basename });
155}156}
lib/compiler/Maker/Step/WriteFile.zig+6-18
...@@ -24,7 +24,6 @@ pub fn make(...@@ -24,7 +24,6 @@ pub fn make(
24 const conf = &maker.scanned_config.configuration;24 const conf = &maker.scanned_config.configuration;
25 const conf_step = step_index.ptr(conf);25 const conf_step = step_index.ptr(conf);
26 const conf_wf = conf_step.extended.get(conf.extra).write_file;26 const conf_wf = conf_step.extended.get(conf.extra).write_file;
27 const cache_root = graph.local_cache_root;
28 const directories = conf_wf.directories.slice;27 const directories = conf_wf.directories.slice;
2928
30 const open_dir_cache = try arena.alloc(Io.Dir, directories.len);29 const open_dir_cache = try arena.alloc(Io.Dir, directories.len);
...@@ -106,25 +105,17 @@ pub fn make(...@@ -106,25 +105,17 @@ pub fn make(
106105
107 if (try step.cacheHit(maker, &man, progress_node)) {106 if (try step.cacheHit(maker, &man, progress_node)) {
108 const digest = man.hitDigestHex();107 const digest = man.hitDigestHex();
109 maker.generatedPath(conf_wf.generated_directory).* = .{108 _ = try maker.setGeneratedPath(conf_wf.generated_directory, .local_cache, &.{ "o", &digest });
110 .root_dir = cache_root,
111 .sub_path = try Io.Dir.path.join(arena, &.{ "o", &digest }),
112 };
113 assert(step.result_cached);109 assert(step.result_cached);
114 return;110 return;
115 }111 }
116112
117 const digest = man.missDigestHex();113 const digest = man.missDigestHex();
118 const out_path: Path = .{114 const out_path = try maker.setGeneratedPath(conf_wf.generated_directory, .local_cache, &.{ "o", &digest });
119 .root_dir = cache_root,
120 .sub_path = try Io.Dir.path.join(arena, &.{ "o", &digest }),
121 };
122115
123 progress_node.setEstimatedTotalItems(total_items);116 progress_node.setEstimatedTotalItems(total_items);
124 try operate(maker, step_index, open_dir_cache, out_path, progress_node);117 try operate(maker, step_index, open_dir_cache, out_path, progress_node);
125 try step.finalizeManifest(maker, &man);118 try step.finalizeManifest(maker, &man);
126
127 maker.generatedPath(conf_wf.generated_directory).* = out_path;
128 },119 },
129 .tmp => {120 .tmp => {
130 step.result_cached = false;121 step.result_cached = false;
...@@ -133,20 +124,17 @@ pub fn make(...@@ -133,20 +124,17 @@ pub fn make(
133 io.random(@ptrCast(&rand_int));124 io.random(@ptrCast(&rand_int));
134 const hex_digest = std.fmt.hex(rand_int);125 const hex_digest = std.fmt.hex(rand_int);
135126
136 const out_path: Path = .{127 const out_path = try maker.setGeneratedPath(conf_wf.generated_directory, .local_cache, &.{
137 .root_dir = cache_root,128 "tmp", &hex_digest,
138 .sub_path = try Io.Dir.path.join(arena, &.{ "tmp", &hex_digest }),129 });
139 };
140130
141 try operate(maker, step_index, open_dir_cache, out_path, progress_node);131 try operate(maker, step_index, open_dir_cache, out_path, progress_node);
142
143 maker.generatedPath(conf_wf.generated_directory).* = out_path;
144 },132 },
145 .mutate => {133 .mutate => {
146 step.result_cached = false;134 step.result_cached = false;
147 const root_path = try maker.resolveLazyPathIndex(arena, conf_wf.mutate_path.value.?, step_index);135 const root_path = try maker.resolveLazyPathIndex(arena, conf_wf.mutate_path.value.?, step_index);
148 try operate(maker, step_index, open_dir_cache, root_path, progress_node);136 try operate(maker, step_index, open_dir_cache, root_path, progress_node);
149 maker.generatedPath(conf_wf.generated_directory).* = root_path;137 _ = try maker.setGeneratedPathPath(conf_wf.generated_directory, root_path);
150 },138 },
151 }139 }
152}140}
lib/std/zig/ErrorBundle.zig+18
...@@ -197,6 +197,24 @@ pub fn renderToTerminal(eb: ErrorBundle, options: RenderOptions, t: Io.Terminal)...@@ -197,6 +197,24 @@ pub fn renderToTerminal(eb: ErrorBundle, options: RenderOptions, t: Io.Terminal)
197 }197 }
198}198}
199199
200pub fn readAlloc(
201 r: *Io.Reader,
202 gpa: Allocator,
203 extra_len: u32,
204 string_bytes_len: u32,
205) Io.Reader.ReadAllocError!ErrorBundle {
206 const extra = try r.readSliceEndianAlloc(gpa, u32, extra_len, .little);
207 errdefer gpa.free(extra);
208
209 const string_bytes = try r.readAlloc(gpa, string_bytes_len);
210 errdefer gpa.free(string_bytes);
211
212 return .{
213 .extra = extra,
214 .string_bytes = string_bytes,
215 };
216}
217
200fn renderErrorMessage(218fn renderErrorMessage(
201 eb: ErrorBundle,219 eb: ErrorBundle,
202 options: RenderOptions,220 options: RenderOptions,
lib/std/zig/Server.zig+13-1
...@@ -8,6 +8,7 @@ const OutMessage = std.zig.Server.Message;...@@ -8,6 +8,7 @@ const OutMessage = std.zig.Server.Message;
8const InMessage = std.zig.Client.Message;8const InMessage = std.zig.Client.Message;
9const Reader = std.Io.Reader;9const Reader = std.Io.Reader;
10const Writer = std.Io.Writer;10const Writer = std.Io.Writer;
11const Configuration = std.Build.Configuration;
1112
12in: *Reader,13in: *Reader,
13out: *Writer,14out: *Writer,
...@@ -113,10 +114,15 @@ pub const Message = struct {...@@ -113,10 +114,15 @@ pub const Message = struct {
113114
114 /// Trailing:115 /// Trailing:
115 /// * error_bundle: ErrorBundle,116 /// * error_bundle: ErrorBundle,
117 /// * generated_file: [generated_files_len]GeneratedFile,
118 /// * path_bytes: [_]u8, // for each GeneratedFile
119 /// - PathPrefix
120 /// - sub_path: [_]u8,
116 pub const BuildStepCompleted = extern struct {121 pub const BuildStepCompleted = extern struct {
117 step_index: std.Build.Configuration.Step.Index,122 step_index: Configuration.Step.Index,
118 status: Status,123 status: Status,
119 error_bundle: ErrorBundle,124 error_bundle: ErrorBundle,
125 generated_files_len: u32,
120 // TODO result_error_msgs126 // TODO result_error_msgs
121 // TODO result_stderr127 // TODO result_stderr
122 // TODO result_peak_rss128 // TODO result_peak_rss
...@@ -130,6 +136,12 @@ pub const Message = struct {...@@ -130,6 +136,12 @@ pub const Message = struct {
130 };136 };
131 };137 };
132138
139 pub const GeneratedFile = extern struct {
140 index: Configuration.GeneratedFileIndex,
141 /// Includes only the path bytes, not the prefix or null byte.
142 path_len: u32,
143 };
144
133 pub const PathPrefix = enum(u8) {145 pub const PathPrefix = enum(u8) {
134 cwd,146 cwd,
135 zig_lib,147 zig_lib,
tools/bsp.zig+29-1
...@@ -184,7 +184,35 @@ pub fn main(init: std.process.Init) !void {...@@ -184,7 +184,35 @@ pub fn main(init: std.process.Init) !void {
184 .bsp_build_started => {},184 .bsp_build_started => {},
185 .bsp_build_completed => if (!watch) break,185 .bsp_build_completed => if (!watch) break,
186 .bsp_step_started => {},186 .bsp_step_started => {},
187 .bsp_step_completed => {},187 .bsp_step_completed => {
188 var reader: Io.Reader = .fixed(body);
189 const bsc = try reader.takeStruct(Server.Message.BuildStepCompleted, .little);
190 log.info("step {q} {t}: ({d} generated files)", .{
191 bsc.step_index.ptr(c).name.slice(c),
192 bsc.status,
193 bsc.generated_files_len,
194 });
195
196 var eb = try std.zig.ErrorBundle.readAlloc(
197 &reader,
198 gpa,
199 bsc.error_bundle.extra_len,
200 bsc.error_bundle.string_bytes_len,
201 );
202 defer eb.deinit(gpa);
203 try eb.renderToStderr(io, .{}, .auto);
204
205 const modified_files: []align(1) Server.Message.GeneratedFile = @ptrCast(
206 try reader.take(bsc.generated_files_len * @sizeOf(Server.Message.GeneratedFile)),
207 );
208 for (modified_files) |modified_file| {
209 const prefix = try reader.takeEnum(Server.Message.PathPrefix, .little);
210 const sub_path = try reader.take(modified_file.path_len);
211 log.info("generated file: {d} {t} {q}", .{
212 modified_file.index, prefix, sub_path,
213 });
214 }
215 },
188 .bsp_configuration => @panic("TODO"),216 .bsp_configuration => @panic("TODO"),
189 else => std.debug.panic("received unexpected message: {f}", .{fmtEnum(header.tag)}),217 else => std.debug.panic("received unexpected message: {f}", .{fmtEnum(header.tag)}),
190 }218 }