aboutsummaryrefslogtreecommitdiff
path: root/src/Compilation.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2020-09-28 15:42:09 -0700
committerAndrew Kelley <andrew@ziglang.org>2020-09-28 15:42:09 -0700
commit412a2f966e18aa792089ac1f41482222d7f2434f (patch)
tree36f4d7f00ce93bc3f10844e3bbf56f75c8ddba8d /src/Compilation.zig
parent91a73a177bc20fa0219dbb6c3cf3dda1c2a465db (diff)
downloadzig-412a2f966e18aa792089ac1f41482222d7f2434f.tar.gz
zig-412a2f966e18aa792089ac1f41482222d7f2434f.zip
store stage1 flags in a trailing byte in the hash id symlink
When we get a cache hit for a stage1 compilation, we need to know about some of the flags such as have_winmain or have_dllmain to know which subsystem to infer during linking. To do this, we append a hex-encoded byte into the intentionally-dangling symlink which contains the cache hash digest rather than a filename. The hex-encoded byte contains the flags we need to infer the subsystem during linking.
Diffstat (limited to 'src/Compilation.zig')
-rw-r--r--src/Compilation.zig50
1 files changed, 36 insertions, 14 deletions
diff --git a/src/Compilation.zig b/src/Compilation.zig
index e539950aba..00eb8c374d 100644
--- a/src/Compilation.zig
+++ b/src/Compilation.zig
@@ -2512,16 +2512,25 @@ fn updateStage1Module(comp: *Compilation) !void {
if (try man.hit()) {
const digest = man.final();
- var prev_digest_buf: [digest.len]u8 = undefined;
+ // We use an extra hex-encoded byte here to store some flags.
+ var prev_digest_buf: [digest.len + 2]u8 = undefined;
const prev_digest: []u8 = directory.handle.readLink(id_symlink_basename, &prev_digest_buf) catch |err| blk: {
log.debug("stage1 {} new_digest={} readlink error: {}", .{ mod.root_pkg.root_src_path, digest, @errorName(err) });
// Handle this as a cache miss.
break :blk prev_digest_buf[0..0];
};
- if (mem.eql(u8, prev_digest, &digest)) {
- log.debug("stage1 {} digest={} match - skipping invocation", .{ mod.root_pkg.root_src_path, digest });
- comp.stage1_lock = man.toOwnedLock();
- return;
+ if (prev_digest.len >= digest.len + 2) {
+ if (mem.eql(u8, prev_digest[0..digest.len], &digest)) {
+ log.debug("stage1 {} digest={} match - skipping invocation", .{ mod.root_pkg.root_src_path, digest });
+ var flags_bytes: [1]u8 = undefined;
+ if (std.fmt.hexToBytes(&flags_bytes, prev_digest[digest.len..])) |_| {
+ comp.stage1_lock = man.toOwnedLock();
+ mod.stage1_flags = @bitCast(@TypeOf(mod.stage1_flags), flags_bytes[0]);
+ return;
+ } else |err| {
+ log.warn("bad cache stage1 digest: '{s}'", .{prev_digest});
+ }
+ }
}
log.debug("stage1 {} prev_digest={} new_digest={}", .{ mod.root_pkg.root_src_path, prev_digest, digest });
man.unhit(prev_hash_state, input_file_count);
@@ -2642,22 +2651,35 @@ fn updateStage1Module(comp: *Compilation) !void {
};
stage1_module.build_object();
- mod.have_c_main = stage1_module.have_c_main;
- mod.have_winmain = stage1_module.have_winmain;
- mod.have_wwinmain = stage1_module.have_wwinmain;
- mod.have_winmain_crt_startup = stage1_module.have_winmain_crt_startup;
- mod.have_wwinmain_crt_startup = stage1_module.have_wwinmain_crt_startup;
- mod.have_dllmain_crt_startup = stage1_module.have_dllmain_crt_startup;
+ mod.stage1_flags = .{
+ .have_c_main = stage1_module.have_c_main,
+ .have_winmain = stage1_module.have_winmain,
+ .have_wwinmain = stage1_module.have_wwinmain,
+ .have_winmain_crt_startup = stage1_module.have_winmain_crt_startup,
+ .have_wwinmain_crt_startup = stage1_module.have_wwinmain_crt_startup,
+ .have_dllmain_crt_startup = stage1_module.have_dllmain_crt_startup,
+ };
stage1_module.destroy();
const digest = man.final();
- log.debug("stage1 {} final digest={}", .{ mod.root_pkg.root_src_path, digest });
-
// Update the dangling symlink with the digest. If it fails we can continue; it only
// means that the next invocation will have an unnecessary cache miss.
- directory.handle.symLink(&digest, id_symlink_basename, .{}) catch |err| {
+ const stage1_flags_byte = @bitCast(u8, mod.stage1_flags);
+ log.debug("stage1 {} final digest={} flags={x}", .{
+ mod.root_pkg.root_src_path, digest, stage1_flags_byte,
+ });
+ var digest_plus_flags: [digest.len + 2]u8 = undefined;
+ digest_plus_flags[0..digest.len].* = digest;
+ assert(std.fmt.formatIntBuf(digest_plus_flags[digest.len..], stage1_flags_byte, 16, false, .{
+ .width = 2,
+ .fill = '0',
+ }) == 2);
+ log.debug("saved digest + flags: '{s}' (byte = {}) have_winmain_crt_startup={}", .{
+ digest_plus_flags, stage1_flags_byte, mod.stage1_flags.have_winmain_crt_startup,
+ });
+ directory.handle.symLink(&digest_plus_flags, id_symlink_basename, .{}) catch |err| {
log.warn("failed to save stage1 hash digest symlink: {}", .{@errorName(err)});
};
// Again failure here only means an unnecessary cache miss.