Skip to content

Commit

Permalink
link: Simplify library path resolution logic
Browse files Browse the repository at this point in the history
  • Loading branch information
Doekin committed Feb 3, 2025
1 parent 5d5219b commit d5c44c9
Showing 1 changed file with 36 additions and 65 deletions.
101 changes: 36 additions & 65 deletions src/link.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2068,30 +2068,47 @@ fn resolveLibInput(

const lib_name = name_query.name;

if (target.isDarwin() and link_mode == .dynamic) tbd: {
// Prefer .tbd over .dylib.
const test_path: Path = .{
.root_dir = lib_directory,
.sub_path = try std.fmt.allocPrint(arena, "lib{s}.tbd", .{lib_name}),
};
try checked_paths.writer(gpa).print("\n {}", .{test_path});
var file = test_path.root_dir.handle.openFile(test_path.sub_path, .{}) catch |err| switch (err) {
error.FileNotFound => break :tbd,
else => |e| fatal("unable to search for tbd library '{}': {s}", .{ test_path, @errorName(e) }),
const FilenameBuilder = struct {
prefix: []const u8,
suffix: []const u8,
fn build(self: @This(), allocator: Allocator, library_name: []const u8) ![]const u8 {
return std.fmt.allocPrint(allocator, "{s}{s}{s}", .{ self.prefix, library_name, self.suffix });
}
};

const initial_count = 1;
var filename_builders: []const FilenameBuilder = &[initial_count]FilenameBuilder{.{ .prefix = target.libPrefix(), .suffix = switch (link_mode) {
.static => target.staticLibSuffix(),
.dynamic => target.dynamicLibSuffix(),
} }};

if (target.isDarwin() and link_mode == .dynamic) {
filename_builders =
// Prefer .tbd over .dylib.
&[_]FilenameBuilder{.{ .prefix = "lib", .suffix = ".tbd" }}
// In the case of Darwin, the main check will be .dylib
++ filename_builders[0..initial_count].*
// Additionally check for .so files.
++ &[_]FilenameBuilder{.{ .prefix = "lib", .suffix = ".so" }};
} else if (target.isMinGW()) {
// In the case of MinGW, the main check will be `libfoo.dll` and `libfoo.a`, but we also need to
// look for `libfoo.dll.a`, `foo.dll` and `foo.lib`.
filename_builders = switch (link_mode) {
.dynamic => filename_builders[0..initial_count].* ++ &[_]FilenameBuilder{
.{ .prefix = "lib", .suffix = ".dll.a" },
.{ .prefix = "", .suffix = ".dll" },
.{ .prefix = "", .suffix = ".lib" },
},
.static => filename_builders[0..initial_count].* ++ &[_]FilenameBuilder{
.{ .prefix = "", .suffix = ".lib" },
},
};
errdefer file.close();
return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query);
}

{
for (filename_builders) |filename_builder| {
const test_path: Path = .{
.root_dir = lib_directory,
.sub_path = try std.fmt.allocPrint(arena, "{s}{s}{s}", .{
target.libPrefix(), lib_name, switch (link_mode) {
.static => target.staticLibSuffix(),
.dynamic => target.dynamicLibSuffix(),
},
}),
.sub_path = try filename_builder.build(arena, lib_name),
};
try checked_paths.writer(gpa).print("\n {}", .{test_path});
switch (try resolvePathInputLib(gpa, arena, unresolved_inputs, resolved_inputs, ld_script_bytes, target, .{
Expand All @@ -2103,52 +2120,6 @@ fn resolveLibInput(
}
}

// In the case of Darwin, the main check will be .dylib, so here we
// additionally check for .so files.
if (target.isDarwin() and link_mode == .dynamic) so: {
const test_path: Path = .{
.root_dir = lib_directory,
.sub_path = try std.fmt.allocPrint(arena, "lib{s}.so", .{lib_name}),
};
try checked_paths.writer(gpa).print("\n {}", .{test_path});
var file = test_path.root_dir.handle.openFile(test_path.sub_path, .{}) catch |err| switch (err) {
error.FileNotFound => break :so,
else => |e| fatal("unable to search for so library '{}': {s}", .{
test_path, @errorName(e),
}),
};
errdefer file.close();
return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query);
}

// In the case of MinGW, the main check will be `libfoo.dll` and `libfoo.a`, but we also need to
// look for `foo.dll`, `foo.lib` and `libfoo.dll.a`.
if (target.isMinGW()) {
const sub_paths = if (link_mode == .dynamic)
&[_][]const u8{
try std.fmt.allocPrint(arena, "lib{s}.dll.a", .{lib_name}),
try std.fmt.allocPrint(arena, "{s}.dll", .{lib_name}),
try std.fmt.allocPrint(arena, "{s}.lib", .{lib_name}),
}
else
&[_][]const u8{
try std.fmt.allocPrint(arena, "{s}.lib", .{lib_name}),
};
for (sub_paths) |sub_path| {
const test_path: Path = .{
.root_dir = lib_directory,
.sub_path = sub_path,
};
try checked_paths.writer(gpa).print("\n {}", .{test_path});
var file = test_path.root_dir.handle.openFile(test_path.sub_path, .{}) catch |err| switch (err) {
error.FileNotFound => continue,
else => |e| fatal("unable to search for {s} library '{}': {s}", .{ @tagName(link_mode), test_path, @errorName(e) }),
};
errdefer file.close();
return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query);
}
}

return .no_match;
}

Expand Down

0 comments on commit d5c44c9

Please sign in to comment.