From c698e55754748fa9e97fed4fe279c604d3b381cd Mon Sep 17 00:00:00 2001 From: Matthew Lugg Date: Wed, 27 May 2026 16:28:52 +0100 Subject: [PATCH] Compilation: don't update C inputs on incremental updates ...at least, for now, so that the use case of performing incremental updates to the *Zig* source code works without crashing the linker. This works around https://codeberg.org/ziglang/zig/issues/32081. --- src/Compilation.zig | 20 ++++++++++++++++---- src/link.zig | 3 +++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/Compilation.zig b/src/Compilation.zig index 180d41f08ce99369294308dc2739d90e8a46b22d..9b187614a76bfc115f244004fb055f9d38eb321a 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -3008,10 +3008,19 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE // For compiling C objects, we rely on the cache hash system to avoid duplicating work. // Add a Job for each C object. - try comp.c_object_work_queue.ensureUnusedCapacity(gpa, comp.c_object_table.count()); - for (comp.c_object_table.keys()) |c_object| { - comp.c_object_work_queue.pushBackAssumeCapacity(c_object); - try comp.appendFileSystemInput(try .fromUnresolved(arena, comp.dirs, &.{c_object.src.src_path})); + if (comp.bin_file != null and comp.bin_file.?.post_prelink) { + assert(comp.config.incremental); + // TODO: this indicates that we are using incremental compilation and this is not the first + // incremental update. The incremental linkers do not (currently?) support updating C inputs + // incrementally. The frontend needs to learn to trigger a full rebuild if a C link input + // changes. For now, to avoid crashing the linker in this case, don't kick off C object + // updates if we've done prelink already. https://codeberg.org/ziglang/zig/issues/32081 + } else { + try comp.c_object_work_queue.ensureUnusedCapacity(gpa, comp.c_object_table.count()); + for (comp.c_object_table.keys()) |c_object| { + comp.c_object_work_queue.pushBackAssumeCapacity(c_object); + try comp.appendFileSystemInput(try .fromUnresolved(arena, comp.dirs, &.{c_object.src.src_path})); + } } for (comp.link_inputs) |input| if (input.path()) |path| { @@ -7595,6 +7604,9 @@ pub fn queuePrelinkTaskMode(comp: *Compilation, path: Cache.Path, must_link: boo /// Only valid to call during `update`. pub fn queuePrelinkTasks(comp: *Compilation, tasks: []const link.PrelinkTask) Io.Cancelable!void { + if (tasks.len > 0) { + if (comp.bin_file) |lf| assert(!lf.post_prelink); + } comp.link_prog_node.increaseEstimatedTotalItems(tasks.len); try comp.link_queue.enqueuePrelink(comp, tasks); } diff --git a/src/link.zig b/src/link.zig index 2c8a4f7aa5ea02dd6fe9047593fc016a0a5a700a..728d2d4f245d83902ef319881b7db128fbf1e85f 100644 --- a/src/link.zig +++ b/src/link.zig @@ -1205,6 +1205,7 @@ pub const File = struct { pub fn loadInput(base: *File, input: Input) anyerror!void { if (base.tag == .lld) return; + assert(!base.post_prelink); switch (base.tag) { inline .elf, .elf2, .wasm => |tag| { dev.check(tag.devFeature()); @@ -1424,6 +1425,8 @@ pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void { return; }; + assert(!base.post_prelink); + var timer = comp.startTimer(); defer if (timer.finish(io)) |ns| { comp.mutex.lockUncancelable(io); -- 2.54.0