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.
This commit is contained in:
@@ -1,3 +1,6 @@
|
||||
* the have_foo flags that we get from stage1 have to be stored in the cache otherwise we get
|
||||
a different result for subsystem when we have a cached stage1 execution result.
|
||||
same deal with extern "foo" libraries used
|
||||
* add jobs to build import libs for windows DLLs for explicitly linked libs
|
||||
* add jobs to build import libs for windows DLLs for extern "foo" functions used
|
||||
* MachO LLD linking
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -75,12 +75,15 @@ global_error_set: std.StringHashMapUnmanaged(u16) = .{},
|
||||
/// previous analysis.
|
||||
generation: u32 = 0,
|
||||
|
||||
have_winmain: bool = false,
|
||||
have_wwinmain: bool = false,
|
||||
have_winmain_crt_startup: bool = false,
|
||||
have_wwinmain_crt_startup: bool = false,
|
||||
have_dllmain_crt_startup: bool = false,
|
||||
have_c_main: bool = false,
|
||||
stage1_flags: packed struct {
|
||||
have_winmain: bool = false,
|
||||
have_wwinmain: bool = false,
|
||||
have_winmain_crt_startup: bool = false,
|
||||
have_wwinmain_crt_startup: bool = false,
|
||||
have_dllmain_crt_startup: bool = false,
|
||||
have_c_main: bool = false,
|
||||
reserved: u2 = 0,
|
||||
} = .{},
|
||||
|
||||
pub const Export = struct {
|
||||
options: std.builtin.ExportOptions,
|
||||
|
||||
@@ -943,14 +943,15 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void {
|
||||
switch (target.os.tag) {
|
||||
.windows => {
|
||||
if (self.base.options.module) |module| {
|
||||
if (module.have_dllmain_crt_startup or is_dyn_lib)
|
||||
if (module.stage1_flags.have_dllmain_crt_startup or is_dyn_lib)
|
||||
break :blk null;
|
||||
if (module.have_c_main or self.base.options.is_test or
|
||||
module.have_winmain_crt_startup or module.have_wwinmain_crt_startup)
|
||||
if (module.stage1_flags.have_c_main or self.base.options.is_test or
|
||||
module.stage1_flags.have_winmain_crt_startup or
|
||||
module.stage1_flags.have_wwinmain_crt_startup)
|
||||
{
|
||||
break :blk .Console;
|
||||
}
|
||||
if (module.have_winmain or module.have_wwinmain)
|
||||
if (module.stage1_flags.have_winmain or module.stage1_flags.have_wwinmain)
|
||||
break :blk .Windows;
|
||||
}
|
||||
},
|
||||
@@ -1068,11 +1069,11 @@ fn linkWithLLD(self: *Coff, comp: *Compilation) !void {
|
||||
try argv.append("-NODEFAULTLIB");
|
||||
if (!is_lib) {
|
||||
if (self.base.options.module) |module| {
|
||||
if (module.have_winmain) {
|
||||
if (module.stage1_flags.have_winmain) {
|
||||
try argv.append("-ENTRY:WinMain");
|
||||
} else if (module.have_wwinmain) {
|
||||
} else if (module.stage1_flags.have_wwinmain) {
|
||||
try argv.append("-ENTRY:wWinMain");
|
||||
} else if (module.have_wwinmain_crt_startup) {
|
||||
} else if (module.stage1_flags.have_wwinmain_crt_startup) {
|
||||
try argv.append("-ENTRY:wWinMainCRTStartup");
|
||||
} else {
|
||||
try argv.append("-ENTRY:WinMainCRTStartup");
|
||||
|
||||
Reference in New Issue
Block a user