authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-01-01 14:40:23-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-01-01 19:49:08-07:00
log7fb9f58f85f1dc9c18c49bc1114d9d978fdbed33
treeb87d68884479fa2ccbaedab55a0d1b8a698b28bd
parent6b2709616e22e7651f16293034cc0d25f0e9be0a

Compilation: rename before flush during whole cache mode

The linker needs to know the file system path of output in the flush function because file paths inside the build artifacts reference each other. Fixes a regression introduced in this branch.

1 files changed, 83 insertions(+), 39 deletions(-)

src/Compilation.zig+83-39
...@@ -2216,39 +2216,6 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void...@@ -2216,39 +2216,6 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void
2216 // -femit-llvm-bc, and -femit-asm, in the case of C objects.2216 // -femit-llvm-bc, and -femit-asm, in the case of C objects.
2217 comp.emitOthers();2217 comp.emitOthers();
22182218
2219 {
2220 if (comp.bin_file) |lf| {
2221 // This is needed before reading the error flags.
2222 lf.flush(comp, main_progress_node) catch |err| switch (err) {
2223 error.FlushFailure => {}, // error reported through link_error_flags
2224 error.LLDReportedFailure => {}, // error reported via lockAndParseLldStderr
2225 else => |e| return e,
2226 };
2227 }
2228
2229 if (comp.module) |zcu| {
2230 try link.File.C.flushEmitH(zcu);
2231
2232 if (zcu.llvm_object) |llvm_object| {
2233 if (build_options.only_c) unreachable;
2234 const default_emit = switch (comp.cache_use) {
2235 .whole => |whole| .{
2236 .directory = whole.tmp_artifact_directory.?,
2237 .sub_path = "dummy",
2238 },
2239 .incremental => |incremental| .{
2240 .directory = incremental.artifact_directory,
2241 .sub_path = "dummy",
2242 },
2243 };
2244 try emitLlvmObject(comp, arena, default_emit, null, llvm_object, main_progress_node);
2245 }
2246 }
2247 }
2248
2249 if (comp.totalErrorCount() != 0) return;
2250 try maybeGenerateAutodocs(comp, main_progress_node);
2251
2252 switch (comp.cache_use) {2219 switch (comp.cache_use) {
2253 .whole => |whole| {2220 .whole => |whole| {
2254 const digest = man.final();2221 const digest = man.final();
...@@ -2261,15 +2228,32 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void...@@ -2261,15 +2228,32 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void
2261 whole.tmp_artifact_directory = null;2228 whole.tmp_artifact_directory = null;
2262 } else unreachable;2229 } else unreachable;
22632230
2264 if (comp.bin_file) |lf| {
2265 lf.destroy();
2266 comp.bin_file = null;
2267 }
2268
2269 const s = std.fs.path.sep_str;2231 const s = std.fs.path.sep_str;
2270 const tmp_dir_sub_path = "tmp" ++ s ++ Package.Manifest.hex64(tmp_dir_rand_int);2232 const tmp_dir_sub_path = "tmp" ++ s ++ Package.Manifest.hex64(tmp_dir_rand_int);
2271 const o_sub_path = "o" ++ s ++ digest;2233 const o_sub_path = "o" ++ s ++ digest;
22722234
2235 // Work around windows `AccessDenied` if any files within this
2236 // directory are open by closing and reopening the file handles.
2237 const need_writable_dance = w: {
2238 if (builtin.os.tag == .windows) {
2239 if (comp.bin_file) |lf| {
2240 // We cannot just call `makeExecutable` as it makes a false
2241 // assumption that we have a file handle open only when linking
2242 // an executable file. This used to be true when our linkers
2243 // were incapable of emitting relocatables and static archive.
2244 // Now that they are capable, we need to unconditionally close
2245 // the file handle and re-open it in the follow up call to
2246 // `makeWritable`.
2247 if (lf.file) |f| {
2248 f.close();
2249 lf.file = null;
2250 break :w true;
2251 }
2252 }
2253 }
2254 break :w false;
2255 };
2256
2273 renameTmpIntoCache(comp.local_cache_directory, tmp_dir_sub_path, o_sub_path) catch |err| {2257 renameTmpIntoCache(comp.local_cache_directory, tmp_dir_sub_path, o_sub_path) catch |err| {
2274 return comp.setMiscFailure(2258 return comp.setMiscFailure(
2275 .rename_results,2259 .rename_results,
...@@ -2283,15 +2267,75 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void...@@ -2283,15 +2267,75 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void
2283 };2267 };
2284 comp.wholeCacheModeSetBinFilePath(whole, &digest);2268 comp.wholeCacheModeSetBinFilePath(whole, &digest);
22852269
2270 // The linker flush functions need to know the final output path
2271 // for debug info purposes because executable debug info contains
2272 // references object file paths.
2273 if (comp.bin_file) |lf| {
2274 lf.emit = .{
2275 .directory = comp.local_cache_directory,
2276 .sub_path = whole.bin_sub_path.?,
2277 };
2278
2279 // Has to be after the `wholeCacheModeSetBinFilePath` above.
2280 if (need_writable_dance) {
2281 try lf.makeWritable();
2282 }
2283 }
2284
2285 try flush(comp, arena, main_progress_node);
2286 if (comp.totalErrorCount() != 0) return;
2287
2286 // Failure here only means an unnecessary cache miss.2288 // Failure here only means an unnecessary cache miss.
2287 man.writeManifest() catch |err| {2289 man.writeManifest() catch |err| {
2288 log.warn("failed to write cache manifest: {s}", .{@errorName(err)});2290 log.warn("failed to write cache manifest: {s}", .{@errorName(err)});
2289 };2291 };
22902292
2293 if (comp.bin_file) |lf| {
2294 lf.destroy();
2295 comp.bin_file = null;
2296 }
2297
2291 assert(whole.lock == null);2298 assert(whole.lock == null);
2292 whole.lock = man.toOwnedLock();2299 whole.lock = man.toOwnedLock();
2293 },2300 },
2294 .incremental => {},2301 .incremental => {
2302 try flush(comp, arena, main_progress_node);
2303 if (comp.totalErrorCount() != 0) return;
2304 },
2305 }
2306}
2307
2308fn flush(comp: *Compilation, arena: Allocator, prog_node: *std.Progress.Node) !void {
2309 if (comp.bin_file) |lf| {
2310 // This is needed before reading the error flags.
2311 lf.flush(comp, prog_node) catch |err| switch (err) {
2312 error.FlushFailure => {}, // error reported through link_error_flags
2313 error.LLDReportedFailure => {}, // error reported via lockAndParseLldStderr
2314 else => |e| return e,
2315 };
2316 }
2317
2318 if (comp.module) |zcu| {
2319 try link.File.C.flushEmitH(zcu);
2320
2321 if (zcu.llvm_object) |llvm_object| {
2322 if (build_options.only_c) unreachable;
2323 const default_emit = switch (comp.cache_use) {
2324 .whole => |whole| .{
2325 .directory = whole.tmp_artifact_directory.?,
2326 .sub_path = "dummy",
2327 },
2328 .incremental => |incremental| .{
2329 .directory = incremental.artifact_directory,
2330 .sub_path = "dummy",
2331 },
2332 };
2333 try emitLlvmObject(comp, arena, default_emit, null, llvm_object, prog_node);
2334 }
2335 }
2336
2337 if (comp.totalErrorCount() == 0) {
2338 try maybeGenerateAutodocs(comp, prog_node);
2295 }2339 }
2296}2340}
22972341