authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-07-31 00:51:07+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-07-31 00:51:07+02:00
log8a4b5424d61a4ac8947cff1b9a8481578573db67
tree8f134bd96936e162c1ad00a0c3b0450ef1789821
parent9be16fe65fc15a74abf32c6b198a28bc5e86cd27
parentd3f6408a418e459a0b0f77d63e05e311c4ea71e8

Merge pull request 'link (OpenBSD): Find versioned shared libraries' (#36135) from vlkrs/zig:openbsd into master

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

1 files changed, 54 insertions(+), 0 deletions(-)

src/link.zig+54
......@@ -2239,6 +2239,60 @@ fn resolveLibInput(
22392239 return finishResolveLibInput(io, resolved_inputs, archive_dedup, test_path, file, link_mode, name_query.query);
22402240 }
22412241
2242 // In the case of OpenBSD, dynamic libraries are always versioned, without
2243 // unversioned symlinks. OpenBSD patches LLD to select the highest-versioned
2244 // shared library, and this code is intended to match that upstream behavior.
2245 if (target.isOpenBSDLibC() and link_mode == .dynamic) versioned: {
2246 const prefix = try std.fmt.allocPrint(arena, "lib{s}.so.", .{lib_name});
2247
2248 var dir = lib_directory.handle.openDir(io, ".", .{ .iterate = true }) catch |err| switch (err) {
2249 error.NotDir, error.FileNotFound => break :versioned,
2250 else => |e| fatal("unable to search for shared library '{s}.*': {s}", .{ prefix, @errorName(e) }),
2251 };
2252 defer dir.close(io);
2253
2254 var best_match_major: u32 = 0;
2255 var best_match_minor: u32 = 0;
2256 var best_match: ?[]const u8 = null;
2257
2258 var iter = dir.iterate();
2259 while (iter.next(io) catch |err| {
2260 fatal("unable to scan library directory '{s}'", .{@errorName(err)});
2261 }) |entry| {
2262 if (entry.kind != .file) continue;
2263 if (!std.mem.startsWith(u8, entry.name, prefix)) continue;
2264
2265 const rest = entry.name[prefix.len..];
2266 var sit = std.mem.splitScalar(u8, rest, '.');
2267 const major_str = sit.next() orelse continue;
2268 const minor_str = sit.next() orelse continue;
2269 if (sit.next() != null) continue;
2270 const major = std.fmt.parseInt(u32, major_str, 10) catch continue;
2271 const minor = std.fmt.parseInt(u32, minor_str, 10) catch continue;
2272
2273 if (major > best_match_major or (major == best_match_major and minor >= best_match_minor)) {
2274 best_match_major = major;
2275 best_match_minor = minor;
2276 best_match = try arena.dupe(u8, entry.name);
2277 }
2278 }
2279
2280 if (best_match) |found| {
2281 const test_path: Path = .{
2282 .root_dir = lib_directory,
2283 .sub_path = found,
2284 };
2285 try checked_paths.print(gpa, "\n {f}", .{test_path});
2286 switch (try resolvePathInputLib(gpa, arena, io, unresolved_inputs, resolved_inputs, ld_script_bytes, archive_dedup, target, .{
2287 .path = test_path,
2288 .query = name_query.query,
2289 }, link_mode, color)) {
2290 .no_match => {},
2291 .ok => return .ok,
2292 }
2293 }
2294 }
2295
22422296 return .no_match;
22432297}
22442298