Commit b94787afd7
src/link/MachO/Zld.zig
@@ -32,7 +32,6 @@ 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) = .{},
@@ -197,6 +196,7 @@ pub fn closeFiles(self: Zld) void {
}
const LinkArgs = struct {
+ syslibroot: ?[]const u8,
libs: []const []const u8,
rpaths: []const []const u8,
libc_stub_path: []const u8,
@@ -238,9 +238,9 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: L
});
try self.populateMetadata();
- try self.parseInputFiles(files);
- try self.parseLibs(args.libs);
- try self.parseLibSystem(args.libc_stub_path);
+ try self.parseInputFiles(files, args.syslibroot);
+ try self.parseLibs(args.libs, args.syslibroot);
+ try self.parseLibSystem(args.libc_stub_path, args.syslibroot);
try self.resolveSymbols();
try self.resolveStubsAndGotEntries();
try self.updateMetadata();
@@ -258,7 +258,7 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: L
try self.flush();
}
-fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
+fn parseInputFiles(self: *Zld, files: []const []const u8, syslibroot: ?[]const u8) !void {
for (files) |file_name| {
const full_path = full_path: {
var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
@@ -280,7 +280,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
self.allocator,
self.arch.?,
full_path,
- self.syslibroot,
+ syslibroot,
)) |dylibs| {
defer self.allocator.free(dylibs);
try self.dylibs.appendSlice(self.allocator, dylibs);
@@ -291,13 +291,13 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
}
}
-fn parseLibs(self: *Zld, libs: []const []const u8) !void {
+fn parseLibs(self: *Zld, libs: []const []const u8, syslibroot: ?[]const u8) !void {
for (libs) |lib| {
if (try Dylib.createAndParseFromPath(
self.allocator,
self.arch.?,
lib,
- self.syslibroot,
+ syslibroot,
)) |dylibs| {
defer self.allocator.free(dylibs);
try self.dylibs.appendSlice(self.allocator, dylibs);
@@ -313,12 +313,12 @@ fn parseLibs(self: *Zld, libs: []const []const u8) !void {
}
}
-fn parseLibSystem(self: *Zld, libc_stub_path: []const u8) !void {
+fn parseLibSystem(self: *Zld, libc_stub_path: []const u8, syslibroot: ?[]const u8) !void {
const dylibs = (try Dylib.createAndParseFromPath(
self.allocator,
self.arch.?,
libc_stub_path,
- self.syslibroot,
+ syslibroot,
)) orelse return error.FailedToParseLibSystem;
defer self.allocator.free(dylibs);
src/link/MachO.zig
@@ -514,15 +514,18 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
}
}
-fn resolvePaths(
+const LibKind = enum {
+ lib,
+ framework,
+};
+
+fn resolveDirs(
arena: *Allocator,
- resolved_paths: *std.ArrayList([]const u8),
+ resolved_dirs: *std.ArrayList([]const u8),
syslibroot: ?[]const u8,
search_dirs: []const []const u8,
- lib_names: []const []const u8,
- kind: enum { lib, framework },
+ lib_kind: LibKind,
) !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);
@@ -547,7 +550,7 @@ fn resolvePaths(
}
if (!found) {
- switch (kind) {
+ switch (lib_kind) {
.lib => log.warn("directory not found for '-L{s}'", .{dir}),
.framework => log.warn("directory not found for '-F{s}'", .{dir}),
}
@@ -556,7 +559,7 @@ fn resolvePaths(
// Verify that search path actually exists
var tmp = fs.cwd().openDir(dir, .{}) catch |err| switch (err) {
error.FileNotFound => {
- switch (kind) {
+ switch (lib_kind) {
.lib => log.warn("directory not found for '-L{s}'", .{dir}),
.framework => log.warn("directory not found for '-F{s}'", .{dir}),
}
@@ -569,48 +572,63 @@ fn resolvePaths(
try resolved_dirs.append(dir);
}
}
+}
+fn resolveLib(
+ arena: *Allocator,
+ lib_dirs: []const []const u8,
+ lib_name: []const u8,
+ lib_kind: LibKind,
+) !?[]const u8 {
// 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) {
+ const exts = switch (lib_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 (exts) |ext| {
+ const lib_name_ext = blk: {
+ switch (lib_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 });
+ for (lib_dirs) |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();
+ // 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;
- }
+ return full_path;
}
+ }
+
+ return null;
+}
- if (!found) {
- switch (kind) {
+fn resolveLibs(
+ arena: *Allocator,
+ resolved_libs: *std.ArrayList([]const u8),
+ lib_dirs: []const []const u8,
+ lib_names: []const []const u8,
+ lib_kind: LibKind,
+) !void {
+ for (lib_names) |lib_name| {
+ if (try resolveLib(arena, lib_dirs, lib_name, lib_kind)) |full_path| {
+ try resolved_libs.append(full_path);
+ } else {
+ switch (lib_kind) {
.lib => {
log.warn("library not found for '-l{s}'", .{lib_name});
log.warn("Library search paths:", .{});
@@ -620,7 +638,7 @@ fn resolvePaths(
log.warn("Framework search paths:", .{});
},
}
- for (resolved_dirs.items) |dir| {
+ for (lib_dirs) |dir| {
log.warn(" {s}", .{dir});
}
}
@@ -789,7 +807,6 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
zld.deinit();
}
zld.arch = target.cpu.arch;
- zld.syslibroot = self.base.options.sysroot;
zld.stack_size = stack_size;
// Positional arguments to the linker such as object files and static archives.
@@ -829,16 +846,56 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
try search_lib_names.append(link_lib);
}
- var libs = std.ArrayList([]const u8).init(arena);
- try resolvePaths(
+ var lib_dirs = std.ArrayList([]const u8).init(arena);
+ try resolveDirs(
arena,
- &libs,
+ &lib_dirs,
self.base.options.sysroot,
self.base.options.lib_dirs,
+ .lib,
+ );
+
+ var libs = std.ArrayList([]const u8).init(arena);
+ try resolveLibs(
+ arena,
+ &libs,
+ lib_dirs.items,
search_lib_names.items,
.lib,
);
+ // If we're compiling native and we can find libSystem.B.{dylib, tbd},
+ // we link against that instead of embedded libSystem.B.tbd file.
+ const libc_stub_path = blk: {
+ if (self.base.options.is_native_os) {
+ if (try resolveLib(arena, lib_dirs.items, "System", .lib)) |full_path| {
+ break :blk full_path;
+ }
+ }
+
+ break :blk try comp.zig_lib_directory.join(arena, &[_][]const u8{
+ "libc", "darwin", "libSystem.B.tbd",
+ });
+ };
+
+ // frameworks
+ var framework_dirs = std.ArrayList([]const u8).init(arena);
+ try resolveDirs(
+ arena,
+ &framework_dirs,
+ self.base.options.sysroot,
+ self.base.options.framework_dirs,
+ .framework,
+ );
+
+ try resolveLibs(
+ arena,
+ &libs,
+ framework_dirs.items,
+ self.base.options.frameworks,
+ .framework,
+ );
+
// rpaths
var rpath_table = std.StringArrayHashMap(void).init(arena);
for (self.base.options.rpath_list) |rpath| {
@@ -852,16 +909,6 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
rpaths.appendAssumeCapacity(key.*);
}
- // frameworks
- try resolvePaths(
- arena,
- &libs,
- self.base.options.sysroot,
- self.base.options.framework_dirs,
- self.base.options.frameworks,
- .framework,
- );
-
if (self.base.options.verbose_link) {
var argv = std.ArrayList([]const u8).init(arena);
@@ -895,11 +942,10 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
}
try zld.link(positionals.items, full_out_path, .{
+ .syslibroot = self.base.options.sysroot,
.libs = libs.items,
.rpaths = rpaths.items,
- .libc_stub_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
- "libc", "darwin", "libSystem.B.tbd",
- }),
+ .libc_stub_path = libc_stub_path,
});
break :outer;