aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2021-06-23 15:11:31 +0200
committerJakub Konka <kubkon@jakubkonka.com>2021-06-24 18:57:11 +0200
commit5ac5cd9de7c5387e37baa4f287d609c5d2f34564 (patch)
tree65d97ee06e85f411493dbef7a5b1688e627f70c6 /src
parent3cb6b6bd90c3b304bf771b37e974dd943c060e2b (diff)
downloadzig-5ac5cd9de7c5387e37baa4f287d609c5d2f34564.tar.gz
zig-5ac5cd9de7c5387e37baa4f287d609c5d2f34564.zip
zld: naively parse all dylib deps in stubs
Diffstat (limited to 'src')
-rw-r--r--src/link/MachO.zig1
-rw-r--r--src/link/MachO/Archive.zig63
-rw-r--r--src/link/MachO/Dylib.zig148
-rw-r--r--src/link/MachO/Object.zig52
-rw-r--r--src/link/MachO/Zld.zig230
-rw-r--r--src/link/tapi.zig3
6 files changed, 263 insertions, 234 deletions
diff --git a/src/link/MachO.zig b/src/link/MachO.zig
index 3521874129..4ede9c516e 100644
--- a/src/link/MachO.zig
+++ b/src/link/MachO.zig
@@ -789,6 +789,7 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
zld.deinit();
}
zld.arch = target.cpu.arch;
+ zld.syslibroot = self.base.options.syslibroot;
zld.stack_size = stack_size;
// Positional arguments to the linker such as object files and static archives.
diff --git a/src/link/MachO/Archive.zig b/src/link/MachO/Archive.zig
index 48bc33f0fa..22439d300a 100644
--- a/src/link/MachO/Archive.zig
+++ b/src/link/MachO/Archive.zig
@@ -8,12 +8,13 @@ const macho = std.macho;
const mem = std.mem;
const Allocator = mem.Allocator;
+const Arch = std.Target.Cpu.Arch;
const Object = @import("Object.zig");
usingnamespace @import("commands.zig");
allocator: *Allocator,
-arch: ?std.Target.Cpu.Arch = null,
+arch: ?Arch = null,
file: ?fs.File = null,
header: ?ar_hdr = null,
name: ?[]const u8 = null,
@@ -85,10 +86,36 @@ const ar_hdr = extern struct {
}
};
-pub fn init(allocator: *Allocator) Archive {
- return .{
+pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u8) !?*Archive {
+ const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) {
+ error.FileNotFound => return null,
+ else => |e| return e,
+ };
+ errdefer file.close();
+
+ const archive = try allocator.create(Archive);
+ errdefer allocator.destroy(archive);
+
+ const name = try allocator.dupe(u8, path);
+ errdefer allocator.free(name);
+
+ archive.* = .{
.allocator = allocator,
+ .arch = arch,
+ .name = name,
+ .file = file,
+ };
+
+ archive.parse() catch |err| switch (err) {
+ error.EndOfStream, error.NotArchive => {
+ archive.deinit();
+ allocator.destroy(archive);
+ return null;
+ },
+ else => |e| return e,
};
+
+ return archive;
}
pub fn deinit(self: *Archive) void {
@@ -116,15 +143,15 @@ pub fn parse(self: *Archive) !void {
const magic = try reader.readBytesNoEof(SARMAG);
if (!mem.eql(u8, &magic, ARMAG)) {
- log.err("invalid magic: expected '{s}', found '{s}'", .{ ARMAG, magic });
- return error.MalformedArchive;
+ log.debug("invalid magic: expected '{s}', found '{s}'", .{ ARMAG, magic });
+ return error.NotArchive;
}
self.header = try reader.readStruct(ar_hdr);
if (!mem.eql(u8, &self.header.?.ar_fmag, ARFMAG)) {
- log.err("invalid header delimiter: expected '{s}', found '{s}'", .{ ARFMAG, self.header.?.ar_fmag });
- return error.MalformedArchive;
+ log.debug("invalid header delimiter: expected '{s}', found '{s}'", .{ ARFMAG, self.header.?.ar_fmag });
+ return error.NotArchive;
}
var embedded_name = try parseName(self.allocator, self.header.?, reader);
@@ -222,23 +249,15 @@ pub fn parseObject(self: Archive, offset: u32) !*Object {
var object = try self.allocator.create(Object);
errdefer self.allocator.destroy(object);
- object.* = Object.init(self.allocator);
- object.arch = self.arch.?;
- object.file = try fs.cwd().openFile(self.name.?, .{});
- object.name = name;
- object.file_offset = @intCast(u32, try reader.context.getPos());
+ object.* = .{
+ .allocator = self.allocator,
+ .arch = self.arch.?,
+ .file = try fs.cwd().openFile(self.name.?, .{}),
+ .name = name,
+ .file_offset = @intCast(u32, try reader.context.getPos()),
+ };
try object.parse();
-
try reader.context.seekTo(0);
return object;
}
-
-pub fn isArchive(file: fs.File) !bool {
- const magic = file.reader().readBytesNoEof(Archive.SARMAG) catch |err| switch (err) {
- error.EndOfStream => return false,
- else => |e| return e,
- };
- try file.seekTo(0);
- return mem.eql(u8, &magic, Archive.ARMAG);
-}
diff --git a/src/link/MachO/Dylib.zig b/src/link/MachO/Dylib.zig
index 44b012905e..723277c541 100644
--- a/src/link/MachO/Dylib.zig
+++ b/src/link/MachO/Dylib.zig
@@ -8,6 +8,7 @@ const macho = std.macho;
const mem = std.mem;
const Allocator = mem.Allocator;
+const Arch = std.Target.Cpu.Arch;
const Symbol = @import("Symbol.zig");
const LibStub = @import("../tapi.zig").LibStub;
@@ -15,10 +16,11 @@ usingnamespace @import("commands.zig");
allocator: *Allocator,
-arch: ?std.Target.Cpu.Arch = null,
+arch: ?Arch = null,
header: ?macho.mach_header_64 = null,
file: ?fs.File = null,
name: ?[]const u8 = null,
+syslibroot: ?[]const u8 = null,
ordinal: ?u16 = null,
@@ -35,6 +37,11 @@ id: ?Id = null,
/// a symbol is referenced by an object file.
symbols: std.StringArrayHashMapUnmanaged(void) = .{},
+// TODO we should keep track of already parsed dylibs so that
+// we don't unnecessarily reparse them again.
+// TODO add dylib dep analysis and extraction for .dylib files.
+dylibs: std.ArrayListUnmanaged(*Dylib) = .{},
+
pub const Id = struct {
name: []const u8,
timestamp: u32,
@@ -46,8 +53,57 @@ pub const Id = struct {
}
};
-pub fn init(allocator: *Allocator) Dylib {
- return .{ .allocator = allocator };
+pub const Error = error{
+ OutOfMemory,
+ EmptyStubFile,
+ MismatchedCpuArchitecture,
+ UnsupportedCpuArchitecture,
+} || fs.File.OpenError || std.os.PReadError;
+
+pub fn createAndParseFromPath(
+ allocator: *Allocator,
+ arch: Arch,
+ path: []const u8,
+ syslibroot: ?[]const u8,
+ recurse_libs: bool,
+) Error!?*Dylib {
+ const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) {
+ error.FileNotFound => return null,
+ else => |e| return e,
+ };
+ errdefer file.close();
+
+ const dylib = try allocator.create(Dylib);
+ errdefer allocator.destroy(dylib);
+
+ const name = try allocator.dupe(u8, path);
+ errdefer allocator.free(name);
+
+ dylib.* = .{
+ .allocator = allocator,
+ .arch = arch,
+ .name = name,
+ .file = file,
+ .syslibroot = syslibroot,
+ };
+
+ dylib.parse(recurse_libs) catch |err| switch (err) {
+ error.EndOfStream, error.NotDylib => {
+ try file.seekTo(0);
+
+ var lib_stub = LibStub.loadFromFile(allocator, file) catch {
+ dylib.deinit();
+ allocator.destroy(dylib);
+ return null;
+ };
+ defer lib_stub.deinit();
+
+ try dylib.parseFromStub(lib_stub, recurse_libs);
+ },
+ else => |e| return e,
+ };
+
+ return dylib;
}
pub fn deinit(self: *Dylib) void {
@@ -60,6 +116,7 @@ pub fn deinit(self: *Dylib) void {
self.allocator.free(key);
}
self.symbols.deinit(self.allocator);
+ self.dylibs.deinit(self.allocator);
if (self.name) |name| {
self.allocator.free(name);
@@ -76,15 +133,15 @@ pub fn closeFile(self: Dylib) void {
}
}
-pub fn parse(self: *Dylib) !void {
+pub fn parse(self: *Dylib, recurse_libs: bool) !void {
log.debug("parsing shared library '{s}'", .{self.name.?});
var reader = self.file.?.reader();
self.header = try reader.readStruct(macho.mach_header_64);
if (self.header.?.filetype != macho.MH_DYLIB) {
- log.err("invalid filetype: expected 0x{x}, found 0x{x}", .{ macho.MH_DYLIB, self.header.?.filetype });
- return error.MalformedDylib;
+ log.debug("invalid filetype: expected 0x{x}, found 0x{x}", .{ macho.MH_DYLIB, self.header.?.filetype });
+ return error.NotDylib;
}
const this_arch: std.Target.Cpu.Arch = switch (self.header.?.cputype) {
@@ -190,7 +247,7 @@ fn addObjCClassSymbols(self: *Dylib, sym_name: []const u8) !void {
}
}
-pub fn parseFromStub(self: *Dylib, lib_stub: LibStub) !void {
+pub fn parseFromStub(self: *Dylib, lib_stub: LibStub, recurse_libs: bool) !void {
if (lib_stub.inner.len == 0) return error.EmptyStubFile;
log.debug("parsing shared library from stub '{s}'", .{self.name.?});
@@ -236,9 +293,17 @@ pub fn parseFromStub(self: *Dylib, lib_stub: LibStub) !void {
for (reexports) |reexp| {
if (!hasTarget(reexp.targets, target_string)) continue;
- for (reexp.symbols) |sym_name| {
- if (self.symbols.contains(sym_name)) continue;
- try self.symbols.putNoClobber(self.allocator, try self.allocator.dupe(u8, sym_name), {});
+ if (reexp.symbols) |symbols| {
+ for (symbols) |sym_name| {
+ if (self.symbols.contains(sym_name)) continue;
+ try self.symbols.putNoClobber(self.allocator, try self.allocator.dupe(u8, sym_name), {});
+ }
+ }
+
+ if (reexp.objc_classes) |classes| {
+ for (classes) |sym_name| {
+ try self.addObjCClassSymbols(sym_name);
+ }
}
}
}
@@ -249,6 +314,60 @@ pub fn parseFromStub(self: *Dylib, lib_stub: LibStub) !void {
}
}
}
+
+ for (lib_stub.inner) |stub| {
+ if (!hasTarget(stub.targets, target_string)) continue;
+
+ if (stub.reexported_libraries) |reexports| reexports: {
+ if (!recurse_libs) break :reexports;
+
+ for (reexports) |reexp| {
+ if (!hasTarget(reexp.targets, target_string)) continue;
+
+ outer: for (reexp.libraries) |lib| {
+ const dirname = fs.path.dirname(lib) orelse {
+ log.warn("unable to resolve dependency {s}", .{lib});
+ continue;
+ };
+ const filename = fs.path.basename(lib);
+ const without_ext = if (mem.lastIndexOfScalar(u8, filename, '.')) |index|
+ filename[0..index]
+ else
+ filename;
+
+ for (&[_][]const u8{ "dylib", "tbd" }) |ext| {
+ const with_ext = try std.fmt.allocPrint(self.allocator, "{s}.{s}", .{
+ without_ext,
+ ext,
+ });
+ defer self.allocator.free(with_ext);
+
+ const lib_path = if (self.syslibroot) |syslibroot|
+ try fs.path.join(self.allocator, &.{ syslibroot, dirname, with_ext })
+ else
+ try fs.path.join(self.allocator, &.{ dirname, with_ext });
+
+ log.debug("trying dependency at fully resolved path {s}", .{lib_path});
+
+ const dylib = (try createAndParseFromPath(
+ self.allocator,
+ self.arch.?,
+ lib_path,
+ self.syslibroot,
+ true,
+ )) orelse {
+ continue;
+ };
+
+ try self.dylibs.append(self.allocator, dylib);
+ continue :outer;
+ } else {
+ log.warn("unable to resolve dependency {s}", .{lib});
+ }
+ }
+ }
+ }
+ }
}
fn hasTarget(targets: []const []const u8, target: []const u8) bool {
@@ -258,15 +377,6 @@ fn hasTarget(targets: []const []const u8, target: []const u8) bool {
return false;
}
-pub fn isDylib(file: fs.File) !bool {
- const header = file.reader().readStruct(macho.mach_header_64) catch |err| switch (err) {
- error.EndOfStream => return false,
- else => |e| return e,
- };
- try file.seekTo(0);
- return header.filetype == macho.MH_DYLIB;
-}
-
pub fn createProxy(self: *Dylib, sym_name: []const u8) !?*Symbol {
if (!self.symbols.contains(sym_name)) return null;
diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig
index 64db2fe091..747adaab87 100644
--- a/src/link/MachO/Object.zig
+++ b/src/link/MachO/Object.zig
@@ -11,6 +11,7 @@ const mem = std.mem;
const reloc = @import("reloc.zig");
const Allocator = mem.Allocator;
+const Arch = std.Target.Cpu.Arch;
const Relocation = reloc.Relocation;
const Symbol = @import("Symbol.zig");
const parseName = @import("Zld.zig").parseName;
@@ -18,7 +19,7 @@ const parseName = @import("Zld.zig").parseName;
usingnamespace @import("commands.zig");
allocator: *Allocator,
-arch: ?std.Target.Cpu.Arch = null,
+arch: ?Arch = null,
header: ?macho.mach_header_64 = null,
file: ?fs.File = null,
file_offset: ?u32 = null,
@@ -173,10 +174,36 @@ const DebugInfo = struct {
}
};
-pub fn init(allocator: *Allocator) Object {
- return .{
+pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u8) !?*Object {
+ const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) {
+ error.FileNotFound => return null,
+ else => |e| return e,
+ };
+ errdefer file.close();
+
+ const object = try allocator.create(Object);
+ errdefer allocator.destroy(object);
+
+ const name = try allocator.dupe(u8, path);
+ errdefer allocator.free(name);
+
+ object.* = .{
.allocator = allocator,
+ .arch = arch,
+ .name = name,
+ .file = file,
};
+
+ object.parse() catch |err| switch (err) {
+ error.EndOfStream, error.NotObject => {
+ object.deinit();
+ allocator.destroy(object);
+ return null;
+ },
+ else => |e| return e,
+ };
+
+ return object;
}
pub fn deinit(self: *Object) void {
@@ -223,11 +250,15 @@ pub fn parse(self: *Object) !void {
self.header = try reader.readStruct(macho.mach_header_64);
if (self.header.?.filetype != macho.MH_OBJECT) {
- log.err("invalid filetype: expected 0x{x}, found 0x{x}", .{ macho.MH_OBJECT, self.header.?.filetype });
- return error.MalformedObject;
+ log.debug("invalid filetype: expected 0x{x}, found 0x{x}", .{
+ macho.MH_OBJECT,
+ self.header.?.filetype,
+ });
+
+ return error.NotObject;
}
- const this_arch: std.Target.Cpu.Arch = switch (self.header.?.cputype) {
+ const this_arch: Arch = switch (self.header.?.cputype) {
macho.CPU_TYPE_ARM64 => .aarch64,
macho.CPU_TYPE_X86_64 => .x86_64,
else => |value| {
@@ -533,12 +564,3 @@ pub fn parseDataInCode(self: *Object) !void {
try self.data_in_code_entries.append(self.allocator, dice);
}
}
-
-pub fn isObject(file: fs.File) !bool {
- const header = file.reader().readStruct(macho.mach_header_64) catch |err| switch (err) {
- error.EndOfStream => return false,
- else => |e| return e,
- };
- try file.seekTo(0);
- return header.filetype == macho.MH_OBJECT;
-}
diff --git a/src/link/MachO/Zld.zig b/src/link/MachO/Zld.zig
index b46feced49..a4ee93cf58 100644
--- a/src/link/MachO/Zld.zig
+++ b/src/link/MachO/Zld.zig
@@ -16,7 +16,6 @@ const Allocator = mem.Allocator;
const Archive = @import("Archive.zig");
const CodeSignature = @import("CodeSignature.zig");
const Dylib = @import("Dylib.zig");
-const LibStub = @import("../tapi.zig").LibStub;
const Object = @import("Object.zig");
const Symbol = @import("Symbol.zig");
const Trie = @import("Trie.zig");
@@ -33,6 +32,7 @@ out_path: ?[]const u8 = null,
// TODO these args will become obselete once Zld is coalesced with incremental
// linker.
+syslibroot: ?[]const u8 = null,
stack_size: u64 = 0,
objects: std.ArrayListUnmanaged(*Object) = .{},
@@ -257,214 +257,90 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: L
}
fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
- const Input = struct {
- kind: union(enum) {
- object: fs.File,
- archive: fs.File,
- dylib: fs.File,
- stub: LibStub,
- },
- name: []const u8,
-
- fn deinit(input: *@This()) void {
- switch (input.kind) {
- .stub => |*stub| {
- stub.deinit();
- },
- else => {},
- }
- }
- };
- var classified = std.ArrayList(Input).init(self.allocator);
- defer {
- for (classified.items) |*input| {
- input.deinit();
- }
- classified.deinit();
- }
-
- // First, classify input files: object, archive, dylib or stub (tbd).
for (files) |file_name| {
- const file = try fs.cwd().openFile(file_name, .{});
const full_path = full_path: {
var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
const path = try std.fs.realpath(file_name, &buffer);
break :full_path try self.allocator.dupe(u8, path);
};
- try_object: {
- if (!(try Object.isObject(file))) break :try_object;
- try classified.append(.{
- .kind = .{ .object = file },
- .name = full_path,
- });
- continue;
- }
-
- try_archive: {
- if (!(try Archive.isArchive(file))) break :try_archive;
- try classified.append(.{
- .kind = .{ .archive = file },
- .name = full_path,
- });
+ if (try Object.createAndParseFromPath(self.allocator, self.arch.?, full_path)) |object| {
+ try self.objects.append(self.allocator, object);
continue;
}
- try_dylib: {
- if (!(try Dylib.isDylib(file))) break :try_dylib;
- try classified.append(.{
- .kind = .{ .dylib = file },
- .name = full_path,
- });
+ if (try Archive.createAndParseFromPath(self.allocator, self.arch.?, full_path)) |archive| {
+ try self.archives.append(self.allocator, archive);
continue;
}
- try_stub: {
- var lib_stub = LibStub.loadFromFile(self.allocator, file) catch {
- break :try_stub;
- };
- try classified.append(.{
- .kind = .{ .stub = lib_stub },
- .name = full_path,
- });
- file.close();
+ if (try Dylib.createAndParseFromPath(
+ self.allocator,
+ self.arch.?,
+ full_path,
+ self.syslibroot,
+ true,
+ )) |dylib| {
+ try self.dylibs.append(self.allocator, dylib);
continue;
}
- file.close();
log.warn("unknown filetype for positional input file: '{s}'", .{file_name});
}
-
- // Based on our classification, proceed with parsing.
- for (classified.items) |input| {
- switch (input.kind) {
- .object => |file| {
- const object = try self.allocator.create(Object);
- errdefer self.allocator.destroy(object);
-
- object.* = Object.init(self.allocator);
- object.arch = self.arch.?;
- object.name = input.name;
- object.file = file;
-
- try object.parse();
- try self.objects.append(self.allocator, object);
- },
- .archive => |file| {
- const archive = try self.allocator.create(Archive);
- errdefer self.allocator.destroy(archive);
-
- archive.* = Archive.init(self.allocator);
- archive.arch = self.arch.?;
- archive.name = input.name;
- archive.file = file;
-
- try archive.parse();
- try self.archives.append(self.allocator, archive);
- },
- .dylib, .stub => {
- const dylib = try self.allocator.create(Dylib);
- errdefer self.allocator.destroy(dylib);
-
- dylib.* = Dylib.init(self.allocator);
- dylib.arch = self.arch.?;
- dylib.name = input.name;
-
- if (input.kind == .dylib) {
- dylib.file = input.kind.dylib;
- try dylib.parse();
- } else {
- try dylib.parseFromStub(input.kind.stub);
- }
-
- try self.dylibs.append(self.allocator, dylib);
- },
- }
- }
}
fn parseLibs(self: *Zld, libs: []const []const u8) !void {
- for (libs) |lib| {
- const file = try fs.cwd().openFile(lib, .{});
-
- var kind: ?union(enum) {
- archive,
- dylib,
- stub: LibStub,
- } = kind: {
- if (try Archive.isArchive(file)) break :kind .archive;
- if (try Dylib.isDylib(file)) break :kind .dylib;
- var lib_stub = LibStub.loadFromFile(self.allocator, file) catch {
- break :kind null;
- };
- break :kind .{ .stub = lib_stub };
- };
- defer {
- if (kind) |*kk| {
- switch (kk.*) {
- .stub => |*stub| {
- stub.deinit();
- },
- else => {},
- }
+ const DylibDeps = struct {
+ fn bubbleUp(out: *std.ArrayList(*Dylib), next: *Dylib) error{OutOfMemory}!void {
+ try out.ensureUnusedCapacity(next.dylibs.items.len);
+ for (next.dylibs.items) |dylib| {
+ out.appendAssumeCapacity(dylib);
+ }
+ for (next.dylibs.items) |dylib| {
+ try bubbleUp(out, dylib);
}
}
+ };
- const unwrapped = kind orelse {
- file.close();
- log.warn("unknown filetype for a library: '{s}'", .{lib});
+ for (libs) |lib| {
+ if (try Dylib.createAndParseFromPath(
+ self.allocator,
+ self.arch.?,
+ lib,
+ self.syslibroot,
+ true,
+ )) |dylib| {
+ try self.dylibs.append(self.allocator, dylib);
continue;
- };
- switch (unwrapped) {
- .archive => {
- const archive = try self.allocator.create(Archive);
- errdefer self.allocator.destroy(archive);
-
- archive.* = Archive.init(self.allocator);
- archive.arch = self.arch.?;
- archive.name = try self.allocator.dupe(u8, lib);
- archive.file = file;
-
- try archive.parse();
- try self.archives.append(self.allocator, archive);
- },
- .dylib, .stub => {
- const dylib = try self.allocator.create(Dylib);
- errdefer self.allocator.destroy(dylib);
-
- dylib.* = Dylib.init(self.allocator);
- dylib.arch = self.arch.?;
- dylib.name = try self.allocator.dupe(u8, lib);
-
- if (unwrapped == .dylib) {
- dylib.file = file;
- try dylib.parse();
- } else {
- try dylib.parseFromStub(unwrapped.stub);
- }
-
- try self.dylibs.append(self.allocator, dylib);
- },
}
- }
-}
-fn parseLibSystem(self: *Zld, libc_stub_path: []const u8) !void {
- const file = try fs.cwd().openFile(libc_stub_path, .{});
- defer file.close();
+ if (try Archive.createAndParseFromPath(self.allocator, self.arch.?, lib)) |archive| {
+ try self.archives.append(self.allocator, archive);
+ continue;
+ }
- var lib_stub = try LibStub.loadFromFile(self.allocator, file);
- defer lib_stub.deinit();
+ log.warn("unknown filetype for a library: '{s}'", .{lib});
+ }
- const dylib = try self.allocator.create(Dylib);
- errdefer self.allocator.destroy(dylib);
+ // Flatten out any parsed dependencies.
+ var deps = std.ArrayList(*Dylib).init(self.allocator);
+ defer deps.deinit();
- dylib.* = Dylib.init(self.allocator);
- dylib.arch = self.arch.?;
- dylib.name = try self.allocator.dupe(u8, libc_stub_path);
+ for (self.dylibs.items) |dylib| {
+ try DylibDeps.bubbleUp(&deps, dylib);
+ }
- try dylib.parseFromStub(lib_stub);
+ try self.dylibs.appendSlice(self.allocator, deps.toOwnedSlice());
+}
+fn parseLibSystem(self: *Zld, libc_stub_path: []const u8) !void {
+ const dylib = (try Dylib.createAndParseFromPath(
+ self.allocator,
+ self.arch.?,
+ libc_stub_path,
+ self.syslibroot,
+ false,
+ )) orelse return error.FailedToParseLibSystem;
self.libsystem_dylib_index = @intCast(u16, self.dylibs.items.len);
try self.dylibs.append(self.allocator, dylib);
diff --git a/src/link/tapi.zig b/src/link/tapi.zig
index 51d51d6ed3..dc696577e8 100644
--- a/src/link/tapi.zig
+++ b/src/link/tapi.zig
@@ -41,7 +41,8 @@ pub const LibStub = struct {
},
reexports: ?[]const struct {
targets: []const []const u8,
- symbols: []const []const u8,
+ symbols: ?[]const []const u8,
+ objc_classes: ?[]const []const u8,
},
allowable_clients: ?[]const struct {
targets: []const []const u8,