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 {
514514 }
515515}
516516
517fn resolvePaths(
517const LibKind = enum {
518 lib,
519 framework,
520};
521
522fn resolveDirs(
518523 arena: *Allocator,
519 resolved_paths: *std.ArrayList([]const u8),
524 resolved_dirs: *std.ArrayList([]const u8),
520525 syslibroot: ?[]const u8,
521526 search_dirs: []const []const u8,
522 lib_names: []const []const u8,
523 kind: enum { lib, framework },
527 lib_kind: LibKind,
524528) !void {
525 var resolved_dirs = std.ArrayList([]const u8).init(arena);
526529 for (search_dirs) |dir| {
527530 if (fs.path.isAbsolute(dir)) {
528531 var candidates = std.ArrayList([]const u8).init(arena);
......@@ -547,7 +550,7 @@ fn resolvePaths(
547550 }
548551
549552 if (!found) {
550 switch (kind) {
553 switch (lib_kind) {
551554 .lib => log.warn("directory not found for '-L{s}'", .{dir}),
552555 .framework => log.warn("directory not found for '-F{s}'", .{dir}),
553556 }
......@@ -556,7 +559,7 @@ fn resolvePaths(
556559 // Verify that search path actually exists
557560 var tmp = fs.cwd().openDir(dir, .{}) catch |err| switch (err) {
558561 error.FileNotFound => {
559 switch (kind) {
562 switch (lib_kind) {
560563 .lib => log.warn("directory not found for '-L{s}'", .{dir}),
561564 .framework => log.warn("directory not found for '-F{s}'", .{dir}),
562565 }
......@@ -569,48 +572,63 @@ fn resolvePaths(
569572 try resolved_dirs.append(dir);
570573 }
571574 }
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 {
573583 // Assume ld64 default: -search_paths_first
574584 // Look in each directory for a dylib (next, tbd), and then for archive
575585 // TODO implement alternative: -search_dylibs_first
576 const exts = switch (kind) {
586 const exts = switch (lib_kind) {
577587 .lib => &[_][]const u8{ "dylib", "tbd", "a" },
578588 .framework => &[_][]const u8{ "dylib", "tbd" },
579589 };
580590
581 for (lib_names) |lib_name| {
582 var found = false;
583
584 ext: for (exts) |ext| {
585 const lib_name_ext = blk: {
586 switch (kind) {
587 .lib => break :blk try std.fmt.allocPrint(arena, "lib{s}.{s}", .{ lib_name, ext }),
588 .framework => {
589 const prefix = try std.fmt.allocPrint(arena, "{s}.framework", .{lib_name});
590 const nn = try std.fmt.allocPrint(arena, "{s}.{s}", .{ lib_name, ext });
591 break :blk try fs.path.join(arena, &[_][]const u8{ prefix, nn });
592 },
593 }
594 };
591 for (exts) |ext| {
592 const lib_name_ext = blk: {
593 switch (lib_kind) {
594 .lib => break :blk try std.fmt.allocPrint(arena, "lib{s}.{s}", .{ lib_name, ext }),
595 .framework => {
596 const prefix = try std.fmt.allocPrint(arena, "{s}.framework", .{lib_name});
597 const nn = try std.fmt.allocPrint(arena, "{s}.{s}", .{ lib_name, ext });
598 break :blk try fs.path.join(arena, &[_][]const u8{ prefix, nn });
599 },
600 }
601 };
595602
596 for (resolved_dirs.items) |dir| {
597 const full_path = try fs.path.join(arena, &[_][]const u8{ dir, lib_name_ext });
603 for (lib_dirs) |dir| {
604 const full_path = try fs.path.join(arena, &[_][]const u8{ dir, lib_name_ext });
598605
599 // Check if the lib file exists.
600 const tmp = fs.cwd().openFile(full_path, .{}) catch |err| switch (err) {
601 error.FileNotFound => continue,
602 else => |e| return e,
603 };
604 defer tmp.close();
606 // Check if the lib file exists.
607 const tmp = fs.cwd().openFile(full_path, .{}) catch |err| switch (err) {
608 error.FileNotFound => continue,
609 else => |e| return e,
610 };
611 defer tmp.close();
605612
606 try resolved_paths.append(full_path);
607 found = true;
608 break :ext;
609 }
613 return full_path;
610614 }
615 }
616
617 return null;
618}
611619
612 if (!found) {
613 switch (kind) {
620fn resolveLibs(
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) {
614632 .lib => {
615633 log.warn("library not found for '-l{s}'", .{lib_name});
616634 log.warn("Library search paths:", .{});
......@@ -620,7 +638,7 @@ fn resolvePaths(
620638 log.warn("Framework search paths:", .{});
621639 },
622640 }
623 for (resolved_dirs.items) |dir| {
641 for (lib_dirs) |dir| {
624642 log.warn(" {s}", .{dir});
625643 }
626644 }
......@@ -789,7 +807,6 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
789807 zld.deinit();
790808 }
791809 zld.arch = target.cpu.arch;
792 zld.syslibroot = self.base.options.sysroot;
793810 zld.stack_size = stack_size;
794811
795812 // Positional arguments to the linker such as object files and static archives.
......@@ -829,16 +846,56 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
829846 try search_lib_names.append(link_lib);
830847 }
831848
832 var libs = std.ArrayList([]const u8).init(arena);
833 try resolvePaths(
849 var lib_dirs = std.ArrayList([]const u8).init(arena);
850 try resolveDirs(
834851 arena,
835 &libs,
852 &lib_dirs,
836853 self.base.options.sysroot,
837854 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,
838863 search_lib_names.items,
839864 .lib,
840865 );
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
842899 // rpaths
843900 var rpath_table = std.StringArrayHashMap(void).init(arena);
844901 for (self.base.options.rpath_list) |rpath| {
......@@ -852,16 +909,6 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
852909 rpaths.appendAssumeCapacity(key.*);
853910 }
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
865912 if (self.base.options.verbose_link) {
866913 var argv = std.ArrayList([]const u8).init(arena);
867914
......@@ -895,11 +942,10 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
895942 }
896943
897944 try zld.link(positionals.items, full_out_path, .{
945 .syslibroot = self.base.options.sysroot,
898946 .libs = libs.items,
899947 .rpaths = rpaths.items,
900 .libc_stub_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
901 "libc", "darwin", "libSystem.B.tbd",
902 }),
948 .libc_stub_path = libc_stub_path,
903949 });
904950
905951 break :outer;
src/link/MachO/Zld.zig+10-10
......@@ -32,7 +32,6 @@ out_path: ?[]const u8 = null,
3232
3333// TODO these args will become obselete once Zld is coalesced with incremental
3434// linker.
35syslibroot: ?[]const u8 = null,
3635stack_size: u64 = 0,
3736
3837objects: std.ArrayListUnmanaged(*Object) = .{},
......@@ -197,6 +196,7 @@ pub fn closeFiles(self: Zld) void {
197196}
198197
199198const LinkArgs = struct {
199 syslibroot: ?[]const u8,
200200 libs: []const []const u8,
201201 rpaths: []const []const u8,
202202 libc_stub_path: []const u8,
......@@ -238,9 +238,9 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: L
238238 });
239239
240240 try self.populateMetadata();
241 try self.parseInputFiles(files);
242 try self.parseLibs(args.libs);
243 try self.parseLibSystem(args.libc_stub_path);
241 try self.parseInputFiles(files, args.syslibroot);
242 try self.parseLibs(args.libs, args.syslibroot);
243 try self.parseLibSystem(args.libc_stub_path, args.syslibroot);
244244 try self.resolveSymbols();
245245 try self.resolveStubsAndGotEntries();
246246 try self.updateMetadata();
......@@ -258,7 +258,7 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: L
258258 try self.flush();
259259}
260260
261fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
261fn parseInputFiles(self: *Zld, files: []const []const u8, syslibroot: ?[]const u8) !void {
262262 for (files) |file_name| {
263263 const full_path = full_path: {
264264 var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
......@@ -280,7 +280,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
280280 self.allocator,
281281 self.arch.?,
282282 full_path,
283 self.syslibroot,
283 syslibroot,
284284 )) |dylibs| {
285285 defer self.allocator.free(dylibs);
286286 try self.dylibs.appendSlice(self.allocator, dylibs);
......@@ -291,13 +291,13 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
291291 }
292292}
293293
294fn parseLibs(self: *Zld, libs: []const []const u8) !void {
294fn parseLibs(self: *Zld, libs: []const []const u8, syslibroot: ?[]const u8) !void {
295295 for (libs) |lib| {
296296 if (try Dylib.createAndParseFromPath(
297297 self.allocator,
298298 self.arch.?,
299299 lib,
300 self.syslibroot,
300 syslibroot,
301301 )) |dylibs| {
302302 defer self.allocator.free(dylibs);
303303 try self.dylibs.appendSlice(self.allocator, dylibs);
......@@ -313,12 +313,12 @@ fn parseLibs(self: *Zld, libs: []const []const u8) !void {
313313 }
314314}
315315
316fn parseLibSystem(self: *Zld, libc_stub_path: []const u8) !void {
316fn parseLibSystem(self: *Zld, libc_stub_path: []const u8, syslibroot: ?[]const u8) !void {
317317 const dylibs = (try Dylib.createAndParseFromPath(
318318 self.allocator,
319319 self.arch.?,
320320 libc_stub_path,
321 self.syslibroot,
321 syslibroot,
322322 )) orelse return error.FailedToParseLibSystem;
323323 defer self.allocator.free(dylibs);
324324