| ... | ... | @@ -2239,6 +2239,60 @@ fn resolveLibInput( |
| 2239 | 2239 | return finishResolveLibInput(io, resolved_inputs, archive_dedup, test_path, file, link_mode, name_query.query); |
| 2240 | 2240 | } |
| 2241 | 2241 | |
| 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 | |
| 2242 | 2296 | return .no_match; |
| 2243 | 2297 | } |
| 2244 | 2298 | |