authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-09-03 15:02:32-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-09-04 17:42:21-07:00
logfc1d90e2a1fdc92c020c3d1d6af6a3f768d8a9d2
tree2101c70c57bc6324a36563e8272e502864efbc2c
parent8ba8b0af6bfa93760ae325734a347670b815ab42

std.Build.Cache: fix some compilation errors from rewrite


17 files changed, 268 insertions(+), 205 deletions(-)

lib/compiler/Maker.zig+10-10
...@@ -702,8 +702,8 @@ pub fn main(init: process.Init.Minimal) !void {...@@ -702,8 +702,8 @@ pub fn main(init: process.Init.Minimal) !void {
702 configure: while (true) {702 configure: while (true) {
703 // Set of files that, if modified, imply that recompiling and rerunning703 // Set of files that, if modified, imply that recompiling and rerunning
704 // configurer is needed.704 // configurer is needed.
705 var configure_source_files: Cache.Manifest.Files = .empty;705 var configure_source_files: Cache.Manifest.SelfContainedFiles = .empty;
706 defer Cache.Manifest.freeFiles(gpa, &configure_source_files);706 defer configure_source_files.deinit(gpa);
707707
708 // If this fails, we can still start the server and wait for user708 // If this fails, we can still start the server and wait for user
709 // to request a rebuild. If it returns error.FailedButCacheIntact709 // to request a rebuild. If it returns error.FailedButCacheIntact
...@@ -1043,7 +1043,7 @@ const ConfigureOptions = struct {...@@ -1043,7 +1043,7 @@ const ConfigureOptions = struct {
1043 fetch_only: bool,1043 fetch_only: bool,
1044 print_configuration: PrintConfiguration,1044 print_configuration: PrintConfiguration,
1045 forks: []Fork,1045 forks: []Fork,
1046 src_files: *Cache.Manifest.Files,1046 src_files: *Cache.Manifest.SelfContainedFiles,
1047};1047};
10481048
1049fn configure(graph: *Graph, options: ConfigureOptions) !ScannedConfig {1049fn configure(graph: *Graph, options: ConfigureOptions) !ScannedConfig {
...@@ -1398,7 +1398,7 @@ fn configure(graph: *Graph, options: ConfigureOptions) !ScannedConfig {...@@ -1398,7 +1398,7 @@ fn configure(graph: *Graph, options: ConfigureOptions) !ScannedConfig {
1398 defer compile_prog_node.end();1398 defer compile_prog_node.end();
13991399
1400 if (config_man) |man| {1400 if (config_man) |man| {
1401 if (try man.hit(compile_prog_node)) {1401 if (.hit == try man.check(compile_prog_node)) {
1402 const digest = man.final();1402 const digest = man.final();
1403 const path: Path = .{1403 const path: Path = .{
1404 .root_dir = graph.local_cache_root,1404 .root_dir = graph.local_cache_root,
...@@ -1497,11 +1497,11 @@ fn configure(graph: *Graph, options: ConfigureOptions) !ScannedConfig {...@@ -1497,11 +1497,11 @@ fn configure(graph: *Graph, options: ConfigureOptions) !ScannedConfig {
1497 }1497 }
14981498
1499 if (config_man) |man| for (configuration.path_deps) |path_dep| {1499 if (config_man) |man| for (configuration.path_deps) |path_dep| {
1500 switch (path_dep.flags.mode) {1500 const path = try confPathDepToCachePath(arena, graph, &configuration, path_dep);
1501 .directory => {}, // TODO1501 try man.addPathPost(path, .{
1502 .contents => try man.addPathPost(try confPathDepToCachePath(arena, graph, &configuration, path_dep)),1502 .handle = if (path_dep.flags.is_directory) .{ .dir = null } else .{ .file = null },
1503 .metadata => {}, // TODO1503 .metadata_only = path_dep.flags.metadata_only,
1504 }1504 });
1505 };1505 };
15061506
1507 // If it is poisoned, there is no point in moving it to cached1507 // If it is poisoned, there is no point in moving it to cached
...@@ -2220,7 +2220,7 @@ fn resolveTopLevelSteps(maker: *Maker, step_names: []const []const u8) ![]const...@@ -2220,7 +2220,7 @@ fn resolveTopLevelSteps(maker: *Maker, step_names: []const []const u8) ![]const
2220fn prepare(2220fn prepare(
2221 maker: *Maker,2221 maker: *Maker,
2222 step_indices: []const Configuration.Step.Index,2222 step_indices: []const Configuration.Step.Index,
2223 configure_source_files: *const Cache.Manifest.Files,2223 configure_source_files: *const Cache.Manifest.SelfContainedFiles,
2224) !void {2224) !void {
2225 const gpa = maker.gpa;2225 const gpa = maker.gpa;
2226 const graph = maker.graph;2226 const graph = maker.graph;
lib/compiler/Maker/Step.zig+17-19
...@@ -726,8 +726,9 @@ pub fn handleChildProcessTerm(s: *Step, maker: *Maker, term: std.process.Child.T...@@ -726,8 +726,9 @@ pub fn handleChildProcessTerm(s: *Step, maker: *Maker, term: std.process.Child.T
726/// Prefer `cacheHitWatched` unless you already added watch inputs726/// Prefer `cacheHitWatched` unless you already added watch inputs
727/// separately from using the cache system.727/// separately from using the cache system.
728pub fn cacheHit(s: *Step, maker: *Maker, man: *Cache.Manifest, parent_progress_node: std.Progress.Node) !bool {728pub fn cacheHit(s: *Step, maker: *Maker, man: *Cache.Manifest, parent_progress_node: std.Progress.Node) !bool {
729 s.result_cached = man.hit(parent_progress_node) catch |err| return failWithCacheError(s, maker, man, err);729 const hit = .hit == (man.check(parent_progress_node) catch |err| return failWithCacheError(s, maker, man, err));
730 return s.result_cached;730 s.result_cached = hit;
731 return hit;
731}732}
732733
733/// Clears previous watch inputs, if any, and then populates watch inputs from734/// Clears previous watch inputs, if any, and then populates watch inputs from
...@@ -735,32 +736,29 @@ pub fn cacheHit(s: *Step, maker: *Maker, man: *Cache.Manifest, parent_progress_n...@@ -735,32 +736,29 @@ pub fn cacheHit(s: *Step, maker: *Maker, man: *Cache.Manifest, parent_progress_n
735///736///
736/// Must be accompanied with `writeManifestAndWatch`.737/// Must be accompanied with `writeManifestAndWatch`.
737pub fn cacheHitWatched(s: *Step, maker: *Maker, man: *Cache.Manifest, parent_progress_node: std.Progress.Node) !bool {738pub fn cacheHitWatched(s: *Step, maker: *Maker, man: *Cache.Manifest, parent_progress_node: std.Progress.Node) !bool {
738 const is_hit = man.hit(parent_progress_node) catch |err| return failWithCacheError(s, maker, man, err);739 const hit = .hit == (man.check(parent_progress_node) catch |err| return failWithCacheError(s, maker, man, err));
739 s.result_cached = is_hit;740 s.result_cached = hit;
740 // The above call to hit() populates the manifest with files, so in case of741 // The above call to hit() populates the manifest with files, so in case of
741 // a hit, we need to populate watch inputs.742 // a hit, we need to populate watch inputs.
742 if (is_hit) try setWatchInputsFromManifest(s, maker, man);743 if (hit) try setWatchInputsFromManifest(s, maker, man);
743 return is_hit;744 return hit;
744}745}
745746
746fn failWithCacheError(747fn failWithCacheError(
747 s: *Step,748 s: *Step,
748 maker: *Maker,749 maker: *Maker,
749 man: *const Cache.Manifest,750 man: *const Cache.Manifest,
750 err: Cache.Manifest.HitError,751 err: Cache.Manifest.Check.Error,
751) error{ OutOfMemory, Canceled, MakeFailed } {752) error{ OutOfMemory, Canceled, MakeFailed } {
752 switch (err) {753 switch (err) {
753 error.CacheCheckFailed => switch (man.diagnostic) {754 error.CacheCheckFailed => switch (man.diagnostic) {
754 .none => unreachable,755 .none => unreachable,
755 .manifest_create, .manifest_read, .manifest_lock => |e| return s.fail(maker, "failed checking cache: {t} {t}", .{756 .manifest_create, .manifest_read, .manifest_lock => |e| {
756 man.diagnostic, e,757 return s.fail(maker, "failed checking cache: {t} {t}", .{ man.diagnostic, e });
757 }),758 },
758 .file_open, .file_stat, .file_read, .file_hash => |op| {759 .file_open, .file_stat, .file_read, .file_hash => |op| {
759 const pp = man.files.keys()[op.file_index].prefixed_path;760 const path = op.path(man);
760 const prefix = man.cache.prefixes()[pp.prefix].path orelse "";761 return s.fail(maker, "failed checking cache: {f} {t} {t}", .{ path, man.diagnostic, op.err });
761 return s.fail(maker, "failed checking cache: {s}{c}{s} {t} {t}", .{
762 prefix, Dir.path.sep, pp.sub_path, man.diagnostic, op.err,
763 });
764 },762 },
765 },763 },
766 error.OutOfMemory, error.Canceled => |e| return e,764 error.OutOfMemory, error.Canceled => |e| return e,
...@@ -795,17 +793,17 @@ pub fn setWatchInputsFromManifest(s: *Step, maker: *Maker, man: *Cache.Manifest)...@@ -795,17 +793,17 @@ pub fn setWatchInputsFromManifest(s: *Step, maker: *Maker, man: *Cache.Manifest)
795pub fn setWatchInputsFromManifestFiles(793pub fn setWatchInputsFromManifestFiles(
796 s: *Step,794 s: *Step,
797 maker: *Maker,795 maker: *Maker,
798 files: *const Cache.Manifest.Files,796 scf: *const Cache.Manifest.SelfContainedFiles,
799 prefixes: []const Cache.Directory,797 prefixes: []const Cache.Directory,
800) !void {798) !void {
801 const graph = maker.graph;799 const graph = maker.graph;
802 const arena = graph.arena; // TODO don't leak into process arena800 const arena = graph.arena; // TODO don't leak into process arena
803 clearWatchInputs(s, maker);801 clearWatchInputs(s, maker);
804 for (files.keys()) |file| {802 for (scf.files.keys()) |file_offset| {
805 // The file path data is freed when the cache manifest is cleaned up at the end of `make`.803 // The file path data is freed when the cache manifest is cleaned up at the end of `make`.
806 const sub_path = try arena.dupe(u8, file.prefixed_path.sub_path);804 const sub_path = try arena.dupe(u8, scf.path(file_offset));
807 try addWatchInputFromPath(s, maker, .{805 try addWatchInputFromPath(s, maker, .{
808 .root_dir = prefixes[file.prefixed_path.prefix],806 .root_dir = prefixes[file_offset.get(scf.contents.items).flags.prefix],
809 .sub_path = Dir.path.dirname(sub_path) orelse "",807 .sub_path = Dir.path.dirname(sub_path) orelse "",
810 }, Dir.path.basename(sub_path));808 }, Dir.path.basename(sub_path));
811 }809 }
lib/compiler/Maker/Step/ObjCopy.zig+1-1
...@@ -34,7 +34,7 @@ pub fn make(...@@ -34,7 +34,7 @@ pub fn make(
34 defer man.deinit();34 defer man.deinit();
3535
36 const input_path = try maker.resolveLazyPath(arena, input_lazy_path, step_index);36 const input_path = try maker.resolveLazyPath(arena, input_lazy_path, step_index);
37 _ = try man.addFilePath(input_path, null);37 _ = try man.addInputPath(input_path, .{});
38 man.hash.addOptionalBytes(only_section);38 man.hash.addOptionalBytes(only_section);
39 man.hash.addOptionalBytes(opt_basename);39 man.hash.addOptionalBytes(opt_basename);
40 man.hash.addOptionalBytes(opt_debug_basename);40 man.hash.addOptionalBytes(opt_debug_basename);
lib/compiler/Maker/Step/Options.zig+1-1
...@@ -42,7 +42,7 @@ pub fn make(...@@ -42,7 +42,7 @@ pub fn make(
42 const lazy_path = arg.path.get(conf);42 const lazy_path = arg.path.get(conf);
43 try step.addWatchInput(maker, arena, lazy_path);43 try step.addWatchInput(maker, arena, lazy_path);
44 const arg_path = try maker.resolveLazyPath(arena, lazy_path, step_index);44 const arg_path = try maker.resolveLazyPath(arena, lazy_path, step_index);
45 _ = try man.addFilePath(arg_path, null);45 _ = try man.addInputPath(arg_path, .{});
46 try args_bytes.print(arena, "pub const {f}: []const u8 = \"{f}\";\n", .{46 try args_bytes.print(arena, "pub const {f}: []const u8 = \"{f}\";\n", .{
47 std.zig.fmtId(name), arg_path.fmtEscapeString(),47 std.zig.fmtId(name), arg_path.fmtEscapeString(),
48 });48 });
lib/compiler/Maker/Step/Run.zig+5-5
...@@ -97,7 +97,7 @@ pub fn make(...@@ -97,7 +97,7 @@ pub fn make(
97 man.hash.add(arg.flags.make_absolute);97 man.hash.add(arg.flags.make_absolute);
98 man.hash.addBytesZ(prefix);98 man.hash.addBytesZ(prefix);
99 man.hash.addBytesZ(suffix);99 man.hash.addBytesZ(suffix);
100 _ = try man.addFilePath(file_path, null);100 _ = try man.addInputPath(file_path, .{});
101 },101 },
102 .path_directory => {102 .path_directory => {
103 const prefix = if (arg.prefix.value) |p| p.slice(conf) else "";103 const prefix = if (arg.prefix.value) |p| p.slice(conf) else "";
...@@ -135,7 +135,7 @@ pub fn make(...@@ -135,7 +135,7 @@ pub fn make(
135 argv_list.appendAssumeCapacity(result.written());135 argv_list.appendAssumeCapacity(result.written());
136 man.hash.addBytesZ(prefix);136 man.hash.addBytesZ(prefix);
137 man.hash.addBytesZ(suffix);137 man.hash.addBytesZ(suffix);
138 _ = try man.addFilePath(file_path, null);138 _ = try man.addInputPath(file_path, .{});
139 },139 },
140 .artifact => {140 .artifact => {
141 const prefix = if (arg.prefix.value) |p| p.slice(conf) else "";141 const prefix = if (arg.prefix.value) |p| p.slice(conf) else "";
...@@ -155,7 +155,7 @@ pub fn make(...@@ -155,7 +155,7 @@ pub fn make(
155 man.hash.add(arg.flags.make_absolute);155 man.hash.add(arg.flags.make_absolute);
156 man.hash.addBytesZ(prefix);156 man.hash.addBytesZ(prefix);
157 man.hash.addBytesZ(suffix);157 man.hash.addBytesZ(suffix);
158 _ = try man.addFilePath(file_path, null);158 _ = try man.addInputPath(file_path, .{});
159 },159 },
160 .output_file, .output_directory => {160 .output_file, .output_directory => {
161 const prefix = if (arg.prefix.value) |p| p.slice(conf) else "";161 const prefix = if (arg.prefix.value) |p| p.slice(conf) else "";
...@@ -211,7 +211,7 @@ pub fn make(...@@ -211,7 +211,7 @@ pub fn make(
211 },211 },
212 .lazy_path => |lazy_path| {212 .lazy_path => |lazy_path| {
213 const file_path = try maker.resolveLazyPathIndex(arena, lazy_path, run_index);213 const file_path = try maker.resolveLazyPathIndex(arena, lazy_path, run_index);
214 _ = try man.addFilePath(file_path, null);214 _ = try man.addInputPath(file_path, .{});
215 },215 },
216 .none => {},216 .none => {},
217 }217 }
...@@ -240,7 +240,7 @@ pub fn make(...@@ -240,7 +240,7 @@ pub fn make(
240240
241 for (conf_run.file_inputs.slice) |lazy_path| {241 for (conf_run.file_inputs.slice) |lazy_path| {
242 const file_path = try maker.resolveLazyPathIndex(arena, lazy_path, run_index);242 const file_path = try maker.resolveLazyPathIndex(arena, lazy_path, run_index);
243 _ = try man.addFilePath(file_path, null);243 _ = try man.addInputPath(file_path, .{});
244 }244 }
245245
246 if (conf_run.cwd.value) |lazy_path| {246 if (conf_run.cwd.value) |lazy_path| {
lib/compiler/Maker/Step/WriteFile.zig+2-2
...@@ -55,7 +55,7 @@ pub fn make(...@@ -55,7 +55,7 @@ pub fn make(
55 man.hash.addBytes(copy.sub_path.slice(conf));55 man.hash.addBytes(copy.sub_path.slice(conf));
56 const src_lazy_path = copy.src_file.get(conf);56 const src_lazy_path = copy.src_file.get(conf);
57 const source_path = try maker.resolveLazyPath(arena, src_lazy_path, step_index);57 const source_path = try maker.resolveLazyPath(arena, src_lazy_path, step_index);
58 _ = try man.addFilePath(source_path, null);58 _ = try man.addInputPath(source_path, .{});
59 try step.addWatchInput(maker, arena, src_lazy_path);59 try step.addWatchInput(maker, arena, src_lazy_path);
60 }60 }
6161
...@@ -96,7 +96,7 @@ pub fn make(...@@ -96,7 +96,7 @@ pub fn make(
96 },96 },
97 .file => {97 .file => {
98 const entry_path = try src_dir_path.join(arena, entry.path);98 const entry_path = try src_dir_path.join(arena, entry.path);
99 _ = try man.addFilePath(entry_path, null);99 _ = try man.addInputPath(entry_path, .{});
100 total_items += 1;100 total_items += 1;
101 },101 },
102 else => continue,102 else => continue,
lib/std/Build/Cache.zig+192-136
...@@ -294,7 +294,7 @@ pub const Manifest = struct {...@@ -294,7 +294,7 @@ pub const Manifest = struct {
294 files: Files = .empty,294 files: Files = .empty,
295 /// Indexes line up with `files`, but only up until `hit` is called. Uses295 /// Indexes line up with `files`, but only up until `hit` is called. Uses
296 /// `Cache.gpa`.296 /// `Cache.gpa`.
297 input_files: std.ArrayList(InputFile) = .empty,297 input_paths: std.ArrayList(InputPath) = .empty,
298 diagnostic: Diagnostic = .none,298 diagnostic: Diagnostic = .none,
299 /// Keeps track of the last time we performed a file system write to observe299 /// Keeps track of the last time we performed a file system write to observe
300 /// what time the file system thinks it is, according to its own granularity.300 /// what time the file system thinks it is, according to its own granularity.
...@@ -304,11 +304,11 @@ pub const Manifest = struct {...@@ -304,11 +304,11 @@ pub const Manifest = struct {
304 /// final terminating byte can be added without allocation. Uses304 /// final terminating byte can be added without allocation. Uses
305 /// `Cache.gpa`.305 /// `Cache.gpa`.
306 contents: std.ArrayList(u8) = .empty,306 contents: std.ArrayList(u8) = .empty,
307 /// All contents from all `input_files` whose contents were requested,307 /// All contents from all `input_paths` whose contents were requested,
308 /// concatenated. Total byte size will be less than `max_input_content_len`308 /// concatenated. Total byte size will be less than `max_input_content_len`
309 /// otherwise an error is returned.309 /// otherwise an error is returned.
310 ///310 ///
311 /// Data is invalidated when `addFilePost` is called.311 /// Data is invalidated when `addPathPost` is called.
312 all_input_content: std.ArrayList(u8) = .empty,312 all_input_content: std.ArrayList(u8) = .empty,
313 max_input_content_len: usize = std.math.maxInt(u32),313 max_input_content_len: usize = std.math.maxInt(u32),
314314
...@@ -328,23 +328,24 @@ pub const Manifest = struct {...@@ -328,23 +328,24 @@ pub const Manifest = struct {
328 InvalidFormat,328 InvalidFormat,
329 } || Allocator.Error || Io.Cancelable;329 } || Allocator.Error || Io.Cancelable;
330330
331 fn fail(c: *Check, m: *Manifest, diagnostic: Diagnostic) void {331 fn fail(c: *Check, m: *Manifest, diagnostic: Diagnostic) error{CacheCheckFailed} {
332 if (!@atomicRmw(bool, &c.diagnostic_lock, .Xchg, true, .unordered)) {332 if (!@atomicRmw(bool, &c.diagnostic_lock, .Xchg, true, .monotonic)) {
333 m.diagnostic = diagnostic;333 m.diagnostic = diagnostic;
334 }334 }
335 return error.CacheCheckFailed;
335 }336 }
336 };337 };
337338
338 pub const Files = std.array_hash_map.Custom(File.Offset, void, File.HashContext, false);339 pub const Files = std.array_hash_map.Custom(File.Offset, void, File.HashContext, false);
339340
340 /// Source files whose prefix and relative path are included when computing341 /// Source files and directories whose prefix and relative path are
341 /// the cache manifest digest. It's the information needed to lazily hash342 /// included when computing the cache manifest digest. It's the information
342 /// the input files only when a cache miss occurs.343 /// needed to lazily hash the input files only when a cache miss occurs.
343 ///344 ///
344 /// `File.prefix`, `File.path`, and `File.mode` will be always populated,345 /// `File.prefix`, `File.path`, and `File.mode` will be always populated,
345 /// but the other fields of `File` will be populated depending on the346 /// but the other fields of `File` will be populated depending on the
346 /// fields of `InputFile`.347 /// fields of `InputPath`.
347 pub const InputFile = struct {348 pub const InputPath = struct {
348 request_handle: bool,349 request_handle: bool,
349 have_handle: bool,350 have_handle: bool,
350 /// Determines whether `File.size`, `File.inode`, and `File.mtime` are populated.351 /// Determines whether `File.size`, `File.inode`, and `File.mtime` are populated.
...@@ -360,7 +361,7 @@ pub const Manifest = struct {...@@ -360,7 +361,7 @@ pub const Manifest = struct {
360 /// `have_handle` determines whether this is populated.361 /// `have_handle` determines whether this is populated.
361 handle: Io.File,362 handle: Io.File,
362363
363 /// Index into `Manifest.input_files`.364 /// Index into `Manifest.input_paths`.
364 pub const Index = enum(u32) {365 pub const Index = enum(u32) {
365 _,366 _,
366 };367 };
...@@ -406,13 +407,13 @@ pub const Manifest = struct {...@@ -406,13 +407,13 @@ pub const Manifest = struct {
406 pub const Offset = enum(u32) {407 pub const Offset = enum(u32) {
407 _,408 _,
408409
409 pub fn get(offset: Offset, m: *const Manifest) *File {410 pub fn get(offset: Offset, contents: []u8) *File {
410 return @ptrCast(m.contents.items[@backingInt(offset)..][0..@sizeOf(File)]);411 return @ptrCast(@alignCast(contents.items[@backingInt(offset)..][0..@sizeOf(File)]));
411 }412 }
412413
413 pub fn getFallible(offset: Offset, m: *const Manifest) error{EndOfStream}!*File {414 pub fn getFallible(offset: Offset, contents: []u8) error{InvalidFormat}!*File {
414 if (@backingInt(offset) + @sizeOf(File) >= m.contents.len) return error.EndOfStream;415 if (@backingInt(offset) + @sizeOf(File) >= contents.items.len) return error.InvalidFormat;
415 return get(offset, m);416 return get(offset, contents);
416 }417 }
417 };418 };
418419
...@@ -432,25 +433,6 @@ pub const Manifest = struct {...@@ -432,25 +433,6 @@ pub const Manifest = struct {
432 }433 }
433 };434 };
434435
435 pub fn path(file: *const File) [:0]const u8 {
436 return pathFallible(file) catch unreachable;
437 }
438
439 pub fn pathFallible(file: *const File) error{EndOfStream}![:0]const u8 {
440 const ptr: [*]u8 = &file.path_start;
441 const len = mem.findScalar(u8, ptr, 0) orelse return error.EndOfStream;
442 return ptr[0..len :0];
443 }
444
445 fn manifestDigestHash(file: *const File, hasher: *Hasher) void {
446 const path_ptr: [*]u8 = &file.path_start;
447 const path_len = mem.findScalar(u8, path_ptr, 0).?;
448 comptime assert(@offsetOf(File, "path_start") - @offsetOf(File, "flags") == 1);
449 // Includes flags and sentinel.
450 const hash_string = (path_ptr - 1)[0 .. path_len + 2];
451 hasher.update(hash_string);
452 }
453
454 fn setStat(file: *File, m: *Manifest, stat: Stat) Io.Cancelable!void {436 fn setStat(file: *File, m: *Manifest, stat: Stat) Io.Cancelable!void {
455 file.size = stat.size;437 file.size = stat.size;
456 file.inode = stat.inode;438 file.inode = stat.inode;
...@@ -490,6 +472,16 @@ pub const Manifest = struct {...@@ -490,6 +472,16 @@ pub const Manifest = struct {
490 pub const FileOp = struct {472 pub const FileOp = struct {
491 file_offset: File.Offset,473 file_offset: File.Offset,
492 err: anyerror,474 err: anyerror,
475
476 /// Returned `Path` references `Manifest.contents`.
477 pub fn path(fo: FileOp, manifest: *const Manifest) Path {
478 const contents = manifest.contents.items;
479 const prefix = fo.file_offset.get(contents).flags.prefix;
480 return .{
481 .root_dir = manifest.cache.prefixes()[prefix],
482 .sub_path = filePath(contents, fo.file_offset),
483 };
484 }
493 };485 };
494 };486 };
495487
...@@ -499,42 +491,49 @@ pub const Manifest = struct {...@@ -499,42 +491,49 @@ pub const Manifest = struct {
499 mtime: Io.Timestamp,491 mtime: Io.Timestamp,
500 };492 };
501493
502 pub const AddInputFileOptions = struct {494 pub const PathHandle = union(enum) {
503 /// If `is_directory` is true, this handle must be opened with495 file: ?Io.File,
504 /// iteration capability.496 /// If provided, this handle must be opened with iteration capability.
505 handle: ?Io.File = null,497 dir: ?Io.Dir,
498 };
499
500 pub const AddInputPathOptions = struct {
501 handle: PathHandle = .{ .file = null },
506 stat: ?Stat = null,502 stat: ?Stat = null,
507 request_handle: bool = false,503 request_handle: bool = false,
508 /// Can request file or directory contents depending on `is_directory`.504 /// Can request file or directory contents depending on `handle`.
509 request_contents: bool = false,505 request_contents: bool = false,
510 /// Contents of a directory are considered to be the sorted list of
511 /// file names of direct entries, separated by null byte. Each file name
512 /// is prefixed by `Io.File.Kind` byte, +1 so that the zero tag is
513 /// not aliased by the entry separator.
514 is_directory: bool = false,
515 /// Content hashing skipped; any difference in metadata implies cache506 /// Content hashing skipped; any difference in metadata implies cache
516 /// miss.507 /// miss.
517 metadata_only: bool = false,508 metadata_only: bool = false,
518 };509 };
519510
520 pub const AddInputFileError = error{511 pub const AddInputPathError = error{
521 /// The same file path has been added to the cache manifest both as a512 /// The same file path has been added to the cache manifest both as a
522 /// directory and as a normal file, making the intended caching513 /// directory and as a normal file, making the intended caching
523 /// behavior ambiguous.514 /// behavior ambiguous.
524 IsDirectoryAmbiguous,515 IsDirectoryAmbiguous,
525 } || Allocator.Error;516 } || Allocator.Error;
526517
527 /// Add a file as a dependency of process being cached. When `hit` is518 /// Add a file or directory path as a dependency of process being cached.
528 /// called, the file's contents will be checked to ensure that it matches519 /// When `hit` is called, the contents will be checked to ensure
529 /// the contents from previous times.520 /// that it matches the contents from previous times.
530 ///521 ///
531 /// The contents of the input file may be requested and subsequently522 /// The contents of the input file may be requested and subsequently
532 /// obtained via methods of the returned `InputFile.Index` after calling523 /// obtained via methods of the returned `InputPath.Index` after calling
533 /// `hit`.524 /// `hit`.
534 pub fn addInputFile(m: *Manifest, path: Path, options: AddInputFileOptions) Allocator.Error!InputFile.Index {525 ///
526 /// Contents of a directory are considered to be the sorted list of file
527 /// names of direct entries, separated by null byte. Each file name is
528 /// prefixed by `Io.File.Kind` byte, +1 so that the zero tag is not aliased
529 /// by the entry separator.
530 ///
531 /// See also:
532 /// * `addPathPost`
533 pub fn addInputPath(m: *Manifest, path: Path, options: AddInputPathOptions) AddInputPathError!InputPath.Index {
535 const gpa = m.cache.gpa;534 const gpa = m.cache.gpa;
536 try m.files.ensureUnusedCapacity(gpa, 1);535 try m.files.ensureUnusedCapacity(gpa, 1);
537 try m.input_files.ensureUnusedCapacity(gpa, 1);536 try m.input_paths.ensureUnusedCapacity(gpa, 1);
538537
539 const prev_contents_len = m.contents.items.len;538 const prev_contents_len = m.contents.items.len;
540 const header: *File = @ptrCast(try m.contents.addManyAsSlice(gpa, @sizeOf(File)));539 const header: *File = @ptrCast(try m.contents.addManyAsSlice(gpa, @sizeOf(File)));
...@@ -558,7 +557,7 @@ pub const Manifest = struct {...@@ -558,7 +557,7 @@ pub const Manifest = struct {
558 });557 });
559 if (gop.found_existing) {558 if (gop.found_existing) {
560 m.contents.shrinkRetainingCapacity(prev_contents_len);559 m.contents.shrinkRetainingCapacity(prev_contents_len);
561 const existing_input_file = &m.input_files.items[gop.index];560 const existing_input_file = &m.input_paths.items[gop.index];
562 if (options.handle) |handle| {561 if (options.handle) |handle| {
563 existing_input_file.handle = handle;562 existing_input_file.handle = handle;
564 existing_input_file.have_handle = true;563 existing_input_file.have_handle = true;
...@@ -579,7 +578,7 @@ pub const Manifest = struct {...@@ -579,7 +578,7 @@ pub const Manifest = struct {
579 if (!options.metadata_only)578 if (!options.metadata_only)
580 existing_header.flags.metadata_only = false;579 existing_header.flags.metadata_only = false;
581 } else {580 } else {
582 m.input_files.appendAssumeCapacity(.{581 m.input_paths.appendAssumeCapacity(.{
583 .request_handle = options.request_handle,582 .request_handle = options.request_handle,
584 .have_handle = options.handle != null,583 .have_handle = options.handle != null,
585 .handle = if (options.handle) |handle| handle else undefined,584 .handle = if (options.handle) |handle| handle else undefined,
...@@ -587,7 +586,7 @@ pub const Manifest = struct {...@@ -587,7 +586,7 @@ pub const Manifest = struct {
587 .have_digest = false,586 .have_digest = false,
588 .have_stat = options.stat != null,587 .have_stat = options.stat != null,
589 });588 });
590 assert(m.input_files.items.len - 1 == gop.index);589 assert(m.input_paths.items.len - 1 == gop.index);
591 if (options.stat) |stat| {590 if (options.stat) |stat| {
592 header.size = stat.size;591 header.size = stat.size;
593 header.inode = stat.inode;592 header.inode = stat.inode;
...@@ -597,9 +596,9 @@ pub const Manifest = struct {...@@ -597,9 +596,9 @@ pub const Manifest = struct {
597 return @fromBackingInt(gop.index);596 return @fromBackingInt(gop.index);
598 }597 }
599598
600 pub fn addInputFileOptional(m: *Manifest, opt_path: ?Path, options: AddInputFileOptions) Allocator.Error!void {599 pub fn addInputFileOptional(m: *Manifest, opt_path: ?Path, options: AddInputPathOptions) Allocator.Error!void {
601 m.hash.add(opt_path != null);600 m.hash.add(opt_path != null);
602 _ = try addInputFile(m, opt_path orelse return, options);601 _ = try addInputPath(m, opt_path orelse return, options);
603 }602 }
604603
605 /// Check the cache to see if the input exists in it.604 /// Check the cache to see if the input exists in it.
...@@ -623,8 +622,8 @@ pub const Manifest = struct {...@@ -623,8 +622,8 @@ pub const Manifest = struct {
623 pub fn checkProgressless(man: *Manifest) Check.Error!Check.Status {622 pub fn checkProgressless(man: *Manifest) Check.Error!Check.Status {
624 assert(man.manifest_file == null);623 assert(man.manifest_file == null);
625624
626 for (man.files.keys()[0..man.input_files.items.len]) |file_off| {625 for (man.files.keys()[0..man.input_paths.items.len]) |file_off| {
627 file_off.get(man).manifestDigestHash(&man.hash.hasher);626 man.digestHash(file_off, &man.hash.hasher);
628 }627 }
629628
630 man.diagnostic = .none;629 man.diagnostic = .none;
...@@ -709,16 +708,16 @@ pub const Manifest = struct {...@@ -709,16 +708,16 @@ pub const Manifest = struct {
709708
710 // We're going to construct a second hash. Its input will begin with the digest we've709 // We're going to construct a second hash. Its input will begin with the digest we've
711 // already computed (`bin_digest`), and then it'll have the digests of each input file,710 // already computed (`bin_digest`), and then it'll have the digests of each input file,
712 // including "post" files (see `addFilePost`). If this is a hit, we learn the set of "post"711 // including "post" files (see `addPathPost`). If this is a hit, we learn the set of "post"
713 // files from the manifest on disk. If this is a miss, we'll learn those from future calls712 // files from the manifest on disk. If this is a miss, we'll learn those from future calls
714 // to `addFilePost` etc. As such, the state of `man.hash.hasher` after this function713 // to `addPathPost` etc. As such, the state of `man.hash.hasher` after this function
715 // depends on whether this is a hit or a miss.714 // depends on whether this is a hit or a miss.
716 //715 //
717 // If we return `CacheStatus.hit`, then `man.hash.hasher` must already include716 // If we return `CacheStatus.hit`, then `man.hash.hasher` must already include
718 // the digests of the "post" files, so the caller can call `final`. Otherwise, on a cache717 // the digests of the "post" files, so the caller can call `final`. Otherwise, on a cache
719 // miss, `man.hash.hasher` will include the digests of all non-"post" files -- that is,718 // miss, `man.hash.hasher` will include the digests of all non-"post" files -- that is,
720 // the ones we've already been told about. The rest will be discovered through calls to719 // the ones we've already been told about. The rest will be discovered through calls to
721 // `addFilePost` etc, which will update the hasher. After all files are added, the user can720 // `addPathPost` etc, which will update the hasher. After all files are added, the user can
722 // use `final`, and will at some point `writeManifest` the file list to disk.721 // use `final`, and will at some point `writeManifest` the file list to disk.
723722
724 man.hash.hasher = hasher_init;723 man.hash.hasher = hasher_init;
...@@ -762,11 +761,11 @@ pub const Manifest = struct {...@@ -762,11 +761,11 @@ pub const Manifest = struct {
762 }761 }
763762
764 fn shrinkFilesToInput(m: *Manifest) void {763 fn shrinkFilesToInput(m: *Manifest) void {
765 if (m.files.count() <= m.input_files.items.len) return;764 if (m.files.count() <= m.input_paths.items.len) return;
766 const off = m.files.keys()[m.input_files.items.len];765 const off = m.files.keys()[m.input_paths.items.len];
767 m.contents.shrinkRetainingCapacity(@backingInt(off));766 m.contents.shrinkRetainingCapacity(@backingInt(off));
768 assert(m.contents.len % @alignOf(File) == 0);767 assert(m.contents.items.len % @alignOf(File) == 0);
769 m.files.shrinkRetainingCapacity(m.input_files.items.len);768 m.files.shrinkRetainingCapacity(m.input_paths.items.len);
770 }769 }
771770
772 /// Assumes that `self.hash.hasher` has been updated only with the original digest and that771 /// Assumes that `self.hash.hasher` has been updated only with the original digest and that
...@@ -784,59 +783,70 @@ pub const Manifest = struct {...@@ -784,59 +783,70 @@ pub const Manifest = struct {
784 return error.CacheCheckFailed;783 return error.CacheCheckFailed;
785 },784 },
786 };785 };
786 const contents = m.contents.items;
787787
788 // Guess number of files based on manifest contents len to reduce allocations.788 var off: u32 = 0;
789 try m.files.ensureUnusedCapacity(gpa, m.contents.len / (@sizeOf(File) + 32));789 var c: Check = .{};
790
791 var file_index: usize = 0;
792 var off: usize = 0;
793790
794 // This group we always want to compute the hash digests, even on a cache miss.791 // This group we always want to compute the hash digests, even on a
792 // cache miss, because they will be used in the manifest digest.
795 var input_group: Io.Group = .init;793 var input_group: Io.Group = .init;
796 defer input_group.cancel(io);794 defer input_group.cancel(io);
797795
796 // First the input files section, which must match our input files,
797 // otherwise it's invalid format.
798 for (m.input_paths.items, m.files.keys()[0..m.input_paths.items.len]) |*input_path, input_file_off| {
799 if (off + 1 >= contents.len) return error.InvalidFormat;
800 const file_off: File.Offset = @fromBackingInt(off);
801 const file = try file_off.getFallible(contents);
802 if (file.flags.prefix >= m.cache.prefixes_len) return error.InvalidFormat;
803 const path = try filePathFallible(contents, file_off);
804 if (path.len == 0) return error.InvalidFormat;
805 if (input_file_off != file_off) return error.InvalidFormat;
806
807 input_group.async(io, checkInputFile, .{ m, &c, file_off, path, input_path });
808
809 off = @intCast(@as(usize, off) + @sizeOf(File) + path.len + 1);
810 }
811
812 // Guess number of files based on manifest contents len to reduce allocations.
813 // This is not an upper bound; subsequent insertions may potentially allocate.
814 try m.files.ensureUnusedCapacity(gpa, contents.len / (@sizeOf(File) + 32));
815
798 // This group we would like to cancel as soon as a cache miss is discovered.816 // This group we would like to cancel as soon as a cache miss is discovered.
799 const PostResult = union(enum) {817 const PostResult = union(enum) {
800 checkFile: Check.Status,818 checkFile: Check.Status,
801 };819 };
802 var post_select_buffer: [10]PostResult = undefined;820 var post_select_buffer: [10]PostResult = undefined;
803 var post_select: Io.Select(PostResult) = .init(&post_select_buffer);821 var post_select: Io.Select(PostResult) = .init(io, &post_select_buffer);
804 var post_select_remaining: usize = 0;822 var post_select_remaining: usize = 0;
805 var c: Check = .{};823 defer post_select.cancelDiscard();
806 defer post_select.cancel(io);
807824
808 while (off + 1 < m.contents.len) {825 while (off + 1 < contents.len) {
809 const file_off: File.Offset = @fromBackingInt(off);826 const file_off: File.Offset = @fromBackingInt(off);
810 const file = try File.getFallible(file_off, m);827 const file = try file_off.getFallible(m);
811 if (file.flags.prefix >= m.cache.prefixes_len) return error.InvalidFormat;828 if (file.flags.prefix >= m.cache.prefixes_len) return error.InvalidFormat;
812 const path = try file.pathFallible();829 const path = try filePathFallible(contents, file_off);
813 if (path.len == 0) return error.InvalidFormat;830 if (path.len == 0) return error.InvalidFormat;
814831
815 if (file_index < m.input_files.items.len) {832 try m.files.put(gpa, file_off, {});
816 if (m.files.keys()[file_index] != file_off) return error.InvalidFormat;
817
818 input_group.async(io, checkInputFile, .{ m, &c, file_off, path });
819 } else {
820 try m.files.put(gpa, file_off);
821833
822 post_select.async(.checkFile, checkFile, .{ m, &c, file_off, path });834 post_select.async(.checkFile, checkFile, .{ m, &c, file_off, path });
823 post_select_remaining += 1;835 post_select_remaining += 1;
824 }
825836
826 file_index += 1;837 off = @intCast(@as(usize, off) + @sizeOf(File) + path.len + 1);
827 off += @sizeOf(File) + path.len + 1;
828 }838 }
829839
830 // Final terminating zero byte to distinguish empty manifest file from840 // Final terminating zero byte to distinguish empty manifest file from
831 // manifest with zero files.841 // manifest with zero files.
832 const file_valid = off + 1 == m.contents.len and m.contents[off] == 0;842 const file_valid = off + 1 == contents.len and contents[off] == 0;
833 if (!file_valid or file_index < m.input_files.items.len) {843 if (!file_valid) {
834 try input_group.await(io);844 try input_group.await(io);
835 return .miss;845 return .miss;
836 }846 }
837847
838 // Don't track the trailing zero byte in contents.848 // Don't track the trailing zero byte in contents.
839 m.contents.len -= 1;849 m.contents.items.len -= 1;
840850
841 var post_await_buffer: [10]PostResult = undefined;851 var post_await_buffer: [10]PostResult = undefined;
842 while (post_select_remaining > 0) {852 while (post_select_remaining > 0) {
...@@ -880,11 +890,17 @@ pub const Manifest = struct {...@@ -880,11 +890,17 @@ pub const Manifest = struct {
880 return .hit;890 return .hit;
881 }891 }
882892
883 fn checkInputFile(m: *Manifest, c: *Check, file_off: File.Offset, file_path: [:0]const u8) Io.Cancelable!void {893 fn checkInputFile(
884 // TODO use already open handle894 m: *Manifest,
885 // TODO use already provided stat895 c: *Check,
886 // TODO implement request_handle896 file_off: File.Offset,
887 // TODO implement request_contents897 file_path: [:0]const u8,
898 input_path: *InputPath,
899 ) Io.Cancelable!void {
900 if (input_path.have_handle) @panic("TODO");
901 if (input_path.have_stat) @panic("TODO");
902 if (input_path.contents != .not_requested) @panic("TODO");
903 if (input_path.request_handle) @panic("TODO");
888 switch (try checkFile(m, c, file_off, file_path)) {904 switch (try checkFile(m, c, file_off, file_path)) {
889 .hit => return,905 .hit => return,
890 .miss => @atomicStore(Check.Status, &c.status, .miss, .unordered),906 .miss => @atomicStore(Check.Status, &c.status, .miss, .unordered),
...@@ -897,7 +913,7 @@ pub const Manifest = struct {...@@ -897,7 +913,7 @@ pub const Manifest = struct {
897 c: *Check,913 c: *Check,
898 file_off: File.Offset,914 file_off: File.Offset,
899 file_path: [:0]const u8,915 file_path: [:0]const u8,
900 ) Io.Cancelable!Check.Status {916 ) error{ Canceled, CacheCheckFailed }!Check.Status {
901 const file = file_off.get(m);917 const file = file_off.get(m);
902 const cache = m.cache;918 const cache = m.cache;
903 const gpa = cache.gpa;919 const gpa = cache.gpa;
...@@ -905,7 +921,7 @@ pub const Manifest = struct {...@@ -905,7 +921,7 @@ pub const Manifest = struct {
905 const parent_dir = cache.prefixes()[file.flags.prefix].handle;921 const parent_dir = cache.prefixes()[file.flags.prefix].handle;
906922
907 if (file.flags.metadata_only) {923 if (file.flags.metadata_only) {
908 const actual_stat = parent_dir.statFile() catch |err| switch (err) {924 const actual_stat = parent_dir.statFile(io, file_path, .{}) catch |err| switch (err) {
909 error.FileNotFound => return .miss,925 error.FileNotFound => return .miss,
910 error.Canceled => |e| return e,926 error.Canceled => |e| return e,
911 else => |e| return c.fail(m, .{ .file_stat = .{927 else => |e| return c.fail(m, .{ .file_stat = .{
...@@ -999,10 +1015,10 @@ pub const Manifest = struct {...@@ -999,10 +1015,10 @@ pub const Manifest = struct {
999 /// not including post files).1015 /// not including post files).
1000 ///1016 ///
1001 /// Assumes that `bin_digest` is populated for all input files.1017 /// Assumes that `bin_digest` is populated for all input files.
1002 pub fn unhit(man: *Manifest, bin_digest: BinDigest) void {1018 pub fn unhit(man: *Manifest, bin_digest: *const BinDigest) void {
1003 // Reset the hash.1019 // Reset the hash.
1004 man.hash.hasher = hasher_init;1020 man.hash.hasher = hasher_init;
1005 man.hash.hasher.update(&bin_digest);1021 man.hash.hasher.update(bin_digest);
1006 man.shrinkFilesToInput();1022 man.shrinkFilesToInput();
1007 for (man.files.keys()) |off| {1023 for (man.files.keys()) |off| {
1008 const file = off.get(man);1024 const file = off.get(man);
...@@ -1053,11 +1069,8 @@ pub const Manifest = struct {...@@ -1053,11 +1069,8 @@ pub const Manifest = struct {
1053 return timestamp.nanoseconds >= man.recent_problematic_timestamp.nanoseconds;1069 return timestamp.nanoseconds >= man.recent_problematic_timestamp.nanoseconds;
1054 }1070 }
10551071
1056 pub const AddFilePostOptions = struct {1072 pub const AddPathPostOptions = struct {
1057 handle: union(enum) {1073 handle: PathHandle = .{ .file = null },
1058 file: ?Io.File,
1059 dir: ?Io.Dir,
1060 } = .{ .file = null },
1061 stat: ?Stat = null,1074 stat: ?Stat = null,
1062 /// If it is a directory, there is a special encoding required for contents, which1075 /// If it is a directory, there is a special encoding required for contents, which
1063 /// is null-separated sorted entries, each one prefixed with `File.Kind`.1076 /// is null-separated sorted entries, each one prefixed with `File.Kind`.
...@@ -1065,7 +1078,7 @@ pub const Manifest = struct {...@@ -1065,7 +1078,7 @@ pub const Manifest = struct {
1065 metadata_only: bool = false,1078 metadata_only: bool = false,
1066 };1079 };
10671080
1068 pub const AddFilePostError = error{1081 pub const AddPathPostError = error{
1069 /// The same file path has been added to the cache manifest both as a1082 /// The same file path has been added to the cache manifest both as a
1070 /// directory and as a normal file, making the intended caching1083 /// directory and as a normal file, making the intended caching
1071 /// behavior ambiguous.1084 /// behavior ambiguous.
...@@ -1074,7 +1087,10 @@ pub const Manifest = struct {...@@ -1074,7 +1087,10 @@ pub const Manifest = struct {
10741087
1075 /// Add a file as a dependency of process being cached, after cache miss1088 /// Add a file as a dependency of process being cached, after cache miss
1076 /// occurs.1089 /// occurs.
1077 pub fn addFilePost(m: *Manifest, path: Path, options: AddFilePostOptions) AddFilePostError!void {1090 ///
1091 /// See also:
1092 /// * `addInputPath`
1093 pub fn addPathPost(m: *Manifest, path: Path, options: AddPathPostOptions) AddPathPostError!void {
1078 assert(m.manifest_file != null);1094 assert(m.manifest_file != null);
1079 const cache = m.cache;1095 const cache = m.cache;
1080 const gpa = cache.gpa;1096 const gpa = cache.gpa;
...@@ -1236,14 +1252,14 @@ pub const Manifest = struct {...@@ -1236,14 +1252,14 @@ pub const Manifest = struct {
1236 // Clang is invoked in single-source mode but other programs may not1252 // Clang is invoked in single-source mode but other programs may not
1237 .target, .target_must_resolve => {},1253 .target, .target_must_resolve => {},
1238 .prereq => |file_path| if (self.manifest_file == null) {1254 .prereq => |file_path| if (self.manifest_file == null) {
1239 _ = try self.addFilePath(.initCwd(file_path), null);1255 _ = try self.addInputPath(.initCwd(file_path), .{});
1240 } else try self.addFilePost(file_path),1256 } else try self.addPathPost(file_path),
1241 .prereq_must_resolve => {1257 .prereq_must_resolve => {
1242 resolve_buf.clearRetainingCapacity();1258 resolve_buf.clearRetainingCapacity();
1243 try token.resolve(gpa, &resolve_buf);1259 try token.resolve(gpa, &resolve_buf);
1244 if (self.manifest_file == null) {1260 if (self.manifest_file == null) {
1245 _ = try self.addFilePath(.initCwd(resolve_buf.items), null);1261 _ = try self.addInputPath(.initCwd(resolve_buf.items), .{});
1246 } else try self.addFilePost(resolve_buf.items);1262 } else try self.addPathPost(resolve_buf.items);
1247 },1263 },
1248 else => |err| {1264 else => |err| {
1249 try err.printError(gpa, &error_buf);1265 try err.printError(gpa, &error_buf);
...@@ -1336,25 +1352,45 @@ pub const Manifest = struct {...@@ -1336,25 +1352,45 @@ pub const Manifest = struct {
1336 return .{ .manifest_file = self.manifest_file.? };1352 return .{ .manifest_file = self.manifest_file.? };
1337 }1353 }
13381354
1339 pub fn takeFiles(man: *Manifest) Files {1355 pub const SelfContainedFiles = struct {
1340 defer man.files = .empty;1356 /// References memory inside `contents`.
1341 return man.files;1357 files: Files,
1342 }1358 contents: std.ArrayList(u8),
1359
1360 pub const empty: @This() = .{
1361 .files = .empty,
1362 .contents = .empty,
1363 };
1364
1365 pub fn deinit(scf: *SelfContainedFiles, gpa: Allocator) void {
1366 scf.files.deinit(gpa);
1367 scf.contents.deinit(gpa);
1368 scf.* = undefined;
1369 }
1370
1371 pub fn path(scf: *const SelfContainedFiles, file_offset: File.Offset) [:0]const u8 {
1372 return filePath(scf.contents.items, file_offset);
1373 }
1374 };
13431375
1344 pub fn freeFiles(gpa: Allocator, files: *Files) void {1376 pub fn takeFiles(m: *Manifest) SelfContainedFiles {
1345 for (files.keys()) |*file| file.deinit(gpa);1377 defer m.files = .empty;
1346 files.deinit(gpa);1378 defer m.contents = .empty;
1379 return .{
1380 .files = m.files,
1381 .contents = m.contents,
1382 };
1347 }1383 }
13481384
1349 /// Releases the manifest file and frees any memory the Manifest was using.1385 /// Releases the manifest file and frees any memory the Manifest was using.
1350 /// `Manifest.hit` must be called first.1386 /// `Manifest.hit` must be called first.
1351 ///1387 ///
1352 /// Don't forget to call `writeManifest` before this!1388 /// Don't forget to call `writeManifest` before this!
1353 pub fn deinit(man: *Manifest) void {1389 pub fn deinit(m: *Manifest) void {
1354 const io = man.cache.io;1390 const io = m.cache.io;
1355 const gpa = man.cache.gpa;1391 const gpa = m.cache.gpa;
13561392
1357 if (man.manifest_file) |file| {1393 if (m.manifest_file) |file| {
1358 if (builtin.os.tag == .windows) {1394 if (builtin.os.tag == .windows) {
1359 // See Lock.release for why this is required on Windows1395 // See Lock.release for why this is required on Windows
1360 file.unlock(io);1396 file.unlock(io);
...@@ -1362,8 +1398,9 @@ pub const Manifest = struct {...@@ -1362,8 +1398,9 @@ pub const Manifest = struct {
13621398
1363 file.close(io);1399 file.close(io);
1364 }1400 }
1365 freeFiles(gpa, &man.files);1401 m.files.deinit(gpa);
1366 man.* = undefined;1402 m.contents.deinit(gpa);
1403 m.* = undefined;
1367 }1404 }
13681405
1369 pub fn populateFileSystemInputs(man: *Manifest, buf: *std.ArrayList(u8)) Allocator.Error!void {1406 pub fn populateFileSystemInputs(man: *Manifest, buf: *std.ArrayList(u8)) Allocator.Error!void {
...@@ -1497,6 +1534,25 @@ pub const Manifest = struct {...@@ -1497,6 +1534,25 @@ pub const Manifest = struct {
1497 hasher.update(contents.items[contents_start..][0..contents_len]);1534 hasher.update(contents.items[contents_start..][0..contents_len]);
1498 hasher.final(bin_digest);1535 hasher.final(bin_digest);
1499 }1536 }
1537
1538 fn digestHash(m: *const Manifest, off: File.Offset, hasher: *Hasher) void {
1539 const contents = m.contents.items;
1540 const flags_off = @offsetOf(File, "flags");
1541 comptime assert(@offsetOf(File, "path_start") - flags_off == 1);
1542 const hash_start = @backingInt(off) + flags_off;
1543 const hash_end = mem.findScalarPos(u8, contents, hash_start, 0).?;
1544 hasher.update(contents[hash_start..hash_end]);
1545 }
1546
1547 fn filePathFallible(contents: []const u8, off: File.Offset) error{InvalidFormat}![:0]const u8 {
1548 const path_start = @backingInt(off) + @offsetOf(File, "path_start");
1549 const path_end = mem.findScalarPos(u8, contents, path_start, 0) orelse return error.InvalidFormat;
1550 return contents[path_start..path_end :0];
1551 }
1552
1553 fn filePath(contents: []const u8, off: File.Offset) [:0]const u8 {
1554 return filePathFallible(contents, off) catch unreachable;
1555 }
1500};1556};
15011557
1502/// Create/Write a file, close it, then grab its stat.mtime timestamp.1558/// Create/Write a file, close it, then grab its stat.mtime timestamp.
...@@ -1555,7 +1611,7 @@ test "cache file and then recall it" {...@@ -1555,7 +1611,7 @@ test "cache file and then recall it" {
1555 ch.hash.add(true);1611 ch.hash.add(true);
1556 ch.hash.add(@as(u16, 1234));1612 ch.hash.add(@as(u16, 1234));
1557 ch.hash.addBytes("1234");1613 ch.hash.addBytes("1234");
1558 _ = try ch.addFilePath(.initCwd(temp_file), null);1614 _ = try ch.addInputPath(.initCwd(temp_file), .{});
15591615
1560 // There should be nothing in the cache1616 // There should be nothing in the cache
1561 try testing.expectEqual(false, try ch.hit(.none));1617 try testing.expectEqual(false, try ch.hit(.none));
...@@ -1570,7 +1626,7 @@ test "cache file and then recall it" {...@@ -1570,7 +1626,7 @@ test "cache file and then recall it" {
1570 ch.hash.add(true);1626 ch.hash.add(true);
1571 ch.hash.add(@as(u16, 1234));1627 ch.hash.add(@as(u16, 1234));
1572 ch.hash.addBytes("1234");1628 ch.hash.addBytes("1234");
1573 _ = try ch.addFilePath(.initCwd(temp_file), null);1629 _ = try ch.addInputPath(.initCwd(temp_file), .{});
15741630
1575 // Cache hit! We just "built" the same file1631 // Cache hit! We just "built" the same file
1576 try testing.expect(try ch.hit(.none));1632 try testing.expect(try ch.hit(.none));
...@@ -1623,7 +1679,7 @@ test "check that changing a file makes cache fail" {...@@ -1623,7 +1679,7 @@ test "check that changing a file makes cache fail" {
1623 defer ch.deinit();1679 defer ch.deinit();
16241680
1625 ch.hash.addBytes("1234");1681 ch.hash.addBytes("1234");
1626 const temp_file_idx = try ch.addFilePath(.initCwd(temp_file), 100);1682 const temp_file_idx = try ch.addInputPath(.initCwd(temp_file), .{ .request_contents = true });
16271683
1628 // There should be nothing in the cache1684 // There should be nothing in the cache
1629 try testing.expectEqual(false, try ch.hit(.none));1685 try testing.expectEqual(false, try ch.hit(.none));
...@@ -1642,7 +1698,7 @@ test "check that changing a file makes cache fail" {...@@ -1642,7 +1698,7 @@ test "check that changing a file makes cache fail" {
1642 defer ch.deinit();1698 defer ch.deinit();
16431699
1644 ch.hash.addBytes("1234");1700 ch.hash.addBytes("1234");
1645 const temp_file_idx = try ch.addFilePath(.initCwd(temp_file), 100);1701 const temp_file_idx = try ch.addInputPath(.initCwd(temp_file), .{ .request_contents = true });
16461702
1647 // A file that we depend on has been updated, so the cache should not contain an entry for it1703 // A file that we depend on has been updated, so the cache should not contain an entry for it
1648 try testing.expectEqual(false, try ch.hit(.none));1704 try testing.expectEqual(false, try ch.hit(.none));
...@@ -1689,7 +1745,7 @@ test "no file inputs" {...@@ -1689,7 +1745,7 @@ test "no file inputs" {
1689 man.hash.addBytes("1234");1745 man.hash.addBytes("1234");
16901746
1691 // There should be nothing in the cache1747 // There should be nothing in the cache
1692 try testing.expectEqual(false, try man.hit(.none));1748 try testing.expectEqual(false, try man.check(.none));
16931749
1694 digest1 = man.final();1750 digest1 = man.final();
16951751
...@@ -1701,7 +1757,7 @@ test "no file inputs" {...@@ -1701,7 +1757,7 @@ test "no file inputs" {
17011757
1702 man.hash.addBytes("1234");1758 man.hash.addBytes("1234");
17031759
1704 try testing.expect(try man.hit(.none));1760 try testing.expect(try man.check(.none));
1705 digest2 = man.final();1761 digest2 = man.final();
1706 try testing.expectEqual(false, man.have_exclusive_lock);1762 try testing.expectEqual(false, man.have_exclusive_lock);
1707 }1763 }
...@@ -1750,12 +1806,12 @@ test "Manifest with files added after initial hash work" {...@@ -1750,12 +1806,12 @@ test "Manifest with files added after initial hash work" {
1750 defer ch.deinit();1806 defer ch.deinit();
17511807
1752 ch.hash.addBytes("1234");1808 ch.hash.addBytes("1234");
1753 _ = try ch.addFilePath(.initCwd(temp_file1), null);1809 _ = try ch.addInputPath(.initCwd(temp_file1), .{});
17541810
1755 // There should be nothing in the cache1811 // There should be nothing in the cache
1756 try testing.expectEqual(false, try ch.hit(.none));1812 try testing.expectEqual(false, try ch.hit(.none));
17571813
1758 _ = try ch.addFilePost(temp_file2);1814 _ = try ch.addPathPost(temp_file2);
17591815
1760 digest1 = ch.final();1816 digest1 = ch.final();
1761 try ch.writeManifest();1817 try ch.writeManifest();
...@@ -1765,7 +1821,7 @@ test "Manifest with files added after initial hash work" {...@@ -1765,7 +1821,7 @@ test "Manifest with files added after initial hash work" {
1765 defer ch.deinit();1821 defer ch.deinit();
17661822
1767 ch.hash.addBytes("1234");1823 ch.hash.addBytes("1234");
1768 _ = try ch.addFilePath(.initCwd(temp_file1), null);1824 _ = try ch.addInputPath(.initCwd(temp_file1), .{});
17691825
1770 try testing.expect(try ch.hit(.none));1826 try testing.expect(try ch.hit(.none));
1771 digest2 = ch.final();1827 digest2 = ch.final();
...@@ -1788,12 +1844,12 @@ test "Manifest with files added after initial hash work" {...@@ -1788,12 +1844,12 @@ test "Manifest with files added after initial hash work" {
1788 defer ch.deinit();1844 defer ch.deinit();
17891845
1790 ch.hash.addBytes("1234");1846 ch.hash.addBytes("1234");
1791 _ = try ch.addFilePath(.initCwd(temp_file1), null);1847 _ = try ch.addInputPath(.initCwd(temp_file1), .{});
17921848
1793 // A file that we depend on has been updated, so the cache should not contain an entry for it1849 // A file that we depend on has been updated, so the cache should not contain an entry for it
1794 try testing.expectEqual(false, try ch.hit(.none));1850 try testing.expectEqual(false, try ch.hit(.none));
17951851
1796 _ = try ch.addFilePost(temp_file2);1852 _ = try ch.addPathPost(temp_file2);
17971853
1798 digest3 = ch.final();1854 digest3 = ch.final();
17991855
lib/std/Build/Configuration.zig+1-1
...@@ -1875,7 +1875,7 @@ pub const PathDep = extern struct {...@@ -1875,7 +1875,7 @@ pub const PathDep = extern struct {
1875 is_directory: bool,1875 is_directory: bool,
1876 metadata_only: bool,1876 metadata_only: bool,
1877 base: LazyPath.Relative.Base,1877 base: LazyPath.Relative.Base,
1878 _: u16 = 0,1878 _: u22 = 0,
1879 };1879 };
1880};1880};
18811881
lib/std/Io/Reader.zig+1
...@@ -393,6 +393,7 @@ pub fn appendRemainingAligned(...@@ -393,6 +393,7 @@ pub fn appendRemainingAligned(
393pub const UnlimitedAllocError = Allocator.Error || ShortError;393pub const UnlimitedAllocError = Allocator.Error || ShortError;
394394
395pub fn appendRemainingUnlimited(r: *Reader, gpa: Allocator, list: *ArrayList(u8)) UnlimitedAllocError!void {395pub fn appendRemainingUnlimited(r: *Reader, gpa: Allocator, list: *ArrayList(u8)) UnlimitedAllocError!void {
396 list.pointer_stability.assertUnlocked();
396 var a: std.Io.Writer.Allocating = .initOwnedSlice(gpa, list.allocatedSlice());397 var a: std.Io.Writer.Allocating = .initOwnedSlice(gpa, list.allocatedSlice());
397 a.writer.end = list.items.len;398 a.writer.end = list.items.len;
398 list.* = .empty;399 list.* = .empty;
src/Compilation.zig+14-14
...@@ -1340,19 +1340,19 @@ pub const cache_helpers = struct {...@@ -1340,19 +1340,19 @@ pub const cache_helpers = struct {
1340 }1340 }
1341 }1341 }
13421342
1343 pub fn hashCSource(self: *Cache.Manifest, c_source: CSourceFile) !void {1343 pub fn hashCSource(man: *Cache.Manifest, c_source: CSourceFile) !void {
1344 _ = try self.addFilePath(.initCwd(c_source.src_path), null);1344 _ = try man.addInputPath(.initCwd(c_source.src_path), .{});
1345 // Hash the extra flags, with special care to call addFile for file parameters.1345 // Hash the extra flags, with special care to call addFile for file parameters.
1346 // TODO this logic can likely be improved by utilizing clang_options_data.zig.1346 // TODO this logic can likely be improved by utilizing clang_options_data.zig.
1347 const file_args = [_][]const u8{"-include"};1347 const file_args = [_][]const u8{"-include"};
1348 var arg_i: usize = 0;1348 var arg_i: usize = 0;
1349 while (arg_i < c_source.extra_flags.len) : (arg_i += 1) {1349 while (arg_i < c_source.extra_flags.len) : (arg_i += 1) {
1350 const arg = c_source.extra_flags[arg_i];1350 const arg = c_source.extra_flags[arg_i];
1351 self.hash.addBytes(arg);1351 man.hash.addBytes(arg);
1352 for (file_args) |file_arg| {1352 for (file_args) |file_arg| {
1353 if (mem.eql(u8, file_arg, arg) and arg_i + 1 < c_source.extra_flags.len) {1353 if (mem.eql(u8, file_arg, arg) and arg_i + 1 < c_source.extra_flags.len) {
1354 arg_i += 1;1354 arg_i += 1;
1355 _ = try self.addFilePath(.initCwd(c_source.extra_flags[arg_i]), null);1355 _ = try man.addInputPath(.initCwd(c_source.extra_flags[arg_i]), .{});
1356 }1356 }
1357 }1357 }
1358 }1358 }
...@@ -2830,7 +2830,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE...@@ -2830,7 +2830,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
2830 man.want_shared_lock = false;2830 man.want_shared_lock = false;
2831 }2831 }
28322832
2833 const is_hit = man.hit(main_progress_node) catch |err| switch (err) {2833 const is_hit = man.check(main_progress_node) catch |err| switch (err) {
2834 error.Canceled, error.OutOfMemory => |e| return e,2834 error.Canceled, error.OutOfMemory => |e| return e,
2835 error.CacheCheckFailed => switch (man.diagnostic) {2835 error.CacheCheckFailed => switch (man.diagnostic) {
2836 .none => unreachable,2836 .none => unreachable,
...@@ -3394,7 +3394,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes...@@ -3394,7 +3394,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes
3394 try link.hashInputs(man, comp.link_inputs);3394 try link.hashInputs(man, comp.link_inputs);
33953395
3396 for (comp.c_objects.items) |c_object| {3396 for (comp.c_objects.items) |c_object| {
3397 _ = try man.addFilePath(.initCwd(c_object.src.src_path), null);3397 _ = try man.addInputPath(.initCwd(c_object.src.src_path), .{});
3398 man.hash.addOptional(c_object.src.ext);3398 man.hash.addOptional(c_object.src.ext);
3399 man.hash.addListOfBytes(c_object.src.extra_flags);3399 man.hash.addListOfBytes(c_object.src.extra_flags);
3400 }3400 }
...@@ -3402,11 +3402,11 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes...@@ -3402,11 +3402,11 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes
3402 for (comp.win32_resources.items) |win32_resource| {3402 for (comp.win32_resources.items) |win32_resource| {
3403 switch (win32_resource.src) {3403 switch (win32_resource.src) {
3404 .rc => |rc_src| {3404 .rc => |rc_src| {
3405 _ = try man.addFilePath(.initCwd(rc_src.src_path), null);3405 _ = try man.addInputPath(.initCwd(rc_src.src_path), .{});
3406 man.hash.addListOfBytes(rc_src.extra_flags);3406 man.hash.addListOfBytes(rc_src.extra_flags);
3407 },3407 },
3408 .manifest => |manifest_path| {3408 .manifest => |manifest_path| {
3409 _ = try man.addFilePath(.initCwd(manifest_path), null);3409 _ = try man.addInputPath(.initCwd(manifest_path), .{});
3410 },3410 },
3411 }3411 }
3412 }3412 }
...@@ -5540,7 +5540,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr...@@ -5540,7 +5540,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
5540 const target = comp.getTarget();5540 const target = comp.getTarget();
5541 assert(target.ofmt != .c);5541 assert(target.ofmt != .c);
5542 const o_ext = target.ofmt.fileExt(target.cpu.arch);5542 const o_ext = target.ofmt.fileExt(target.cpu.arch);
5543 const digest = if (!comp.disable_c_depfile and try man.hit(child_progress_node)) man.final() else blk: {5543 const digest = if (!comp.disable_c_depfile and try man.check(child_progress_node)) man.final() else blk: {
5544 var argv: std.array_list.Managed([]const u8) = .init(gpa);5544 var argv: std.array_list.Managed([]const u8) = .init(gpa);
5545 defer argv.deinit();5545 defer argv.deinit();
55465546
...@@ -5801,7 +5801,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr...@@ -5801,7 +5801,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
5801 }5801 }
58025802
5803 // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.5803 // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.
5804 if (comp.disable_c_depfile) _ = try man.hit(child_progress_node);5804 if (comp.disable_c_depfile) _ = try man.check(child_progress_node);
58055805
5806 // Rename into place.5806 // Rename into place.
5807 const digest = man.final();5807 const digest = man.final();
...@@ -5884,12 +5884,12 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32...@@ -5884,12 +5884,12 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
5884 // the XML data as a RT_MANIFEST resource. This means we can skip preprocessing,5884 // the XML data as a RT_MANIFEST resource. This means we can skip preprocessing,
5885 // include paths, CLI options, etc.5885 // include paths, CLI options, etc.
5886 if (win32_resource.src == .manifest) {5886 if (win32_resource.src == .manifest) {
5887 _ = try man.addFilePath(.initCwd(src_path), null);5887 _ = try man.addInputPath(.initCwd(src_path), .{});
58885888
5889 const rc_basename = try std.fmt.allocPrint(arena, "{s}.rc", .{src_basename});5889 const rc_basename = try std.fmt.allocPrint(arena, "{s}.rc", .{src_basename});
5890 const res_basename = try std.fmt.allocPrint(arena, "{s}.res", .{src_basename});5890 const res_basename = try std.fmt.allocPrint(arena, "{s}.res", .{src_basename});
58915891
5892 const digest = if (try man.hit(child_progress_node)) man.final() else blk: {5892 const digest = if (try man.check(child_progress_node)) man.final() else blk: {
5893 // The digest only depends on the .manifest file, so we can5893 // The digest only depends on the .manifest file, so we can
5894 // get the digest now and write the .res directly to the cache5894 // get the digest now and write the .res directly to the cache
5895 const digest = man.final();5895 const digest = man.final();
...@@ -5977,12 +5977,12 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32...@@ -5977,12 +5977,12 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
5977 // We now know that we're compiling an .rc file5977 // We now know that we're compiling an .rc file
5978 const rc_src = win32_resource.src.rc;5978 const rc_src = win32_resource.src.rc;
59795979
5980 _ = try man.addFilePath(.initCwd(rc_src.src_path), null);5980 _ = try man.addInputPath(.initCwd(rc_src.src_path), .{});
5981 man.hash.addListOfBytes(rc_src.extra_flags);5981 man.hash.addListOfBytes(rc_src.extra_flags);
59825982
5983 const rc_basename_noext = src_basename[0 .. src_basename.len - fs.path.extension(src_basename).len];5983 const rc_basename_noext = src_basename[0 .. src_basename.len - fs.path.extension(src_basename).len];
59845984
5985 const digest = if (try man.hit(child_progress_node)) man.final() else blk: {5985 const digest = if (try man.check(child_progress_node)) man.final() else blk: {
5986 var zig_cache_tmp_dir = try comp.dirs.local_cache.handle.createDirPathOpen(io, "tmp", .{});5986 var zig_cache_tmp_dir = try comp.dirs.local_cache.handle.createDirPathOpen(io, "tmp", .{});
5987 defer zig_cache_tmp_dir.close(io);5987 defer zig_cache_tmp_dir.close(io);
59885988
src/libs/freebsd.zig+5-3
...@@ -458,12 +458,14 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -458,12 +458,14 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
458 man.hash.add(target.abi);458 man.hash.add(target.abi);
459 man.hash.add(target_os_version);459 man.hash.add(target_os_version);
460460
461 const abilists_index = try man.addFilePath(.{461 const abilists_index = try man.addInputPath(.{
462 .root_dir = comp.dirs.zig_lib,462 .root_dir = comp.dirs.zig_lib,
463 .sub_path = abilists_path,463 .sub_path = abilists_path,
464 }, abilists_max_size);464 }, .{
465 .request_contents = true,
466 });
465467
466 if (try man.hit(prog_node)) {468 if (try man.check(prog_node)) {
467 const digest = man.final();469 const digest = man.final();
468470
469 return queueSharedObjects(comp, .{471 return queueSharedObjects(comp, .{
src/libs/glibc.zig+5-3
...@@ -698,12 +698,14 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -698,12 +698,14 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
698 man.hash.add(target.abi);698 man.hash.add(target.abi);
699 man.hash.add(target_version);699 man.hash.add(target_version);
700700
701 const abilists_index = try man.addFilePath(.{701 const abilists_index = try man.addInputPath(.{
702 .root_dir = comp.dirs.zig_lib,702 .root_dir = comp.dirs.zig_lib,
703 .sub_path = abilists_path,703 .sub_path = abilists_path,
704 }, abilists_max_size);704 }, .{
705 .request_contents = true,
706 });
705707
706 if (try man.hit(prog_node)) {708 if (try man.check(prog_node)) {
707 const digest = man.final();709 const digest = man.final();
708710
709 return queueSharedObjects(comp, .{711 return queueSharedObjects(comp, .{
src/libs/mingw.zig+2-2
...@@ -246,12 +246,12 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8, prog_node: std.P...@@ -246,12 +246,12 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8, prog_node: std.P
246 var man = cache.obtain();246 var man = cache.obtain();
247 defer man.deinit();247 defer man.deinit();
248248
249 _ = try man.addFilePath(def_file_path, null);249 _ = try man.addInputPath(def_file_path, .{});
250250
251 const final_lib_basename = try std.fmt.allocPrint(gpa, "{s}.lib", .{lib_name});251 const final_lib_basename = try std.fmt.allocPrint(gpa, "{s}.lib", .{lib_name});
252 errdefer gpa.free(final_lib_basename);252 errdefer gpa.free(final_lib_basename);
253253
254 const is_hit = man.hit(prog_node) catch |err| switch (err) {254 const is_hit = man.check(prog_node) catch |err| switch (err) {
255 error.CacheCheckFailed => switch (man.diagnostic) {255 error.CacheCheckFailed => switch (man.diagnostic) {
256 .none => unreachable,256 .none => unreachable,
257 .manifest_create, .manifest_read, .manifest_lock => |e| {257 .manifest_create, .manifest_read, .manifest_lock => |e| {
src/libs/netbsd.zig+5-3
...@@ -406,12 +406,14 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -406,12 +406,14 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
406 man.hash.add(target.abi);406 man.hash.add(target.abi);
407 man.hash.add(target_version);407 man.hash.add(target_version);
408408
409 const abilists_index = try man.addFilePath(.{409 const abilists_index = try man.addInputPath(.{
410 .root_dir = comp.dirs.zig_lib,410 .root_dir = comp.dirs.zig_lib,
411 .sub_path = abilists_path,411 .sub_path = abilists_path,
412 }, abilists_max_size);412 }, .{
413 .request_contents = true,
414 });
413415
414 if (try man.hit(prog_node)) {416 if (try man.check(prog_node)) {
415 const digest = man.final();417 const digest = man.final();
416418
417 return queueSharedObjects(comp, .{419 return queueSharedObjects(comp, .{
src/libs/openbsd.zig+5-3
...@@ -327,12 +327,14 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -327,12 +327,14 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
327 man.hash.add(target.abi);327 man.hash.add(target.abi);
328 man.hash.add(target_version);328 man.hash.add(target_version);
329329
330 const abilists_index = try man.addFilePath(.{330 const abilists_index = try man.addInputPath(.{
331 .root_dir = comp.dirs.zig_lib,331 .root_dir = comp.dirs.zig_lib,
332 .sub_path = abilists_path,332 .sub_path = abilists_path,
333 }, abilists_max_size);333 }, .{
334 .request_contents = true,
335 });
334336
335 if (try man.hit(prog_node)) {337 if (try man.check(prog_node)) {
336 const digest = man.final();338 const digest = man.final();
337339
338 return queueSharedObjects(comp, .{340 return queueSharedObjects(comp, .{
src/link/MachO.zig+1-1
...@@ -155,7 +155,7 @@ pub fn hashAddFrameworks(man: *Cache.Manifest, hm: []const Framework) !void {...@@ -155,7 +155,7 @@ pub fn hashAddFrameworks(man: *Cache.Manifest, hm: []const Framework) !void {
155 for (hm) |value| {155 for (hm) |value| {
156 man.hash.add(value.needed);156 man.hash.add(value.needed);
157 man.hash.add(value.weak);157 man.hash.add(value.weak);
158 _ = try man.addFilePath(value.path, null);158 _ = try man.addInputPath(value.path, .{});
159 }159 }
160}160}
161161
src/main.zig+1-1
...@@ -4862,7 +4862,7 @@ fn cmdTranslateC(...@@ -4862,7 +4862,7 @@ fn cmdTranslateC(
4862 Compilation.cache_helpers.hashCSource(&man, c_source_file) catch |err|4862 Compilation.cache_helpers.hashCSource(&man, c_source_file) catch |err|
4863 fatal("unable to process {q}: {t}", .{ c_source_file.src_path, err });4863 fatal("unable to process {q}: {t}", .{ c_source_file.src_path, err });
48644864
4865 const result: Compilation.TranslateCResult = if (try man.hit(prog_node)) .{4865 const result: Compilation.TranslateCResult = if (try man.check(prog_node)) .{
4866 .digest = man.finalBin(),4866 .digest = man.finalBin(),
4867 .cache_hit = true,4867 .cache_hit = true,
4868 .errors = std.zig.ErrorBundle.empty,4868 .errors = std.zig.ErrorBundle.empty,