mirror of
https://github.com/ziglang/zig.git
synced 2026-02-12 20:37:54 +00:00
zld: link against system libSystem.tbd
when native OS _and_ `libSystem.tbd` can be found. Otherwise, fallback to linking against Zig-provided `lib/libc/darwin/libSystem.B.tbd`.
This commit is contained in:
parent
1534cd2f88
commit
b94787afd7
@ -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 (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;
|
||||
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 });
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (!found) {
|
||||
switch (kind) {
|
||||
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();
|
||||
|
||||
return full_path;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user