authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-09-11 19:08:30-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-09-16 13:12:47-07:00
logb91a6dc5b1c99ec8308fd14224d9cd8c44785021
tree1eaf4bf93c93ca9150785b62f522dfb7a01ed0a7
parenta24b4758f4cabe7c690a5707f2fe2fda913b549c

update to newest std.Build.Cache API


15 files changed, 184 insertions(+), 151 deletions(-)

lib/compiler/Maker.zig+2-2
......@@ -1543,7 +1543,7 @@ fn configure(graph: *Graph, options: ConfigureOptions) !ScannedConfig {
15431543 config_tmp_path, final_path, e,
15441544 });
15451545 };
1546 man.writeManifest() catch |err| log.warn("failed to write cache manifest: {t}", .{err});
1546 man.finalize() catch |err| log.warn("failed to write cache manifest: {t}", .{err});
15471547 options.src_files.* = man.takeFiles();
15481548 break :cp .{ final_path, man.toOwnedLock() };
15491549 }
......@@ -1934,7 +1934,7 @@ fn cacheCatOne(input_hex_digest: []const u8, contents: []const u8, writer: *Io.W
19341934 while (off + 1 < contents.len) {
19351935 const file_off: Cache.Manifest.File.Offset = @fromBackingInt(@intCast(off));
19361936 const file = try file_off.getFallibleConst(contents);
1937 const path = try Cache.Manifest.filePathFallible(contents, file_off);
1937 const path = try file_off.pathFallible(contents);
19381938 if (path.len == 0) return error.InvalidFormat;
19391939
19401940 var file_obj = try files_tuple.beginStructField(.{ .whitespace_style = .{ .wrap = false } });
lib/compiler/Maker/Step.zig+7-8
......@@ -734,7 +734,7 @@ pub fn cacheHit(s: *Step, maker: *Maker, man: *Cache.Manifest, parent_progress_n
734734/// Clears previous watch inputs, if any, and then populates watch inputs from
735735/// the full set of files picked up by the cache manifest.
736736///
737/// Must be accompanied with `writeManifestAndWatch`.
737/// Must be accompanied with `finalizeManifestAndWatch`.
738738pub fn cacheHitWatched(s: *Step, maker: *Maker, man: *Cache.Manifest, parent_progress_node: std.Progress.Node) !bool {
739739 const hit = .hit == (man.check(parent_progress_node) catch |err| return failWithCacheError(s, maker, man, err));
740740 s.result_cached = hit;
......@@ -748,7 +748,7 @@ fn failWithCacheError(
748748 s: *Step,
749749 maker: *Maker,
750750 man: *const Cache.Manifest,
751 err: Cache.Manifest.Check.Error,
751 err: Cache.Manifest.CheckError,
752752) error{ OutOfMemory, Canceled, MakeFailed } {
753753 switch (err) {
754754 error.CacheCheckFailed => switch (man.diagnostic) {
......@@ -762,15 +762,14 @@ fn failWithCacheError(
762762 },
763763 },
764764 error.OutOfMemory, error.Canceled => |e| return e,
765 error.InvalidFormat => return s.fail(maker, "failed checking cache: invalid manifest file format", .{}),
766765 }
767766}
768767
769/// Prefer `writeManifestAndWatch` unless you already added watch inputs
768/// Prefer `finalizeManifestAndWatch` unless you already added watch inputs
770769/// separately from using the cache system.
771pub fn writeManifest(s: *Step, maker: *Maker, man: *Cache.Manifest) !void {
770pub fn finalizeManifest(s: *Step, maker: *Maker, man: *Cache.Manifest) !void {
772771 if (s.test_results.isSuccess()) {
773 man.writeManifest() catch |err| switch (err) {
772 man.finalize() catch |err| switch (err) {
774773 error.Canceled => |e| return e,
775774 else => |e| try s.addError(maker, "failed writing cache manifest: {t}", .{e}),
776775 };
......@@ -781,8 +780,8 @@ pub fn writeManifest(s: *Step, maker: *Maker, man: *Cache.Manifest) !void {
781780/// the full set of files picked up by the cache manifest.
782781///
783782/// Must be accompanied with `cacheHitWatched`.
784pub fn writeManifestAndWatch(s: *Step, maker: *Maker, man: *Cache.Manifest) !void {
785 try writeManifest(s, maker, man);
783pub fn finalizeManifestAndWatch(s: *Step, maker: *Maker, man: *Cache.Manifest) !void {
784 try finalizeManifest(s, maker, man);
786785 try setWatchInputsFromManifest(s, maker, man);
787786}
788787
lib/compiler/Maker/Step/ConfigHeader.zig+1-1
......@@ -169,7 +169,7 @@ pub fn make(
169169 .sub_path = try Io.Dir.path.join(arena, &.{ "o", &digest }),
170170 };
171171
172 try step.writeManifest(maker, &man);
172 try step.finalizeManifest(maker, &man);
173173}
174174
175175fn ensureAllValuesUsed(
lib/compiler/Maker/Step/ObjCopy.zig+1-1
......@@ -165,7 +165,7 @@ pub fn make(
165165
166166 maker.generatedPath(conf_oc.output_file).* = dest_path;
167167
168 step.writeManifest(maker, &man) catch |err| switch (err) {
168 step.finalizeManifest(maker, &man) catch |err| switch (err) {
169169 error.Canceled => |e| return e,
170170 else => |e| try step.addError(maker, "failed writing cache manifest: {t}", .{e}),
171171 };
lib/compiler/Maker/Step/Options.zig+1-1
......@@ -95,7 +95,7 @@ pub fn make(
9595 },
9696 };
9797
98 try step.writeManifestAndWatch(maker, &man);
98 try step.finalizeManifestAndWatch(maker, &man);
9999
100100 maker.generatedPath(conf_options.generated_file).* = out_path;
101101}
lib/compiler/Maker/Step/Run.zig+2-2
......@@ -275,7 +275,7 @@ pub fn make(
275275 try populateGeneratedStdIo(maker, &conf_run, cache_root, &digest);
276276 try populateGeneratedPathsCreateDirs(arena, run_index, maker, output_dir_path, output_placeholders.items, argv_list.items);
277277 try runCommand(arena, run, run_index, maker, progress_node, argv_list.items, has_side_effects, output_dir_path, null);
278 if (!has_side_effects) try step.writeManifestAndWatch(maker, &man);
278 if (!has_side_effects) try step.finalizeManifestAndWatch(maker, &man);
279279 return;
280280 }
281281
......@@ -344,7 +344,7 @@ pub fn make(
344344 };
345345 }
346346
347 if (!has_side_effects) try step.writeManifestAndWatch(maker, &man);
347 if (!has_side_effects) try step.finalizeManifestAndWatch(maker, &man);
348348
349349 try populateGeneratedStdIo(maker, &conf_run, cache_root, &digest);
350350 try populateGeneratedPaths(maker, output_placeholders.items, cache_root, &digest);
lib/compiler/Maker/Step/WriteFile.zig+1-1
......@@ -122,7 +122,7 @@ pub fn make(
122122
123123 progress_node.setEstimatedTotalItems(total_items);
124124 try operate(maker, step_index, open_dir_cache, out_path, progress_node);
125 try step.writeManifest(maker, &man);
125 try step.finalizeManifest(maker, &man);
126126
127127 maker.generatedPath(conf_wf.generated_directory).* = out_path;
128128 },
lib/std/Build/Cache.zig+154-107
......@@ -325,30 +325,59 @@ pub const Manifest = struct {
325325 have_stat: bool,
326326 /// Determines whether `File.digest` is populated.
327327 have_digest: bool,
328 contents: packed union(u64) {
329 status: enum(u64) {
330 unrequested = std.math.maxInt(u64) - 1,
331 requested = std.math.maxInt(u64),
332 _,
333 pub fn populated(this: @This()) bool {
334 return switch (this) {
335 .unrequested, .requested => false,
336 _ => true,
337 };
338 }
339 },
340 populated: packed struct(u64) {
328 contents: struct {
329 pop_off: enum(u32) { unpopulated = std.math.maxInt(u32), _ },
330 req_len: enum(u32) { unrequested = std.math.maxInt(u32) - 1, requested = std.math.maxInt(u32), _ },
331
332 pub const requested: @This() = .{
333 .pop_off = .unpopulated,
334 .req_len = .requested,
335 };
336
337 pub const unrequested: @This() = .{
338 .pop_off = .unpopulated,
339 .req_len = .unrequested,
340 };
341
342 pub fn populated(p: Populated) @This() {
343 return .{
344 .pop_off = @fromBackingInt(p.off),
345 .req_len = @fromBackingInt(p.len),
346 };
347 }
348
349 pub const Unwrapped = union(enum) {
350 unrequested,
351 requested,
352 populated: Populated,
353 };
354
355 pub const Populated = struct {
341356 off: u32,
342357 len: u32,
343 },
358 };
359
360 pub fn unwrap(this: @This()) Unwrapped {
361 return switch (this.pop_off) {
362 .unpopulated => switch (this.req_len) {
363 .unrequested => .unrequested,
364 .requested => .requested,
365 _ => unreachable,
366 },
367 _ => .{ .populated = .{
368 .off = @backingInt(this.pop_off),
369 .len = @backingInt(this.req_len),
370 } },
371 };
372 }
344373
345374 pub fn get(this: @This(), all_contents: []const u8) ?[]const u8 {
346 return if (this.status.populated())
347 all_contents[this.status.populated.off..][0..this.status.populated.len]
348 else
349 null;
375 return switch (this.unwrap()) {
376 .unrequested, .requested => null,
377 .populated => |p| all_contents[p.off..][0..p.len],
378 };
350379 }
351 } align(@alignOf(u32)),
380 },
352381 /// `have_handle` determines whether this is populated.
353382 handle: union {
354383 file: Io.File,
......@@ -369,14 +398,13 @@ pub const Manifest = struct {
369398 return manifest.input_paths.items[@backingInt(i)];
370399 }
371400
401 pub fn offset(i: @This(), manifest: *const Manifest) File.Offset {
402 return manifest.files.keys()[@backingInt(i)];
403 }
404
372405 pub fn contents(i: @This(), manifest: *const Manifest) []const u8 {
373406 const input_path = get(i, manifest);
374 const populated = switch (input_path.contents.status) {
375 .unrequested => unreachable, // Must request contents before calling `check`.
376 .requested => unreachable, // Must call `check` first.
377 _ => input_path.contents.populated,
378 };
379 return manifest.all_input_content.items[populated.off..][0..populated.len];
407 return input_path.contents.get(manifest.all_input_content.items).?;
380408 }
381409 };
382410
......@@ -454,7 +482,7 @@ pub const Manifest = struct {
454482 comptime assert(@offsetOf(File, "path_start") - flags_off == 1);
455483 const hash_start = @backingInt(off) + flags_off;
456484 const hash_end = mem.findScalarPos(u8, contents, hash_start, 0).?;
457 return contents[hash_start..hash_end];
485 return contents[hash_start..hash_end :0];
458486 }
459487
460488 pub fn pathFallible(off: File.Offset, contents: []const u8) error{InvalidFormat}![:0]const u8 {
......@@ -464,7 +492,7 @@ pub const Manifest = struct {
464492 }
465493
466494 pub fn path(off: File.Offset, contents: []const u8) [:0]const u8 {
467 return pathFallible(contents, off) catch unreachable;
495 return pathFallible(off, contents) catch unreachable;
468496 }
469497 };
470498
......@@ -501,7 +529,7 @@ pub const Manifest = struct {
501529 return .{
502530 .size = file.size,
503531 .inode = file.inode,
504 .mtime = file.mtime,
532 .mtime = .fromNanoseconds(file.mtime),
505533 };
506534 }
507535
......@@ -664,9 +692,9 @@ pub const Manifest = struct {
664692 existing_input_file.have_handle = true;
665693 },
666694 }
667 if (options.request_contents) switch (existing_input_file.contents.status) {
668 .requested, .unrequested => existing_input_file.contents = .{ .status = .requested },
669 _ => {},
695 if (options.request_contents) switch (existing_input_file.contents.unwrap()) {
696 .requested, .unrequested => existing_input_file.contents = .requested,
697 .populated => {},
670698 };
671699 const existing_header = m.files.keys()[gop.index].get(m.contents.items);
672700 if (options.stat) |stat| {
......@@ -689,7 +717,7 @@ pub const Manifest = struct {
689717 .file => |opt_file| if (opt_file) |file| .{ .file = file } else undefined,
690718 .dir => |opt_dir| if (opt_dir) |dir| .{ .dir = dir } else undefined,
691719 },
692 .contents = .{ .status = if (options.request_contents) .requested else .unrequested },
720 .contents = if (options.request_contents) .requested else .unrequested,
693721 .have_digest = false,
694722 .have_stat = options.stat != null,
695723 });
......@@ -712,6 +740,7 @@ pub const Manifest = struct {
712740 pub const CheckResult = union(enum) {
713741 hit,
714742 incomplete_manifest,
743 invalid_manifest,
715744 path_deleted: File.Offset,
716745 directory_status_changed: File.Offset,
717746 metadata_changed: File.Offset,
......@@ -858,7 +887,7 @@ pub const Manifest = struct {
858887 // We've just had a miss with the shared lock, and upgraded to an exclusive lock. Someone
859888 // else might have modified the digest, so we need to check again before deciding to miss.
860889 // Before trying again, we must reset `man.hash.hasher` and `man.files`.
861 // This is basically just the first half of `unhit`.
890 // This is basically just the first half of `undoCheck`.
862891 man.hash.hasher = hasher_init;
863892 man.hash.hasher.update(&input_digest);
864893 man.shrinkFilesToInput();
......@@ -870,7 +899,7 @@ pub const Manifest = struct {
870899 // Cache miss, but `checkLocked` guarantees that all input files have their digests computed, even on a
871900 // cache miss, which is needed because they will be used in the manifest digest.
872901 man.dirty = true;
873 unhit(man, &input_digest);
902 undoCheck(man, &input_digest);
874903 return miss_result;
875904 }
876905
......@@ -918,7 +947,7 @@ pub const Manifest = struct {
918947 // contents on disk, and then later truncate the contents array.
919948 //
920949 // The file on disk already supposedly includes the extra null byte that we have to maintain.
921 const input_contents_len = m.contents.len;
950 const input_contents_len = m.contents.items.len;
922951 // After this resize, every return statement needs to modify m.contents length.
923952 try m.contents.resize(gpa, input_contents_len + manifest_size);
924953 errdefer m.contents.shrinkRetainingCapacity(input_contents_len);
......@@ -931,7 +960,7 @@ pub const Manifest = struct {
931960 if (n != manifest_size) return checkLockedMiss(m, input_contents_len, .incomplete_manifest);
932961 }
933962 const disk_contents = m.contents.items[0..manifest_size];
934 const input_contents = m.contents.items[manifest_size..input_contents_len];
963 const input_contents = m.contents.items[manifest_size..][0..input_contents_len];
935964
936965 // First the input files section, which must match our input files, otherwise it's invalid or incomplete.
937966 var off: usize = 0;
......@@ -955,14 +984,16 @@ pub const Manifest = struct {
955984 // Validate and check discovered files.
956985 while (off + 1 < disk_contents.len) {
957986 const file_off: File.Offset = @fromBackingInt(@intCast(off));
958 const file = try file_off.getFallible(disk_contents);
987 const file = file_off.getFallible(disk_contents) catch
988 return checkLockedMiss(m, input_contents_len, .invalid_manifest);
959989 if (file.flags.prefix >= m.cache.prefixes_len)
960990 return checkLockedMiss(m, input_contents_len, .invalid_manifest);
961 const path = try file_off.pathFallible(disk_contents);
991 const path = file_off.pathFallible(disk_contents) catch
992 return checkLockedMiss(m, input_contents_len, .invalid_manifest);
962993 if (path.len == 0) return checkLockedMiss(m, input_contents_len, .invalid_manifest);
963994
964995 try m.files.putContext(gpa, file_off, {}, .{ .contents = disk_contents });
965 const result = try checkDiscoveredPath(file_off, file_off.path(disk_contents));
996 const result = try checkDiscoveredPath(m, file_off, disk_contents);
966997 if (result != .hit) return checkLockedMiss(m, input_contents_len, result);
967998
968999 off += File.sizeOf(path.len);
......@@ -994,7 +1025,10 @@ pub const Manifest = struct {
9941025 result: CheckResult,
9951026 ) CheckError!CheckResult {
9961027 const file_offs = m.files.keys();
997 const off = if (file_offs.len - next_file_index == 0) input_contents_len else file_offs[next_file_index];
1028 const off = if (file_offs.len - next_file_index == 0)
1029 input_contents_len
1030 else
1031 @backingInt(file_offs[next_file_index]);
9981032 const copy_len = input_contents_len - off;
9991033 @memcpy(
10001034 m.contents.items[off..][0..copy_len],
......@@ -1021,7 +1055,7 @@ pub const Manifest = struct {
10211055 m: *Manifest,
10221056 file_off: File.Offset,
10231057 input_path: *InputPath,
1024 contents: []const u8,
1058 contents: []u8,
10251059 ) CheckError!void {
10261060 const cache = m.cache;
10271061 const io = cache.io;
......@@ -1031,7 +1065,10 @@ pub const Manifest = struct {
10311065
10321066 if (input_path.have_digest) return;
10331067
1034 const stat_path_ok = input_path.contents.status.populated() or input_file.flags.metadata_only;
1068 const stat_path_ok = switch (input_path.contents.unwrap()) {
1069 .populated => true,
1070 .unrequested, .requested => input_file.flags.metadata_only,
1071 };
10351072 if (!input_path.have_stat and stat_path_ok) {
10361073 // Since this is an input file, FileNotFound counts as a failure, not a cache miss.
10371074 const actual_stat = switch (input_path.getHandle(input_file)) {
......@@ -1074,7 +1111,7 @@ pub const Manifest = struct {
10741111 return;
10751112 }
10761113
1077 if (input_path.contents.get()) |file_or_dir_contents| {
1114 if (input_path.contents.get(m.all_input_content.items)) |file_or_dir_contents| {
10781115 assert(stat_path_ok);
10791116 var hasher = hasher_init;
10801117 hasher.update(file_or_dir_contents);
......@@ -1122,12 +1159,14 @@ pub const Manifest = struct {
11221159 .err = e,
11231160 } }),
11241161 };
1125 defer if (input_path.contents.status == .requested) {
1126 input_path.contents = .{ .populated = .{
1162 defer switch (input_path.contents.unwrap()) {
1163 .requested => input_path.contents = .populated(.{
11271164 .off = @intCast(dir_contents_start),
11281165 .len = @intCast(m.all_input_content.items.len - dir_contents_start),
1129 } };
1130 } else m.all_input_content.shrinkRetainingCapacity(dir_contents_start);
1166 }),
1167 .unrequested => m.all_input_content.shrinkRetainingCapacity(dir_contents_start),
1168 .populated => unreachable,
1169 };
11311170 } else {
11321171 const opened_file = if (input_path.have_handle)
11331172 input_path.handle.file
......@@ -1164,7 +1203,11 @@ pub const Manifest = struct {
11641203 } }),
11651204 };
11661205
1167 if (input_path.contents.status == .requested) @panic("TODO");
1206 switch (input_path.contents.unwrap()) {
1207 .requested => @panic("TODO"),
1208 .unrequested => {},
1209 .populated => unreachable,
1210 }
11681211 }
11691212 }
11701213
......@@ -1173,8 +1216,8 @@ pub const Manifest = struct {
11731216 m: *Manifest,
11741217 file_off: File.Offset,
11751218 input_path: *InputPath,
1176 disk_contents: []const u8,
1177 input_contents: []const u8,
1219 disk_contents: []u8,
1220 input_contents: []u8,
11781221 ) CheckError!CheckResult {
11791222 const cache = m.cache;
11801223 const io = cache.io;
......@@ -1191,7 +1234,7 @@ pub const Manifest = struct {
11911234 }
11921235
11931236 if (input_path.have_stat) {
1194 const changed = try disk_file.setStatChanged(m, input_file.stat);
1237 const changed = try disk_file.setStatChanged(m, input_file.stat());
11951238 if (!changed) return .hit;
11961239 }
11971240
......@@ -1239,7 +1282,7 @@ pub const Manifest = struct {
12391282 return .{ .metadata_changed = file_off };
12401283 }
12411284
1242 if (input_path.contents.get()) |file_or_dir_contents| {
1285 if (input_path.contents.get(m.all_input_content.items)) |file_or_dir_contents| {
12431286 var hasher = hasher_init;
12441287 hasher.update(file_or_dir_contents);
12451288 hasher.final(&disk_file.digest);
......@@ -1287,12 +1330,14 @@ pub const Manifest = struct {
12871330 .err = e,
12881331 } }),
12891332 };
1290 defer if (input_path.contents.status == .requested) {
1291 input_path.contents = .{ .populated = .{
1333 defer switch (input_path.contents.unwrap()) {
1334 .requested => input_path.contents = .populated(.{
12921335 .off = @intCast(dir_contents_start),
12931336 .len = @intCast(m.all_input_content.items.len - dir_contents_start),
1294 } };
1295 } else m.all_input_content.shrinkRetainingCapacity(dir_contents_start);
1337 }),
1338 .unrequested => m.all_input_content.shrinkRetainingCapacity(dir_contents_start),
1339 .populated => unreachable,
1340 };
12961341
12971342 if (mem.eql(u8, &disk_file.digest, &input_file.digest)) return .hit;
12981343 return .{ .contents_changed = file_off };
......@@ -1330,30 +1375,30 @@ pub const Manifest = struct {
13301375 .err = e,
13311376 } }),
13321377 };
1333 if (input_path.contents.status == .requested) @panic("TODO");
1378 switch (input_path.contents.unwrap()) {
1379 .requested => @panic("TODO"),
1380 .unrequested => {},
1381 .populated => unreachable,
1382 }
13341383
13351384 if (mem.eql(u8, &disk_file.digest, &input_file.digest)) return .hit;
13361385 return .{ .contents_changed = file_off };
13371386 }
13381387 }
13391388
1340 fn checkDiscoveredPath(
1341 m: *Manifest,
1342 file_off: File.Offset,
1343 file_path: [:0]const u8,
1344 contents: []const u8,
1345 ) CheckError!CheckResult {
1389 fn checkDiscoveredPath(m: *Manifest, file_off: File.Offset, contents: []u8) CheckError!CheckResult {
13461390 const file = file_off.get(contents);
13471391 const cache = m.cache;
13481392 const gpa = cache.gpa;
13491393 const io = cache.io;
13501394 const parent_dir = cache.prefixes()[file.flags.prefix].handle;
1395 const file_path = file_off.path(contents);
13511396
13521397 if (file.flags.metadata_only) {
13531398 const actual_stat = parent_dir.statFile(io, file_path, .{}) catch |err| switch (err) {
13541399 error.FileNotFound => return .{ .path_deleted = file_off },
13551400 error.Canceled => |e| return e,
1356 else => |e| return fail(m, .{ .file_stat = .{
1401 else => |e| return fail(&m.diagnostic, .{ .file_stat = .{
13571402 .file_offset = file_off,
13581403 .err = e,
13591404 } }),
......@@ -1376,7 +1421,7 @@ pub const Manifest = struct {
13761421 error.FileNotFound => return .{ .path_deleted = file_off },
13771422 error.NotDir => return .{ .directory_status_changed = file_off },
13781423 error.Canceled => |e| return e,
1379 else => |e| return fail(m, .{ .file_open = .{
1424 else => |e| return fail(&m.diagnostic, .{ .file_open = .{
13801425 .file_offset = file_off,
13811426 .err = e,
13821427 } }),
......@@ -1385,7 +1430,7 @@ pub const Manifest = struct {
13851430
13861431 const actual_stat = opened_dir.stat(io) catch |err| switch (err) {
13871432 error.Canceled => |e| return e,
1388 else => |e| return fail(m, .{ .file_stat = .{
1433 else => |e| return fail(&m.diagnostic, .{ .file_stat = .{
13891434 .file_offset = file_off,
13901435 .err = e,
13911436 } }),
......@@ -1394,9 +1439,9 @@ pub const Manifest = struct {
13941439 const prev_digest: BinDigest = file.digest;
13951440 const dir_contents_start = m.all_input_content.items.len;
13961441 defer m.all_input_content.shrinkRetainingCapacity(dir_contents_start);
1397 hashDir(gpa, io, opened_dir, &file.digest, &m.all_input_contents) catch |err| switch (err) {
1442 hashDir(gpa, io, opened_dir, &file.digest, &m.all_input_content) catch |err| switch (err) {
13981443 error.Canceled, error.OutOfMemory => |e| return e,
1399 else => |e| return fail(m, .{ .file_read = .{
1444 else => |e| return fail(&m.diagnostic, .{ .file_read = .{
14001445 .file_offset = file_off,
14011446 .err = e,
14021447 } }),
......@@ -1411,7 +1456,7 @@ pub const Manifest = struct {
14111456 error.FileNotFound => return .{ .path_deleted = file_off },
14121457 error.IsDir => return .{ .directory_status_changed = file_off },
14131458 error.Canceled => |e| return e,
1414 else => |e| return fail(m, .{ .file_open = .{
1459 else => |e| return fail(&m.diagnostic, .{ .file_open = .{
14151460 .file_offset = file_off,
14161461 .err = e,
14171462 } }),
......@@ -1420,7 +1465,7 @@ pub const Manifest = struct {
14201465
14211466 const actual_stat = opened_file.stat(io) catch |err| switch (err) {
14221467 error.Canceled => |e| return e,
1423 else => |e| return fail(m, .{ .file_stat = .{
1468 else => |e| return fail(&m.diagnostic, .{ .file_stat = .{
14241469 .file_offset = file_off,
14251470 .err = e,
14261471 } }),
......@@ -1430,7 +1475,7 @@ pub const Manifest = struct {
14301475 const prev_digest: BinDigest = file.digest;
14311476 hashFile(io, opened_file, &file.digest) catch |err| switch (err) {
14321477 error.Canceled => |e| return e,
1433 else => |e| return fail(m, .{ .file_read = .{
1478 else => |e| return fail(&m.diagnostic, .{ .file_read = .{
14341479 .file_offset = file_off,
14351480 .err = e,
14361481 } }),
......@@ -1453,7 +1498,7 @@ pub const Manifest = struct {
14531498 /// not including discovered files).
14541499 ///
14551500 /// Assumes that `digest` is populated for all input files.
1456 pub fn unhit(man: *Manifest, input_digest: *const BinDigest) void {
1501 pub fn undoCheck(man: *Manifest, input_digest: *const BinDigest) void {
14571502 // Reset the hash.
14581503 man.hash.hasher = hasher_init;
14591504 man.hash.hasher.update(input_digest);
......@@ -2117,8 +2162,7 @@ test "cache file and then recall it" {
21172162 ch.hash.addBytes("1234");
21182163 _ = try ch.addInputPath(.initCwd(temp_file), .{});
21192164
2120 // There should be nothing in the cache
2121 try testing.expectEqual(.miss, try ch.check(.none));
2165 try testing.expectEqual(.incomplete_manifest, try ch.check(.none));
21222166
21232167 digest1 = ch.final();
21242168 try ch.finalize();
......@@ -2185,8 +2229,7 @@ test "check that changing a file makes cache fail" {
21852229 man.hash.addBytes("1234");
21862230 const temp_file_idx = try man.addInputPath(.initCwd(temp_file), .{ .request_contents = true });
21872231
2188 // There should be nothing in the cache
2189 try testing.expectEqual(.miss, try man.check(.none));
2232 try testing.expectEqual(.incomplete_manifest, try man.check(.none));
21902233
21912234 try testing.expectEqualStrings(original_temp_file_contents, temp_file_idx.contents(&man));
21922235
......@@ -2204,11 +2247,13 @@ test "check that changing a file makes cache fail" {
22042247 man.hash.addBytes("1234");
22052248 const temp_file_idx = try man.addInputPath(.initCwd(temp_file), .{ .request_contents = true });
22062249
2207 // A file that we depend on has been updated, so the cache should not contain an entry for it
2208 try testing.expectEqual(.miss, try man.check(.none));
2250 // The one input file changed.
2251 try testing.expectEqual(
2252 @as(Manifest.CheckResult, .{ .contents_changed = temp_file_idx.offset(&man) }),
2253 try man.check(.none),
2254 );
22092255
2210 // The cache system does not keep the contents of re-hashed input files.
2211 try testing.expectEqual(false, temp_file_idx.get(&man).contents.status.populated());
2256 try testing.expectEqualStrings(updated_temp_file_contents, temp_file_idx.contents(&man));
22122257
22132258 digest2 = man.final();
22142259
......@@ -2248,8 +2293,7 @@ test "no file inputs" {
22482293
22492294 man.hash.addBytes("1234");
22502295
2251 // There should be nothing in the cache
2252 try testing.expectEqual(.miss, try man.check(.none));
2296 try testing.expectEqual(.incomplete_manifest, try man.check(.none));
22532297
22542298 digest1 = man.final();
22552299
......@@ -2306,31 +2350,30 @@ test "Manifest with files added after initial hash work" {
23062350 defer cache.manifest_dir.close(io);
23072351
23082352 {
2309 var ch = cache.obtain();
2310 defer ch.deinit();
2353 var man = cache.obtain();
2354 defer man.deinit();
23112355
2312 ch.hash.addBytes("1234");
2313 _ = try ch.addInputPath(.initCwd(temp_file1), .{});
2356 man.hash.addBytes("1234");
2357 _ = try man.addInputPath(.initCwd(temp_file1), .{});
23142358
2315 // There should be nothing in the cache
2316 try testing.expectEqual(.miss, try ch.check(.none));
2359 try testing.expectEqual(.incomplete_manifest, try man.check(.none));
23172360
2318 _ = try ch.addDiscoveredPath(.{ .discovered_path = .{ .unresolved = .initCwd(temp_file2) } });
2361 try man.addDiscoveredPath(.{ .discovered_path = .{ .unresolved = .initCwd(temp_file2) } });
23192362
2320 digest1 = ch.final();
2321 try ch.finalize();
2363 digest1 = man.final();
2364 try man.finalize();
23222365 }
23232366 {
2324 var ch = cache.obtain();
2325 defer ch.deinit();
2367 var man = cache.obtain();
2368 defer man.deinit();
23262369
2327 ch.hash.addBytes("1234");
2328 _ = try ch.addInputPath(.initCwd(temp_file1), .{});
2370 man.hash.addBytes("1234");
2371 _ = try man.addInputPath(.initCwd(temp_file1), .{});
23292372
2330 try testing.expect(.hit == try ch.check(.none));
2331 digest2 = ch.final();
2373 try testing.expect(.hit == try man.check(.none));
2374 digest2 = man.final();
23322375
2333 try testing.expectEqual(false, ch.have_exclusive_lock);
2376 try testing.expectEqual(false, man.have_exclusive_lock);
23342377 }
23352378 try testing.expect(mem.eql(u8, &digest1, &digest2));
23362379
......@@ -2344,20 +2387,24 @@ test "Manifest with files added after initial hash work" {
23442387 }
23452388
23462389 {
2347 var ch = cache.obtain();
2348 defer ch.deinit();
2390 var man = cache.obtain();
2391 defer man.deinit();
23492392
2350 ch.hash.addBytes("1234");
2351 _ = try ch.addInputPath(.initCwd(temp_file1), .{});
2393 man.hash.addBytes("1234");
2394 _ = try man.addInputPath(.initCwd(temp_file1), .{});
23522395
2353 // A file that we depend on has been updated, so the cache should not contain an entry for it
2354 try testing.expectEqual(.miss, try ch.check(.none));
2396 switch (try man.check(.none)) {
2397 .contents_changed => |off| {
2398 try testing.expectEqualStrings(temp_file2, off.path(man.contents.items));
2399 },
2400 else => return error.TestFailed,
2401 }
23552402
2356 _ = try ch.addDiscoveredPath(.{ .discovered_path = .{ .unresolved = .initCwd(temp_file2) } });
2403 try man.addDiscoveredPath(.{ .discovered_path = .{ .unresolved = .initCwd(temp_file2) } });
23572404
2358 digest3 = ch.final();
2405 digest3 = man.final();
23592406
2360 try ch.finalize();
2407 try man.finalize();
23612408 }
23622409
23632410 try testing.expect(!mem.eql(u8, &digest1, &digest3));
src/Compilation.zig+8-12
......@@ -2856,7 +2856,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
28562856 log.debug("CacheMode.whole cache miss for {s}", .{comp.root_name});
28572857
28582858 if (ignore_hit) {
2859 // Okay, now set this back so that `writeManifest` will downgrade our lock later.
2859 // Okay, now set this back so that `Manifest.finalize` will downgrade our lock later.
28602860 man.want_shared_lock = true;
28612861 }
28622862
......@@ -3144,7 +3144,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
31443144 }
31453145
31463146 // Failure here only means an unnecessary cache miss.
3147 man.writeManifest() catch |err| log.warn("failed to write cache manifest: {t}", .{err});
3147 man.finalize() catch |err| log.warn("failed to write cache manifest: {t}", .{err});
31483148
31493149 assert(whole.lock == null);
31503150 whole.lock = man.toOwnedLock();
......@@ -5810,11 +5810,8 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
58105810 // possible we had a hit and the manifest is dirty, for example if the file mtime changed but
58115811 // the contents were the same, we hit the cache but the manifest is dirty and we need to update
58125812 // it to prevent doing a full file content comparison the next time around.
5813 man.writeManifest() catch |err| {
5814 log.warn("failed to write cache manifest when compiling '{s}': {s}", .{
5815 c_object.src.src_path, @errorName(err),
5816 });
5817 };
5813 man.finalize() catch |err|
5814 log.warn("failed to write cache manifest when compiling {q}: {t}", .{ c_object.src.src_path, err });
58185815 }
58195816
58205817 const o_basename = try std.fmt.allocPrint(arena, "{s}{s}", .{ o_basename_noext, o_ext });
......@@ -5950,9 +5947,8 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
59505947 };
59515948
59525949 if (man.have_exclusive_lock) {
5953 man.writeManifest() catch |err| {
5954 log.warn("failed to write cache manifest when compiling '{s}': {s}", .{ src_path, @errorName(err) });
5955 };
5950 man.finalize() catch |err|
5951 log.warn("failed to write cache manifest when compiling {q}: {t}", .{ src_path, err });
59565952 }
59575953
59585954 win32_resource.status = .{
......@@ -6060,8 +6056,8 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
60606056 // possible we had a hit and the manifest is dirty, for example if the file mtime changed but
60616057 // the contents were the same, we hit the cache but the manifest is dirty and we need to update
60626058 // it to prevent doing a full file content comparison the next time around.
6063 man.writeManifest() catch |err| {
6064 log.warn("failed to write cache manifest when compiling '{s}': {s}", .{ rc_src.src_path, @errorName(err) });
6059 man.finalize() catch |err| {
6060 log.warn("failed to write cache manifest when compiling {q}: {t}", .{ rc_src.src_path, err });
60656061 };
60666062 }
60676063
src/libs/freebsd.zig+1-3
......@@ -982,9 +982,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
982982 try buildSharedLib(comp, arena, o_directory, asm_file_basename, lib, prog_node);
983983 }
984984
985 man.writeManifest() catch |err| {
986 log.warn("failed to write cache manifest for FreeBSD libc stubs: {s}", .{@errorName(err)});
987 };
985 man.finalize() catch |err| log.warn("failed to write cache manifest for FreeBSD libc stubs: {t}", .{err});
988986
989987 return queueSharedObjects(comp, .{
990988 .lock = man.toOwnedLock(),
src/libs/glibc.zig+1-3
......@@ -1131,9 +1131,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
11311131 try buildSharedLib(comp, arena, o_directory, asm_file_basename, lib, prog_node);
11321132 }
11331133
1134 man.writeManifest() catch |err| {
1135 log.warn("failed to write cache manifest for glibc stubs: {s}", .{@errorName(err)});
1136 };
1134 man.finalize() catch |err| log.warn("failed to write cache manifest for glibc stubs: {t}", .{err});
11371135
11381136 return queueSharedObjects(comp, .{
11391137 .lock = man.toOwnedLock(),
src/libs/mingw.zig+2-3
......@@ -363,9 +363,8 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8, prog_node: std.P
363363 try file_writer.interface.flush();
364364 }
365365
366 man.writeManifest() catch |err| {
367 log.warn("failed to write cache manifest for DLL import {s}.lib: {s}", .{ lib_name, @errorName(err) });
368 };
366 man.finalize() catch |err|
367 log.warn("failed to write cache manifest for DLL import {s}.lib: {t}", .{ lib_name, err });
369368
370369 comp.mutex.lockUncancelable(io);
371370 defer comp.mutex.unlock(io);
src/libs/netbsd.zig+1-3
......@@ -643,9 +643,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
643643 try buildSharedLib(comp, arena, o_directory, asm_file_basename, lib, prog_node);
644644 }
645645
646 man.writeManifest() catch |err| {
647 log.warn("failed to write cache manifest for NetBSD libc stubs: {s}", .{@errorName(err)});
648 };
646 man.finalize() catch |err| log.warn("failed to write cache manifest for NetBSD libc stubs: {t}", .{err});
649647
650648 return queueSharedObjects(comp, .{
651649 .lock = man.toOwnedLock(),
src/libs/openbsd.zig+1-3
......@@ -564,9 +564,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
564564 try buildSharedLib(comp, arena, o_directory, asm_file_basename, lib, prog_node);
565565 }
566566
567 man.writeManifest() catch |err| {
568 log.warn("failed to write cache manifest for OpenBSD libc stubs: {s}", .{@errorName(err)});
569 };
567 man.finalize() catch |err| log.warn("failed to write cache manifest for OpenBSD libc stubs: {t}", .{err});
570568
571569 return queueSharedObjects(comp, .{
572570 .lock = man.toOwnedLock(),
src/main.zig+1-1
......@@ -4906,7 +4906,7 @@ fn cmdTranslateC(
49064906 }
49074907 }
49084908
4909 man.writeManifest() catch |err| warn("failed to write cache manifest: {t}", .{err});
4909 man.finalize() catch |err| warn("failed to write cache manifest: {t}", .{err});
49104910 break :result result;
49114911 };
49124912