aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/link/MachO.zig212
-rw-r--r--src/link/MachO/Stub.zig37
-rw-r--r--src/link/tapi.zig3
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,