mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
Merge pull request #18262 from ziglang/fix-18259
std.Build.Step.Run: fix depfile support
This commit is contained in:
commit
f64205b445
2 changed files with 108 additions and 40 deletions
|
|
@ -179,6 +179,7 @@ fn getPrefixSubpath(allocator: Allocator, prefix: []const u8, path: []u8) ![]u8
|
||||||
pub const bin_digest_len = 16;
|
pub const bin_digest_len = 16;
|
||||||
pub const hex_digest_len = bin_digest_len * 2;
|
pub const hex_digest_len = bin_digest_len * 2;
|
||||||
pub const BinDigest = [bin_digest_len]u8;
|
pub const BinDigest = [bin_digest_len]u8;
|
||||||
|
pub const HexDigest = [hex_digest_len]u8;
|
||||||
|
|
||||||
/// This is currently just an arbitrary non-empty string that can't match another manifest line.
|
/// This is currently just an arbitrary non-empty string that can't match another manifest line.
|
||||||
const manifest_header = "0";
|
const manifest_header = "0";
|
||||||
|
|
@ -300,11 +301,11 @@ pub const HashHelper = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a hex encoded hash of the inputs, mutating the state of the hasher.
|
/// Returns a hex encoded hash of the inputs, mutating the state of the hasher.
|
||||||
pub fn final(hh: *HashHelper) [hex_digest_len]u8 {
|
pub fn final(hh: *HashHelper) HexDigest {
|
||||||
var bin_digest: BinDigest = undefined;
|
var bin_digest: BinDigest = undefined;
|
||||||
hh.hasher.final(&bin_digest);
|
hh.hasher.final(&bin_digest);
|
||||||
|
|
||||||
var out_digest: [hex_digest_len]u8 = undefined;
|
var out_digest: HexDigest = undefined;
|
||||||
_ = fmt.bufPrint(
|
_ = fmt.bufPrint(
|
||||||
&out_digest,
|
&out_digest,
|
||||||
"{s}",
|
"{s}",
|
||||||
|
|
@ -360,7 +361,7 @@ pub const Manifest = struct {
|
||||||
// will then use the same timestamp, to avoid unnecessary filesystem writes.
|
// will then use the same timestamp, to avoid unnecessary filesystem writes.
|
||||||
want_refresh_timestamp: bool = true,
|
want_refresh_timestamp: bool = true,
|
||||||
files: std.ArrayListUnmanaged(File) = .{},
|
files: std.ArrayListUnmanaged(File) = .{},
|
||||||
hex_digest: [hex_digest_len]u8,
|
hex_digest: HexDigest,
|
||||||
/// Populated when hit() returns an error because of one
|
/// Populated when hit() returns an error because of one
|
||||||
/// of the files listed in the manifest.
|
/// of the files listed in the manifest.
|
||||||
failed_file_index: ?usize = null,
|
failed_file_index: ?usize = null,
|
||||||
|
|
@ -843,7 +844,7 @@ pub const Manifest = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a hex encoded hash of the inputs.
|
/// Returns a hex encoded hash of the inputs.
|
||||||
pub fn final(self: *Manifest) [hex_digest_len]u8 {
|
pub fn final(self: *Manifest) HexDigest {
|
||||||
assert(self.manifest_file != null);
|
assert(self.manifest_file != null);
|
||||||
|
|
||||||
// We don't close the manifest file yet, because we want to
|
// We don't close the manifest file yet, because we want to
|
||||||
|
|
@ -855,7 +856,7 @@ pub const Manifest = struct {
|
||||||
var bin_digest: BinDigest = undefined;
|
var bin_digest: BinDigest = undefined;
|
||||||
self.hash.hasher.final(&bin_digest);
|
self.hash.hasher.final(&bin_digest);
|
||||||
|
|
||||||
var out_digest: [hex_digest_len]u8 = undefined;
|
var out_digest: HexDigest = undefined;
|
||||||
_ = fmt.bufPrint(
|
_ = fmt.bufPrint(
|
||||||
&out_digest,
|
&out_digest,
|
||||||
"{s}",
|
"{s}",
|
||||||
|
|
@ -1035,8 +1036,8 @@ test "cache file and then recall it" {
|
||||||
std.time.sleep(1);
|
std.time.sleep(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
var digest1: [hex_digest_len]u8 = undefined;
|
var digest1: HexDigest = undefined;
|
||||||
var digest2: [hex_digest_len]u8 = undefined;
|
var digest2: HexDigest = undefined;
|
||||||
|
|
||||||
{
|
{
|
||||||
var cache = Cache{
|
var cache = Cache{
|
||||||
|
|
@ -1103,8 +1104,8 @@ test "check that changing a file makes cache fail" {
|
||||||
std.time.sleep(1);
|
std.time.sleep(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
var digest1: [hex_digest_len]u8 = undefined;
|
var digest1: HexDigest = undefined;
|
||||||
var digest2: [hex_digest_len]u8 = undefined;
|
var digest2: HexDigest = undefined;
|
||||||
|
|
||||||
{
|
{
|
||||||
var cache = Cache{
|
var cache = Cache{
|
||||||
|
|
@ -1166,8 +1167,8 @@ test "no file inputs" {
|
||||||
|
|
||||||
const temp_manifest_dir = "no_file_inputs_manifest_dir";
|
const temp_manifest_dir = "no_file_inputs_manifest_dir";
|
||||||
|
|
||||||
var digest1: [hex_digest_len]u8 = undefined;
|
var digest1: HexDigest = undefined;
|
||||||
var digest2: [hex_digest_len]u8 = undefined;
|
var digest2: HexDigest = undefined;
|
||||||
|
|
||||||
var cache = Cache{
|
var cache = Cache{
|
||||||
.gpa = testing.allocator,
|
.gpa = testing.allocator,
|
||||||
|
|
@ -1225,9 +1226,9 @@ test "Manifest with files added after initial hash work" {
|
||||||
std.time.sleep(1);
|
std.time.sleep(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
var digest1: [hex_digest_len]u8 = undefined;
|
var digest1: HexDigest = undefined;
|
||||||
var digest2: [hex_digest_len]u8 = undefined;
|
var digest2: HexDigest = undefined;
|
||||||
var digest3: [hex_digest_len]u8 = undefined;
|
var digest3: HexDigest = undefined;
|
||||||
|
|
||||||
{
|
{
|
||||||
var cache = Cache{
|
var cache = Cache{
|
||||||
|
|
|
||||||
|
|
@ -243,7 +243,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
|
/// Add a prefixed path argument to a dep file (.d) for the child process to
|
||||||
/// write its discovered additional dependencies.
|
/// write its discovered additional dependencies.
|
||||||
/// Only one dep file argument is allowed by instance.
|
/// 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);
|
assert(self.dep_output_file == null);
|
||||||
|
|
||||||
const b = self.step.owner;
|
const b = self.step.owner;
|
||||||
|
|
@ -258,6 +258,8 @@ pub fn addPrefixedDepFileOutputArg(self: *Run, prefix: []const u8, basename: []c
|
||||||
self.dep_output_file = dep_file;
|
self.dep_output_file = dep_file;
|
||||||
|
|
||||||
self.argv.append(.{ .output = dep_file }) catch @panic("OOM");
|
self.argv.append(.{ .output = dep_file }) catch @panic("OOM");
|
||||||
|
|
||||||
|
return .{ .generated = &dep_file.generated_file };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn addArg(self: *Run, arg: []const u8) void {
|
pub fn addArg(self: *Run, arg: []const u8) void {
|
||||||
|
|
@ -448,6 +450,10 @@ fn checksContainStderr(checks: []const StdIo.Check) bool {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const IndexedOutput = struct {
|
||||||
|
index: usize,
|
||||||
|
output: *Output,
|
||||||
|
};
|
||||||
fn make(step: *Step, prog_node: *std.Progress.Node) !void {
|
fn make(step: *Step, prog_node: *std.Progress.Node) !void {
|
||||||
const b = step.owner;
|
const b = step.owner;
|
||||||
const arena = b.allocator;
|
const arena = b.allocator;
|
||||||
|
|
@ -455,10 +461,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
|
||||||
const has_side_effects = self.hasSideEffects();
|
const has_side_effects = self.hasSideEffects();
|
||||||
|
|
||||||
var argv_list = ArrayList([]const u8).init(arena);
|
var argv_list = ArrayList([]const u8).init(arena);
|
||||||
var output_placeholders = ArrayList(struct {
|
var output_placeholders = ArrayList(IndexedOutput).init(arena);
|
||||||
index: usize,
|
|
||||||
output: *Output,
|
|
||||||
}).init(arena);
|
|
||||||
|
|
||||||
var man = b.cache.obtain();
|
var man = b.cache.obtain();
|
||||||
defer man.deinit();
|
defer man.deinit();
|
||||||
|
|
@ -540,32 +543,25 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
|
||||||
if (try step.cacheHit(&man)) {
|
if (try step.cacheHit(&man)) {
|
||||||
// cache hit, skip running command
|
// cache hit, skip running command
|
||||||
const digest = man.final();
|
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| {
|
try populateGeneratedPaths(
|
||||||
output.generated_file.path = try b.cache_root.join(arena, &.{
|
arena,
|
||||||
"o", &digest, output.basename,
|
output_placeholders.items,
|
||||||
});
|
self.captured_stdout,
|
||||||
}
|
self.captured_stderr,
|
||||||
|
b.cache_root,
|
||||||
if (self.captured_stderr) |output| {
|
&digest,
|
||||||
output.generated_file.path = try b.cache_root.join(arena, &.{
|
);
|
||||||
"o", &digest, output.basename,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
step.result_cached = true;
|
step.result_cached = true;
|
||||||
return;
|
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| {
|
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_path = try fs.path.join(arena, &output_components);
|
||||||
const output_sub_dir_path = fs.path.dirname(output_sub_path).?;
|
const output_sub_dir_path = fs.path.dirname(output_sub_path).?;
|
||||||
b.cache_root.handle.makePath(output_sub_dir_path) catch |err| {
|
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 {
|
||||||
argv_list.items[placeholder.index] = cli_arg;
|
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|
|
if (self.dep_output_file) |dep_output_file|
|
||||||
try man.addDepFilePost(std.fs.cwd(), dep_output_file.generated_file.getPath());
|
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 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(
|
fn formatTerm(
|
||||||
|
|
@ -639,7 +706,7 @@ fn runCommand(
|
||||||
self: *Run,
|
self: *Run,
|
||||||
argv: []const []const u8,
|
argv: []const []const u8,
|
||||||
has_side_effects: bool,
|
has_side_effects: bool,
|
||||||
digest: ?*const [std.Build.Cache.hex_digest_len]u8,
|
tmp_dir_path: ?[]const u8,
|
||||||
prog_node: *std.Progress.Node,
|
prog_node: *std.Progress.Node,
|
||||||
) !void {
|
) !void {
|
||||||
const step = &self.step;
|
const step = &self.step;
|
||||||
|
|
@ -812,7 +879,7 @@ fn runCommand(
|
||||||
},
|
},
|
||||||
}) |stream| {
|
}) |stream| {
|
||||||
if (stream.captured) |output| {
|
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);
|
const output_path = try b.cache_root.join(arena, &output_components);
|
||||||
output.generated_file.path = output_path;
|
output.generated_file.path = output_path;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue