authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-06-26 10:11:37+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-06-26 10:11:39+02:00
logb94787afd7e0b06c2daea76ca5a812962794ed00
treea1b5362f3c3b8b68dbafc8d823f3681884d4633a
parent1534cd2f88d94f320a5735b55c0ce3aebb905b6c

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`.

2 files changed, 110 insertions(+), 64 deletions(-)

src/link/MachO.zig+100-54
...@@ -514,15 +514,18 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {...@@ -514,15 +514,18 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
514 }514 }
515}515}
516516
517fn resolvePaths(517const LibKind = enum {
518 lib,
519 framework,
520};
521
522fn resolveDirs(
518 arena: *Allocator,523 arena: *Allocator,
519 resolved_paths: *std.ArrayList([]const u8),524 resolved_dirs: *std.ArrayList([]const u8),
520 syslibroot: ?[]const u8,525 syslibroot: ?[]const u8,
521 search_dirs: []const []const u8,526 search_dirs: []const []const u8,
522 lib_names: []const []const u8,527 lib_kind: LibKind,
523 kind: enum { lib, framework },
524) !void {528) !void {
525 var resolved_dirs = std.ArrayList([]const u8).init(arena);
526 for (search_dirs) |dir| {529 for (search_dirs) |dir| {
527 if (fs.path.isAbsolute(dir)) {530 if (fs.path.isAbsolute(dir)) {
528 var candidates = std.ArrayList([]const u8).init(arena);531 var candidates = std.ArrayList([]const u8).init(arena);
...@@ -547,7 +550,7 @@ fn resolvePaths(...@@ -547,7 +550,7 @@ fn resolvePaths(
547 }550 }
548551
549 if (!found) {552 if (!found) {
550 switch (kind) {553 switch (lib_kind) {
551 .lib => log.warn("directory not found for '-L{s}'", .{dir}),554 .lib => log.warn("directory not found for '-L{s}'", .{dir}),
552 .framework => log.warn("directory not found for '-F{s}'", .{dir}),555 .framework => log.warn("directory not found for '-F{s}'", .{dir}),
553 }556 }
...@@ -556,7 +559,7 @@ fn resolvePaths(...@@ -556,7 +559,7 @@ fn resolvePaths(
556 // Verify that search path actually exists559 // Verify that search path actually exists
557 var tmp = fs.cwd().openDir(dir, .{}) catch |err| switch (err) {560 var tmp = fs.cwd().openDir(dir, .{}) catch |err| switch (err) {
558 error.FileNotFound => {561 error.FileNotFound => {
559 switch (kind) {562 switch (lib_kind) {
560 .lib => log.warn("directory not found for '-L{s}'", .{dir}),563 .lib => log.warn("directory not found for '-L{s}'", .{dir}),
561 .framework => log.warn("directory not found for '-F{s}'", .{dir}),564 .framework => log.warn("directory not found for '-F{s}'", .{dir}),
562 }565 }
...@@ -569,48 +572,63 @@ fn resolvePaths(...@@ -569,48 +572,63 @@ fn resolvePaths(
569 try resolved_dirs.append(dir);572 try resolved_dirs.append(dir);
570 }573 }
571 }574 }
575}
572576
577fn resolveLib(
578 arena: *Allocator,
579 lib_dirs: []const []const u8,
580 lib_name: []const u8,
581 lib_kind: LibKind,
582) !?[]const u8 {
573 // Assume ld64 default: -search_paths_first583 // Assume ld64 default: -search_paths_first
574 // Look in each directory for a dylib (next, tbd), and then for archive584 // Look in each directory for a dylib (next, tbd), and then for archive
575 // TODO implement alternative: -search_dylibs_first585 // TODO implement alternative: -search_dylibs_first
576 const exts = switch (kind) {586 const exts = switch (lib_kind) {
577 .lib => &[_][]const u8{ "dylib", "tbd", "a" },587 .lib => &[_][]const u8{ "dylib", "tbd", "a" },
578 .framework => &[_][]const u8{ "dylib", "tbd" },588 .framework => &[_][]const u8{ "dylib", "tbd" },
579 };589 };
580590
581 for (lib_names) |lib_name| {591 for (exts) |ext| {
582 var found = false;592 const lib_name_ext = blk: {
583593 switch (lib_kind) {
584 ext: for (exts) |ext| {594 .lib => break :blk try std.fmt.allocPrint(arena, "lib{s}.{s}", .{ lib_name, ext }),
585 const lib_name_ext = blk: {595 .framework => {
586 switch (kind) {596 const prefix = try std.fmt.allocPrint(arena, "{s}.framework", .{lib_name});
587 .lib => break :blk try std.fmt.allocPrint(arena, "lib{s}.{s}", .{ lib_name, ext }),597 const nn = try std.fmt.allocPrint(arena, "{s}.{s}", .{ lib_name, ext });
588 .framework => {598 break :blk try fs.path.join(arena, &[_][]const u8{ prefix, nn });
589 const prefix = try std.fmt.allocPrint(arena, "{s}.framework", .{lib_name});599 },
590 const nn = try std.fmt.allocPrint(arena, "{s}.{s}", .{ lib_name, ext });600 }
591 break :blk try fs.path.join(arena, &[_][]const u8{ prefix, nn });601 };
592 },
593 }
594 };
595602
596 for (resolved_dirs.items) |dir| {603 for (lib_dirs) |dir| {
597 const full_path = try fs.path.join(arena, &[_][]const u8{ dir, lib_name_ext });604 const full_path = try fs.path.join(arena, &[_][]const u8{ dir, lib_name_ext });
598605
599 // Check if the lib file exists.606 // Check if the lib file exists.
600 const tmp = fs.cwd().openFile(full_path, .{}) catch |err| switch (err) {607 const tmp = fs.cwd().openFile(full_path, .{}) catch |err| switch (err) {
601 error.FileNotFound => continue,608 error.FileNotFound => continue,
602 else => |e| return e,609 else => |e| return e,
603 };610 };
604 defer tmp.close();611 defer tmp.close();
605612
606 try resolved_paths.append(full_path);613 return full_path;
607 found = true;
608 break :ext;
609 }
610 }614 }
615 }
616
617 return null;
618}
611619
612 if (!found) {620fn resolveLibs(
613 switch (kind) {621 arena: *Allocator,
622 resolved_libs: *std.ArrayList([]const u8),
623 lib_dirs: []const []const u8,
624 lib_names: []const []const u8,
625 lib_kind: LibKind,
626) !void {
627 for (lib_names) |lib_name| {
628 if (try resolveLib(arena, lib_dirs, lib_name, lib_kind)) |full_path| {
629 try resolved_libs.append(full_path);
630 } else {
631 switch (lib_kind) {
614 .lib => {632 .lib => {
615 log.warn("library not found for '-l{s}'", .{lib_name});633 log.warn("library not found for '-l{s}'", .{lib_name});
616 log.warn("Library search paths:", .{});634 log.warn("Library search paths:", .{});
...@@ -620,7 +638,7 @@ fn resolvePaths(...@@ -620,7 +638,7 @@ fn resolvePaths(
620 log.warn("Framework search paths:", .{});638 log.warn("Framework search paths:", .{});
621 },639 },
622 }640 }
623 for (resolved_dirs.items) |dir| {641 for (lib_dirs) |dir| {
624 log.warn(" {s}", .{dir});642 log.warn(" {s}", .{dir});
625 }643 }
626 }644 }
...@@ -789,7 +807,6 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {...@@ -789,7 +807,6 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
789 zld.deinit();807 zld.deinit();
790 }808 }
791 zld.arch = target.cpu.arch;809 zld.arch = target.cpu.arch;
792 zld.syslibroot = self.base.options.sysroot;
793 zld.stack_size = stack_size;810 zld.stack_size = stack_size;
794811
795 // Positional arguments to the linker such as object files and static archives.812 // Positional arguments to the linker such as object files and static archives.
...@@ -829,16 +846,56 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {...@@ -829,16 +846,56 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
829 try search_lib_names.append(link_lib);846 try search_lib_names.append(link_lib);
830 }847 }
831848
832 var libs = std.ArrayList([]const u8).init(arena);849 var lib_dirs = std.ArrayList([]const u8).init(arena);
833 try resolvePaths(850 try resolveDirs(
834 arena,851 arena,
835 &libs,852 &lib_dirs,
836 self.base.options.sysroot,853 self.base.options.sysroot,
837 self.base.options.lib_dirs,854 self.base.options.lib_dirs,
855 .lib,
856 );
857
858 var libs = std.ArrayList([]const u8).init(arena);
859 try resolveLibs(
860 arena,
861 &libs,
862 lib_dirs.items,
838 search_lib_names.items,863 search_lib_names.items,
839 .lib,864 .lib,
840 );865 );
841866
867 // If we're compiling native and we can find libSystem.B.{dylib, tbd},
868 // we link against that instead of embedded libSystem.B.tbd file.
869 const libc_stub_path = blk: {
870 if (self.base.options.is_native_os) {
871 if (try resolveLib(arena, lib_dirs.items, "System", .lib)) |full_path| {
872 break :blk full_path;
873 }
874 }
875
876 break :blk try comp.zig_lib_directory.join(arena, &[_][]const u8{
877 "libc", "darwin", "libSystem.B.tbd",
878 });
879 };
880
881 // frameworks
882 var framework_dirs = std.ArrayList([]const u8).init(arena);
883 try resolveDirs(
884 arena,
885 &framework_dirs,
886 self.base.options.sysroot,
887 self.base.options.framework_dirs,
888 .framework,
889 );
890
891 try resolveLibs(
892 arena,
893 &libs,
894 framework_dirs.items,
895 self.base.options.frameworks,
896 .framework,
897 );
898
842 // rpaths899 // rpaths
843 var rpath_table = std.StringArrayHashMap(void).init(arena);900 var rpath_table = std.StringArrayHashMap(void).init(arena);
844 for (self.base.options.rpath_list) |rpath| {901 for (self.base.options.rpath_list) |rpath| {
...@@ -852,16 +909,6 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {...@@ -852,16 +909,6 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
852 rpaths.appendAssumeCapacity(key.*);909 rpaths.appendAssumeCapacity(key.*);
853 }910 }
854911
855 // frameworks
856 try resolvePaths(
857 arena,
858 &libs,
859 self.base.options.sysroot,
860 self.base.options.framework_dirs,
861 self.base.options.frameworks,
862 .framework,
863 );
864
865 if (self.base.options.verbose_link) {912 if (self.base.options.verbose_link) {
866 var argv = std.ArrayList([]const u8).init(arena);913 var argv = std.ArrayList([]const u8).init(arena);
867914
...@@ -895,11 +942,10 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {...@@ -895,11 +942,10 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
895 }942 }
896943
897 try zld.link(positionals.items, full_out_path, .{944 try zld.link(positionals.items, full_out_path, .{
945 .syslibroot = self.base.options.sysroot,
898 .libs = libs.items,946 .libs = libs.items,
899 .rpaths = rpaths.items,947 .rpaths = rpaths.items,
900 .libc_stub_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{948 .libc_stub_path = libc_stub_path,
901 "libc", "darwin", "libSystem.B.tbd",
902 }),
903 });949 });
904950
905 break :outer;951 break :outer;
src/link/MachO/Zld.zig+10-10
...@@ -32,7 +32,6 @@ out_path: ?[]const u8 = null,...@@ -32,7 +32,6 @@ out_path: ?[]const u8 = null,
3232
33// TODO these args will become obselete once Zld is coalesced with incremental33// TODO these args will become obselete once Zld is coalesced with incremental
34// linker.34// linker.
35syslibroot: ?[]const u8 = null,
36stack_size: u64 = 0,35stack_size: u64 = 0,
3736
38objects: std.ArrayListUnmanaged(*Object) = .{},37objects: std.ArrayListUnmanaged(*Object) = .{},
...@@ -197,6 +196,7 @@ pub fn closeFiles(self: Zld) void {...@@ -197,6 +196,7 @@ pub fn closeFiles(self: Zld) void {
197}196}
198197
199const LinkArgs = struct {198const LinkArgs = struct {
199 syslibroot: ?[]const u8,
200 libs: []const []const u8,200 libs: []const []const u8,
201 rpaths: []const []const u8,201 rpaths: []const []const u8,
202 libc_stub_path: []const u8,202 libc_stub_path: []const u8,
...@@ -238,9 +238,9 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: L...@@ -238,9 +238,9 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: L
238 });238 });
239239
240 try self.populateMetadata();240 try self.populateMetadata();
241 try self.parseInputFiles(files);241 try self.parseInputFiles(files, args.syslibroot);
242 try self.parseLibs(args.libs);242 try self.parseLibs(args.libs, args.syslibroot);
243 try self.parseLibSystem(args.libc_stub_path);243 try self.parseLibSystem(args.libc_stub_path, args.syslibroot);
244 try self.resolveSymbols();244 try self.resolveSymbols();
245 try self.resolveStubsAndGotEntries();245 try self.resolveStubsAndGotEntries();
246 try self.updateMetadata();246 try self.updateMetadata();
...@@ -258,7 +258,7 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: L...@@ -258,7 +258,7 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: L
258 try self.flush();258 try self.flush();
259}259}
260260
261fn parseInputFiles(self: *Zld, files: []const []const u8) !void {261fn parseInputFiles(self: *Zld, files: []const []const u8, syslibroot: ?[]const u8) !void {
262 for (files) |file_name| {262 for (files) |file_name| {
263 const full_path = full_path: {263 const full_path = full_path: {
264 var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;264 var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
...@@ -280,7 +280,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {...@@ -280,7 +280,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
280 self.allocator,280 self.allocator,
281 self.arch.?,281 self.arch.?,
282 full_path,282 full_path,
283 self.syslibroot,283 syslibroot,
284 )) |dylibs| {284 )) |dylibs| {
285 defer self.allocator.free(dylibs);285 defer self.allocator.free(dylibs);
286 try self.dylibs.appendSlice(self.allocator, dylibs);286 try self.dylibs.appendSlice(self.allocator, dylibs);
...@@ -291,13 +291,13 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {...@@ -291,13 +291,13 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
291 }291 }
292}292}
293293
294fn parseLibs(self: *Zld, libs: []const []const u8) !void {294fn parseLibs(self: *Zld, libs: []const []const u8, syslibroot: ?[]const u8) !void {
295 for (libs) |lib| {295 for (libs) |lib| {
296 if (try Dylib.createAndParseFromPath(296 if (try Dylib.createAndParseFromPath(
297 self.allocator,297 self.allocator,
298 self.arch.?,298 self.arch.?,
299 lib,299 lib,
300 self.syslibroot,300 syslibroot,
301 )) |dylibs| {301 )) |dylibs| {
302 defer self.allocator.free(dylibs);302 defer self.allocator.free(dylibs);
303 try self.dylibs.appendSlice(self.allocator, dylibs);303 try self.dylibs.appendSlice(self.allocator, dylibs);
...@@ -313,12 +313,12 @@ fn parseLibs(self: *Zld, libs: []const []const u8) !void {...@@ -313,12 +313,12 @@ fn parseLibs(self: *Zld, libs: []const []const u8) !void {
313 }313 }
314}314}
315315
316fn parseLibSystem(self: *Zld, libc_stub_path: []const u8) !void {316fn parseLibSystem(self: *Zld, libc_stub_path: []const u8, syslibroot: ?[]const u8) !void {
317 const dylibs = (try Dylib.createAndParseFromPath(317 const dylibs = (try Dylib.createAndParseFromPath(
318 self.allocator,318 self.allocator,
319 self.arch.?,319 self.arch.?,
320 libc_stub_path,320 libc_stub_path,
321 self.syslibroot,321 syslibroot,
322 )) orelse return error.FailedToParseLibSystem;322 )) orelse return error.FailedToParseLibSystem;
323 defer self.allocator.free(dylibs);323 defer self.allocator.free(dylibs);
324324