authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-09-21 00:22:22-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-09-21 13:08:49-07:00
logcf33f1003fd02abaf91078725d9c972dd51fc5e1
tree4005c517ac60d12213b095ec60def90ea5f6230a
parentecd95943a9a174284a5e90f208df4d508aafd098

link frontend: remove dso_exact, add exact_name to dso

linker still wants the path to the shared object, but now also accepts an exact name to put into the NEEDED entry. closes #31823

10 files changed, 87 insertions(+), 86 deletions(-)

src/Compilation.zig+3-2
...@@ -2891,12 +2891,13 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE...@@ -2891,12 +2891,13 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
2891 }2891 }
2892 }2892 }
28932893
2894 for (comp.link_inputs) |input| if (input.path()) |path| {2894 for (comp.link_inputs) |input| {
2895 const path = input.path();
2895 try comp.appendFileSystemInput(try .fromUnresolved(arena, comp.dirs, &.{2896 try comp.appendFileSystemInput(try .fromUnresolved(arena, comp.dirs, &.{
2896 path.root_dir.path orelse ".",2897 path.root_dir.path orelse ".",
2897 path.sub_path,2898 path.sub_path,
2898 }));2899 }));
2899 };2900 }
29002901
2901 // For compiling Win32 resources, we rely on the cache hash system to avoid duplicating work.2902 // For compiling Win32 resources, we rely on the cache hash system to avoid duplicating work.
2902 // Add a Job for each Win32 resource file.2903 // Add a Job for each Win32 resource file.
src/link.zig+21-27
...@@ -1506,7 +1506,6 @@ pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void {...@@ -1506,7 +1506,6 @@ pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void {
1506 .object => |obj| diags.addParseError(obj.path, "failed to parse object: {t}", .{e}),1506 .object => |obj| diags.addParseError(obj.path, "failed to parse object: {t}", .{e}),
1507 .archive => |obj| diags.addParseError(obj.path, "failed to parse archive: {t}", .{e}),1507 .archive => |obj| diags.addParseError(obj.path, "failed to parse archive: {t}", .{e}),
1508 .res => |res| diags.addParseError(res.path, "failed to parse Windows resource: {t}", .{e}),1508 .res => |res| diags.addParseError(res.path, "failed to parse Windows resource: {t}", .{e}),
1509 .dso_exact => diags.addError("failed to handle dso_exact: {t}", .{e}),
1510 },1509 },
1511 };1510 };
1512 prog_node.completeOne();1511 prog_node.completeOne();
...@@ -1821,8 +1820,6 @@ pub const UnresolvedInput = union(enum) {...@@ -1821,8 +1820,6 @@ pub const UnresolvedInput = union(enum) {
1821 /// Strings that come from GNU ld scripts. Is it a filename? Is it a path?1820 /// Strings that come from GNU ld scripts. Is it a filename? Is it a path?
1822 /// Who knows! Fuck around and find out.1821 /// Who knows! Fuck around and find out.
1823 ambiguous_name: NameQuery,1822 ambiguous_name: NameQuery,
1824 /// Put exactly this string in the dynamic section, no rpath.
1825 dso_exact: Input.DsoExact,
18261823
1827 pub const NameQuery = struct {1824 pub const NameQuery = struct {
1828 name: []const u8,1825 name: []const u8,
...@@ -1875,7 +1872,6 @@ pub const Input = union(enum) {...@@ -1875,7 +1872,6 @@ pub const Input = union(enum) {
1875 /// May not be a GNU ld script. Those are resolved when converting from1872 /// May not be a GNU ld script. Those are resolved when converting from
1876 /// `UnresolvedInput` to `Input` values.1873 /// `UnresolvedInput` to `Input` values.
1877 dso: Dso,1874 dso: Dso,
1878 dso_exact: DsoExact,
18791875
1880 pub const Object = struct {1876 pub const Object = struct {
1881 path: Path,1877 path: Path,
...@@ -1895,6 +1891,9 @@ pub const Input = union(enum) {...@@ -1895,6 +1891,9 @@ pub const Input = union(enum) {
1895 needed: bool,1891 needed: bool,
1896 weak: bool,1892 weak: bool,
1897 reexport: bool,1893 reexport: bool,
1894 /// Does not include any ":" prefix. Indicates that this string, exactly, should go into the NEEDED
1895 /// entry, without affecting any rpaths.
1896 exact_name: ?[]const u8,
1898 };1897 };
18991898
1900 pub const DsoExact = struct {1899 pub const DsoExact = struct {
...@@ -1903,21 +1902,17 @@ pub const Input = union(enum) {...@@ -1903,21 +1902,17 @@ pub const Input = union(enum) {
1903 name: []const u8,1902 name: []const u8,
1904 };1903 };
19051904
1906 /// Returns `null` in the case of `dso_exact`.1905 pub fn path(input: Input) Path {
1907 pub fn path(input: Input) ?Path {
1908 return switch (input) {1906 return switch (input) {
1909 .object, .archive => |obj| obj.path,1907 .object, .archive => |obj| obj.path,
1910 inline .res, .dso => |x| x.path,1908 inline .res, .dso => |x| x.path,
1911 .dso_exact => null,
1912 };1909 };
1913 }1910 }
19141911
1915 /// Returns `null` in the case of `dso_exact`.1912 pub fn pathAndFile(input: Input) struct { Path, Io.File } {
1916 pub fn pathAndFile(input: Input) ?struct { Path, Io.File } {
1917 return switch (input) {1913 return switch (input) {
1918 .object, .archive => |obj| .{ obj.path, obj.file },1914 .object, .archive => |obj| .{ obj.path, obj.file },
1919 inline .res, .dso => |x| .{ x.path, x.file },1915 inline .res, .dso => |x| .{ x.path, x.file },
1920 .dso_exact => null,
1921 };1916 };
1922 }1917 }
19231918
...@@ -1925,7 +1920,6 @@ pub const Input = union(enum) {...@@ -1925,7 +1920,6 @@ pub const Input = union(enum) {
1925 return switch (input) {1920 return switch (input) {
1926 .object, .archive => |obj| obj.path.basename(),1921 .object, .archive => |obj| obj.path.basename(),
1927 inline .res, .dso => |x| x.path.basename(),1922 inline .res, .dso => |x| x.path.basename(),
1928 .dso_exact => "dso_exact",
1929 };1923 };
1930 }1924 }
1931};1925};
...@@ -1956,9 +1950,7 @@ pub fn hashInputs(man: *Cache.Manifest, link_inputs: []const Input) !void {...@@ -1956,9 +1950,7 @@ pub fn hashInputs(man: *Cache.Manifest, link_inputs: []const Input) !void {
1956 man.hash.add(dso.needed);1950 man.hash.add(dso.needed);
1957 man.hash.add(dso.weak);1951 man.hash.add(dso.weak);
1958 man.hash.add(dso.reexport);1952 man.hash.add(dso.reexport);
1959 },1953 man.hash.addOptionalBytes(dso.exact_name);
1960 .dso_exact => |dso_exact| {
1961 man.hash.addBytes(dso_exact.name);
1962 },1954 },
1963 }1955 }
1964 }1956 }
...@@ -2194,10 +2186,6 @@ pub fn resolveInputs(...@@ -2194,10 +2186,6 @@ pub fn resolveInputs(
2194 }2186 }
2195 continue;2187 continue;
2196 },2188 },
2197 .dso_exact => |dso_exact| {
2198 try resolved_inputs.append(gpa, .{ .dso_exact = dso_exact });
2199 continue;
2200 },
2201 }2189 }
2202 comptime unreachable;2190 comptime unreachable;
2203 }2191 }
...@@ -2418,13 +2406,18 @@ fn finishResolveLibInput(...@@ -2418,13 +2406,18 @@ fn finishResolveLibInput(
2418 .hidden = query.hidden,2406 .hidden = query.hidden,
2419 } });2407 } });
2420 },2408 },
2421 .dynamic => resolved_inputs.appendAssumeCapacity(.{ .dso = .{2409 .dynamic => resolved_inputs.appendAssumeCapacity(.{
2422 .path = path,2410 .dso = .{
2423 .file = file,2411 .path = path,
2424 .needed = query.needed,2412 .file = file,
2425 .weak = query.weak,2413 .needed = query.needed,
2426 .reexport = query.reexport,2414 .weak = query.weak,
2427 } }),2415 .reexport = query.reexport,
2416 // Here we assume that `Path.sub_path` is usable as `exact_name`, however the code after this point
2417 // has no business making that assumption.
2418 .exact_name = if (query.name_done) path.sub_path else null,
2419 },
2420 }),
2428 }2421 }
2429 return .ok;2422 return .ok;
2430}2423}
...@@ -2608,6 +2601,7 @@ pub fn openDso(io: Io, path: Path, needed: bool, weak: bool, reexport: bool) !In...@@ -2608,6 +2601,7 @@ pub fn openDso(io: Io, path: Path, needed: bool, weak: bool, reexport: bool) !In
2608 .needed = needed,2601 .needed = needed,
2609 .weak = weak,2602 .weak = weak,
2610 .reexport = reexport,2603 .reexport = reexport,
2604 .exact_name = null,
2611 };2605 };
2612}2606}
26132607
...@@ -2639,7 +2633,7 @@ pub fn anyObjectInputs(inputs: []const Input) bool {...@@ -2639,7 +2633,7 @@ pub fn anyObjectInputs(inputs: []const Input) bool {
2639pub fn countObjectInputs(inputs: []const Input) usize {2633pub fn countObjectInputs(inputs: []const Input) usize {
2640 var count: usize = 0;2634 var count: usize = 0;
2641 for (inputs) |input| switch (input) {2635 for (inputs) |input| switch (input) {
2642 .dso, .dso_exact => continue,2636 .dso => continue,
2643 .res, .object, .archive => count += 1,2637 .res, .object, .archive => count += 1,
2644 };2638 };
2645 return count;2639 return count;
...@@ -2649,7 +2643,7 @@ pub fn countObjectInputs(inputs: []const Input) usize {...@@ -2649,7 +2643,7 @@ pub fn countObjectInputs(inputs: []const Input) usize {
2649pub fn firstObjectInput(inputs: []const Input) ?Input.Object {2643pub fn firstObjectInput(inputs: []const Input) ?Input.Object {
2650 for (inputs) |input| switch (input) {2644 for (inputs) |input| switch (input) {
2651 .object, .archive => |obj| return obj,2645 .object, .archive => |obj| return obj,
2652 .res, .dso, .dso_exact => continue,2646 .res, .dso => continue,
2653 };2647 };
2654 return null;2648 return null;
2655}2649}
src/link/Coff.zig+1-2
...@@ -3905,7 +3905,7 @@ pub fn loadInput(coff: *Coff, input: link.Input) link.Error!void {...@@ -3905,7 +3905,7 @@ pub fn loadInput(coff: *Coff, input: link.Input) link.Error!void {
3905 const comp = coff.base.comp;3905 const comp = coff.base.comp;
3906 const io = comp.io;3906 const io = comp.io;
39073907
3908 const path = input.path() orelse unreachable;3908 const path = input.path();
3909 const gop = try coff.inputs.getOrPut(comp.gpa, path);3909 const gop = try coff.inputs.getOrPut(comp.gpa, path);
3910 if (gop.found_existing) return;3910 if (gop.found_existing) return;
3911 errdefer _ = coff.inputs.swapRemove(path);3911 errdefer _ = coff.inputs.swapRemove(path);
...@@ -3935,7 +3935,6 @@ pub fn loadInput(coff: *Coff, input: link.Input) link.Error!void {...@@ -3935,7 +3935,6 @@ pub fn loadInput(coff: *Coff, input: link.Input) link.Error!void {
3935 coff.loadDll(dso.path, &fr) catch |err|3935 coff.loadDll(dso.path, &fr) catch |err|
3936 return coff.failLoadInput(err, &fr, dso.path);3936 return coff.failLoadInput(err, &fr, dso.path);
3937 },3937 },
3938 .dso_exact => unreachable,
3939 }3938 }
3940}3939}
39413940
src/link/Elf.zig+2-2
...@@ -722,7 +722,6 @@ pub fn loadInput(self: *Elf, input: link.Input) !void {...@@ -722,7 +722,6 @@ pub fn loadInput(self: *Elf, input: link.Input) !void {
722 const argv = &self.dump_argv_list;722 const argv = &self.dump_argv_list;
723 switch (input) {723 switch (input) {
724 .res => unreachable,724 .res => unreachable,
725 .dso_exact => |dso_exact| try argv.appendSlice(gpa, &.{ "-l", dso_exact.name }),
726 .object, .archive => |obj| try argv.append(gpa, try obj.path.toString(comp.arena)),725 .object, .archive => |obj| try argv.append(gpa, try obj.path.toString(comp.arena)),
727 .dso => |dso| try argv.append(gpa, try dso.path.toString(comp.arena)),726 .dso => |dso| try argv.append(gpa, try dso.path.toString(comp.arena)),
728 }727 }
...@@ -730,7 +729,6 @@ pub fn loadInput(self: *Elf, input: link.Input) !void {...@@ -730,7 +729,6 @@ pub fn loadInput(self: *Elf, input: link.Input) !void {
730729
731 switch (input) {730 switch (input) {
732 .res => unreachable,731 .res => unreachable,
733 .dso_exact => @panic("TODO"),
734 .object => |obj| try parseObject(self, obj),732 .object => |obj| try parseObject(self, obj),
735 .archive => |obj| if (self.base.isStaticLib()) {733 .archive => |obj| if (self.base.isStaticLib()) {
736 // Ignore static library inputs when generating a static library.734 // Ignore static library inputs when generating a static library.
...@@ -1120,6 +1118,8 @@ fn parseDso(...@@ -1120,6 +1118,8 @@ fn parseDso(
11201118
1121 const handle = dso.file;1119 const handle = dso.file;
11221120
1121 if (dso.exact_name != null) @panic("TODO");
1122
1123 const stat: Stat = .init(try handle.stat(io));1123 const stat: Stat = .init(try handle.stat(io));
1124 var header = try SharedObject.parseHeader(gpa, io, diags, dso.path, handle, stat, target);1124 var header = try SharedObject.parseHeader(gpa, io, diags, dso.path, handle, stat, target);
1125 defer header.deinit(gpa);1125 defer header.deinit(gpa);
src/link/Elf2.zig+12-19
...@@ -6228,36 +6228,29 @@ fn loadInputInner(elf: *Elf, input: link.Input) (Error || error{BadMagic})!void...@@ -6228,36 +6228,29 @@ fn loadInputInner(elf: *Elf, input: link.Input) (Error || error{BadMagic})!void
6228 },6228 },
6229 .res => unreachable,6229 .res => unreachable,
6230 .dso => |dso| {6230 .dso => |dso| {
6231 if (dso.exact_name) |exact_name| {
6232 // This means the path field is still valid, but the NEEDED entry must be set to
6233 // exactly the `exact_name` string.
6234 std.debug.panic("load dso_exact {q}", .{exact_name});
6235 if (elf.shndx.dynamic != .UNDEF) {
6236 try elf.needed.put(elf.base.comp.gpa, try elf.string(.dynstr, exact_name), {});
6237 }
6238 }
6231 try elf.needed.ensureUnusedCapacity(elf.base.comp.gpa, 1);6239 try elf.needed.ensureUnusedCapacity(elf.base.comp.gpa, 1);
6232 var fr = dso.file.reader(io, &buf);6240 var fr = dso.file.reader(io, &buf);
6233 elf.loadDso(dso.path, &fr) catch |err| switch (err) {6241 elf.loadDso(dso.path, &fr) catch |err| switch (err) {
6234 else => |e| return e,6242 else => |e| return e,
6235 error.EndOfStream => return diags.failParse(6243 error.EndOfStream => return diags.failParse(dso.path, "unexpected eof", .{}),
6236 dso.path,
6237 "unexpected eof",
6238 .{},
6239 ),
6240 error.AccessDenied, error.Unexpected, error.Unseekable => |e| return diags.fail(6244 error.AccessDenied, error.Unexpected, error.Unseekable => |e| return diags.fail(
6241 "failed to read \"{f}\": {t}",6245 "failed to read {qf}: {t}",
6242 .{ dso.path.fmtEscapeString(), e },6246 .{ dso.path, e },
6243 ),6247 ),
6244 error.ReadFailed => switch (fr.err.?) {6248 error.ReadFailed => switch (fr.err.?) {
6245 error.Canceled => |e| return e,6249 error.Canceled => |e| return e,
6246 else => |e| return diags.fail(6250 else => |e| return diags.fail("failed to read {qf}: {t}", .{ dso.path, e }),
6247 "failed to read \"{f}\": {t}",
6248 .{ dso.path.fmtEscapeString(), e },
6249 ),
6250 },6251 },
6251 };6252 };
6252 },6253 },
6253 .dso_exact => |dso_exact| {
6254 log.debug("load dso_exact '{f}'", .{std.zig.fmtString(dso_exact.name)});
6255 if (elf.shndx.dynamic != .UNDEF) {
6256 try elf.needed.put(elf.base.comp.gpa, try elf.string(.dynstr, dso_exact.name), {});
6257 }
6258 // TODO: we need to get a resolved file path from the frontend, because we need to read
6259 // the shared object to discover symbol types.
6260 },
6261 }6254 }
6262}6255}
6263fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (LoadParseInputError || error{BadMagic})!void {6256fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (LoadParseInputError || error{BadMagic})!void {
src/link/Lld.zig+22-14
...@@ -309,9 +309,9 @@ fn linkAsArchive(lld: *Lld, arena: Allocator) link.Error!void {...@@ -309,9 +309,9 @@ fn linkAsArchive(lld: *Lld, arena: Allocator) link.Error!void {
309309
310 try object_files.ensureUnusedCapacity(arena, comp.link_inputs.len);310 try object_files.ensureUnusedCapacity(arena, comp.link_inputs.len);
311 for (comp.link_inputs) |input| switch (input) {311 for (comp.link_inputs) |input| switch (input) {
312 .dso, .dso_exact, .archive => {}, // static archives should not contain shared libraries or other static archives312 .dso, .archive => {}, // static archives should not contain shared libraries or other static archives
313 .res, .object => {313 .res, .object => {
314 const path = try input.path().?.toStringZ(arena);314 const path = try input.path().toStringZ(arena);
315 object_files.appendAssumeCapacity(path);315 object_files.appendAssumeCapacity(path);
316 },316 },
317 };317 };
...@@ -551,7 +551,6 @@ fn coffLink(lld: *Lld, arena: Allocator) !void {...@@ -551,7 +551,6 @@ fn coffLink(lld: *Lld, arena: Allocator) !void {
551551
552 try argv.ensureUnusedCapacity(comp.link_inputs.len);552 try argv.ensureUnusedCapacity(comp.link_inputs.len);
553 for (comp.link_inputs) |link_input| switch (link_input) {553 for (comp.link_inputs) |link_input| switch (link_input) {
554 .dso_exact => unreachable, // not applicable to PE/COFF
555 inline .dso, .res => |x| {554 inline .dso, .res => |x| {
556 argv.appendAssumeCapacity(try x.path.toString(arena));555 argv.appendAssumeCapacity(try x.path.toString(arena));
557 },556 },
...@@ -1114,10 +1113,6 @@ fn elfLink(lld: *Lld, arena: Allocator) !void {...@@ -1114,10 +1113,6 @@ fn elfLink(lld: *Lld, arena: Allocator) !void {
1114 }1113 }
1115 try argv.append(try obj.path.toString(arena));1114 try argv.append(try obj.path.toString(arena));
1116 },1115 },
1117 .dso_exact => |dso_exact| {
1118 assert(dso_exact.name[0] == ':');
1119 try argv.appendSlice(&.{ "-l", dso_exact.name });
1120 },
1121 };1116 };
11221117
1123 if (whole_archive) {1118 if (whole_archive) {
...@@ -1161,7 +1156,7 @@ fn elfLink(lld: *Lld, arena: Allocator) !void {...@@ -1161,7 +1156,7 @@ fn elfLink(lld: *Lld, arena: Allocator) !void {
11611156
1162 for (base.comp.link_inputs) |link_input| switch (link_input) {1157 for (base.comp.link_inputs) |link_input| switch (link_input) {
1163 .res => unreachable, // Windows-only1158 .res => unreachable, // Windows-only
1164 .object, .archive, .dso_exact => continue,1159 .object, .archive => continue,
1165 .dso => |dso| {1160 .dso => |dso| {
1166 const lib_as_needed = !dso.needed;1161 const lib_as_needed = !dso.needed;
1167 switch ((@as(u2, @intFromBool(lib_as_needed)) << 1) | @intFromBool(as_needed)) {1162 switch ((@as(u2, @intFromBool(lib_as_needed)) << 1) | @intFromBool(as_needed)) {
...@@ -1176,11 +1171,25 @@ fn elfLink(lld: *Lld, arena: Allocator) !void {...@@ -1176,11 +1171,25 @@ fn elfLink(lld: *Lld, arena: Allocator) !void {
1176 },1171 },
1177 }1172 }
11781173
1179 // By this time, we depend on these libs being dynamically linked1174 if (dso.exact_name) |exact_name| {
1180 // libraries and not static libraries (the check for that needs to be earlier),1175 // LLD does not have a way to specify full path to the DSO while also specifying
1181 // but they could be full paths to .so files, in which case we1176 // the exact value for NEEDED, so we have to use a combination of -L and -l args.
1182 // want to avoid prepending "-l".1177 assert(mem.endsWith(u8, dso.path.sub_path, exact_name));
1183 argv.appendAssumeCapacity(try dso.path.toString(arena));1178 const truncated_path: Cache.Path = .{
1179 .root_dir = dso.path.root_dir,
1180 .sub_path = dso.path.sub_path[0 .. dso.path.sub_path.len - exact_name.len],
1181 };
1182 try argv.ensureUnusedCapacity(3);
1183 argv.appendAssumeCapacity("-L");
1184 argv.appendAssumeCapacity(try truncated_path.toString(arena));
1185 argv.appendAssumeCapacity(try arena.print("-l:{s}", .{exact_name}));
1186 } else {
1187 // By this time, we depend on these libs being dynamically linked
1188 // libraries and not static libraries (the check for that needs to be earlier),
1189 // but they could be full paths to .so files, in which case we
1190 // want to avoid prepending "-l".
1191 argv.appendAssumeCapacity(try dso.path.toString(arena));
1192 }
1184 },1193 },
1185 };1194 };
11861195
...@@ -1588,7 +1597,6 @@ fn wasmLink(lld: *Lld, arena: Allocator) !void {...@@ -1588,7 +1597,6 @@ fn wasmLink(lld: *Lld, arena: Allocator) !void {
1588 .dso => |dso| {1597 .dso => |dso| {
1589 try argv.append(try dso.path.toString(arena));1598 try argv.append(try dso.path.toString(arena));
1590 },1599 },
1591 .dso_exact => unreachable,
1592 .res => unreachable,1600 .res => unreachable,
1593 };1601 };
1594 if (whole_archive) {1602 if (whole_archive) {
src/link/MachO.zig+21-13
...@@ -372,7 +372,6 @@ pub fn flush(...@@ -372,7 +372,6 @@ pub fn flush(
372 for (comp.link_inputs) |link_input| switch (link_input) {372 for (comp.link_inputs) |link_input| switch (link_input) {
373 .dso => continue, // handled below373 .dso => continue, // handled below
374 .object, .archive => positionals.appendAssumeCapacity(link_input),374 .object, .archive => positionals.appendAssumeCapacity(link_input),
375 .dso_exact => @panic("TODO"),
376 .res => unreachable,375 .res => unreachable,
377 };376 };
378377
...@@ -406,7 +405,7 @@ pub fn flush(...@@ -406,7 +405,7 @@ pub fn flush(
406405
407 for (positionals.items) |link_input| {406 for (positionals.items) |link_input| {
408 self.classifyInputFile(link_input) catch |err|407 self.classifyInputFile(link_input) catch |err|
409 diags.addParseError(link_input.path().?, "failed to read input file: {s}", .{@errorName(err)});408 diags.addParseError(link_input.path(), "failed to read input file: {t}", .{err});
410 }409 }
411410
412 var system_libs = std.array_list.Managed(SystemLib).init(gpa);411 var system_libs = std.array_list.Managed(SystemLib).init(gpa);
...@@ -447,11 +446,11 @@ pub fn flush(...@@ -447,11 +446,11 @@ pub fn flush(
447 };446 };
448447
449 for (comp.link_inputs) |link_input| switch (link_input) {448 for (comp.link_inputs) |link_input| switch (link_input) {
450 .object, .archive, .dso_exact => continue,449 .object, .archive => continue,
451 .res => unreachable,450 .res => unreachable,
452 .dso => {451 .dso => {
453 self.classifyInputFile(link_input) catch |err|452 self.classifyInputFile(link_input) catch |err|
454 diags.addParseError(link_input.path().?, "failed to parse input file: {s}", .{@errorName(err)});453 diags.addParseError(link_input.path(), "failed to parse input file: {t}", .{err});
455 },454 },
456 };455 };
457456
...@@ -655,8 +654,13 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {...@@ -655,8 +654,13 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
655 for (comp.link_inputs) |link_input| switch (link_input) {654 for (comp.link_inputs) |link_input| switch (link_input) {
656 .object, .archive => |obj| try argv.append(try obj.path.toString(arena)),655 .object, .archive => |obj| try argv.append(try obj.path.toString(arena)),
657 .res => |res| try argv.append(try res.path.toString(arena)),656 .res => |res| try argv.append(try res.path.toString(arena)),
658 .dso => |dso| try argv.append(try dso.path.toString(arena)),657 .dso => |dso| {
659 .dso_exact => |dso_exact| try argv.appendSlice(&.{ "-l", dso_exact.name }),658 if (dso.exact_name) |exact_name| {
659 try argv.appendSlice(&.{ "-l", try arena.print(":{s}", .{exact_name}) });
660 } else {
661 try argv.append(try dso.path.toString(arena));
662 }
663 },
660 };664 };
661665
662 for (comp.c_objects.items) |c_object| {666 for (comp.c_objects.items) |c_object| {
...@@ -748,7 +752,6 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {...@@ -748,7 +752,6 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
748 if (obj.must_link) try argv.append("-force_load"); // TODO: verify this752 if (obj.must_link) try argv.append("-force_load"); // TODO: verify this
749 try argv.append(try obj.path.toString(arena));753 try argv.append(try obj.path.toString(arena));
750 },754 },
751 .dso_exact => |dso_exact| try argv.appendSlice(&.{ "-l", dso_exact.name }),
752 };755 };
753756
754 for (comp.c_objects.items) |c_object| {757 for (comp.c_objects.items) |c_object| {
...@@ -775,15 +778,21 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {...@@ -775,15 +778,21 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
775 }778 }
776779
777 for (comp.link_inputs) |link_input| switch (link_input) {780 for (comp.link_inputs) |link_input| switch (link_input) {
778 .object, .archive, .dso_exact => continue, // handled above781 .object, .archive => continue, // handled above
779 .res => unreachable, // windows only782 .res => unreachable, // windows only
780 .dso => |dso| {783 .dso => |dso| {
784 try argv.ensureUnusedCapacity(2);
781 if (dso.needed) {785 if (dso.needed) {
782 try argv.appendSlice(&.{ "-needed-l", try dso.path.toString(arena) });786 argv.appendAssumeCapacity("-needed-l");
783 } else if (dso.weak) {787 } else if (dso.weak) {
784 try argv.appendSlice(&.{ "-weak-l", try dso.path.toString(arena) });788 argv.appendAssumeCapacity("-weak-l");
789 } else {
790 argv.appendAssumeCapacity("-l");
791 }
792 if (dso.exact_name) |exact_name| {
793 argv.appendAssumeCapacity(try arena.print(":{s}", .{exact_name}));
785 } else {794 } else {
786 try argv.appendSlice(&.{ "-l", try dso.path.toString(arena) });795 argv.appendAssumeCapacity(try dso.path.toString(arena));
787 }796 }
788 },797 },
789 };798 };
...@@ -870,7 +879,7 @@ pub fn classifyInputFile(self: *MachO, input: link.Input) !void {...@@ -870,7 +879,7 @@ pub fn classifyInputFile(self: *MachO, input: link.Input) !void {
870 const comp = self.base.comp;879 const comp = self.base.comp;
871 const io = comp.io;880 const io = comp.io;
872881
873 const path, const file = input.pathAndFile().?;882 const path, const file = input.pathAndFile();
874 // TODO don't classify now, it's too late. The input file has already been classified883 // TODO don't classify now, it's too late. The input file has already been classified
875 log.debug("classifying input file {f}", .{path});884 log.debug("classifying input file {f}", .{path});
876885
...@@ -4478,7 +4487,6 @@ const SystemLib = struct {...@@ -4478,7 +4487,6 @@ const SystemLib = struct {
44784487
4479 fn fromLinkInput(link_input: link.Input) SystemLib {4488 fn fromLinkInput(link_input: link.Input) SystemLib {
4480 return switch (link_input) {4489 return switch (link_input) {
4481 .dso_exact => unreachable,
4482 .res => unreachable,4490 .res => unreachable,
4483 .object, .archive => |obj| .{4491 .object, .archive => |obj| .{
4484 .path = obj.path,4492 .path = obj.path,
src/link/MachO/relocatable.zig+3-3
...@@ -19,7 +19,7 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat...@@ -19,7 +19,7 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat
19 // Instead of invoking a full-blown `-r` mode on the input which sadly will strip all19 // Instead of invoking a full-blown `-r` mode on the input which sadly will strip all
20 // debug info segments/sections (this is apparently by design by Apple), we copy20 // debug info segments/sections (this is apparently by design by Apple), we copy
21 // the *only* input file over.21 // the *only* input file over.
22 const path = positionals.items[0].path().?;22 const path = positionals.items[0].path();
23 const in_file = path.root_dir.handle.openFile(io, path.sub_path, .{}) catch |err|23 const in_file = path.root_dir.handle.openFile(io, path.sub_path, .{}) catch |err|
24 return diags.fail("failed to open {f}: {s}", .{ path, @errorName(err) });24 return diags.fail("failed to open {f}: {s}", .{ path, @errorName(err) });
25 const stat = in_file.stat(io) catch |err|25 const stat = in_file.stat(io) catch |err|
...@@ -31,7 +31,7 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat...@@ -31,7 +31,7 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat
3131
32 for (positionals.items) |link_input| {32 for (positionals.items) |link_input| {
33 macho_file.classifyInputFile(link_input) catch |err|33 macho_file.classifyInputFile(link_input) catch |err|
34 diags.addParseError(link_input.path().?, "failed to read input file: {s}", .{@errorName(err)});34 diags.addParseError(link_input.path(), "failed to read input file: {t}", .{err});
35 }35 }
3636
37 if (diags.hasErrors()) return error.AlreadyReported;37 if (diags.hasErrors()) return error.AlreadyReported;
...@@ -102,7 +102,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?...@@ -102,7 +102,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
102102
103 for (positionals.items) |link_input| {103 for (positionals.items) |link_input| {
104 macho_file.classifyInputFile(link_input) catch |err|104 macho_file.classifyInputFile(link_input) catch |err|
105 diags.addParseError(link_input.path().?, "failed to read input file: {s}", .{@errorName(err)});105 diags.addParseError(link_input.path(), "failed to read input file: {t}", .{err});
106 }106 }
107107
108 if (diags.hasErrors()) return error.AlreadyReported;108 if (diags.hasErrors()) return error.AlreadyReported;
src/link/Wasm.zig-2
...@@ -3788,7 +3788,6 @@ pub fn loadInput(wasm: *Wasm, input: link.Input) !void {...@@ -3788,7 +3788,6 @@ pub fn loadInput(wasm: *Wasm, input: link.Input) !void {
3788 const argv = &wasm.dump_argv_list;3788 const argv = &wasm.dump_argv_list;
3789 switch (input) {3789 switch (input) {
3790 .res => unreachable,3790 .res => unreachable,
3791 .dso_exact => unreachable,
3792 .dso => unreachable,3791 .dso => unreachable,
3793 .object, .archive => |obj| {3792 .object, .archive => |obj| {
3794 try argv.append(gpa, try obj.path.toString(comp.arena));3793 try argv.append(gpa, try obj.path.toString(comp.arena));
...@@ -3798,7 +3797,6 @@ pub fn loadInput(wasm: *Wasm, input: link.Input) !void {...@@ -3798,7 +3797,6 @@ pub fn loadInput(wasm: *Wasm, input: link.Input) !void {
37983797
3799 switch (input) {3798 switch (input) {
3800 .res => unreachable,3799 .res => unreachable,
3801 .dso_exact => unreachable,
3802 .dso => unreachable,3800 .dso => unreachable,
3803 .object => |obj| try parseObject(wasm, obj),3801 .object => |obj| try parseObject(wasm, obj),
3804 .archive => |obj| try parseArchive(wasm, obj),3802 .archive => |obj| try parseArchive(wasm, obj),
src/main.zig+2-2
...@@ -4277,10 +4277,10 @@ fn createModule(...@@ -4277,10 +4277,10 @@ fn createModule(
4277 &create_module.link_inputs,4277 &create_module.link_inputs,
4278 create_module.lib_directories.items,4278 create_module.lib_directories.items,
4279 color,4279 color,
4280 ) catch |err| fatal("failed to resolve link inputs: {s}", .{@errorName(err)});4280 ) catch |err| fatal("failed to resolve link inputs: {t}", .{err});
42814281
4282 if (!create_module.opts.any_dyn_libs) for (create_module.link_inputs.items) |item| switch (item) {4282 if (!create_module.opts.any_dyn_libs) for (create_module.link_inputs.items) |item| switch (item) {
4283 .dso, .dso_exact => {4283 .dso => {
4284 create_module.opts.any_dyn_libs = true;4284 create_module.opts.any_dyn_libs = true;
4285 break;4285 break;
4286 },4286 },