| ... | ... | @@ -243,7 +243,7 @@ pub fn addDepFileOutputArg(self: *Run, basename: []const u8) std.Build.LazyPath |
| 243 | 243 | /// Add a prefixed path argument to a dep file (.d) for the child process to |
| 244 | 244 | /// write its discovered additional dependencies. |
| 245 | 245 | /// Only one dep file argument is allowed by instance. |
| 246 | | pub fn addPrefixedDepFileOutputArg(self: *Run, prefix: []const u8, basename: []const u8) void { |
| 246 | pub fn addPrefixedDepFileOutputArg(self: *Run, prefix: []const u8, basename: []const u8) std.Build.LazyPath { |
| 247 | 247 | assert(self.dep_output_file == null); |
| 248 | 248 | |
| 249 | 249 | const b = self.step.owner; |
| ... | ... | @@ -258,6 +258,8 @@ pub fn addPrefixedDepFileOutputArg(self: *Run, prefix: []const u8, basename: []c |
| 258 | 258 | self.dep_output_file = dep_file; |
| 259 | 259 | |
| 260 | 260 | self.argv.append(.{ .output = dep_file }) catch @panic("OOM"); |
| 261 | |
| 262 | return .{ .generated = &dep_file.generated_file }; |
| 261 | 263 | } |
| 262 | 264 | |
| 263 | 265 | pub fn addArg(self: *Run, arg: []const u8) void { |
| ... | ... | @@ -448,6 +450,10 @@ fn checksContainStderr(checks: []const StdIo.Check) bool { |
| 448 | 450 | return false; |
| 449 | 451 | } |
| 450 | 452 | |
| 453 | const IndexedOutput = struct { |
| 454 | index: usize, |
| 455 | output: *Output, |
| 456 | }; |
| 451 | 457 | fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 452 | 458 | const b = step.owner; |
| 453 | 459 | const arena = b.allocator; |
| ... | ... | @@ -455,10 +461,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 455 | 461 | const has_side_effects = self.hasSideEffects(); |
| 456 | 462 | |
| 457 | 463 | var argv_list = ArrayList([]const u8).init(arena); |
| 458 | | var output_placeholders = ArrayList(struct { |
| 459 | | index: usize, |
| 460 | | output: *Output, |
| 461 | | }).init(arena); |
| 464 | var output_placeholders = ArrayList(IndexedOutput).init(arena); |
| 462 | 465 | |
| 463 | 466 | var man = b.cache.obtain(); |
| 464 | 467 | defer man.deinit(); |
| ... | ... | @@ -540,32 +543,25 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 540 | 543 | if (try step.cacheHit(&man)) { |
| 541 | 544 | // cache hit, skip running command |
| 542 | 545 | const digest = man.final(); |
| 543 | | for (output_placeholders.items) |placeholder| { |
| 544 | | placeholder.output.generated_file.path = try b.cache_root.join(arena, &.{ |
| 545 | | "o", &digest, placeholder.output.basename, |
| 546 | | }); |
| 547 | | } |
| 548 | 546 | |
| 549 | | if (self.captured_stdout) |output| { |
| 550 | | output.generated_file.path = try b.cache_root.join(arena, &.{ |
| 551 | | "o", &digest, output.basename, |
| 552 | | }); |
| 553 | | } |
| 554 | | |
| 555 | | if (self.captured_stderr) |output| { |
| 556 | | output.generated_file.path = try b.cache_root.join(arena, &.{ |
| 557 | | "o", &digest, output.basename, |
| 558 | | }); |
| 559 | | } |
| 547 | try populateGeneratedPaths( |
| 548 | arena, |
| 549 | output_placeholders.items, |
| 550 | self.captured_stdout, |
| 551 | self.captured_stderr, |
| 552 | b.cache_root, |
| 553 | &digest, |
| 554 | ); |
| 560 | 555 | |
| 561 | 556 | step.result_cached = true; |
| 562 | 557 | return; |
| 563 | 558 | } |
| 564 | 559 | |
| 565 | | const digest = man.final(); |
| 560 | const rand_int = std.crypto.random.int(u64); |
| 561 | const tmp_dir_path = "tmp" ++ fs.path.sep_str ++ std.Build.hex64(rand_int); |
| 566 | 562 | |
| 567 | 563 | for (output_placeholders.items) |placeholder| { |
| 568 | | const output_components = .{ "o", &digest, placeholder.output.basename }; |
| 564 | const output_components = .{ tmp_dir_path, placeholder.output.basename }; |
| 569 | 565 | const output_sub_path = try fs.path.join(arena, &output_components); |
| 570 | 566 | const output_sub_dir_path = fs.path.dirname(output_sub_path).?; |
| 571 | 567 | b.cache_root.handle.makePath(output_sub_dir_path) catch |err| { |
| ... | ... | @@ -582,12 +578,83 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { |
| 582 | 578 | argv_list.items[placeholder.index] = cli_arg; |
| 583 | 579 | } |
| 584 | 580 | |
| 585 | | try runCommand(self, argv_list.items, has_side_effects, &digest, prog_node); |
| 581 | try runCommand(self, argv_list.items, has_side_effects, tmp_dir_path, prog_node); |
| 586 | 582 | |
| 587 | 583 | if (self.dep_output_file) |dep_output_file| |
| 588 | 584 | try man.addDepFilePost(std.fs.cwd(), dep_output_file.generated_file.getPath()); |
| 589 | 585 | |
| 586 | const digest = man.final(); |
| 587 | |
| 588 | const any_output = output_placeholders.items.len > 0 or |
| 589 | self.captured_stdout != null or self.captured_stderr != null; |
| 590 | |
| 591 | // Rename into place |
| 592 | if (any_output) { |
| 593 | const o_sub_path = "o" ++ fs.path.sep_str ++ &digest; |
| 594 | |
| 595 | b.cache_root.handle.rename(tmp_dir_path, o_sub_path) catch |err| { |
| 596 | if (err == error.PathAlreadyExists) { |
| 597 | b.cache_root.handle.deleteTree(o_sub_path) catch |del_err| { |
| 598 | return step.fail("unable to remove dir '{}'{s}: {s}", .{ |
| 599 | b.cache_root, |
| 600 | tmp_dir_path, |
| 601 | @errorName(del_err), |
| 602 | }); |
| 603 | }; |
| 604 | b.cache_root.handle.rename(tmp_dir_path, o_sub_path) catch |retry_err| { |
| 605 | return step.fail("unable to rename dir '{}{s}' to '{}{s}': {s}", .{ |
| 606 | b.cache_root, tmp_dir_path, |
| 607 | b.cache_root, o_sub_path, |
| 608 | @errorName(retry_err), |
| 609 | }); |
| 610 | }; |
| 611 | } else { |
| 612 | return step.fail("unable to rename dir '{}{s}' to '{}{s}': {s}", .{ |
| 613 | b.cache_root, tmp_dir_path, |
| 614 | b.cache_root, o_sub_path, |
| 615 | @errorName(err), |
| 616 | }); |
| 617 | } |
| 618 | }; |
| 619 | } |
| 620 | |
| 590 | 621 | try step.writeManifest(&man); |
| 622 | |
| 623 | try populateGeneratedPaths( |
| 624 | arena, |
| 625 | output_placeholders.items, |
| 626 | self.captured_stdout, |
| 627 | self.captured_stderr, |
| 628 | b.cache_root, |
| 629 | &digest, |
| 630 | ); |
| 631 | } |
| 632 | |
| 633 | fn populateGeneratedPaths( |
| 634 | arena: std.mem.Allocator, |
| 635 | output_placeholders: []const IndexedOutput, |
| 636 | captured_stdout: ?*Output, |
| 637 | captured_stderr: ?*Output, |
| 638 | cache_root: Build.Cache.Directory, |
| 639 | digest: *const Build.Cache.HexDigest, |
| 640 | ) !void { |
| 641 | for (output_placeholders) |placeholder| { |
| 642 | placeholder.output.generated_file.path = try cache_root.join(arena, &.{ |
| 643 | "o", digest, placeholder.output.basename, |
| 644 | }); |
| 645 | } |
| 646 | |
| 647 | if (captured_stdout) |output| { |
| 648 | output.generated_file.path = try cache_root.join(arena, &.{ |
| 649 | "o", digest, output.basename, |
| 650 | }); |
| 651 | } |
| 652 | |
| 653 | if (captured_stderr) |output| { |
| 654 | output.generated_file.path = try cache_root.join(arena, &.{ |
| 655 | "o", digest, output.basename, |
| 656 | }); |
| 657 | } |
| 591 | 658 | } |
| 592 | 659 | |
| 593 | 660 | fn formatTerm( |
| ... | ... | @@ -639,7 +706,7 @@ fn runCommand( |
| 639 | 706 | self: *Run, |
| 640 | 707 | argv: []const []const u8, |
| 641 | 708 | has_side_effects: bool, |
| 642 | | digest: ?*const [std.Build.Cache.hex_digest_len]u8, |
| 709 | tmp_dir_path: ?[]const u8, |
| 643 | 710 | prog_node: *std.Progress.Node, |
| 644 | 711 | ) !void { |
| 645 | 712 | const step = &self.step; |
| ... | ... | @@ -812,7 +879,7 @@ fn runCommand( |
| 812 | 879 | }, |
| 813 | 880 | }) |stream| { |
| 814 | 881 | if (stream.captured) |output| { |
| 815 | | const output_components = .{ "o", digest.?, output.basename }; |
| 882 | const output_components = .{ tmp_dir_path.?, output.basename }; |
| 816 | 883 | const output_path = try b.cache_root.join(arena, &output_components); |
| 817 | 884 | output.generated_file.path = output_path; |
| 818 | 885 | |