authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-08-08 09:38:38+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-08-09 02:44:15+02:00
log83b57947e328163263bb1e581bdf790bc15e8395
treecdcf93ca148e02f37432b6aa84970cc08bd8a522
parent8e741045bc672858dfe2ca85c8253fb755afd375

link: don't include static libraries in other static libraries

Follow-up to 9aa93a045ebbf7d5c6349eb41e99ca516ab9ba65, which fixed this bug for *shared* library inputs, but not *static* library inputs. Supersedes https://codeberg.org/ziglang/zig/pulls/31383 by fixing the bug at the compiler level instead of working around it in the build system. This seems preferable because it is useful to the compiler to have full information about a compilation's link inputs---for instance this could interact with https://github.com/ziglang/zig/issues/20654 in the future by having the compiler learn about a static library's ABI even if that static library does not ultimately contribute to the link. Resolves: https://codeberg.org/ziglang/zig/issues/35624

3 files changed, 14 insertions(+), 10 deletions(-)

src/link/Elf.zig+7-8
...@@ -714,7 +714,6 @@ pub fn loadInput(self: *Elf, input: link.Input) !void {...@@ -714,7 +714,6 @@ pub fn loadInput(self: *Elf, input: link.Input) !void {
714 const target = self.getTarget();714 const target = self.getTarget();
715 const debug_fmt_strip = comp.config.debug_format == .strip;715 const debug_fmt_strip = comp.config.debug_format == .strip;
716 const default_sym_version = self.default_sym_version;716 const default_sym_version = self.default_sym_version;
717 const is_static_lib = self.base.isStaticLib();
718717
719 if (comp.verbose_link) {718 if (comp.verbose_link) {
720 comp.mutex.lockUncancelable(io); // protect comp.arena719 comp.mutex.lockUncancelable(io); // protect comp.arena
...@@ -733,7 +732,11 @@ pub fn loadInput(self: *Elf, input: link.Input) !void {...@@ -733,7 +732,11 @@ pub fn loadInput(self: *Elf, input: link.Input) !void {
733 .res => unreachable,732 .res => unreachable,
734 .dso_exact => @panic("TODO"),733 .dso_exact => @panic("TODO"),
735 .object => |obj| try parseObject(self, obj),734 .object => |obj| try parseObject(self, obj),
736 .archive => |obj| try parseArchive(gpa, io, diags, &self.file_handles, &self.files, target, debug_fmt_strip, default_sym_version, &self.objects, obj, is_static_lib),735 .archive => |obj| if (self.base.isStaticLib()) {
736 // Ignore static library inputs when generating a static library.
737 } else {
738 try parseArchive(gpa, io, diags, &self.file_handles, &self.files, target, debug_fmt_strip, default_sym_version, &self.objects, obj);
739 },
737 .dso => |dso| try parseDso(gpa, io, diags, dso, &self.shared_objects, &self.files, target),740 .dso => |dso| try parseDso(gpa, io, diags, dso, &self.shared_objects, &self.files, target),
738 }741 }
739}742}
...@@ -1083,7 +1086,6 @@ fn parseArchive(...@@ -1083,7 +1086,6 @@ fn parseArchive(
1083 default_sym_version: elf.Versym,1086 default_sym_version: elf.Versym,
1084 objects: *std.ArrayList(File.Index),1087 objects: *std.ArrayList(File.Index),
1085 obj: link.Input.Object,1088 obj: link.Input.Object,
1086 is_static_lib: bool,
1087) !void {1089) !void {
1088 const tracy = trace(@src());1090 const tracy = trace(@src());
1089 defer tracy.end();1091 defer tracy.end();
...@@ -1092,17 +1094,14 @@ fn parseArchive(...@@ -1092,17 +1094,14 @@ fn parseArchive(
1092 var archive = try Archive.parse(gpa, io, diags, file_handles, obj.path, fh);1094 var archive = try Archive.parse(gpa, io, diags, file_handles, obj.path, fh);
1093 defer archive.deinit(gpa);1095 defer archive.deinit(gpa);
10941096
1095 const init_alive = if (is_static_lib) true else obj.must_link;
1096
1097 for (archive.objects) |extracted| {1097 for (archive.objects) |extracted| {
1098 const index: File.Index = @intCast(try files.addOne(gpa));1098 const index: File.Index = @intCast(try files.addOne(gpa));
1099 files.set(index, .{ .object = extracted });1099 files.set(index, .{ .object = extracted });
1100 const object = &files.items(.data)[index].object;1100 const object = &files.items(.data)[index].object;
1101 object.index = index;1101 object.index = index;
1102 object.alive = init_alive;1102 object.alive = obj.must_link;
1103 try object.parseCommon(gpa, io, diags, obj.path, obj.file, target);1103 try object.parseCommon(gpa, io, diags, obj.path, obj.file, target);
1104 if (!is_static_lib)1104 try object.parse(gpa, io, diags, obj.path, obj.file, target, debug_fmt_strip, default_sym_version);
1105 try object.parse(gpa, io, diags, obj.path, obj.file, target, debug_fmt_strip, default_sym_version);
1106 try objects.append(gpa, index);1105 try objects.append(gpa, index);
1107 }1106 }
1108}1107}
src/link/Lld.zig+2-2
...@@ -306,8 +306,8 @@ fn linkAsArchive(lld: *Lld, arena: Allocator) link.Error!void {...@@ -306,8 +306,8 @@ fn linkAsArchive(lld: *Lld, arena: Allocator) link.Error!void {
306306
307 try object_files.ensureUnusedCapacity(arena, comp.link_inputs.len);307 try object_files.ensureUnusedCapacity(arena, comp.link_inputs.len);
308 for (comp.link_inputs) |input| switch (input) {308 for (comp.link_inputs) |input| switch (input) {
309 .res, .dso, .dso_exact => {}, // shared libraries should not be included in static archives309 .dso, .dso_exact, .archive => {}, // static archives should not contain shared libraries or other static archives
310 .object, .archive => {310 .res, .object => {
311 const path = try input.path().?.toStringZ(arena);311 const path = try input.path().?.toStringZ(arena);
312 object_files.appendAssumeCapacity(path);312 object_files.appendAssumeCapacity(path);
313 },313 },
src/link/MachO.zig+5
...@@ -992,6 +992,11 @@ fn addArchive(self: *MachO, lib: link.Input.Object, handle: File.HandleIndex, fa...@@ -992,6 +992,11 @@ fn addArchive(self: *MachO, lib: link.Input.Object, handle: File.HandleIndex, fa
992 const tracy = trace(@src());992 const tracy = trace(@src());
993 defer tracy.end();993 defer tracy.end();
994994
995 if (self.base.isStaticLib()) {
996 // Ignore static library inputs when generating a static library.
997 return;
998 }
999
995 const gpa = self.base.comp.gpa;1000 const gpa = self.base.comp.gpa;
9961001
997 var archive: Archive = .{};1002 var archive: Archive = .{};