diff options
Diffstat (limited to 'src/link')
| -rw-r--r-- | src/link/MachO.zig | 212 | ||||
| -rw-r--r-- | src/link/MachO/Stub.zig | 37 | ||||
| -rw-r--r-- | src/link/tapi.zig | 3 |
3 files changed, 165 insertions, 87 deletions
diff --git a/src/link/MachO.zig b/src/link/MachO.zig index b7696f6a7c..c16957b97d 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -514,6 +514,119 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { } } +fn resolvePaths( + arena: *Allocator, + resolved_paths: *std.ArrayList([]const u8), + syslibroot: ?[]const u8, + search_dirs: []const []const u8, + lib_names: []const []const u8, + kind: enum { lib, framework }, +) !void { + var resolved_dirs = std.ArrayList([]const u8).init(arena); + for (search_dirs) |dir| { + if (fs.path.isAbsolute(dir)) { + var candidates = std.ArrayList([]const u8).init(arena); + if (syslibroot) |root| { + const full_path = try fs.path.join(arena, &[_][]const u8{ root, dir }); + try candidates.append(full_path); + } + try candidates.append(dir); + + var found = false; + for (candidates.items) |candidate| { + // Verify that search path actually exists + var tmp = fs.cwd().openDir(candidate, .{}) catch |err| switch (err) { + error.FileNotFound => continue, + else => |e| return e, + }; + defer tmp.close(); + + try resolved_dirs.append(candidate); + found = true; + break; + } + + if (!found) { + switch (kind) { + .lib => log.warn("directory not found for '-L{s}'", .{dir}), + .framework => log.warn("directory not found for '-F{s}'", .{dir}), + } + } + } else { + // Verify that search path actually exists + var tmp = fs.cwd().openDir(dir, .{}) catch |err| switch (err) { + error.FileNotFound => { + switch (kind) { + .lib => log.warn("directory not found for '-L{s}'", .{dir}), + .framework => log.warn("directory not found for '-F{s}'", .{dir}), + } + continue; + }, + else => |e| return e, + }; + defer tmp.close(); + + try resolved_dirs.append(dir); + } + } + + // Assume ld64 default: -search_paths_first + // Look in each directory for a dylib (next, tbd), and then for archive + // TODO implement alternative: -search_dylibs_first + const exts = switch (kind) { + .lib => &[_][]const u8{ "dylib", "tbd", "a" }, + .framework => &[_][]const u8{ "dylib", "tbd" }, + }; + + for (lib_names) |lib_name| { + var found = false; + + ext: for (exts) |ext| { + const lib_name_ext = blk: { + switch (kind) { + .lib => break :blk try std.fmt.allocPrint(arena, "lib{s}.{s}", .{ lib_name, ext }), + .framework => { + const prefix = try std.fmt.allocPrint(arena, "{s}.framework", .{lib_name}); + const nn = try std.fmt.allocPrint(arena, "{s}.{s}", .{ lib_name, ext }); + break :blk try fs.path.join(arena, &[_][]const u8{ prefix, nn }); + }, + } + }; + + for (resolved_dirs.items) |dir| { + const full_path = try fs.path.join(arena, &[_][]const u8{ dir, lib_name_ext }); + + // Check if the lib file exists. + const tmp = fs.cwd().openFile(full_path, .{}) catch |err| switch (err) { + error.FileNotFound => continue, + else => |e| return e, + }; + defer tmp.close(); + + try resolved_paths.append(full_path); + found = true; + break :ext; + } + } + + if (!found) { + switch (kind) { + .lib => { + log.warn("library not found for '-l{s}'", .{lib_name}); + log.warn("Library search paths:", .{}); + }, + .framework => { + log.warn("framework not found for '-f{s}'", .{lib_name}); + log.warn("Framework search paths:", .{}); + }, + } + for (resolved_dirs.items) |dir| { + log.warn(" {s}", .{dir}); + } + } + } +} + fn linkWithLLD(self: *MachO, comp: *Compilation) !void { const tracy = trace(@src()); defer tracy.end(); @@ -700,7 +813,6 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { } // Shared and static libraries passed via `-l` flag. - var libs = std.ArrayList([]const u8).init(arena); var search_lib_names = std.ArrayList([]const u8).init(arena); const system_libs = self.base.options.system_libs.keys(); @@ -716,84 +828,15 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { try search_lib_names.append(link_lib); } - var search_lib_dirs = std.ArrayList([]const u8).init(arena); - - for (self.base.options.lib_dirs) |path| { - if (fs.path.isAbsolute(path)) { - var candidates = std.ArrayList([]const u8).init(arena); - if (self.base.options.syslibroot) |syslibroot| { - const full_path = try fs.path.join(arena, &[_][]const u8{ syslibroot, path }); - try candidates.append(full_path); - } - try candidates.append(path); - - var found = false; - for (candidates.items) |candidate| { - // Verify that search path actually exists - var tmp = fs.cwd().openDir(candidate, .{}) catch |err| switch (err) { - error.FileNotFound => continue, - else => |e| return e, - }; - defer tmp.close(); - - try search_lib_dirs.append(candidate); - found = true; - break; - } - - if (!found) { - log.warn("directory not found for '-L{s}'", .{path}); - } - } else { - // Verify that search path actually exists - var tmp = fs.cwd().openDir(path, .{}) catch |err| switch (err) { - error.FileNotFound => { - log.warn("directory not found for '-L{s}'", .{path}); - continue; - }, - else => |e| return e, - }; - defer tmp.close(); - - try search_lib_dirs.append(path); - } - } - - // Assume ld64 default: -search_paths_first - // Look in each directory for a dylib (next, tbd), and then for archive - // TODO implement alternative: -search_dylibs_first - const exts = &[_][]const u8{ "dylib", "tbd", "a" }; - - for (search_lib_names.items) |l_name| { - var found = false; - - ext: for (exts) |ext| { - const l_name_ext = try std.fmt.allocPrint(arena, "lib{s}.{s}", .{ l_name, ext }); - - for (search_lib_dirs.items) |lib_dir| { - const full_path = try fs.path.join(arena, &[_][]const u8{ lib_dir, l_name_ext }); - - // Check if the lib file exists. - const tmp = fs.cwd().openFile(full_path, .{}) catch |err| switch (err) { - error.FileNotFound => continue, - else => |e| return e, - }; - defer tmp.close(); - - try libs.append(full_path); - found = true; - break :ext; - } - } - - if (!found) { - log.warn("library not found for '-l{s}'", .{l_name}); - log.warn("Library search paths:", .{}); - for (search_lib_dirs.items) |lib_dir| { - log.warn(" {s}", .{lib_dir}); - } - } - } + var libs = std.ArrayList([]const u8).init(arena); + try resolvePaths( + arena, + &libs, + self.base.options.syslibroot, + self.base.options.lib_dirs, + search_lib_names.items, + .lib, + ); // rpaths var rpath_table = std.StringArrayHashMap(void).init(arena); @@ -809,9 +852,14 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { } // frameworks - for (self.base.options.frameworks) |framework| { - log.warn("frameworks not yet supported for '-framework {s}'", .{framework}); - } + try resolvePaths( + arena, + &libs, + self.base.options.syslibroot, + self.base.options.framework_dirs, + self.base.options.frameworks, + .framework, + ); if (self.base.options.verbose_link) { var argv = std.ArrayList([]const u8).init(arena); diff --git a/src/link/MachO/Stub.zig b/src/link/MachO/Stub.zig index 3e1474539d..6111690a7d 100644 --- a/src/link/MachO/Stub.zig +++ b/src/link/MachO/Stub.zig @@ -60,7 +60,7 @@ pub fn parse(self: *Stub) !void { const lib_stub = self.lib_stub orelse return error.EmptyStubFile; if (lib_stub.inner.len == 0) return error.EmptyStubFile; - log.debug("parsing shared library from stub '{s}'", .{self.name.?}); + log.warn("parsing shared library from stub '{s}'", .{self.name.?}); const umbrella_lib = lib_stub.inner[0]; self.id = .{ @@ -84,9 +84,24 @@ pub fn parse(self: *Stub) !void { for (exports) |exp| { if (!hasTarget(exp.targets, target_string)) continue; - for (exp.symbols) |sym_name| { - if (self.symbols.contains(sym_name)) continue; - try self.symbols.putNoClobber(self.allocator, sym_name, {}); + if (exp.symbols) |symbols| { + for (symbols) |sym_name| { + if (self.symbols.contains(sym_name)) continue; + try self.symbols.putNoClobber(self.allocator, sym_name, {}); + } + } + + if (exp.objc_classes) |classes| { + for (classes) |sym_name| { + log.warn(" | {s}", .{sym_name}); + const actual_sym_name = try std.fmt.allocPrint( + self.allocator, + "_OBJC_CLASS_$_{s}", + .{sym_name}, + ); + if (self.symbols.contains(actual_sym_name)) continue; + try self.symbols.putNoClobber(self.allocator, actual_sym_name, {}); + } } } } @@ -101,6 +116,20 @@ pub fn parse(self: *Stub) !void { } } } + + if (stub.objc_classes) |classes| { + log.warn(" | objc_classes", .{}); + for (classes) |sym_name| { + log.warn(" | {s}", .{sym_name}); + const actual_sym_name = try std.fmt.allocPrint( + self.allocator, + "_OBJC_METACLASS_$_{s}", + .{sym_name}, + ); + if (self.symbols.contains(actual_sym_name)) continue; + try self.symbols.putNoClobber(self.allocator, actual_sym_name, {}); + } + } } } diff --git a/src/link/tapi.zig b/src/link/tapi.zig index efa7227def..51d51d6ed3 100644 --- a/src/link/tapi.zig +++ b/src/link/tapi.zig @@ -36,7 +36,8 @@ pub const LibStub = struct { }, exports: ?[]const struct { targets: []const []const u8, - symbols: []const []const u8, + symbols: ?[]const []const u8, + objc_classes: ?[]const []const u8, }, reexports: ?[]const struct { targets: []const []const u8, |
