Skip to content

Commit dc9b6ec

Browse files
committed
macho: refactor resolving libs and frameworks when searching dependent dylibs
1 parent 51d60d1 commit dc9b6ec

File tree

1 file changed

+63
-63
lines changed

1 file changed

+63
-63
lines changed

src/link/MachO.zig

Lines changed: 63 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1173,58 +1173,54 @@ fn isHoisted(self: *MachO, install_name: []const u8) bool {
11731173
return false;
11741174
}
11751175

1176-
fn accessPath(
1176+
fn accessLibPath2(
11771177
arena: Allocator,
11781178
test_path: *std.ArrayList(u8),
11791179
checked_paths: *std.ArrayList([]const u8),
1180-
path: []const u8,
1181-
) !bool {
1182-
test_path.clearRetainingCapacity();
1183-
try test_path.appendSlice(path);
1184-
std.fs.cwd().access(path, .{}) catch |err| switch (err) {
1185-
error.FileNotFound => {
1186-
try checked_paths.append(try arena.dupe(u8, test_path.items));
1187-
return false;
1188-
},
1189-
else => |e| return e,
1190-
};
1191-
return true;
1192-
}
1193-
1194-
fn resolveLib(
1195-
arena: Allocator,
1196-
test_path: *std.ArrayList(u8),
1197-
checked_paths: *std.ArrayList([]const u8),
1198-
search_dirs: []const []const u8,
1180+
search_dir: []const u8,
11991181
name: []const u8,
12001182
) !bool {
1201-
const path = try std.fmt.allocPrint(arena, "lib{s}", .{name});
1202-
for (search_dirs) |dir| {
1203-
for (&[_][]const u8{ ".tbd", ".dylib" }) |ext| {
1204-
const with_ext = try std.fmt.allocPrint(arena, "{s}{s}", .{ path, ext });
1205-
const full_path = try std.fs.path.join(arena, &[_][]const u8{ dir, with_ext });
1206-
if (try accessPath(arena, test_path, checked_paths, full_path)) return true;
1207-
}
1183+
const sep = fs.path.sep_str;
1184+
1185+
for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
1186+
test_path.clearRetainingCapacity();
1187+
try test_path.writer().print("{s}" ++ sep ++ "lib{s}{s}", .{ search_dir, name, ext });
1188+
try checked_paths.append(try arena.dupe(u8, test_path.items));
1189+
std.fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {
1190+
error.FileNotFound => continue,
1191+
else => |e| return e,
1192+
};
1193+
return true;
12081194
}
1195+
12091196
return false;
12101197
}
12111198

1212-
fn resolveFramework(
1199+
fn accessFrameworkPath(
12131200
arena: Allocator,
12141201
test_path: *std.ArrayList(u8),
12151202
checked_paths: *std.ArrayList([]const u8),
1216-
search_dirs: []const []const u8,
1203+
search_dir: []const u8,
12171204
name: []const u8,
12181205
) !bool {
1219-
const prefix = try std.fmt.allocPrint(arena, "{s}.framework", .{name});
1220-
const path = try std.fs.path.join(arena, &[_][]const u8{ prefix, name });
1221-
for (search_dirs) |dir| {
1222-
for (&[_][]const u8{ ".tbd", ".dylib" }) |ext| {
1223-
const with_ext = try std.fmt.allocPrint(arena, "{s}{s}", .{ path, ext });
1224-
const full_path = try std.fs.path.join(arena, &[_][]const u8{ dir, with_ext });
1225-
if (try accessPath(arena, test_path, checked_paths, full_path)) return true;
1226-
}
1206+
const sep = fs.path.sep_str;
1207+
1208+
for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
1209+
test_path.clearRetainingCapacity();
1210+
try test_path.writer().print("{s}" ++ sep ++ "{s}.framework" ++ sep ++ "{s}{s}", .{
1211+
search_dir,
1212+
name,
1213+
name,
1214+
ext,
1215+
});
1216+
try checked_paths.append(try arena.dupe(u8, test_path.items));
1217+
std.fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {
1218+
error.FileNotFound => continue,
1219+
else => |e| return e,
1220+
};
1221+
return true;
12271222
}
1223+
12281224
return false;
12291225
}
12301226

@@ -1265,38 +1261,39 @@ fn parseDependentDylibs(self: *MachO) !void {
12651261
var checked_paths = std.ArrayList([]const u8).init(arena);
12661262

12671263
const full_path = full_path: {
1268-
fail: {
1264+
{
12691265
const stem = std.fs.path.stem(id.name);
12701266

12711267
// Framework
1272-
if (try resolveFramework(
1273-
arena,
1274-
&test_path,
1275-
&checked_paths,
1276-
framework_dirs,
1277-
stem,
1278-
)) break :full_path test_path.items;
1268+
for (framework_dirs) |dir| {
1269+
test_path.clearRetainingCapacity();
1270+
if (try accessFrameworkPath(arena, &test_path, &checked_paths, dir, stem)) break :full_path test_path.items;
1271+
}
12791272

12801273
// Library
12811274
const lib_name = eatPrefix(stem, "lib") orelse stem;
1282-
if (try resolveLib(
1283-
arena,
1284-
&test_path,
1285-
&checked_paths,
1286-
lib_dirs,
1287-
lib_name,
1288-
)) break :full_path test_path.items;
1289-
break :fail;
1275+
for (lib_dirs) |dir| {
1276+
test_path.clearRetainingCapacity();
1277+
if (try accessLibPath2(arena, &test_path, &checked_paths, dir, lib_name)) break :full_path test_path.items;
1278+
}
12901279
}
12911280

12921281
if (std.fs.path.isAbsolute(id.name)) {
1293-
const path = if (self.base.comp.sysroot) |root|
1294-
try std.fs.path.join(arena, &.{ root, id.name })
1295-
else
1296-
id.name;
1297-
for (&[_][]const u8{ "", ".tbd", ".dylib" }) |ext| {
1298-
const full_path = try std.fmt.allocPrint(arena, "{s}{s}", .{ path, ext });
1299-
if (try accessPath(arena, &test_path, &checked_paths, full_path)) break :full_path test_path.items;
1282+
const existing_ext = std.fs.path.extension(id.name);
1283+
const path = if (existing_ext.len > 0) id.name[0 .. id.name.len - existing_ext.len] else id.name;
1284+
for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
1285+
test_path.clearRetainingCapacity();
1286+
if (self.base.comp.sysroot) |root| {
1287+
try test_path.writer().print("{s}" ++ std.fs.path.sep_str ++ "{s}{s}", .{ root, path, ext });
1288+
} else {
1289+
try test_path.writer().print("{s}{s}", .{ path, ext });
1290+
}
1291+
try checked_paths.append(try arena.dupe(u8, test_path.items));
1292+
std.fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {
1293+
error.FileNotFound => continue,
1294+
else => |e| return e,
1295+
};
1296+
break :full_path test_path.items;
13001297
}
13011298
}
13021299

@@ -1305,6 +1302,7 @@ fn parseDependentDylibs(self: *MachO) !void {
13051302
for (self.getFile(dylib.umbrella).?.dylib.rpaths.keys()) |rpath| {
13061303
const prefix = eatPrefix(rpath, "@loader_path/") orelse rpath;
13071304
const rel_path = try std.fs.path.join(arena, &.{ prefix, path });
1305+
try checked_paths.append(rel_path);
13081306
var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
13091307
const full_path = std.fs.realpath(rel_path, &buffer) catch continue;
13101308
break :full_path full_path;
@@ -1317,8 +1315,11 @@ fn parseDependentDylibs(self: *MachO) !void {
13171315
return error.Unhandled;
13181316
}
13191317

1318+
try checked_paths.append(try arena.dupe(u8, id.name));
13201319
var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
1321-
const full_path = std.fs.realpath(id.name, &buffer) catch {
1320+
if (std.fs.realpath(id.name, &buffer)) |full_path| {
1321+
break :full_path full_path;
1322+
} else |_| {
13221323
try self.reportMissingDependencyError(
13231324
self.getFile(dylib_index).?.dylib.getUmbrella(self).index,
13241325
id.name,
@@ -1328,8 +1329,7 @@ fn parseDependentDylibs(self: *MachO) !void {
13281329
);
13291330
has_errors = true;
13301331
continue;
1331-
};
1332-
break :full_path full_path;
1332+
}
13331333
};
13341334
const lib = SystemLib{
13351335
.path = full_path,

0 commit comments

Comments
 (0)