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 {
514514 }
515515}
516516
517const LibKind = enum {
518 lib,
519 framework,
520};
521
522fn resolveDirs(
517fn resolveSearchDir(
523518 arena: *Allocator,
524 resolved_dirs: *std.ArrayList([]const u8),
519 dir: []const u8,
525520 syslibroot: ?[]const u8,
526 search_dirs: []const []const u8,
527 lib_kind: LibKind,
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();
521) !?[]const u8 {
522 var candidates = std.ArrayList([]const u8).init(arena);
546523
547 try resolved_dirs.append(candidate);
548 found = true;
549 break;
550 }
524 if (fs.path.isAbsolute(dir)) {
525 if (syslibroot) |root| {
526 const full_path = try fs.path.join(arena, &[_][]const u8{ root, dir });
527 try candidates.append(full_path);
528 }
529 }
551530
552 if (!found) {
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();
531 try candidates.append(dir);
571532
572 try resolved_dirs.append(dir);
573 }
533 for (candidates.items) |candidate| {
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;
574542 }
543
544 return null;
575545}
576546
577547fn resolveLib(
578548 arena: *Allocator,
579 lib_dirs: []const []const u8,
580 lib_name: []const u8,
581 lib_kind: LibKind,
549 search_dirs: []const []const u8,
550 name: []const u8,
551 ext: []const u8,
582552) !?[]const u8 {
583 // Assume ld64 default: -search_paths_first
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 };
553 const search_name = try std.fmt.allocPrint(arena, "lib{s}{s}", .{ name, ext });
607554
608 for (lib_dirs) |dir| {
609 const full_path = try fs.path.join(arena, &[_][]const u8{ dir, with_prefix });
555 for (search_dirs) |dir| {
556 const full_path = try fs.path.join(arena, &[_][]const u8{ dir, search_name });
610557
611 // Check if the lib file exists.
612 const tmp = fs.cwd().openFile(full_path, .{}) catch |err| switch (err) {
613 error.FileNotFound => continue,
614 else => |e| return e,
615 };
616 defer tmp.close();
558 // Check if the file exists.
559 const tmp = fs.cwd().openFile(full_path, .{}) catch |err| switch (err) {
560 error.FileNotFound => continue,
561 else => |e| return e,
562 };
563 defer tmp.close();
617564
618 return full_path;
619 }
565 return full_path;
620566 }
621567
622568 return null;
623569}
624570
625fn resolveLibs(
571fn resolveFramework(
626572 arena: *Allocator,
627 resolved_libs: *std.ArrayList([]const u8),
628 lib_dirs: []const []const u8,
629 lib_names: []const []const u8,
630 lib_kind: LibKind,
631) !void {
632 for (lib_names) |lib_name| {
633 if (try resolveLib(arena, lib_dirs, lib_name, lib_kind)) |full_path| {
634 try resolved_libs.append(full_path);
635 } else {
636 switch (lib_kind) {
637 .lib => {
638 log.warn("library not found for '-l{s}'", .{lib_name});
639 log.warn("Library search paths:", .{});
640 },
641 .framework => {
642 log.warn("framework not found for '-f{s}'", .{lib_name});
643 log.warn("Framework search paths:", .{});
644 },
645 }
646 for (lib_dirs) |dir| {
647 log.warn(" {s}", .{dir});
648 }
649 }
573 search_dirs: []const []const u8,
574 name: []const u8,
575 ext: []const u8,
576) !?[]const u8 {
577 const search_name = try std.fmt.allocPrint(arena, "{s}{s}", .{ name, ext });
578 const prefix_path = try std.fmt.allocPrint(arena, "{s}.framework", .{name});
579
580 for (search_dirs) |dir| {
581 const full_path = try fs.path.join(arena, &[_][]const u8{ dir, prefix_path, search_name });
582
583 // Check if the file exists.
584 const tmp = fs.cwd().openFile(full_path, .{}) catch |err| switch (err) {
585 error.FileNotFound => continue,
586 else => |e| return e,
587 };
588 defer tmp.close();
589
590 return full_path;
650591 }
592
593 return null;
651594}
652595
653596fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
......@@ -852,56 +795,96 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
852795 }
853796
854797 var lib_dirs = std.ArrayList([]const u8).init(arena);
855 try resolveDirs(
856 arena,
857 &lib_dirs,
858 self.base.options.sysroot,
859 self.base.options.lib_dirs,
860 .lib,
861 );
798 for (self.base.options.lib_dirs) |dir| {
799 if (try resolveSearchDir(arena, dir, self.base.options.sysroot)) |search_dir| {
800 try lib_dirs.append(search_dir);
801 } else {
802 log.warn("directory not found for '-L{s}'", .{dir});
803 }
804 }
862805
863806 var libs = std.ArrayList([]const u8).init(arena);
864 try resolveLibs(
865 arena,
866 &libs,
867 lib_dirs.items,
868 search_lib_names.items,
869 .lib,
870 );
807 var lib_not_found = false;
808 for (search_lib_names.items) |lib_name| {
809 // Assume ld64 default: -search_paths_first
810 // Look in each directory for a dylib (stub first), and then for archive
811 // TODO implement alternative: -search_dylibs_first
812 for (&[_][]const u8{ ".tbd", ".dylib", ".a" }) |ext| {
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
872830 // If we're compiling native and we can find libSystem.B.{dylib, tbd},
873831 // we link against that instead of embedded libSystem.B.tbd file.
874 var link_native_libsystem = false;
875 if (self.base.options.is_native_os) {
876 if (try resolveLib(arena, lib_dirs.items, "System", .lib)) |full_path| {
832 var native_libsystem_available = false;
833 if (self.base.options.is_native_os) blk: {
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| {
877837 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 }
879850 }
880851 }
881 if (!link_native_libsystem) {
852 if (!native_libsystem_available) {
882853 const full_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
883854 "libc", "darwin", "libSystem.B.tbd",
884855 });
885 try positionals.append(full_path);
856 try libs.append(full_path);
886857 }
887858
888859 // frameworks
889860 var framework_dirs = std.ArrayList([]const u8).init(arena);
890 try resolveDirs(
891 arena,
892 &framework_dirs,
893 self.base.options.sysroot,
894 self.base.options.framework_dirs,
895 .framework,
896 );
861 for (self.base.options.framework_dirs) |dir| {
862 if (try resolveSearchDir(arena, dir, self.base.options.sysroot)) |search_dir| {
863 try framework_dirs.append(search_dir);
864 } else {
865 log.warn("directory not found for '-F{s}'", .{dir});
866 }
867 }
897868
898 try resolveLibs(
899 arena,
900 &libs,
901 framework_dirs.items,
902 self.base.options.frameworks,
903 .framework,
904 );
869 var framework_not_found = false;
870 for (self.base.options.frameworks) |framework| {
871 for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
872 if (try resolveFramework(arena, framework_dirs.items, framework, ext)) |full_path| {
873 try libs.append(full_path);
874 break;
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
906889 // rpaths
907890 var rpath_table = std.StringArrayHashMap(void).init(arena);
......@@ -937,8 +920,9 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
937920 try argv.append("-o");
938921 try argv.append(full_out_path);
939922
940 if (link_native_libsystem) {
923 if (native_libsystem_available) {
941924 try argv.append("-lSystem");
925 try argv.append("-lc");
942926 }
943927
944928 for (search_lib_names.items) |l_name| {
src/link/MachO/Dylib.zig+3-2
......@@ -369,10 +369,11 @@ fn parseSymbols(self: *Dylib) !void {
369369 _ = try self.file.?.preadAll(strtab, symtab_cmd.stroff + self.library_offset);
370370
371371 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));
376377 const name = try self.allocator.dupe(u8, sym_name);
377378 try self.symbols.putNoClobber(self.allocator, name, {});
378379 }
src/link/MachO/Zld.zig+1-1
......@@ -1644,7 +1644,7 @@ fn resolveSymbols(self: *Zld) !void {
16441644 loop: while (unresolved.popOrNull()) |undef| {
16451645 const proxy = self.imports.get(undef.name) orelse outer: {
16461646 const proxy = inner: {
1647 for (self.dylibs.items) |dylib, i| {
1647 for (self.dylibs.items) |dylib| {
16481648 const proxy = (try dylib.createProxy(undef.name)) orelse continue;
16491649 try referenced.put(dylib, {});
16501650 break :inner proxy;