authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-06-28 17:42:59+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-06-28 17:42:59+02:00
log9b5a463111534a892177f731397cbab1f586e437
treead94ed01013661fe3e251ea6bd44f7224acbf705
parenteca12b74b8f2ff9510de67907df2bc272614c8c8

zld: if libSystem.dylib found, then need to link libc.dylib too


3 files changed, 136 insertions(+), 151 deletions(-)

src/link/MachO.zig+132-148
...@@ -514,140 +514,83 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {...@@ -514,140 +514,83 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
514 }514 }
515}515}
516516
517const LibKind = enum {517fn resolveSearchDir(
518 lib,
519 framework,
520};
521
522fn resolveDirs(
523 arena: *Allocator,518 arena: *Allocator,
524 resolved_dirs: *std.ArrayList([]const u8),519 dir: []const u8,
525 syslibroot: ?[]const u8,520 syslibroot: ?[]const u8,
526 search_dirs: []const []const u8,521) !?[]const u8 {
527 lib_kind: LibKind,522 var candidates = std.ArrayList([]const u8).init(arena);
528) !void {
529 for (search_dirs) |dir| {
530 if (fs.path.isAbsolute(dir)) {
531 var candidates = std.ArrayList([]const u8).init(arena);
532 if (syslibroot) |root| {
533 const full_path = try fs.path.join(arena, &[_][]const u8{ root, dir });
534 try candidates.append(full_path);
535 }
536 try candidates.append(dir);
537
538 var found = false;
539 for (candidates.items) |candidate| {
540 // Verify that search path actually exists
541 var tmp = fs.cwd().openDir(candidate, .{}) catch |err| switch (err) {
542 error.FileNotFound => continue,
543 else => |e| return e,
544 };
545 defer tmp.close();
546523
547 try resolved_dirs.append(candidate);524 if (fs.path.isAbsolute(dir)) {
548 found = true;525 if (syslibroot) |root| {
549 break;526 const full_path = try fs.path.join(arena, &[_][]const u8{ root, dir });
550 }527 try candidates.append(full_path);
528 }
529 }
551530
552 if (!found) {531 try candidates.append(dir);
553 switch (lib_kind) {
554 .lib => log.warn("directory not found for '-L{s}'", .{dir}),
555 .framework => log.warn("directory not found for '-F{s}'", .{dir}),
556 }
557 }
558 } else {
559 // Verify that search path actually exists
560 var tmp = fs.cwd().openDir(dir, .{}) catch |err| switch (err) {
561 error.FileNotFound => {
562 switch (lib_kind) {
563 .lib => log.warn("directory not found for '-L{s}'", .{dir}),
564 .framework => log.warn("directory not found for '-F{s}'", .{dir}),
565 }
566 continue;
567 },
568 else => |e| return e,
569 };
570 defer tmp.close();
571532
572 try resolved_dirs.append(dir);533 for (candidates.items) |candidate| {
573 }534 // Verify that search path actually exists
535 var tmp = fs.cwd().openDir(candidate, .{}) catch |err| switch (err) {
536 error.FileNotFound => continue,
537 else => |e| return e,
538 };
539 defer tmp.close();
540
541 return candidate;
574 }542 }
543
544 return null;
575}545}
576546
577fn resolveLib(547fn resolveLib(
578 arena: *Allocator,548 arena: *Allocator,
579 lib_dirs: []const []const u8,549 search_dirs: []const []const u8,
580 lib_name: []const u8,550 name: []const u8,
581 lib_kind: LibKind,551 ext: []const u8,
582) !?[]const u8 {552) !?[]const u8 {
583 // Assume ld64 default: -search_paths_first553 const search_name = try std.fmt.allocPrint(arena, "lib{s}{s}", .{ name, ext });
584 // Look in each directory for a dylib (next, tbd), and then for archive
585 // TODO implement alternative: -search_dylibs_first
586 const exts = switch (lib_kind) {
587 .lib => &[_]?[]const u8{ "dylib", "tbd", "a" },
588 .framework => &[_]?[]const u8{ null, "dylib", "tbd" },
589 };
590
591 for (exts) |ext| {
592 const lib_name_ext = if (ext) |some|
593 try std.fmt.allocPrint(arena, "{s}.{s}", .{ lib_name, some })
594 else
595 lib_name;
596 const with_prefix = blk: {
597 switch (lib_kind) {
598 .lib => {
599 break :blk try std.fmt.allocPrint(arena, "lib{s}", .{lib_name_ext});
600 },
601 .framework => {
602 const prefix = try std.fmt.allocPrint(arena, "{s}.framework", .{lib_name});
603 break :blk try fs.path.join(arena, &[_][]const u8{ prefix, lib_name_ext });
604 },
605 }
606 };
607554
608 for (lib_dirs) |dir| {555 for (search_dirs) |dir| {
609 const full_path = try fs.path.join(arena, &[_][]const u8{ dir, with_prefix });556 const full_path = try fs.path.join(arena, &[_][]const u8{ dir, search_name });
610557
611 // Check if the lib file exists.558 // Check if the file exists.
612 const tmp = fs.cwd().openFile(full_path, .{}) catch |err| switch (err) {559 const tmp = fs.cwd().openFile(full_path, .{}) catch |err| switch (err) {
613 error.FileNotFound => continue,560 error.FileNotFound => continue,
614 else => |e| return e,561 else => |e| return e,
615 };562 };
616 defer tmp.close();563 defer tmp.close();
617564
618 return full_path;565 return full_path;
619 }
620 }566 }
621567
622 return null;568 return null;
623}569}
624570
625fn resolveLibs(571fn resolveFramework(
626 arena: *Allocator,572 arena: *Allocator,
627 resolved_libs: *std.ArrayList([]const u8),573 search_dirs: []const []const u8,
628 lib_dirs: []const []const u8,574 name: []const u8,
629 lib_names: []const []const u8,575 ext: []const u8,
630 lib_kind: LibKind,576) !?[]const u8 {
631) !void {577 const search_name = try std.fmt.allocPrint(arena, "{s}{s}", .{ name, ext });
632 for (lib_names) |lib_name| {578 const prefix_path = try std.fmt.allocPrint(arena, "{s}.framework", .{name});
633 if (try resolveLib(arena, lib_dirs, lib_name, lib_kind)) |full_path| {579
634 try resolved_libs.append(full_path);580 for (search_dirs) |dir| {
635 } else {581 const full_path = try fs.path.join(arena, &[_][]const u8{ dir, prefix_path, search_name });
636 switch (lib_kind) {582
637 .lib => {583 // Check if the file exists.
638 log.warn("library not found for '-l{s}'", .{lib_name});584 const tmp = fs.cwd().openFile(full_path, .{}) catch |err| switch (err) {
639 log.warn("Library search paths:", .{});585 error.FileNotFound => continue,
640 },586 else => |e| return e,
641 .framework => {587 };
642 log.warn("framework not found for '-f{s}'", .{lib_name});588 defer tmp.close();
643 log.warn("Framework search paths:", .{});589
644 },590 return full_path;
645 }
646 for (lib_dirs) |dir| {
647 log.warn(" {s}", .{dir});
648 }
649 }
650 }591 }
592
593 return null;
651}594}
652595
653fn linkWithLLD(self: *MachO, comp: *Compilation) !void {596fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
...@@ -852,56 +795,96 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {...@@ -852,56 +795,96 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
852 }795 }
853796
854 var lib_dirs = std.ArrayList([]const u8).init(arena);797 var lib_dirs = std.ArrayList([]const u8).init(arena);
855 try resolveDirs(798 for (self.base.options.lib_dirs) |dir| {
856 arena,799 if (try resolveSearchDir(arena, dir, self.base.options.sysroot)) |search_dir| {
857 &lib_dirs,800 try lib_dirs.append(search_dir);
858 self.base.options.sysroot,801 } else {
859 self.base.options.lib_dirs,802 log.warn("directory not found for '-L{s}'", .{dir});
860 .lib,803 }
861 );804 }
862805
863 var libs = std.ArrayList([]const u8).init(arena);806 var libs = std.ArrayList([]const u8).init(arena);
864 try resolveLibs(807 var lib_not_found = false;
865 arena,808 for (search_lib_names.items) |lib_name| {
866 &libs,809 // Assume ld64 default: -search_paths_first
867 lib_dirs.items,810 // Look in each directory for a dylib (stub first), and then for archive
868 search_lib_names.items,811 // TODO implement alternative: -search_dylibs_first
869 .lib,812 for (&[_][]const u8{ ".tbd", ".dylib", ".a" }) |ext| {
870 );813 if (try resolveLib(arena, lib_dirs.items, lib_name, ext)) |full_path| {
814 try libs.append(full_path);
815 break;
816 }
817 } else {
818 log.warn("library not found for '-l{s}'", .{lib_name});
819 lib_not_found = true;
820 }
821 }
822
823 if (lib_not_found) {
824 log.warn("Library search paths:", .{});
825 for (lib_dirs.items) |dir| {
826 log.warn(" {s}", .{dir});
827 }
828 }
871829
872 // If we're compiling native and we can find libSystem.B.{dylib, tbd},830 // If we're compiling native and we can find libSystem.B.{dylib, tbd},
873 // we link against that instead of embedded libSystem.B.tbd file.831 // we link against that instead of embedded libSystem.B.tbd file.
874 var link_native_libsystem = false;832 var native_libsystem_available = false;
875 if (self.base.options.is_native_os) {833 if (self.base.options.is_native_os) blk: {
876 if (try resolveLib(arena, lib_dirs.items, "System", .lib)) |full_path| {834 // Try stub file first. If we hit it, then we're done as the stub file
835 // re-exports every single symbol definition.
836 if (try resolveLib(arena, lib_dirs.items, "System", ".tbd")) |full_path| {
877 try libs.append(full_path);837 try libs.append(full_path);
878 link_native_libsystem = true;838 native_libsystem_available = true;
839 break :blk;
840 }
841 // If we didn't hit the stub file, try .dylib next. However, libSystem.dylib
842 // doesn't export libc.dylib which we'll need to resolve subsequently also.
843 if (try resolveLib(arena, lib_dirs.items, "System", ".dylib")) |libsystem_path| {
844 if (try resolveLib(arena, lib_dirs.items, "c", ".dylib")) |libc_path| {
845 try libs.append(libsystem_path);
846 try libs.append(libc_path);
847 native_libsystem_available = true;
848 break :blk;
849 }
879 }850 }
880 }851 }
881 if (!link_native_libsystem) {852 if (!native_libsystem_available) {
882 const full_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{853 const full_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
883 "libc", "darwin", "libSystem.B.tbd",854 "libc", "darwin", "libSystem.B.tbd",
884 });855 });
885 try positionals.append(full_path);856 try libs.append(full_path);
886 }857 }
887858
888 // frameworks859 // frameworks
889 var framework_dirs = std.ArrayList([]const u8).init(arena);860 var framework_dirs = std.ArrayList([]const u8).init(arena);
890 try resolveDirs(861 for (self.base.options.framework_dirs) |dir| {
891 arena,862 if (try resolveSearchDir(arena, dir, self.base.options.sysroot)) |search_dir| {
892 &framework_dirs,863 try framework_dirs.append(search_dir);
893 self.base.options.sysroot,864 } else {
894 self.base.options.framework_dirs,865 log.warn("directory not found for '-F{s}'", .{dir});
895 .framework,866 }
896 );867 }
897868
898 try resolveLibs(869 var framework_not_found = false;
899 arena,870 for (self.base.options.frameworks) |framework| {
900 &libs,871 for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
901 framework_dirs.items,872 if (try resolveFramework(arena, framework_dirs.items, framework, ext)) |full_path| {
902 self.base.options.frameworks,873 try libs.append(full_path);
903 .framework,874 break;
904 );875 }
876 } else {
877 log.warn("framework not found for '-f{s}'", .{framework});
878 framework_not_found = true;
879 }
880 }
881
882 if (framework_not_found) {
883 log.warn("Framework search paths:", .{});
884 for (framework_dirs.items) |dir| {
885 log.warn(" {s}", .{dir});
886 }
887 }
905888
906 // rpaths889 // rpaths
907 var rpath_table = std.StringArrayHashMap(void).init(arena);890 var rpath_table = std.StringArrayHashMap(void).init(arena);
...@@ -937,8 +920,9 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {...@@ -937,8 +920,9 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
937 try argv.append("-o");920 try argv.append("-o");
938 try argv.append(full_out_path);921 try argv.append(full_out_path);
939922
940 if (link_native_libsystem) {923 if (native_libsystem_available) {
941 try argv.append("-lSystem");924 try argv.append("-lSystem");
925 try argv.append("-lc");
942 }926 }
943927
944 for (search_lib_names.items) |l_name| {928 for (search_lib_names.items) |l_name| {
src/link/MachO/Dylib.zig+3-2
...@@ -369,10 +369,11 @@ fn parseSymbols(self: *Dylib) !void {...@@ -369,10 +369,11 @@ fn parseSymbols(self: *Dylib) !void {
369 _ = try self.file.?.preadAll(strtab, symtab_cmd.stroff + self.library_offset);369 _ = try self.file.?.preadAll(strtab, symtab_cmd.stroff + self.library_offset);
370370
371 for (slice) |sym| {371 for (slice) |sym| {
372 const sym_name = mem.spanZ(@ptrCast([*:0]const u8, strtab.ptr + sym.n_strx));372 const add_to_symtab = Symbol.isExt(sym) and (Symbol.isSect(sym) or Symbol.isIndr(sym));
373373
374 if (!(Symbol.isSect(sym) and Symbol.isExt(sym))) continue;374 if (!add_to_symtab) continue;
375375
376 const sym_name = mem.spanZ(@ptrCast([*:0]const u8, strtab.ptr + sym.n_strx));
376 const name = try self.allocator.dupe(u8, sym_name);377 const name = try self.allocator.dupe(u8, sym_name);
377 try self.symbols.putNoClobber(self.allocator, name, {});378 try self.symbols.putNoClobber(self.allocator, name, {});
378 }379 }
src/link/MachO/Zld.zig+1-1
...@@ -1644,7 +1644,7 @@ fn resolveSymbols(self: *Zld) !void {...@@ -1644,7 +1644,7 @@ fn resolveSymbols(self: *Zld) !void {
1644 loop: while (unresolved.popOrNull()) |undef| {1644 loop: while (unresolved.popOrNull()) |undef| {
1645 const proxy = self.imports.get(undef.name) orelse outer: {1645 const proxy = self.imports.get(undef.name) orelse outer: {
1646 const proxy = inner: {1646 const proxy = inner: {
1647 for (self.dylibs.items) |dylib, i| {1647 for (self.dylibs.items) |dylib| {
1648 const proxy = (try dylib.createProxy(undef.name)) orelse continue;1648 const proxy = (try dylib.createProxy(undef.name)) orelse continue;
1649 try referenced.put(dylib, {});1649 try referenced.put(dylib, {});
1650 break :inner proxy;1650 break :inner proxy;