authorgravatar for kappaloris@gmail.comLoris Cro <kappaloris@gmail.com> 2023-12-11 23:08:22+01:00
committergravatar for kappaloris@gmail.comLoris Cro <kappaloris@gmail.com> 2024-01-02 11:54:32+01:00
log65878c16ee3e6677912343328e39c87c8f89c784
tree26a7cdcae8597e5691c180d93f64740534640e01
parent26e27f5f644437526b5ed5cad6559db8250bb545

std.Build.Step.Run: fix depfile support


1 files changed, 93 insertions(+), 26 deletions(-)

lib/std/Build/Step/Run.zig+93-26
......@@ -249,7 +249,7 @@ pub fn addDepFileOutputArg(self: *Run, basename: []const u8) std.Build.LazyPath
249249/// Add a prefixed path argument to a dep file (.d) for the child process to
250250/// write its discovered additional dependencies.
251251/// Only one dep file argument is allowed by instance.
252pub fn addPrefixedDepFileOutputArg(self: *Run, prefix: []const u8, basename: []const u8) void {
252pub fn addPrefixedDepFileOutputArg(self: *Run, prefix: []const u8, basename: []const u8) std.Build.LazyPath {
253253 assert(self.dep_output_file == null);
254254
255255 const b = self.step.owner;
......@@ -264,6 +264,8 @@ pub fn addPrefixedDepFileOutputArg(self: *Run, prefix: []const u8, basename: []c
264264 self.dep_output_file = dep_file;
265265
266266 self.argv.append(.{ .output = dep_file }) catch @panic("OOM");
267
268 return .{ .generated = &dep_file.generated_file };
267269}
268270
269271pub fn addArg(self: *Run, arg: []const u8) void {
......@@ -454,6 +456,10 @@ fn checksContainStderr(checks: []const StdIo.Check) bool {
454456 return false;
455457}
456458
459const IndexedOutput = struct {
460 index: usize,
461 output: *Output,
462};
457463fn make(step: *Step, prog_node: *std.Progress.Node) !void {
458464 const b = step.owner;
459465 const arena = b.allocator;
......@@ -461,10 +467,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
461467 const has_side_effects = self.hasSideEffects();
462468
463469 var argv_list = ArrayList([]const u8).init(arena);
464 var output_placeholders = ArrayList(struct {
465 index: usize,
466 output: *Output,
467 }).init(arena);
470 var output_placeholders = ArrayList(IndexedOutput).init(arena);
468471
469472 var man = b.cache.obtain();
470473 defer man.deinit();
......@@ -546,32 +549,25 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
546549 if (try step.cacheHit(&man)) {
547550 // cache hit, skip running command
548551 const digest = man.final();
549 for (output_placeholders.items) |placeholder| {
550 placeholder.output.generated_file.path = try b.cache_root.join(arena, &.{
551 "o", &digest, placeholder.output.basename,
552 });
553 }
554552
555 if (self.captured_stdout) |output| {
556 output.generated_file.path = try b.cache_root.join(arena, &.{
557 "o", &digest, output.basename,
558 });
559 }
560
561 if (self.captured_stderr) |output| {
562 output.generated_file.path = try b.cache_root.join(arena, &.{
563 "o", &digest, output.basename,
564 });
565 }
553 try populateGeneratedPaths(
554 arena,
555 output_placeholders.items,
556 self.captured_stdout,
557 self.captured_stderr,
558 b.cache_root,
559 &digest,
560 );
566561
567562 step.result_cached = true;
568563 return;
569564 }
570565
571 const digest = man.final();
566 const rand_int = std.crypto.random.int(u64);
567 const tmp_dir_path = "tmp" ++ fs.path.sep_str ++ std.Build.hex64(rand_int);
572568
573569 for (output_placeholders.items) |placeholder| {
574 const output_components = .{ "o", &digest, placeholder.output.basename };
570 const output_components = .{ tmp_dir_path, placeholder.output.basename };
575571 const output_sub_path = try fs.path.join(arena, &output_components);
576572 const output_sub_dir_path = fs.path.dirname(output_sub_path).?;
577573 b.cache_root.handle.makePath(output_sub_dir_path) catch |err| {
......@@ -588,12 +584,83 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
588584 argv_list.items[placeholder.index] = cli_arg;
589585 }
590586
591 try runCommand(self, argv_list.items, has_side_effects, &digest, prog_node);
587 try runCommand(self, argv_list.items, has_side_effects, tmp_dir_path, prog_node);
592588
593589 if (self.dep_output_file) |dep_output_file|
594590 try man.addDepFilePost(std.fs.cwd(), dep_output_file.generated_file.getPath());
595591
592 const digest = man.final();
593
594 const any_output = output_placeholders.items.len > 0 or
595 self.captured_stdout != null or self.captured_stderr != null;
596
597 // Rename into place
598 if (any_output) {
599 const o_sub_path = "o" ++ fs.path.sep_str ++ &digest;
600
601 b.cache_root.handle.rename(tmp_dir_path, o_sub_path) catch |err| {
602 if (err == error.PathAlreadyExists) {
603 b.cache_root.handle.deleteTree(o_sub_path) catch |del_err| {
604 return step.fail("unable to remove dir '{}'{s}: {s}", .{
605 b.cache_root,
606 tmp_dir_path,
607 @errorName(del_err),
608 });
609 };
610 b.cache_root.handle.rename(tmp_dir_path, o_sub_path) catch |retry_err| {
611 return step.fail("unable to rename dir '{}{s}' to '{}{s}': {s}", .{
612 b.cache_root, tmp_dir_path,
613 b.cache_root, o_sub_path,
614 @errorName(retry_err),
615 });
616 };
617 } else {
618 return step.fail("unable to rename dir '{}{s}' to '{}{s}': {s}", .{
619 b.cache_root, tmp_dir_path,
620 b.cache_root, o_sub_path,
621 @errorName(err),
622 });
623 }
624 };
625 }
626
596627 try step.writeManifest(&man);
628
629 try populateGeneratedPaths(
630 arena,
631 output_placeholders.items,
632 self.captured_stdout,
633 self.captured_stderr,
634 b.cache_root,
635 &digest,
636 );
637}
638
639fn populateGeneratedPaths(
640 arena: std.mem.Allocator,
641 output_placeholders: []const IndexedOutput,
642 captured_stdout: ?*Output,
643 captured_stderr: ?*Output,
644 cache_root: Build.Cache.Directory,
645 digest: *const Build.Cache.HexDigest,
646) !void {
647 for (output_placeholders) |placeholder| {
648 placeholder.output.generated_file.path = try cache_root.join(arena, &.{
649 "o", digest, placeholder.output.basename,
650 });
651 }
652
653 if (captured_stdout) |output| {
654 output.generated_file.path = try cache_root.join(arena, &.{
655 "o", digest, output.basename,
656 });
657 }
658
659 if (captured_stderr) |output| {
660 output.generated_file.path = try cache_root.join(arena, &.{
661 "o", digest, output.basename,
662 });
663 }
597664}
598665
599666fn formatTerm(
......@@ -645,7 +712,7 @@ fn runCommand(
645712 self: *Run,
646713 argv: []const []const u8,
647714 has_side_effects: bool,
648 digest: ?*const [std.Build.Cache.hex_digest_len]u8,
715 tmp_dir_path: ?[]const u8,
649716 prog_node: *std.Progress.Node,
650717) !void {
651718 const step = &self.step;
......@@ -816,7 +883,7 @@ fn runCommand(
816883 },
817884 }) |stream| {
818885 if (stream.captured) |output| {
819 const output_components = .{ "o", digest.?, output.basename };
886 const output_components = .{ tmp_dir_path.?, output.basename };
820887 const output_path = try b.cache_root.join(arena, &output_components);
821888 output.generated_file.path = output_path;
822889