From b91a6dc5b1c99ec8308fd14224d9cd8c44785021 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 11 Sep 2026 19:08:30 -0700 Subject: [PATCH] update to newest std.Build.Cache API --- lib/compiler/Maker.zig | 4 +- lib/compiler/Maker/Step.zig | 15 +- lib/compiler/Maker/Step/ConfigHeader.zig | 2 +- lib/compiler/Maker/Step/ObjCopy.zig | 2 +- lib/compiler/Maker/Step/Options.zig | 2 +- lib/compiler/Maker/Step/Run.zig | 4 +- lib/compiler/Maker/Step/WriteFile.zig | 2 +- lib/std/Build/Cache.zig | 261 +++++++++++++---------- src/Compilation.zig | 20 +- src/libs/freebsd.zig | 4 +- src/libs/glibc.zig | 4 +- src/libs/mingw.zig | 5 +- src/libs/netbsd.zig | 4 +- src/libs/openbsd.zig | 4 +- src/main.zig | 2 +- 15 files changed, 184 insertions(+), 151 deletions(-) diff --git a/lib/compiler/Maker.zig b/lib/compiler/Maker.zig index 9e7d1b01e47b034279d83577eeeabb3cf24ebfc7..118bcffb8dcfcc6dab6f37dcbf6678b716344594 100644 --- a/lib/compiler/Maker.zig +++ b/lib/compiler/Maker.zig @@ -1543,7 +1543,7 @@ fn configure(graph: *Graph, options: ConfigureOptions) !ScannedConfig { config_tmp_path, final_path, e, }); }; - man.writeManifest() catch |err| log.warn("failed to write cache manifest: {t}", .{err}); + man.finalize() catch |err| log.warn("failed to write cache manifest: {t}", .{err}); options.src_files.* = man.takeFiles(); break :cp .{ final_path, man.toOwnedLock() }; } @@ -1934,7 +1934,7 @@ fn cacheCatOne(input_hex_digest: []const u8, contents: []const u8, writer: *Io.W while (off + 1 < contents.len) { const file_off: Cache.Manifest.File.Offset = @fromBackingInt(@intCast(off)); const file = try file_off.getFallibleConst(contents); - const path = try Cache.Manifest.filePathFallible(contents, file_off); + const path = try file_off.pathFallible(contents); if (path.len == 0) return error.InvalidFormat; var file_obj = try files_tuple.beginStructField(.{ .whitespace_style = .{ .wrap = false } }); diff --git a/lib/compiler/Maker/Step.zig b/lib/compiler/Maker/Step.zig index 25ea943f39d61909415e80741832b547b7f60334..c3ff8962b0d5cd940a766c7b4e6aef9ed7faeb9c 100644 --- a/lib/compiler/Maker/Step.zig +++ b/lib/compiler/Maker/Step.zig @@ -734,7 +734,7 @@ pub fn cacheHit(s: *Step, maker: *Maker, man: *Cache.Manifest, parent_progress_n /// Clears previous watch inputs, if any, and then populates watch inputs from /// the full set of files picked up by the cache manifest. /// -/// Must be accompanied with `writeManifestAndWatch`. +/// Must be accompanied with `finalizeManifestAndWatch`. pub fn cacheHitWatched(s: *Step, maker: *Maker, man: *Cache.Manifest, parent_progress_node: std.Progress.Node) !bool { const hit = .hit == (man.check(parent_progress_node) catch |err| return failWithCacheError(s, maker, man, err)); s.result_cached = hit; @@ -748,7 +748,7 @@ fn failWithCacheError( s: *Step, maker: *Maker, man: *const Cache.Manifest, - err: Cache.Manifest.Check.Error, + err: Cache.Manifest.CheckError, ) error{ OutOfMemory, Canceled, MakeFailed } { switch (err) { error.CacheCheckFailed => switch (man.diagnostic) { @@ -762,15 +762,14 @@ fn failWithCacheError( }, }, error.OutOfMemory, error.Canceled => |e| return e, - error.InvalidFormat => return s.fail(maker, "failed checking cache: invalid manifest file format", .{}), } } -/// Prefer `writeManifestAndWatch` unless you already added watch inputs +/// Prefer `finalizeManifestAndWatch` unless you already added watch inputs /// separately from using the cache system. -pub fn writeManifest(s: *Step, maker: *Maker, man: *Cache.Manifest) !void { +pub fn finalizeManifest(s: *Step, maker: *Maker, man: *Cache.Manifest) !void { if (s.test_results.isSuccess()) { - man.writeManifest() catch |err| switch (err) { + man.finalize() catch |err| switch (err) { error.Canceled => |e| return e, else => |e| try s.addError(maker, "failed writing cache manifest: {t}", .{e}), }; @@ -781,8 +780,8 @@ pub fn writeManifest(s: *Step, maker: *Maker, man: *Cache.Manifest) !void { /// the full set of files picked up by the cache manifest. /// /// Must be accompanied with `cacheHitWatched`. -pub fn writeManifestAndWatch(s: *Step, maker: *Maker, man: *Cache.Manifest) !void { - try writeManifest(s, maker, man); +pub fn finalizeManifestAndWatch(s: *Step, maker: *Maker, man: *Cache.Manifest) !void { + try finalizeManifest(s, maker, man); try setWatchInputsFromManifest(s, maker, man); } diff --git a/lib/compiler/Maker/Step/ConfigHeader.zig b/lib/compiler/Maker/Step/ConfigHeader.zig index 20152955fe469b751648032e54152a7aa2b53f67..4ea9444d25b0dc6995ecfc43a3901105ce087be9 100644 --- a/lib/compiler/Maker/Step/ConfigHeader.zig +++ b/lib/compiler/Maker/Step/ConfigHeader.zig @@ -169,7 +169,7 @@ pub fn make( .sub_path = try Io.Dir.path.join(arena, &.{ "o", &digest }), }; - try step.writeManifest(maker, &man); + try step.finalizeManifest(maker, &man); } fn ensureAllValuesUsed( diff --git a/lib/compiler/Maker/Step/ObjCopy.zig b/lib/compiler/Maker/Step/ObjCopy.zig index 7924b21c683866a3536bf72e2bf9b04f3850f3c5..db045d5f51e46e080e080d4fa434cff40e6ce1cd 100644 --- a/lib/compiler/Maker/Step/ObjCopy.zig +++ b/lib/compiler/Maker/Step/ObjCopy.zig @@ -165,7 +165,7 @@ pub fn make( maker.generatedPath(conf_oc.output_file).* = dest_path; - step.writeManifest(maker, &man) catch |err| switch (err) { + step.finalizeManifest(maker, &man) catch |err| switch (err) { error.Canceled => |e| return e, else => |e| try step.addError(maker, "failed writing cache manifest: {t}", .{e}), }; diff --git a/lib/compiler/Maker/Step/Options.zig b/lib/compiler/Maker/Step/Options.zig index e0812402e1b976b98cc9e15f42d77afd04c4f326..ef932c7dae0bbf38284d38eebd53f1f1997b7b2f 100644 --- a/lib/compiler/Maker/Step/Options.zig +++ b/lib/compiler/Maker/Step/Options.zig @@ -95,7 +95,7 @@ pub fn make( }, }; - try step.writeManifestAndWatch(maker, &man); + try step.finalizeManifestAndWatch(maker, &man); maker.generatedPath(conf_options.generated_file).* = out_path; } diff --git a/lib/compiler/Maker/Step/Run.zig b/lib/compiler/Maker/Step/Run.zig index 04b5764d04a191ace28403be0737635f047019fb..f8b58d215997479660975b7b15de0c92c4e625ac 100644 --- a/lib/compiler/Maker/Step/Run.zig +++ b/lib/compiler/Maker/Step/Run.zig @@ -275,7 +275,7 @@ pub fn make( try populateGeneratedStdIo(maker, &conf_run, cache_root, &digest); try populateGeneratedPathsCreateDirs(arena, run_index, maker, output_dir_path, output_placeholders.items, argv_list.items); try runCommand(arena, run, run_index, maker, progress_node, argv_list.items, has_side_effects, output_dir_path, null); - if (!has_side_effects) try step.writeManifestAndWatch(maker, &man); + if (!has_side_effects) try step.finalizeManifestAndWatch(maker, &man); return; } @@ -344,7 +344,7 @@ pub fn make( }; } - if (!has_side_effects) try step.writeManifestAndWatch(maker, &man); + if (!has_side_effects) try step.finalizeManifestAndWatch(maker, &man); try populateGeneratedStdIo(maker, &conf_run, cache_root, &digest); try populateGeneratedPaths(maker, output_placeholders.items, cache_root, &digest); diff --git a/lib/compiler/Maker/Step/WriteFile.zig b/lib/compiler/Maker/Step/WriteFile.zig index afea7de96ea7d9598cd2d4f2e55febc40cbad0d1..5f7bad0e44e7ce45fc04d30dd943a478db731690 100644 --- a/lib/compiler/Maker/Step/WriteFile.zig +++ b/lib/compiler/Maker/Step/WriteFile.zig @@ -122,7 +122,7 @@ pub fn make( progress_node.setEstimatedTotalItems(total_items); try operate(maker, step_index, open_dir_cache, out_path, progress_node); - try step.writeManifest(maker, &man); + try step.finalizeManifest(maker, &man); maker.generatedPath(conf_wf.generated_directory).* = out_path; }, diff --git a/lib/std/Build/Cache.zig b/lib/std/Build/Cache.zig index 64c740790b85ab9a0daa9d8d36a290b68130e433..e44efe4c59a0b329c8e908576f02238694579e30 100644 --- a/lib/std/Build/Cache.zig +++ b/lib/std/Build/Cache.zig @@ -325,30 +325,59 @@ pub const Manifest = struct { have_stat: bool, /// Determines whether `File.digest` is populated. have_digest: bool, - contents: packed union(u64) { - status: enum(u64) { - unrequested = std.math.maxInt(u64) - 1, - requested = std.math.maxInt(u64), - _, - pub fn populated(this: @This()) bool { - return switch (this) { - .unrequested, .requested => false, - _ => true, - }; - } - }, - populated: packed struct(u64) { + contents: struct { + pop_off: enum(u32) { unpopulated = std.math.maxInt(u32), _ }, + req_len: enum(u32) { unrequested = std.math.maxInt(u32) - 1, requested = std.math.maxInt(u32), _ }, + + pub const requested: @This() = .{ + .pop_off = .unpopulated, + .req_len = .requested, + }; + + pub const unrequested: @This() = .{ + .pop_off = .unpopulated, + .req_len = .unrequested, + }; + + pub fn populated(p: Populated) @This() { + return .{ + .pop_off = @fromBackingInt(p.off), + .req_len = @fromBackingInt(p.len), + }; + } + + pub const Unwrapped = union(enum) { + unrequested, + requested, + populated: Populated, + }; + + pub const Populated = struct { off: u32, len: u32, - }, + }; + + pub fn unwrap(this: @This()) Unwrapped { + return switch (this.pop_off) { + .unpopulated => switch (this.req_len) { + .unrequested => .unrequested, + .requested => .requested, + _ => unreachable, + }, + _ => .{ .populated = .{ + .off = @backingInt(this.pop_off), + .len = @backingInt(this.req_len), + } }, + }; + } pub fn get(this: @This(), all_contents: []const u8) ?[]const u8 { - return if (this.status.populated()) - all_contents[this.status.populated.off..][0..this.status.populated.len] - else - null; + return switch (this.unwrap()) { + .unrequested, .requested => null, + .populated => |p| all_contents[p.off..][0..p.len], + }; } - } align(@alignOf(u32)), + }, /// `have_handle` determines whether this is populated. handle: union { file: Io.File, @@ -369,14 +398,13 @@ pub const Manifest = struct { return manifest.input_paths.items[@backingInt(i)]; } + pub fn offset(i: @This(), manifest: *const Manifest) File.Offset { + return manifest.files.keys()[@backingInt(i)]; + } + pub fn contents(i: @This(), manifest: *const Manifest) []const u8 { const input_path = get(i, manifest); - const populated = switch (input_path.contents.status) { - .unrequested => unreachable, // Must request contents before calling `check`. - .requested => unreachable, // Must call `check` first. - _ => input_path.contents.populated, - }; - return manifest.all_input_content.items[populated.off..][0..populated.len]; + return input_path.contents.get(manifest.all_input_content.items).?; } }; @@ -454,7 +482,7 @@ pub const Manifest = struct { comptime assert(@offsetOf(File, "path_start") - flags_off == 1); const hash_start = @backingInt(off) + flags_off; const hash_end = mem.findScalarPos(u8, contents, hash_start, 0).?; - return contents[hash_start..hash_end]; + return contents[hash_start..hash_end :0]; } pub fn pathFallible(off: File.Offset, contents: []const u8) error{InvalidFormat}![:0]const u8 { @@ -464,7 +492,7 @@ pub const Manifest = struct { } pub fn path(off: File.Offset, contents: []const u8) [:0]const u8 { - return pathFallible(contents, off) catch unreachable; + return pathFallible(off, contents) catch unreachable; } }; @@ -501,7 +529,7 @@ pub const Manifest = struct { return .{ .size = file.size, .inode = file.inode, - .mtime = file.mtime, + .mtime = .fromNanoseconds(file.mtime), }; } @@ -664,9 +692,9 @@ pub const Manifest = struct { existing_input_file.have_handle = true; }, } - if (options.request_contents) switch (existing_input_file.contents.status) { - .requested, .unrequested => existing_input_file.contents = .{ .status = .requested }, - _ => {}, + if (options.request_contents) switch (existing_input_file.contents.unwrap()) { + .requested, .unrequested => existing_input_file.contents = .requested, + .populated => {}, }; const existing_header = m.files.keys()[gop.index].get(m.contents.items); if (options.stat) |stat| { @@ -689,7 +717,7 @@ pub const Manifest = struct { .file => |opt_file| if (opt_file) |file| .{ .file = file } else undefined, .dir => |opt_dir| if (opt_dir) |dir| .{ .dir = dir } else undefined, }, - .contents = .{ .status = if (options.request_contents) .requested else .unrequested }, + .contents = if (options.request_contents) .requested else .unrequested, .have_digest = false, .have_stat = options.stat != null, }); @@ -712,6 +740,7 @@ pub const Manifest = struct { pub const CheckResult = union(enum) { hit, incomplete_manifest, + invalid_manifest, path_deleted: File.Offset, directory_status_changed: File.Offset, metadata_changed: File.Offset, @@ -858,7 +887,7 @@ pub const Manifest = struct { // We've just had a miss with the shared lock, and upgraded to an exclusive lock. Someone // else might have modified the digest, so we need to check again before deciding to miss. // Before trying again, we must reset `man.hash.hasher` and `man.files`. - // This is basically just the first half of `unhit`. + // This is basically just the first half of `undoCheck`. man.hash.hasher = hasher_init; man.hash.hasher.update(&input_digest); man.shrinkFilesToInput(); @@ -870,7 +899,7 @@ pub const Manifest = struct { // Cache miss, but `checkLocked` guarantees that all input files have their digests computed, even on a // cache miss, which is needed because they will be used in the manifest digest. man.dirty = true; - unhit(man, &input_digest); + undoCheck(man, &input_digest); return miss_result; } @@ -918,7 +947,7 @@ pub const Manifest = struct { // contents on disk, and then later truncate the contents array. // // The file on disk already supposedly includes the extra null byte that we have to maintain. - const input_contents_len = m.contents.len; + const input_contents_len = m.contents.items.len; // After this resize, every return statement needs to modify m.contents length. try m.contents.resize(gpa, input_contents_len + manifest_size); errdefer m.contents.shrinkRetainingCapacity(input_contents_len); @@ -931,7 +960,7 @@ pub const Manifest = struct { if (n != manifest_size) return checkLockedMiss(m, input_contents_len, .incomplete_manifest); } const disk_contents = m.contents.items[0..manifest_size]; - const input_contents = m.contents.items[manifest_size..input_contents_len]; + const input_contents = m.contents.items[manifest_size..][0..input_contents_len]; // First the input files section, which must match our input files, otherwise it's invalid or incomplete. var off: usize = 0; @@ -955,14 +984,16 @@ pub const Manifest = struct { // Validate and check discovered files. while (off + 1 < disk_contents.len) { const file_off: File.Offset = @fromBackingInt(@intCast(off)); - const file = try file_off.getFallible(disk_contents); + const file = file_off.getFallible(disk_contents) catch + return checkLockedMiss(m, input_contents_len, .invalid_manifest); if (file.flags.prefix >= m.cache.prefixes_len) return checkLockedMiss(m, input_contents_len, .invalid_manifest); - const path = try file_off.pathFallible(disk_contents); + const path = file_off.pathFallible(disk_contents) catch + return checkLockedMiss(m, input_contents_len, .invalid_manifest); if (path.len == 0) return checkLockedMiss(m, input_contents_len, .invalid_manifest); try m.files.putContext(gpa, file_off, {}, .{ .contents = disk_contents }); - const result = try checkDiscoveredPath(file_off, file_off.path(disk_contents)); + const result = try checkDiscoveredPath(m, file_off, disk_contents); if (result != .hit) return checkLockedMiss(m, input_contents_len, result); off += File.sizeOf(path.len); @@ -994,7 +1025,10 @@ pub const Manifest = struct { result: CheckResult, ) CheckError!CheckResult { const file_offs = m.files.keys(); - const off = if (file_offs.len - next_file_index == 0) input_contents_len else file_offs[next_file_index]; + const off = if (file_offs.len - next_file_index == 0) + input_contents_len + else + @backingInt(file_offs[next_file_index]); const copy_len = input_contents_len - off; @memcpy( m.contents.items[off..][0..copy_len], @@ -1021,7 +1055,7 @@ pub const Manifest = struct { m: *Manifest, file_off: File.Offset, input_path: *InputPath, - contents: []const u8, + contents: []u8, ) CheckError!void { const cache = m.cache; const io = cache.io; @@ -1031,7 +1065,10 @@ pub const Manifest = struct { if (input_path.have_digest) return; - const stat_path_ok = input_path.contents.status.populated() or input_file.flags.metadata_only; + const stat_path_ok = switch (input_path.contents.unwrap()) { + .populated => true, + .unrequested, .requested => input_file.flags.metadata_only, + }; if (!input_path.have_stat and stat_path_ok) { // Since this is an input file, FileNotFound counts as a failure, not a cache miss. const actual_stat = switch (input_path.getHandle(input_file)) { @@ -1074,7 +1111,7 @@ pub const Manifest = struct { return; } - if (input_path.contents.get()) |file_or_dir_contents| { + if (input_path.contents.get(m.all_input_content.items)) |file_or_dir_contents| { assert(stat_path_ok); var hasher = hasher_init; hasher.update(file_or_dir_contents); @@ -1122,12 +1159,14 @@ pub const Manifest = struct { .err = e, } }), }; - defer if (input_path.contents.status == .requested) { - input_path.contents = .{ .populated = .{ + defer switch (input_path.contents.unwrap()) { + .requested => input_path.contents = .populated(.{ .off = @intCast(dir_contents_start), .len = @intCast(m.all_input_content.items.len - dir_contents_start), - } }; - } else m.all_input_content.shrinkRetainingCapacity(dir_contents_start); + }), + .unrequested => m.all_input_content.shrinkRetainingCapacity(dir_contents_start), + .populated => unreachable, + }; } else { const opened_file = if (input_path.have_handle) input_path.handle.file @@ -1164,7 +1203,11 @@ pub const Manifest = struct { } }), }; - if (input_path.contents.status == .requested) @panic("TODO"); + switch (input_path.contents.unwrap()) { + .requested => @panic("TODO"), + .unrequested => {}, + .populated => unreachable, + } } } @@ -1173,8 +1216,8 @@ pub const Manifest = struct { m: *Manifest, file_off: File.Offset, input_path: *InputPath, - disk_contents: []const u8, - input_contents: []const u8, + disk_contents: []u8, + input_contents: []u8, ) CheckError!CheckResult { const cache = m.cache; const io = cache.io; @@ -1191,7 +1234,7 @@ pub const Manifest = struct { } if (input_path.have_stat) { - const changed = try disk_file.setStatChanged(m, input_file.stat); + const changed = try disk_file.setStatChanged(m, input_file.stat()); if (!changed) return .hit; } @@ -1239,7 +1282,7 @@ pub const Manifest = struct { return .{ .metadata_changed = file_off }; } - if (input_path.contents.get()) |file_or_dir_contents| { + if (input_path.contents.get(m.all_input_content.items)) |file_or_dir_contents| { var hasher = hasher_init; hasher.update(file_or_dir_contents); hasher.final(&disk_file.digest); @@ -1287,12 +1330,14 @@ pub const Manifest = struct { .err = e, } }), }; - defer if (input_path.contents.status == .requested) { - input_path.contents = .{ .populated = .{ + defer switch (input_path.contents.unwrap()) { + .requested => input_path.contents = .populated(.{ .off = @intCast(dir_contents_start), .len = @intCast(m.all_input_content.items.len - dir_contents_start), - } }; - } else m.all_input_content.shrinkRetainingCapacity(dir_contents_start); + }), + .unrequested => m.all_input_content.shrinkRetainingCapacity(dir_contents_start), + .populated => unreachable, + }; if (mem.eql(u8, &disk_file.digest, &input_file.digest)) return .hit; return .{ .contents_changed = file_off }; @@ -1330,30 +1375,30 @@ pub const Manifest = struct { .err = e, } }), }; - if (input_path.contents.status == .requested) @panic("TODO"); + switch (input_path.contents.unwrap()) { + .requested => @panic("TODO"), + .unrequested => {}, + .populated => unreachable, + } if (mem.eql(u8, &disk_file.digest, &input_file.digest)) return .hit; return .{ .contents_changed = file_off }; } } - fn checkDiscoveredPath( - m: *Manifest, - file_off: File.Offset, - file_path: [:0]const u8, - contents: []const u8, - ) CheckError!CheckResult { + fn checkDiscoveredPath(m: *Manifest, file_off: File.Offset, contents: []u8) CheckError!CheckResult { const file = file_off.get(contents); const cache = m.cache; const gpa = cache.gpa; const io = cache.io; const parent_dir = cache.prefixes()[file.flags.prefix].handle; + const file_path = file_off.path(contents); if (file.flags.metadata_only) { const actual_stat = parent_dir.statFile(io, file_path, .{}) catch |err| switch (err) { error.FileNotFound => return .{ .path_deleted = file_off }, error.Canceled => |e| return e, - else => |e| return fail(m, .{ .file_stat = .{ + else => |e| return fail(&m.diagnostic, .{ .file_stat = .{ .file_offset = file_off, .err = e, } }), @@ -1376,7 +1421,7 @@ pub const Manifest = struct { error.FileNotFound => return .{ .path_deleted = file_off }, error.NotDir => return .{ .directory_status_changed = file_off }, error.Canceled => |e| return e, - else => |e| return fail(m, .{ .file_open = .{ + else => |e| return fail(&m.diagnostic, .{ .file_open = .{ .file_offset = file_off, .err = e, } }), @@ -1385,7 +1430,7 @@ pub const Manifest = struct { const actual_stat = opened_dir.stat(io) catch |err| switch (err) { error.Canceled => |e| return e, - else => |e| return fail(m, .{ .file_stat = .{ + else => |e| return fail(&m.diagnostic, .{ .file_stat = .{ .file_offset = file_off, .err = e, } }), @@ -1394,9 +1439,9 @@ pub const Manifest = struct { const prev_digest: BinDigest = file.digest; const dir_contents_start = m.all_input_content.items.len; defer m.all_input_content.shrinkRetainingCapacity(dir_contents_start); - hashDir(gpa, io, opened_dir, &file.digest, &m.all_input_contents) catch |err| switch (err) { + hashDir(gpa, io, opened_dir, &file.digest, &m.all_input_content) catch |err| switch (err) { error.Canceled, error.OutOfMemory => |e| return e, - else => |e| return fail(m, .{ .file_read = .{ + else => |e| return fail(&m.diagnostic, .{ .file_read = .{ .file_offset = file_off, .err = e, } }), @@ -1411,7 +1456,7 @@ pub const Manifest = struct { error.FileNotFound => return .{ .path_deleted = file_off }, error.IsDir => return .{ .directory_status_changed = file_off }, error.Canceled => |e| return e, - else => |e| return fail(m, .{ .file_open = .{ + else => |e| return fail(&m.diagnostic, .{ .file_open = .{ .file_offset = file_off, .err = e, } }), @@ -1420,7 +1465,7 @@ pub const Manifest = struct { const actual_stat = opened_file.stat(io) catch |err| switch (err) { error.Canceled => |e| return e, - else => |e| return fail(m, .{ .file_stat = .{ + else => |e| return fail(&m.diagnostic, .{ .file_stat = .{ .file_offset = file_off, .err = e, } }), @@ -1430,7 +1475,7 @@ pub const Manifest = struct { const prev_digest: BinDigest = file.digest; hashFile(io, opened_file, &file.digest) catch |err| switch (err) { error.Canceled => |e| return e, - else => |e| return fail(m, .{ .file_read = .{ + else => |e| return fail(&m.diagnostic, .{ .file_read = .{ .file_offset = file_off, .err = e, } }), @@ -1453,7 +1498,7 @@ pub const Manifest = struct { /// not including discovered files). /// /// Assumes that `digest` is populated for all input files. - pub fn unhit(man: *Manifest, input_digest: *const BinDigest) void { + pub fn undoCheck(man: *Manifest, input_digest: *const BinDigest) void { // Reset the hash. man.hash.hasher = hasher_init; man.hash.hasher.update(input_digest); @@ -2117,8 +2162,7 @@ test "cache file and then recall it" { ch.hash.addBytes("1234"); _ = try ch.addInputPath(.initCwd(temp_file), .{}); - // There should be nothing in the cache - try testing.expectEqual(.miss, try ch.check(.none)); + try testing.expectEqual(.incomplete_manifest, try ch.check(.none)); digest1 = ch.final(); try ch.finalize(); @@ -2185,8 +2229,7 @@ test "check that changing a file makes cache fail" { man.hash.addBytes("1234"); const temp_file_idx = try man.addInputPath(.initCwd(temp_file), .{ .request_contents = true }); - // There should be nothing in the cache - try testing.expectEqual(.miss, try man.check(.none)); + try testing.expectEqual(.incomplete_manifest, try man.check(.none)); try testing.expectEqualStrings(original_temp_file_contents, temp_file_idx.contents(&man)); @@ -2204,11 +2247,13 @@ test "check that changing a file makes cache fail" { man.hash.addBytes("1234"); const temp_file_idx = try man.addInputPath(.initCwd(temp_file), .{ .request_contents = true }); - // A file that we depend on has been updated, so the cache should not contain an entry for it - try testing.expectEqual(.miss, try man.check(.none)); + // The one input file changed. + try testing.expectEqual( + @as(Manifest.CheckResult, .{ .contents_changed = temp_file_idx.offset(&man) }), + try man.check(.none), + ); - // The cache system does not keep the contents of re-hashed input files. - try testing.expectEqual(false, temp_file_idx.get(&man).contents.status.populated()); + try testing.expectEqualStrings(updated_temp_file_contents, temp_file_idx.contents(&man)); digest2 = man.final(); @@ -2248,8 +2293,7 @@ test "no file inputs" { man.hash.addBytes("1234"); - // There should be nothing in the cache - try testing.expectEqual(.miss, try man.check(.none)); + try testing.expectEqual(.incomplete_manifest, try man.check(.none)); digest1 = man.final(); @@ -2306,31 +2350,30 @@ test "Manifest with files added after initial hash work" { defer cache.manifest_dir.close(io); { - var ch = cache.obtain(); - defer ch.deinit(); + var man = cache.obtain(); + defer man.deinit(); - ch.hash.addBytes("1234"); - _ = try ch.addInputPath(.initCwd(temp_file1), .{}); + man.hash.addBytes("1234"); + _ = try man.addInputPath(.initCwd(temp_file1), .{}); - // There should be nothing in the cache - try testing.expectEqual(.miss, try ch.check(.none)); + try testing.expectEqual(.incomplete_manifest, try man.check(.none)); - _ = try ch.addDiscoveredPath(.{ .discovered_path = .{ .unresolved = .initCwd(temp_file2) } }); + try man.addDiscoveredPath(.{ .discovered_path = .{ .unresolved = .initCwd(temp_file2) } }); - digest1 = ch.final(); - try ch.finalize(); + digest1 = man.final(); + try man.finalize(); } { - var ch = cache.obtain(); - defer ch.deinit(); + var man = cache.obtain(); + defer man.deinit(); - ch.hash.addBytes("1234"); - _ = try ch.addInputPath(.initCwd(temp_file1), .{}); + man.hash.addBytes("1234"); + _ = try man.addInputPath(.initCwd(temp_file1), .{}); - try testing.expect(.hit == try ch.check(.none)); - digest2 = ch.final(); + try testing.expect(.hit == try man.check(.none)); + digest2 = man.final(); - try testing.expectEqual(false, ch.have_exclusive_lock); + try testing.expectEqual(false, man.have_exclusive_lock); } try testing.expect(mem.eql(u8, &digest1, &digest2)); @@ -2344,20 +2387,24 @@ test "Manifest with files added after initial hash work" { } { - var ch = cache.obtain(); - defer ch.deinit(); + var man = cache.obtain(); + defer man.deinit(); - ch.hash.addBytes("1234"); - _ = try ch.addInputPath(.initCwd(temp_file1), .{}); + man.hash.addBytes("1234"); + _ = try man.addInputPath(.initCwd(temp_file1), .{}); - // A file that we depend on has been updated, so the cache should not contain an entry for it - try testing.expectEqual(.miss, try ch.check(.none)); + switch (try man.check(.none)) { + .contents_changed => |off| { + try testing.expectEqualStrings(temp_file2, off.path(man.contents.items)); + }, + else => return error.TestFailed, + } - _ = try ch.addDiscoveredPath(.{ .discovered_path = .{ .unresolved = .initCwd(temp_file2) } }); + try man.addDiscoveredPath(.{ .discovered_path = .{ .unresolved = .initCwd(temp_file2) } }); - digest3 = ch.final(); + digest3 = man.final(); - try ch.finalize(); + try man.finalize(); } try testing.expect(!mem.eql(u8, &digest1, &digest3)); diff --git a/src/Compilation.zig b/src/Compilation.zig index 38229017566600e927fb5dfe2d51f9491bce1d2f..6e97e9ca1a50f9038160e65e2531dbd908846a19 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -2856,7 +2856,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE log.debug("CacheMode.whole cache miss for {s}", .{comp.root_name}); if (ignore_hit) { - // Okay, now set this back so that `writeManifest` will downgrade our lock later. + // Okay, now set this back so that `Manifest.finalize` will downgrade our lock later. man.want_shared_lock = true; } @@ -3144,7 +3144,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE } // Failure here only means an unnecessary cache miss. - man.writeManifest() catch |err| log.warn("failed to write cache manifest: {t}", .{err}); + man.finalize() catch |err| log.warn("failed to write cache manifest: {t}", .{err}); assert(whole.lock == null); whole.lock = man.toOwnedLock(); @@ -5810,11 +5810,8 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr // possible we had a hit and the manifest is dirty, for example if the file mtime changed but // the contents were the same, we hit the cache but the manifest is dirty and we need to update // it to prevent doing a full file content comparison the next time around. - man.writeManifest() catch |err| { - log.warn("failed to write cache manifest when compiling '{s}': {s}", .{ - c_object.src.src_path, @errorName(err), - }); - }; + man.finalize() catch |err| + log.warn("failed to write cache manifest when compiling {q}: {t}", .{ c_object.src.src_path, err }); } 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 }; if (man.have_exclusive_lock) { - man.writeManifest() catch |err| { - log.warn("failed to write cache manifest when compiling '{s}': {s}", .{ src_path, @errorName(err) }); - }; + man.finalize() catch |err| + log.warn("failed to write cache manifest when compiling {q}: {t}", .{ src_path, err }); } win32_resource.status = .{ @@ -6060,8 +6056,8 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32 // possible we had a hit and the manifest is dirty, for example if the file mtime changed but // the contents were the same, we hit the cache but the manifest is dirty and we need to update // it to prevent doing a full file content comparison the next time around. - man.writeManifest() catch |err| { - log.warn("failed to write cache manifest when compiling '{s}': {s}", .{ rc_src.src_path, @errorName(err) }); + man.finalize() catch |err| { + log.warn("failed to write cache manifest when compiling {q}: {t}", .{ rc_src.src_path, err }); }; } diff --git a/src/libs/freebsd.zig b/src/libs/freebsd.zig index bda03f2787e4ff60e19e920ee3a43ab246366193..b02b3569af70d363eb73619f7bdd7cd514e0d1cc 100644 --- a/src/libs/freebsd.zig +++ b/src/libs/freebsd.zig @@ -982,9 +982,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye try buildSharedLib(comp, arena, o_directory, asm_file_basename, lib, prog_node); } - man.writeManifest() catch |err| { - log.warn("failed to write cache manifest for FreeBSD libc stubs: {s}", .{@errorName(err)}); - }; + man.finalize() catch |err| log.warn("failed to write cache manifest for FreeBSD libc stubs: {t}", .{err}); return queueSharedObjects(comp, .{ .lock = man.toOwnedLock(), diff --git a/src/libs/glibc.zig b/src/libs/glibc.zig index 67dd70eae78487ab5473c06a63bab226b91c6205..08b9214d6db5d64a8fef5dcf4dde164e9f7f9f12 100644 --- a/src/libs/glibc.zig +++ b/src/libs/glibc.zig @@ -1131,9 +1131,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye try buildSharedLib(comp, arena, o_directory, asm_file_basename, lib, prog_node); } - man.writeManifest() catch |err| { - log.warn("failed to write cache manifest for glibc stubs: {s}", .{@errorName(err)}); - }; + man.finalize() catch |err| log.warn("failed to write cache manifest for glibc stubs: {t}", .{err}); return queueSharedObjects(comp, .{ .lock = man.toOwnedLock(), diff --git a/src/libs/mingw.zig b/src/libs/mingw.zig index f0d0ef2990089fd1d6ac7ef5844678d1950f7b3c..f6593e64af7dc6f48ff2c450db77ce7c792c19eb 100644 --- a/src/libs/mingw.zig +++ b/src/libs/mingw.zig @@ -363,9 +363,8 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8, prog_node: std.P try file_writer.interface.flush(); } - man.writeManifest() catch |err| { - log.warn("failed to write cache manifest for DLL import {s}.lib: {s}", .{ lib_name, @errorName(err) }); - }; + man.finalize() catch |err| + log.warn("failed to write cache manifest for DLL import {s}.lib: {t}", .{ lib_name, err }); comp.mutex.lockUncancelable(io); defer comp.mutex.unlock(io); diff --git a/src/libs/netbsd.zig b/src/libs/netbsd.zig index 8cafe51563f5d6e32971fb77035f4f7e54d65409..9d120d46ae2db878175c5ff5b84c8ebf7eaf7c9b 100644 --- a/src/libs/netbsd.zig +++ b/src/libs/netbsd.zig @@ -643,9 +643,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye try buildSharedLib(comp, arena, o_directory, asm_file_basename, lib, prog_node); } - man.writeManifest() catch |err| { - log.warn("failed to write cache manifest for NetBSD libc stubs: {s}", .{@errorName(err)}); - }; + man.finalize() catch |err| log.warn("failed to write cache manifest for NetBSD libc stubs: {t}", .{err}); return queueSharedObjects(comp, .{ .lock = man.toOwnedLock(), diff --git a/src/libs/openbsd.zig b/src/libs/openbsd.zig index dea2c5c3350afcced2f7c8c005a1ceb24a102f8d..e65fc524967c09300979897a0e5dd089e5fd8ad1 100644 --- a/src/libs/openbsd.zig +++ b/src/libs/openbsd.zig @@ -564,9 +564,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye try buildSharedLib(comp, arena, o_directory, asm_file_basename, lib, prog_node); } - man.writeManifest() catch |err| { - log.warn("failed to write cache manifest for OpenBSD libc stubs: {s}", .{@errorName(err)}); - }; + man.finalize() catch |err| log.warn("failed to write cache manifest for OpenBSD libc stubs: {t}", .{err}); return queueSharedObjects(comp, .{ .lock = man.toOwnedLock(), diff --git a/src/main.zig b/src/main.zig index bcffbfee9176c9c5fb050927d147a5e39332788b..d7f6fe574c4c228166cf6fc90b00f46cd0cd6501 100644 --- a/src/main.zig +++ b/src/main.zig @@ -4906,7 +4906,7 @@ fn cmdTranslateC( } } - man.writeManifest() catch |err| warn("failed to write cache manifest: {t}", .{err}); + man.finalize() catch |err| warn("failed to write cache manifest: {t}", .{err}); break :result result; }; -- 2.54.0