std.Build.Step.Run: fix depfile support

This commit is contained in:
Loris Cro 2023-12-11 23:08:22 +01:00
parent 26e27f5f64
commit 65878c16ee

View File

@ -249,7 +249,7 @@ pub fn addDepFileOutputArg(self: *Run, basename: []const u8) std.Build.LazyPath
/// Add a prefixed path argument to a dep file (.d) for the child process to
/// write its discovered additional dependencies.
/// Only one dep file argument is allowed by instance.
pub fn addPrefixedDepFileOutputArg(self: *Run, prefix: []const u8, basename: []const u8) void {
pub fn addPrefixedDepFileOutputArg(self: *Run, prefix: []const u8, basename: []const u8) std.Build.LazyPath {
assert(self.dep_output_file == null);
const b = self.step.owner;
@ -264,6 +264,8 @@ pub fn addPrefixedDepFileOutputArg(self: *Run, prefix: []const u8, basename: []c
self.dep_output_file = dep_file;
self.argv.append(.{ .output = dep_file }) catch @panic("OOM");
return .{ .generated = &dep_file.generated_file };
}
pub fn addArg(self: *Run, arg: []const u8) void {
@ -454,6 +456,10 @@ fn checksContainStderr(checks: []const StdIo.Check) bool {
return false;
}
const IndexedOutput = struct {
index: usize,
output: *Output,
};
fn make(step: *Step, prog_node: *std.Progress.Node) !void {
const b = step.owner;
const arena = b.allocator;
@ -461,10 +467,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
const has_side_effects = self.hasSideEffects();
var argv_list = ArrayList([]const u8).init(arena);
var output_placeholders = ArrayList(struct {
index: usize,
output: *Output,
}).init(arena);
var output_placeholders = ArrayList(IndexedOutput).init(arena);
var man = b.cache.obtain();
defer man.deinit();
@ -546,32 +549,25 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
if (try step.cacheHit(&man)) {
// cache hit, skip running command
const digest = man.final();
for (output_placeholders.items) |placeholder| {
placeholder.output.generated_file.path = try b.cache_root.join(arena, &.{
"o", &digest, placeholder.output.basename,
});
}
if (self.captured_stdout) |output| {
output.generated_file.path = try b.cache_root.join(arena, &.{
"o", &digest, output.basename,
});
}
if (self.captured_stderr) |output| {
output.generated_file.path = try b.cache_root.join(arena, &.{
"o", &digest, output.basename,
});
}
try populateGeneratedPaths(
arena,
output_placeholders.items,
self.captured_stdout,
self.captured_stderr,
b.cache_root,
&digest,
);
step.result_cached = true;
return;
}
const digest = man.final();
const rand_int = std.crypto.random.int(u64);
const tmp_dir_path = "tmp" ++ fs.path.sep_str ++ std.Build.hex64(rand_int);
for (output_placeholders.items) |placeholder| {
const output_components = .{ "o", &digest, placeholder.output.basename };
const output_components = .{ tmp_dir_path, placeholder.output.basename };
const output_sub_path = try fs.path.join(arena, &output_components);
const output_sub_dir_path = fs.path.dirname(output_sub_path).?;
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 {
argv_list.items[placeholder.index] = cli_arg;
}
try runCommand(self, argv_list.items, has_side_effects, &digest, prog_node);
try runCommand(self, argv_list.items, has_side_effects, tmp_dir_path, prog_node);
if (self.dep_output_file) |dep_output_file|
try man.addDepFilePost(std.fs.cwd(), dep_output_file.generated_file.getPath());
const digest = man.final();
const any_output = output_placeholders.items.len > 0 or
self.captured_stdout != null or self.captured_stderr != null;
// Rename into place
if (any_output) {
const o_sub_path = "o" ++ fs.path.sep_str ++ &digest;
b.cache_root.handle.rename(tmp_dir_path, o_sub_path) catch |err| {
if (err == error.PathAlreadyExists) {
b.cache_root.handle.deleteTree(o_sub_path) catch |del_err| {
return step.fail("unable to remove dir '{}'{s}: {s}", .{
b.cache_root,
tmp_dir_path,
@errorName(del_err),
});
};
b.cache_root.handle.rename(tmp_dir_path, o_sub_path) catch |retry_err| {
return step.fail("unable to rename dir '{}{s}' to '{}{s}': {s}", .{
b.cache_root, tmp_dir_path,
b.cache_root, o_sub_path,
@errorName(retry_err),
});
};
} else {
return step.fail("unable to rename dir '{}{s}' to '{}{s}': {s}", .{
b.cache_root, tmp_dir_path,
b.cache_root, o_sub_path,
@errorName(err),
});
}
};
}
try step.writeManifest(&man);
try populateGeneratedPaths(
arena,
output_placeholders.items,
self.captured_stdout,
self.captured_stderr,
b.cache_root,
&digest,
);
}
fn populateGeneratedPaths(
arena: std.mem.Allocator,
output_placeholders: []const IndexedOutput,
captured_stdout: ?*Output,
captured_stderr: ?*Output,
cache_root: Build.Cache.Directory,
digest: *const Build.Cache.HexDigest,
) !void {
for (output_placeholders) |placeholder| {
placeholder.output.generated_file.path = try cache_root.join(arena, &.{
"o", digest, placeholder.output.basename,
});
}
if (captured_stdout) |output| {
output.generated_file.path = try cache_root.join(arena, &.{
"o", digest, output.basename,
});
}
if (captured_stderr) |output| {
output.generated_file.path = try cache_root.join(arena, &.{
"o", digest, output.basename,
});
}
}
fn formatTerm(
@ -645,7 +712,7 @@ fn runCommand(
self: *Run,
argv: []const []const u8,
has_side_effects: bool,
digest: ?*const [std.Build.Cache.hex_digest_len]u8,
tmp_dir_path: ?[]const u8,
prog_node: *std.Progress.Node,
) !void {
const step = &self.step;
@ -816,7 +883,7 @@ fn runCommand(
},
}) |stream| {
if (stream.captured) |output| {
const output_components = .{ "o", digest.?, output.basename };
const output_components = .{ tmp_dir_path.?, output.basename };
const output_path = try b.cache_root.join(arena, &output_components);
output.generated_file.path = output_path;