authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-09-22 02:08:08+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-09-22 02:08:08+02:00
loge3381ce10ee1ffec2ab7b82dd1b87a5aedaeef97
tree7616c3532d4956bfb34b6c168274c68469fcc32e
parent48abf1a34e90acd42501f5296ba6a16c90f60fe9
parent77d47494c7ccbe045b713900b32a85c859f78ed0

Merge pull request 'linker: remove dso_exact, make `-l:` arguments use library search paths' (#36909) from dso-exact-name into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/36909

11 files changed, 239 insertions(+), 148 deletions(-)

src/Compilation.zig+3-2
......@@ -2891,12 +2891,13 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
28912891 }
28922892 }
28932893
2894 for (comp.link_inputs) |input| if (input.path()) |path| {
2894 for (comp.link_inputs) |input| {
2895 const path = input.path();
28952896 try comp.appendFileSystemInput(try .fromUnresolved(arena, comp.dirs, &.{
28962897 path.root_dir.path orelse ".",
28972898 path.sub_path,
28982899 }));
2899 };
2900 }
29002901
29012902 // For compiling Win32 resources, we rely on the cache hash system to avoid duplicating work.
29022903 // Add a Job for each Win32 resource file.
src/link.zig+135-72
......@@ -995,11 +995,7 @@ pub const File = struct {
995995 .{},
996996 ) catch |err| {
997997 const diags = &base.comp.link_diags;
998 return diags.fail("failed to copy '{f}' to '{f}': {t}", .{
999 std.fmt.alt(@as(Path, cached_pp_file_path), .formatEscapeChar),
1000 std.fmt.alt(@as(Path, emit), .formatEscapeChar),
1001 err,
1002 });
998 return diags.fail("failed to copy {qf} to {qf}: {t}", .{ cached_pp_file_path, emit, err });
1003999 };
10041000 return;
10051001 }
......@@ -1510,7 +1506,6 @@ pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void {
15101506 .object => |obj| diags.addParseError(obj.path, "failed to parse object: {t}", .{e}),
15111507 .archive => |obj| diags.addParseError(obj.path, "failed to parse archive: {t}", .{e}),
15121508 .res => |res| diags.addParseError(res.path, "failed to parse Windows resource: {t}", .{e}),
1513 .dso_exact => diags.addError("failed to handle dso_exact: {t}", .{e}),
15141509 },
15151510 };
15161511 prog_node.completeOne();
......@@ -1740,7 +1735,7 @@ pub fn doZcuTask(comp: *Compilation, tid: Zcu.PerThread.Id, task: ZcuTask) void
17401735 if (comp.bin_file) |lf| {
17411736 lf.updateLineNumber(pt, line_update.inst, line_update.line) catch |err| switch (err) {
17421737 error.OutOfMemory => diags.setAllocFailure(),
1743 else => |e| log.err("update line number failed: {s}", .{@errorName(e)}),
1738 else => |e| log.err("update line number failed: {t}", .{e}),
17441739 };
17451740 }
17461741 }
......@@ -1753,7 +1748,7 @@ pub fn doZcuTask(comp: *Compilation, tid: Zcu.PerThread.Id, task: ZcuTask) void
17531748 if (comp.bin_file) |lf| {
17541749 lf.lostTracking(pt, ti) catch |err| switch (err) {
17551750 error.OutOfMemory => diags.setAllocFailure(),
1756 else => |e| log.err("lost tracking failed: {s}", .{@errorName(e)}),
1751 else => |e| log.err("lost tracking failed: {t}", .{e}),
17571752 };
17581753 }
17591754 }
......@@ -1824,13 +1819,14 @@ pub const UnresolvedInput = union(enum) {
18241819 path_query: PathQuery,
18251820 /// Strings that come from GNU ld scripts. Is it a filename? Is it a path?
18261821 /// Who knows! Fuck around and find out.
1827 ambiguous_name: NameQuery,
1828 /// Put exactly this string in the dynamic section, no rpath.
1829 dso_exact: Input.DsoExact,
1822 ambiguous_name: AmbiguousNameQuery,
18301823
18311824 pub const NameQuery = struct {
18321825 name: []const u8,
18331826 query: Query,
1827 // Corresponds to GNU ld `-l :path/to/filename`, meaning that `name` is a path relative to
1828 // the library search path rather than just a library name.
1829 name_done: bool,
18341830 };
18351831
18361832 pub const PathQuery = struct {
......@@ -1838,6 +1834,11 @@ pub const UnresolvedInput = union(enum) {
18381834 query: Query,
18391835 };
18401836
1837 pub const AmbiguousNameQuery = struct {
1838 name: []const u8,
1839 query: Query,
1840 };
1841
18411842 pub const Query = struct {
18421843 needed: bool = false,
18431844 weak: bool = false,
......@@ -1871,7 +1872,6 @@ pub const Input = union(enum) {
18711872 /// May not be a GNU ld script. Those are resolved when converting from
18721873 /// `UnresolvedInput` to `Input` values.
18731874 dso: Dso,
1874 dso_exact: DsoExact,
18751875
18761876 pub const Object = struct {
18771877 path: Path,
......@@ -1891,29 +1891,22 @@ pub const Input = union(enum) {
18911891 needed: bool,
18921892 weak: bool,
18931893 reexport: bool,
1894 };
1894 fallback_soname: FallbackSoname,
18951895
1896 pub const DsoExact = struct {
1897 /// Includes the ":" prefix. This is intended to be put into the DSO
1898 /// section verbatim with no corresponding rpaths.
1899 name: []const u8,
1896 pub const FallbackSoname = enum { basename, full_path };
19001897 };
19011898
1902 /// Returns `null` in the case of `dso_exact`.
1903 pub fn path(input: Input) ?Path {
1899 pub fn path(input: Input) Path {
19041900 return switch (input) {
19051901 .object, .archive => |obj| obj.path,
19061902 inline .res, .dso => |x| x.path,
1907 .dso_exact => null,
19081903 };
19091904 }
19101905
1911 /// Returns `null` in the case of `dso_exact`.
1912 pub fn pathAndFile(input: Input) ?struct { Path, Io.File } {
1906 pub fn pathAndFile(input: Input) struct { Path, Io.File } {
19131907 return switch (input) {
19141908 .object, .archive => |obj| .{ obj.path, obj.file },
19151909 inline .res, .dso => |x| .{ x.path, x.file },
1916 .dso_exact => null,
19171910 };
19181911 }
19191912
......@@ -1921,7 +1914,6 @@ pub const Input = union(enum) {
19211914 return switch (input) {
19221915 .object, .archive => |obj| obj.path.basename(),
19231916 inline .res, .dso => |x| x.path.basename(),
1924 .dso_exact => "dso_exact",
19251917 };
19261918 }
19271919};
......@@ -1952,9 +1944,7 @@ pub fn hashInputs(man: *Cache.Manifest, link_inputs: []const Input) !void {
19521944 man.hash.add(dso.needed);
19531945 man.hash.add(dso.weak);
19541946 man.hash.add(dso.reexport);
1955 },
1956 .dso_exact => |dso_exact| {
1957 man.hash.addBytes(dso_exact.name);
1947 man.hash.add(dso.fallback_soname);
19581948 },
19591949 }
19601950 }
......@@ -2005,7 +1995,7 @@ pub fn resolveInputs(
20051995 .name_query => |name_query| {
20061996 const query = name_query.query;
20071997
2008 // Checked in the first pass above while looking for libc libraries.
1998 // Checked in the first pass in `main.zig` while looking for libc libraries.
20091999 assert(!fs.path.isAbsolute(name_query.name));
20102000
20112001 checked_paths.clearRetainingCapacity();
......@@ -2190,10 +2180,6 @@ pub fn resolveInputs(
21902180 }
21912181 continue;
21922182 },
2193 .dso_exact => |dso_exact| {
2194 try resolved_inputs.append(gpa, .{ .dso_exact = dso_exact });
2195 continue;
2196 },
21972183 }
21982184 comptime unreachable;
21992185 }
......@@ -2201,8 +2187,8 @@ pub fn resolveInputs(
22012187 if (failed_libs.items.len > 0) {
22022188 for (failed_libs.items) |f| {
22032189 const searched_paths = if (f.checked_paths.len == 0) " none" else f.checked_paths;
2204 std.log.err("unable to find {s} system library '{s}' using strategy '{s}'. searched paths:{s}", .{
2205 @tagName(f.preferred_mode), f.name, @tagName(f.strategy), searched_paths,
2190 std.log.err("unable to find {t} system library {q} using strategy {t}. searched paths:{s}", .{
2191 f.preferred_mode, f.name, f.strategy, searched_paths,
22062192 });
22072193 }
22082194 std.process.exit(1);
......@@ -2237,7 +2223,7 @@ fn resolveLibInput(
22372223
22382224 const lib_name = name_query.name;
22392225
2240 if (target.os.tag.isDarwin() and link_mode == .dynamic) tbd: {
2226 if (target.os.tag.isDarwin() and link_mode == .dynamic and !name_query.name_done) tbd: {
22412227 // Prefer .tbd over .dylib.
22422228 const test_path: Path = .{
22432229 .root_dir = lib_directory,
......@@ -2246,17 +2232,27 @@ fn resolveLibInput(
22462232 try checked_paths.print(gpa, "\n {f}", .{test_path});
22472233 var file = test_path.root_dir.handle.openFile(io, test_path.sub_path, .{}) catch |err| switch (err) {
22482234 error.FileNotFound => break :tbd,
2249 else => |e| fatal("unable to search for tbd library '{f}': {s}", .{ test_path, @errorName(e) }),
2235 else => |e| fatal("searching for tbd library {qf}: {t}", .{ test_path, e }),
22502236 };
22512237 errdefer file.close(io);
2252 return finishResolveLibInput(io, resolved_inputs, archive_dedup, test_path, file, link_mode, name_query.query);
2238 return finishResolveLibInput(
2239 io,
2240 resolved_inputs,
2241 archive_dedup,
2242 test_path,
2243 file,
2244 link_mode,
2245 name_query.query,
2246 .basename,
2247 );
22532248 }
22542249
22552250 {
22562251 const test_path: Path = .{
22572252 .root_dir = lib_directory,
2258 .sub_path = try std.fmt.allocPrint(arena, "{s}{s}{s}", .{
2259 target.libPrefix(), lib_name,
2253 .sub_path = if (name_query.name_done) lib_name else try std.fmt.allocPrint(arena, "{s}{s}{s}", .{
2254 target.libPrefix(),
2255 lib_name,
22602256 switch (link_mode) {
22612257 .static => target.staticLibSuffix(),
22622258 .dynamic => target.dynamicLibSuffix(),
......@@ -2267,7 +2263,7 @@ fn resolveLibInput(
22672263 switch (try resolvePathInputLib(gpa, arena, io, unresolved_inputs, resolved_inputs, ld_script_bytes, archive_dedup, target, .{
22682264 .path = test_path,
22692265 .query = name_query.query,
2270 }, link_mode, color)) {
2266 }, link_mode, color, .basename)) {
22712267 .no_match => {},
22722268 .ok => return .ok,
22732269 }
......@@ -2275,7 +2271,7 @@ fn resolveLibInput(
22752271
22762272 // In the case of Darwin, the main check will be .dylib, so here we
22772273 // additionally check for .so files.
2278 if (target.os.tag.isDarwin() and link_mode == .dynamic) so: {
2274 if (target.os.tag.isDarwin() and link_mode == .dynamic and !name_query.name_done) so: {
22792275 const test_path: Path = .{
22802276 .root_dir = lib_directory,
22812277 .sub_path = try std.fmt.allocPrint(arena, "lib{s}.so", .{lib_name}),
......@@ -2283,17 +2279,24 @@ fn resolveLibInput(
22832279 try checked_paths.print(gpa, "\n {f}", .{test_path});
22842280 var file = test_path.root_dir.handle.openFile(io, test_path.sub_path, .{}) catch |err| switch (err) {
22852281 error.FileNotFound => break :so,
2286 else => |e| fatal("unable to search for so library '{f}': {s}", .{
2287 test_path, @errorName(e),
2288 }),
2282 else => |e| fatal("unable to search for so library {qf}: {t}", .{ test_path, e }),
22892283 };
22902284 errdefer file.close(io);
2291 return finishResolveLibInput(io, resolved_inputs, archive_dedup, test_path, file, link_mode, name_query.query);
2285 return finishResolveLibInput(
2286 io,
2287 resolved_inputs,
2288 archive_dedup,
2289 test_path,
2290 file,
2291 link_mode,
2292 name_query.query,
2293 .basename,
2294 );
22922295 }
22932296
22942297 // In the case of MinGW, the main check will be .lib but we also need to
22952298 // look for `libfoo.a`.
2296 if (target.isMinGW() and link_mode == .static) mingw: {
2299 if (target.isMinGW() and link_mode == .static and !name_query.name_done) mingw: {
22972300 const test_path: Path = .{
22982301 .root_dir = lib_directory,
22992302 .sub_path = try std.fmt.allocPrint(arena, "lib{s}.a", .{lib_name}),
......@@ -2301,21 +2304,32 @@ fn resolveLibInput(
23012304 try checked_paths.print(gpa, "\n {f}", .{test_path});
23022305 var file = test_path.root_dir.handle.openFile(io, test_path.sub_path, .{}) catch |err| switch (err) {
23032306 error.FileNotFound => break :mingw,
2304 else => |e| fatal("unable to search for static library '{f}': {s}", .{ test_path, @errorName(e) }),
2307 else => |e| fatal("unable to search for static library {qf}: {t}", .{ test_path, e }),
23052308 };
23062309 errdefer file.close(io);
2307 return finishResolveLibInput(io, resolved_inputs, archive_dedup, test_path, file, link_mode, name_query.query);
2310 return finishResolveLibInput(
2311 io,
2312 resolved_inputs,
2313 archive_dedup,
2314 test_path,
2315 file,
2316 link_mode,
2317 name_query.query,
2318 .basename,
2319 );
23082320 }
23092321
23102322 // In the case of OpenBSD, dynamic libraries are always versioned, without
23112323 // unversioned symlinks. OpenBSD patches LLD to select the highest-versioned
23122324 // shared library, and this code is intended to match that upstream behavior.
2313 if (target.isOpenBSDLibC() and link_mode == .dynamic) versioned: {
2325 if (target.isOpenBSDLibC() and link_mode == .dynamic and !name_query.name_done) versioned: {
23142326 const prefix = try std.fmt.allocPrint(arena, "lib{s}.so.", .{lib_name});
23152327
23162328 var dir = lib_directory.handle.openDir(io, ".", .{ .iterate = true }) catch |err| switch (err) {
23172329 error.NotDir, error.FileNotFound => break :versioned,
2318 else => |e| fatal("unable to search for shared library '{s}.*': {s}", .{ prefix, @errorName(e) }),
2330 else => |e| fatal("unable to search for shared library \"{f}.*\": {t}", .{
2331 std.zig.fmtString(prefix), e,
2332 }),
23192333 };
23202334 defer dir.close(io);
23212335
......@@ -2325,7 +2339,7 @@ fn resolveLibInput(
23252339
23262340 var iter = dir.iterate();
23272341 while (iter.next(io) catch |err| {
2328 fatal("unable to scan library directory '{s}'", .{@errorName(err)});
2342 fatal("scanning library directory: {t}", .{err});
23292343 }) |entry| {
23302344 if (entry.kind != .file) continue;
23312345 if (!std.mem.startsWith(u8, entry.name, prefix)) continue;
......@@ -2354,7 +2368,7 @@ fn resolveLibInput(
23542368 switch (try resolvePathInputLib(gpa, arena, io, unresolved_inputs, resolved_inputs, ld_script_bytes, archive_dedup, target, .{
23552369 .path = test_path,
23562370 .query = name_query.query,
2357 }, link_mode, color)) {
2371 }, link_mode, color, .basename)) {
23582372 .no_match => {},
23592373 .ok => return .ok,
23602374 }
......@@ -2395,6 +2409,7 @@ fn finishResolveLibInput(
23952409 file: Io.File,
23962410 link_mode: std.lang.LinkMode,
23972411 query: UnresolvedInput.Query,
2412 fallback_soname: Input.Dso.FallbackSoname,
23982413) ResolveLibInputResult {
23992414 switch (link_mode) {
24002415 .static => {
......@@ -2413,13 +2428,16 @@ fn finishResolveLibInput(
24132428 .hidden = query.hidden,
24142429 } });
24152430 },
2416 .dynamic => resolved_inputs.appendAssumeCapacity(.{ .dso = .{
2417 .path = path,
2418 .file = file,
2419 .needed = query.needed,
2420 .weak = query.weak,
2421 .reexport = query.reexport,
2422 } }),
2431 .dynamic => resolved_inputs.appendAssumeCapacity(.{
2432 .dso = .{
2433 .path = path,
2434 .file = file,
2435 .needed = query.needed,
2436 .weak = query.weak,
2437 .reexport = query.reexport,
2438 .fallback_soname = fallback_soname,
2439 },
2440 }),
24232441 }
24242442 return .ok;
24252443}
......@@ -2441,11 +2459,37 @@ fn resolvePathInput(
24412459 color: std.zig.Color,
24422460) Allocator.Error!?ResolveLibInputResult {
24432461 switch (Compilation.classifyFileExt(pq.path.sub_path)) {
2444 .static_library => return try resolvePathInputLib(gpa, arena, io, unresolved_inputs, resolved_inputs, ld_script_bytes, archive_dedup, target, pq, .static, color),
2445 .shared_library => return try resolvePathInputLib(gpa, arena, io, unresolved_inputs, resolved_inputs, ld_script_bytes, archive_dedup, target, pq, .dynamic, color),
2462 .static_library => return try resolvePathInputLib(
2463 gpa,
2464 arena,
2465 io,
2466 unresolved_inputs,
2467 resolved_inputs,
2468 ld_script_bytes,
2469 archive_dedup,
2470 target,
2471 pq,
2472 .static,
2473 color,
2474 .full_path,
2475 ),
2476 .shared_library => return try resolvePathInputLib(
2477 gpa,
2478 arena,
2479 io,
2480 unresolved_inputs,
2481 resolved_inputs,
2482 ld_script_bytes,
2483 archive_dedup,
2484 target,
2485 pq,
2486 .dynamic,
2487 color,
2488 .full_path,
2489 ),
24462490 .object => {
24472491 var file = pq.path.root_dir.handle.openFile(io, pq.path.sub_path, .{}) catch |err|
2448 fatal("failed to open object {f}: {s}", .{ pq.path, @errorName(err) });
2492 fatal("failed to open object {f}: {t}", .{ pq.path, err });
24492493 errdefer file.close(io);
24502494 try resolved_inputs.append(gpa, .{ .object = .{
24512495 .path = pq.path,
......@@ -2457,7 +2501,7 @@ fn resolvePathInput(
24572501 },
24582502 .res => {
24592503 var file = pq.path.root_dir.handle.openFile(io, pq.path.sub_path, .{}) catch |err|
2460 fatal("failed to open windows resource {f}: {s}", .{ pq.path, @errorName(err) });
2504 fatal("failed to open windows resource {f}: {t}", .{ pq.path, err });
24612505 errdefer file.close(io);
24622506 try resolved_inputs.append(gpa, .{ .res = .{
24632507 .path = pq.path,
......@@ -2485,6 +2529,7 @@ fn resolvePathInputLib(
24852529 pq: UnresolvedInput.PathQuery,
24862530 link_mode: std.lang.LinkMode,
24872531 color: std.zig.Color,
2532 fallback_soname: Input.Dso.FallbackSoname,
24882533) Allocator.Error!ResolveLibInputResult {
24892534 try resolved_inputs.ensureUnusedCapacity(gpa, 1);
24902535 try archive_dedup.ensureUnusedCapacity(gpa, 1);
......@@ -2498,21 +2543,30 @@ fn resolvePathInputLib(
24982543 }) {
24992544 var file = test_path.root_dir.handle.openFile(io, test_path.sub_path, .{}) catch |err| switch (err) {
25002545 error.FileNotFound => return .no_match,
2501 else => |e| fatal("unable to search for {t} library '{f}': {t}", .{
2546 else => |e| fatal("unable to search for {t} library {qf}: {t}", .{
25022547 link_mode, std.fmt.alt(test_path, .formatEscapeChar), e,
25032548 }),
25042549 };
25052550 errdefer file.close(io);
25062551 try ld_script_bytes.resize(gpa, @max(std.elf.MAGIC.len, std.elf.ARMAG.len));
25072552 const n = file.readPositionalAll(io, ld_script_bytes.items, 0) catch |err|
2508 fatal("failed to read '{f}': {t}", .{ std.fmt.alt(test_path, .formatEscapeChar), err });
2553 fatal("failed to read {qf}: {t}", .{ test_path, err });
25092554 const buf = ld_script_bytes.items[0..n];
25102555 if (mem.startsWith(u8, buf, std.elf.MAGIC) or
25112556 mem.startsWith(u8, buf, std.elf.ARMAG) or
25122557 mem.startsWith(u8, buf, std.elf.ARMAG_THIN))
25132558 {
25142559 // Appears to be an ELF or archive file.
2515 return finishResolveLibInput(io, resolved_inputs, archive_dedup, test_path, file, link_mode, pq.query);
2560 return finishResolveLibInput(
2561 io,
2562 resolved_inputs,
2563 archive_dedup,
2564 test_path,
2565 file,
2566 link_mode,
2567 pq.query,
2568 fallback_soname,
2569 );
25162570 }
25172571 const stat = file.stat(io) catch |err|
25182572 fatal("failed to stat {f}: {t}", .{ test_path, err });
......@@ -2563,6 +2617,7 @@ fn resolvePathInputLib(
25632617 unresolved_inputs.appendAssumeCapacity(.{ .name_query = .{
25642618 .name = try arena.dupe(u8, arg.path["-l".len..]),
25652619 .query = query,
2620 .name_done = false,
25662621 } });
25672622 } else {
25682623 unresolved_inputs.appendAssumeCapacity(.{ .ambiguous_name = .{
......@@ -2577,12 +2632,19 @@ fn resolvePathInputLib(
25772632
25782633 var file = test_path.root_dir.handle.openFile(io, test_path.sub_path, .{}) catch |err| switch (err) {
25792634 error.FileNotFound => return .no_match,
2580 else => |e| fatal("unable to search for {s} library {f}: {s}", .{
2581 @tagName(link_mode), test_path, @errorName(e),
2582 }),
2635 else => |e| fatal("unable to search for {t} library {f}: {t}", .{ link_mode, test_path, e }),
25832636 };
25842637 errdefer file.close(io);
2585 return finishResolveLibInput(io, resolved_inputs, archive_dedup, test_path, file, link_mode, pq.query);
2638 return finishResolveLibInput(
2639 io,
2640 resolved_inputs,
2641 archive_dedup,
2642 test_path,
2643 file,
2644 link_mode,
2645 pq.query,
2646 fallback_soname,
2647 );
25862648}
25872649
25882650pub fn openObject(io: Io, path: Path, must_link: bool, hidden: bool) !Input.Object {
......@@ -2605,6 +2667,7 @@ pub fn openDso(io: Io, path: Path, needed: bool, weak: bool, reexport: bool) !In
26052667 .needed = needed,
26062668 .weak = weak,
26072669 .reexport = reexport,
2670 .fallback_soname = .full_path,
26082671 };
26092672}
26102673
......@@ -2636,7 +2699,7 @@ pub fn anyObjectInputs(inputs: []const Input) bool {
26362699pub fn countObjectInputs(inputs: []const Input) usize {
26372700 var count: usize = 0;
26382701 for (inputs) |input| switch (input) {
2639 .dso, .dso_exact => continue,
2702 .dso => continue,
26402703 .res, .object, .archive => count += 1,
26412704 };
26422705 return count;
......@@ -2646,7 +2709,7 @@ pub fn countObjectInputs(inputs: []const Input) usize {
26462709pub fn firstObjectInput(inputs: []const Input) ?Input.Object {
26472710 for (inputs) |input| switch (input) {
26482711 .object, .archive => |obj| return obj,
2649 .res, .dso, .dso_exact => continue,
2712 .res, .dso => continue,
26502713 };
26512714 return null;
26522715}
src/link/Coff.zig+1-2
......@@ -3905,7 +3905,7 @@ pub fn loadInput(coff: *Coff, input: link.Input) link.Error!void {
39053905 const comp = coff.base.comp;
39063906 const io = comp.io;
39073907
3908 const path = input.path() orelse unreachable;
3908 const path = input.path();
39093909 const gop = try coff.inputs.getOrPut(comp.gpa, path);
39103910 if (gop.found_existing) return;
39113911 errdefer _ = coff.inputs.swapRemove(path);
......@@ -3935,7 +3935,6 @@ pub fn loadInput(coff: *Coff, input: link.Input) link.Error!void {
39353935 coff.loadDll(dso.path, &fr) catch |err|
39363936 return coff.failLoadInput(err, &fr, dso.path);
39373937 },
3938 .dso_exact => unreachable,
39393938 }
39403939}
39413940
src/link/Elf.zig+9-4
......@@ -722,7 +722,6 @@ pub fn loadInput(self: *Elf, input: link.Input) !void {
722722 const argv = &self.dump_argv_list;
723723 switch (input) {
724724 .res => unreachable,
725 .dso_exact => |dso_exact| try argv.appendSlice(gpa, &.{ "-l", dso_exact.name }),
726725 .object, .archive => |obj| try argv.append(gpa, try obj.path.toString(comp.arena)),
727726 .dso => |dso| try argv.append(gpa, try dso.path.toString(comp.arena)),
728727 }
......@@ -730,14 +729,13 @@ pub fn loadInput(self: *Elf, input: link.Input) !void {
730729
731730 switch (input) {
732731 .res => unreachable,
733 .dso_exact => @panic("TODO"),
734732 .object => |obj| try parseObject(self, obj),
735733 .archive => |obj| if (self.base.isStaticLib()) {
736734 // Ignore static library inputs when generating a static library.
737735 } else {
738736 try parseArchive(gpa, io, diags, &self.file_handles, &self.files, target, debug_fmt_strip, default_sym_version, &self.objects, obj);
739737 },
740 .dso => |dso| try parseDso(gpa, io, diags, dso, &self.shared_objects, &self.files, target),
738 .dso => |dso| try parseDso(gpa, comp.arena, io, diags, dso, &self.shared_objects, &self.files, target),
741739 }
742740}
743741
......@@ -1108,6 +1106,7 @@ fn parseArchive(
11081106
11091107fn parseDso(
11101108 gpa: Allocator,
1109 arena: Allocator,
11111110 io: Io,
11121111 diags: *Diags,
11131112 dso: link.Input.Dso,
......@@ -1124,7 +1123,12 @@ fn parseDso(
11241123 var header = try SharedObject.parseHeader(gpa, io, diags, dso.path, handle, stat, target);
11251124 defer header.deinit(gpa);
11261125
1127 const soname = header.soname() orelse dso.path.basename();
1126 const fallback_soname: []const u8 = switch (dso.fallback_soname) {
1127 .full_path => try dso.path.toString(arena),
1128 .basename => fs.path.basename(dso.path.sub_path),
1129 };
1130
1131 const soname = header.soname() orelse fallback_soname;
11281132
11291133 const gop = try shared_objects.getOrPut(gpa, soname);
11301134 if (gop.found_existing) return;
......@@ -1156,6 +1160,7 @@ fn parseDso(
11561160 .symbols_extra = .empty,
11571161 .symbols_resolver = .empty,
11581162 .output_symtab_ctx = .{},
1163 .fallback_soname = fallback_soname,
11591164 },
11601165 });
11611166 const so = fileLookup(files.*, index, null).?.shared_object;
src/link/Elf/SharedObject.zig+3-1
......@@ -31,6 +31,8 @@ alive: bool,
3131
3232output_symtab_ctx: Elf.SymtabCtx,
3333
34fallback_soname: []const u8,
35
3436pub fn deinit(so: *SharedObject, gpa: Allocator) void {
3537 gpa.free(so.path.sub_path);
3638 so.parsed.deinit(gpa);
......@@ -427,7 +429,7 @@ pub fn asFile(self: *SharedObject) File {
427429}
428430
429431pub fn soname(self: *SharedObject) []const u8 {
430 return self.parsed.soname() orelse self.path.basename();
432 return self.parsed.soname() orelse self.fallback_soname;
431433}
432434
433435pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void {
src/link/Elf2.zig+15-22
......@@ -6230,34 +6230,19 @@ fn loadInputInner(elf: *Elf, input: link.Input) (Error || error{BadMagic})!void
62306230 .dso => |dso| {
62316231 try elf.needed.ensureUnusedCapacity(elf.base.comp.gpa, 1);
62326232 var fr = dso.file.reader(io, &buf);
6233 elf.loadDso(dso.path, &fr) catch |err| switch (err) {
6233 elf.loadDso(dso.path, dso.fallback_soname, &fr) catch |err| switch (err) {
62346234 else => |e| return e,
6235 error.EndOfStream => return diags.failParse(
6236 dso.path,
6237 "unexpected eof",
6238 .{},
6239 ),
6235 error.EndOfStream => return diags.failParse(dso.path, "unexpected eof", .{}),
62406236 error.AccessDenied, error.Unexpected, error.Unseekable => |e| return diags.fail(
6241 "failed to read \"{f}\": {t}",
6242 .{ dso.path.fmtEscapeString(), e },
6237 "failed to read {qf}: {t}",
6238 .{ dso.path, e },
62436239 ),
62446240 error.ReadFailed => switch (fr.err.?) {
62456241 error.Canceled => |e| return e,
6246 else => |e| return diags.fail(
6247 "failed to read \"{f}\": {t}",
6248 .{ dso.path.fmtEscapeString(), e },
6249 ),
6242 else => |e| return diags.fail("failed to read {qf}: {t}", .{ dso.path, e }),
62506243 },
62516244 };
62526245 },
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 },
62616246 }
62626247}
62636248fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (LoadParseInputError || error{BadMagic})!void {
......@@ -6867,7 +6852,12 @@ fn populateArchiveMemberName(elf: *Elf, member_ar_hdr: *std.elf.ar_hdr, member_n
68676852 @memcpy(dest_slice[0 .. dest_slice.len - 2], member_name);
68686853 @memcpy(dest_slice[dest_slice.len - 2 ..], "/\n"); // yes, the terminator is weird
68696854}
6870fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (LoadParseInputError || error{BadMagic})!void {
6855fn loadDso(
6856 elf: *Elf,
6857 path: std.Build.Cache.Path,
6858 fallback_soname: link.Input.Dso.FallbackSoname,
6859 fr: *Io.File.Reader,
6860) (LoadParseInputError || error{BadMagic})!void {
68716861 const comp = elf.base.comp;
68726862 const gpa = comp.gpa;
68736863 const diags = &comp.link_diags;
......@@ -6963,7 +6953,10 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (LoadPars
69636953 }
69646954 break std.mem.sliceTo(dynstr[@intCast(val)..], 0);
69656955 }
6966 } else std.fs.path.basename(path.sub_path);
6956 } else switch (fallback_soname) {
6957 .basename => std.fs.path.basename(path.sub_path),
6958 .full_path => try path.toString(comp.arena),
6959 };
69676960 try elf.needed.put(gpa, try elf.string(.dynstr, soname), {});
69686961
69696962 // Scan the symbol table and populate `elf.dso_globals`.
src/link/Lld.zig+21-14
......@@ -309,9 +309,9 @@ fn linkAsArchive(lld: *Lld, arena: Allocator) link.Error!void {
309309
310310 try object_files.ensureUnusedCapacity(arena, comp.link_inputs.len);
311311 for (comp.link_inputs) |input| switch (input) {
312 .dso, .dso_exact, .archive => {}, // static archives should not contain shared libraries or other static archives
312 .dso, .archive => {}, // static archives should not contain shared libraries or other static archives
313313 .res, .object => {
314 const path = try input.path().?.toStringZ(arena);
314 const path = try input.path().toStringZ(arena);
315315 object_files.appendAssumeCapacity(path);
316316 },
317317 };
......@@ -551,7 +551,6 @@ fn coffLink(lld: *Lld, arena: Allocator) !void {
551551
552552 try argv.ensureUnusedCapacity(comp.link_inputs.len);
553553 for (comp.link_inputs) |link_input| switch (link_input) {
554 .dso_exact => unreachable, // not applicable to PE/COFF
555554 inline .dso, .res => |x| {
556555 argv.appendAssumeCapacity(try x.path.toString(arena));
557556 },
......@@ -1114,10 +1113,6 @@ fn elfLink(lld: *Lld, arena: Allocator) !void {
11141113 }
11151114 try argv.append(try obj.path.toString(arena));
11161115 },
1117 .dso_exact => |dso_exact| {
1118 assert(dso_exact.name[0] == ':');
1119 try argv.appendSlice(&.{ "-l", dso_exact.name });
1120 },
11211116 };
11221117
11231118 if (whole_archive) {
......@@ -1159,9 +1154,16 @@ fn elfLink(lld: *Lld, arena: Allocator) !void {
11591154 argv.appendAssumeCapacity("--as-needed");
11601155 var as_needed = true;
11611156
1157 // When we have a DSO input, in order to trick LLD into putting the basename in its
1158 // `DT_NEEDED` entry while still allowing us to tell it the exact path to the shared
1159 // object, we pass it on the CLI as "-l:/absolute/path/to/libfoo.so". This will treat
1160 // the given path not actually as an absolute path, but as relative to the library
1161 // search path, so the root directory must therefore be the only library search path.
1162 try argv.append("-L/");
1163
11621164 for (base.comp.link_inputs) |link_input| switch (link_input) {
11631165 .res => unreachable, // Windows-only
1164 .object, .archive, .dso_exact => continue,
1166 .object, .archive => continue,
11651167 .dso => |dso| {
11661168 const lib_as_needed = !dso.needed;
11671169 switch ((@as(u2, @intFromBool(lib_as_needed)) << 1) | @intFromBool(as_needed)) {
......@@ -1176,11 +1178,17 @@ fn elfLink(lld: *Lld, arena: Allocator) !void {
11761178 },
11771179 }
11781180
1179 // By this time, we depend on these libs being dynamically linked
1180 // libraries and not static libraries (the check for that needs to be earlier),
1181 // but they could be full paths to .so files, in which case we
1182 // want to avoid prepending "-l".
1183 argv.appendAssumeCapacity(try dso.path.toString(arena));
1181 // By this time, we depend on these libs being dynamically linked libraries and
1182 // not static libraries (the check for that needs to be earlier), but they could
1183 // be full file paths, in which case we don't want to use the "-l:" strategy.
1184 switch (dso.fallback_soname) {
1185 .basename => try argv.append(try arena.print("-l:{s}", .{try fs.path.resolve(arena, &.{
1186 comp.dirs.cwd,
1187 dso.path.root_dir.path orelse ".",
1188 dso.path.sub_path,
1189 })})),
1190 .full_path => try argv.append(try dso.path.toString(arena)),
1191 }
11841192 },
11851193 };
11861194
......@@ -1588,7 +1596,6 @@ fn wasmLink(lld: *Lld, arena: Allocator) !void {
15881596 .dso => |dso| {
15891597 try argv.append(try dso.path.toString(arena));
15901598 },
1591 .dso_exact => unreachable,
15921599 .res => unreachable,
15931600 };
15941601 if (whole_archive) {
src/link/MachO.zig+13-13
......@@ -372,7 +372,6 @@ pub fn flush(
372372 for (comp.link_inputs) |link_input| switch (link_input) {
373373 .dso => continue, // handled below
374374 .object, .archive => positionals.appendAssumeCapacity(link_input),
375 .dso_exact => @panic("TODO"),
376375 .res => unreachable,
377376 };
378377
......@@ -406,7 +405,7 @@ pub fn flush(
406405
407406 for (positionals.items) |link_input| {
408407 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});
410409 }
411410
412411 var system_libs = std.array_list.Managed(SystemLib).init(gpa);
......@@ -447,11 +446,11 @@ pub fn flush(
447446 };
448447
449448 for (comp.link_inputs) |link_input| switch (link_input) {
450 .object, .archive, .dso_exact => continue,
449 .object, .archive => continue,
451450 .res => unreachable,
452451 .dso => {
453452 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});
455454 },
456455 };
457456
......@@ -655,8 +654,9 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
655654 for (comp.link_inputs) |link_input| switch (link_input) {
656655 .object, .archive => |obj| try argv.append(try obj.path.toString(arena)),
657656 .res => |res| try argv.append(try res.path.toString(arena)),
658 .dso => |dso| try argv.append(try dso.path.toString(arena)),
659 .dso_exact => |dso_exact| try argv.appendSlice(&.{ "-l", dso_exact.name }),
657 .dso => |dso| {
658 try argv.append(try dso.path.toString(arena));
659 },
660660 };
661661
662662 for (comp.c_objects.items) |c_object| {
......@@ -748,7 +748,6 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
748748 if (obj.must_link) try argv.append("-force_load"); // TODO: verify this
749749 try argv.append(try obj.path.toString(arena));
750750 },
751 .dso_exact => |dso_exact| try argv.appendSlice(&.{ "-l", dso_exact.name }),
752751 };
753752
754753 for (comp.c_objects.items) |c_object| {
......@@ -775,16 +774,18 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
775774 }
776775
777776 for (comp.link_inputs) |link_input| switch (link_input) {
778 .object, .archive, .dso_exact => continue, // handled above
777 .object, .archive => continue, // handled above
779778 .res => unreachable, // windows only
780779 .dso => |dso| {
780 try argv.ensureUnusedCapacity(2);
781781 if (dso.needed) {
782 try argv.appendSlice(&.{ "-needed-l", try dso.path.toString(arena) });
782 argv.appendAssumeCapacity("-needed-l");
783783 } else if (dso.weak) {
784 try argv.appendSlice(&.{ "-weak-l", try dso.path.toString(arena) });
784 argv.appendAssumeCapacity("-weak-l");
785785 } else {
786 try argv.appendSlice(&.{ "-l", try dso.path.toString(arena) });
786 argv.appendAssumeCapacity("-l");
787787 }
788 argv.appendAssumeCapacity(try dso.path.toString(arena));
788789 },
789790 };
790791
......@@ -870,7 +871,7 @@ pub fn classifyInputFile(self: *MachO, input: link.Input) !void {
870871 const comp = self.base.comp;
871872 const io = comp.io;
872873
873 const path, const file = input.pathAndFile().?;
874 const path, const file = input.pathAndFile();
874875 // TODO don't classify now, it's too late. The input file has already been classified
875876 log.debug("classifying input file {f}", .{path});
876877
......@@ -4478,7 +4479,6 @@ const SystemLib = struct {
44784479
44794480 fn fromLinkInput(link_input: link.Input) SystemLib {
44804481 return switch (link_input) {
4481 .dso_exact => unreachable,
44824482 .res => unreachable,
44834483 .object, .archive => |obj| .{
44844484 .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
1919 // Instead of invoking a full-blown `-r` mode on the input which sadly will strip all
2020 // debug info segments/sections (this is apparently by design by Apple), we copy
2121 // the *only* input file over.
22 const path = positionals.items[0].path().?;
22 const path = positionals.items[0].path();
2323 const in_file = path.root_dir.handle.openFile(io, path.sub_path, .{}) catch |err|
2424 return diags.fail("failed to open {f}: {s}", .{ path, @errorName(err) });
2525 const stat = in_file.stat(io) catch |err|
......@@ -31,7 +31,7 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation, module_obj_path: ?Pat
3131
3232 for (positionals.items) |link_input| {
3333 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});
3535 }
3636
3737 if (diags.hasErrors()) return error.AlreadyReported;
......@@ -102,7 +102,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ?
102102
103103 for (positionals.items) |link_input| {
104104 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});
106106 }
107107
108108 if (diags.hasErrors()) return error.AlreadyReported;
src/link/Wasm.zig-2
......@@ -3788,7 +3788,6 @@ pub fn loadInput(wasm: *Wasm, input: link.Input) !void {
37883788 const argv = &wasm.dump_argv_list;
37893789 switch (input) {
37903790 .res => unreachable,
3791 .dso_exact => unreachable,
37923791 .dso => unreachable,
37933792 .object, .archive => |obj| {
37943793 try argv.append(gpa, try obj.path.toString(comp.arena));
......@@ -3798,7 +3797,6 @@ pub fn loadInput(wasm: *Wasm, input: link.Input) !void {
37983797
37993798 switch (input) {
38003799 .res => unreachable,
3801 .dso_exact => unreachable,
38023800 .dso => unreachable,
38033801 .object => |obj| try parseObject(wasm, obj),
38043802 .archive => |obj| try parseArchive(wasm, obj),
src/main.zig+36-13
......@@ -70,10 +70,6 @@ var stdin_buffer: [4096]u8 align(std.heap.page_size_min) = undefined;
7070/// This can be global since stdout is a singleton.
7171var stdout_buffer: [4096]u8 align(std.heap.page_size_min) = undefined;
7272
73/// Shaming all the locations that inappropriately use an O(N) search algorithm.
74/// Please delete this and fix the compilation errors!
75pub const @"bad O(N)" = void;
76
7773const normal_usage =
7874 \\Usage: zig [command] [options]
7975 \\
......@@ -807,7 +803,7 @@ const compile_usage =
807803 \\ --verbose-llvm-cpu-features Enable compiler debug output for LLVM CPU features
808804 \\ --debug-log [scope] Enable printing debug/info log messages for scope
809805 \\ --debug-compile-errors Crash with helpful diagnostics at the first compile error
810 \\ --debug-link-snapshot Enable dumping of the linker's state in JSON format
806 \\ --debug-link-snapshot Dump linker state and output file information for troubleshooting
811807 \\ --debug-rt[=mode] Build compiler runtime libraries with [mode] optimization
812808 \\ (debug if [=mode] is omitted)
813809 \\ --debug-incremental Enable incremental compilation debug features
......@@ -1355,6 +1351,7 @@ fn buildOutputType(
13551351 .search_strategy = lib_search_strategy,
13561352 .allow_so_scripts = allow_so_scripts,
13571353 },
1354 .name_done = false,
13581355 } });
13591356 } else if (mem.eql(u8, arg, "--needed-library") or
13601357 mem.eql(u8, arg, "-needed-l") or
......@@ -1370,6 +1367,7 @@ fn buildOutputType(
13701367 .search_strategy = lib_search_strategy,
13711368 .allow_so_scripts = allow_so_scripts,
13721369 },
1370 .name_done = false,
13731371 } });
13741372 } else if (mem.eql(u8, arg, "-weak_library") or mem.eql(u8, arg, "-weak-l")) {
13751373 try create_module.cli_link_inputs.append(arena, .{ .name_query = .{
......@@ -1381,6 +1379,7 @@ fn buildOutputType(
13811379 .search_strategy = lib_search_strategy,
13821380 .allow_so_scripts = allow_so_scripts,
13831381 },
1382 .name_done = false,
13841383 } });
13851384 } else if (mem.eql(u8, arg, "-D")) {
13861385 try cc_argv.appendSlice(arena, &.{ arg, args_iter.nextOrFatal() });
......@@ -1843,6 +1842,7 @@ fn buildOutputType(
18431842 .search_strategy = lib_search_strategy,
18441843 .allow_so_scripts = allow_so_scripts,
18451844 },
1845 .name_done = false,
18461846 } });
18471847 } else if (mem.cutPrefix(u8, arg, "-needed-l")) |name| {
18481848 try create_module.cli_link_inputs.append(arena, .{ .name_query = .{
......@@ -1854,6 +1854,7 @@ fn buildOutputType(
18541854 .search_strategy = lib_search_strategy,
18551855 .allow_so_scripts = allow_so_scripts,
18561856 },
1857 .name_done = false,
18571858 } });
18581859 } else if (mem.cutPrefix(u8, arg, "-weak-l")) |name| {
18591860 try create_module.cli_link_inputs.append(arena, .{ .name_query = .{
......@@ -1865,6 +1866,7 @@ fn buildOutputType(
18651866 .search_strategy = lib_search_strategy,
18661867 .allow_so_scripts = allow_so_scripts,
18671868 },
1869 .name_done = false,
18681870 } });
18691871 } else if (mem.startsWith(u8, arg, "-D")) {
18701872 try cc_argv.append(arena, arg);
......@@ -2083,12 +2085,24 @@ fn buildOutputType(
20832085 // We don't know whether this library is part of libc or libc++ until
20842086 // we resolve the target, so we simply append to the list for now.
20852087 if (mem.startsWith(u8, it.only_arg, ":")) {
2086 // -l :path/to/filename is used when callers need
2087 // more control over what's in the resulting
2088 // binary: no extra rpaths and DSO filename exactly
2089 // as provided. CGo compilation depends on this.
2090 try create_module.cli_link_inputs.append(arena, .{ .dso_exact = .{
2091 .name = it.only_arg,
2088 // -l :path/to/filename indicates:
2089 // * No extra rpaths.
2090 // * NEEDED entry should be exactly the string
2091 // after the colon. No file system paths prepended.
2092 // * The DSO still must be found at compile/link
2093 // time and its entries used to resolve symbols.
2094 // CGo compilation depends on this.
2095 try create_module.cli_link_inputs.append(arena, .{ .name_query = .{
2096 .name = it.only_arg[1..],
2097 .query = .{
2098 .must_link = must_link,
2099 .needed = needed,
2100 .weak = false,
2101 .preferred_mode = lib_preferred_mode,
2102 .search_strategy = lib_search_strategy,
2103 .allow_so_scripts = allow_so_scripts,
2104 },
2105 .name_done = true,
20922106 } });
20932107 } else {
20942108 const compiler_rt_classification = target_util.classifyCompilerRtLibName(it.only_arg);
......@@ -2114,6 +2128,7 @@ fn buildOutputType(
21142128 .search_strategy = lib_search_strategy,
21152129 .allow_so_scripts = allow_so_scripts,
21162130 },
2131 .name_done = false,
21172132 } });
21182133 }
21192134 }
......@@ -2544,6 +2559,7 @@ fn buildOutputType(
25442559 .search_strategy = lib_search_strategy,
25452560 .allow_so_scripts = allow_so_scripts,
25462561 },
2562 .name_done = false,
25472563 } }),
25482564 .weak_framework => try create_module.frameworks.put(arena, it.only_arg, .{ .weak = true }),
25492565 .headerpad_max_install_names => headerpad_max_install_names = true,
......@@ -2913,6 +2929,7 @@ fn buildOutputType(
29132929 .search_strategy = lib_search_strategy,
29142930 .allow_so_scripts = allow_so_scripts,
29152931 },
2932 .name_done = false,
29162933 } });
29172934 } else if (mem.cutPrefix(u8, arg, "-weak-l")) |rest| {
29182935 try create_module.cli_link_inputs.append(arena, .{ .name_query = .{
......@@ -2924,6 +2941,7 @@ fn buildOutputType(
29242941 .search_strategy = lib_search_strategy,
29252942 .allow_so_scripts = allow_so_scripts,
29262943 },
2944 .name_done = false,
29272945 } });
29282946 } else if (mem.eql(u8, arg, "-weak_library")) {
29292947 try create_module.cli_link_inputs.append(arena, .{ .name_query = .{
......@@ -2935,6 +2953,7 @@ fn buildOutputType(
29352953 .search_strategy = lib_search_strategy,
29362954 .allow_so_scripts = allow_so_scripts,
29372955 },
2956 .name_done = false,
29382957 } });
29392958 } else if (mem.eql(u8, arg, "-compatibility_version")) {
29402959 const compat_version = linker_args_it.nextOrFatal();
......@@ -4175,6 +4194,10 @@ fn createModule(
41754194 fatal("cannot use absolute path as a system library: {s}", .{lib_name});
41764195 }
41774196
4197 if (!nq.name_done and std.mem.findScalar(u8, nq.name, '/') != null) {
4198 fatal("cannot use path separator in system library name: {s}", .{lib_name});
4199 }
4200
41784201 unresolved_link_inputs.appendAssumeCapacity(cli_link_input);
41794202 any_name_queries_remaining = true;
41804203 },
......@@ -4269,10 +4292,10 @@ fn createModule(
42694292 &create_module.link_inputs,
42704293 create_module.lib_directories.items,
42714294 color,
4272 ) catch |err| fatal("failed to resolve link inputs: {s}", .{@errorName(err)});
4295 ) catch |err| fatal("failed to resolve link inputs: {t}", .{err});
42734296
42744297 if (!create_module.opts.any_dyn_libs) for (create_module.link_inputs.items) |item| switch (item) {
4275 .dso, .dso_exact => {
4298 .dso => {
42764299 create_module.opts.any_dyn_libs = true;
42774300 break;
42784301 },