authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-06-20 19:21:15+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-06-24 18:53:28+02:00
log72f2f68938d626299e2bb5aa3b8932a45d4ae778
treeefedd7e4a7cd7e29f948baa013ead3c01b28ee19
parent8216ce67895f5605d1720df4e5e6636395f2fc92

zld: parse framework dirs and names


3 files changed, 165 insertions(+), 87 deletions(-)

src/link/MachO.zig+130-82
......@@ -514,6 +514,119 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
514514 }
515515}
516516
517fn resolvePaths(
518 arena: *Allocator,
519 resolved_paths: *std.ArrayList([]const u8),
520 syslibroot: ?[]const u8,
521 search_dirs: []const []const u8,
522 lib_names: []const []const u8,
523 kind: enum { lib, framework },
524) !void {
525 var resolved_dirs = std.ArrayList([]const u8).init(arena);
526 for (search_dirs) |dir| {
527 if (fs.path.isAbsolute(dir)) {
528 var candidates = std.ArrayList([]const u8).init(arena);
529 if (syslibroot) |root| {
530 const full_path = try fs.path.join(arena, &[_][]const u8{ root, dir });
531 try candidates.append(full_path);
532 }
533 try candidates.append(dir);
534
535 var found = false;
536 for (candidates.items) |candidate| {
537 // Verify that search path actually exists
538 var tmp = fs.cwd().openDir(candidate, .{}) catch |err| switch (err) {
539 error.FileNotFound => continue,
540 else => |e| return e,
541 };
542 defer tmp.close();
543
544 try resolved_dirs.append(candidate);
545 found = true;
546 break;
547 }
548
549 if (!found) {
550 switch (kind) {
551 .lib => log.warn("directory not found for '-L{s}'", .{dir}),
552 .framework => log.warn("directory not found for '-F{s}'", .{dir}),
553 }
554 }
555 } else {
556 // Verify that search path actually exists
557 var tmp = fs.cwd().openDir(dir, .{}) catch |err| switch (err) {
558 error.FileNotFound => {
559 switch (kind) {
560 .lib => log.warn("directory not found for '-L{s}'", .{dir}),
561 .framework => log.warn("directory not found for '-F{s}'", .{dir}),
562 }
563 continue;
564 },
565 else => |e| return e,
566 };
567 defer tmp.close();
568
569 try resolved_dirs.append(dir);
570 }
571 }
572
573 // Assume ld64 default: -search_paths_first
574 // Look in each directory for a dylib (next, tbd), and then for archive
575 // TODO implement alternative: -search_dylibs_first
576 const exts = switch (kind) {
577 .lib => &[_][]const u8{ "dylib", "tbd", "a" },
578 .framework => &[_][]const u8{ "dylib", "tbd" },
579 };
580
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 };
595
596 for (resolved_dirs.items) |dir| {
597 const full_path = try fs.path.join(arena, &[_][]const u8{ dir, lib_name_ext });
598
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();
605
606 try resolved_paths.append(full_path);
607 found = true;
608 break :ext;
609 }
610 }
611
612 if (!found) {
613 switch (kind) {
614 .lib => {
615 log.warn("library not found for '-l{s}'", .{lib_name});
616 log.warn("Library search paths:", .{});
617 },
618 .framework => {
619 log.warn("framework not found for '-f{s}'", .{lib_name});
620 log.warn("Framework search paths:", .{});
621 },
622 }
623 for (resolved_dirs.items) |dir| {
624 log.warn(" {s}", .{dir});
625 }
626 }
627 }
628}
629
517630fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
518631 const tracy = trace(@src());
519632 defer tracy.end();
......@@ -700,7 +813,6 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
700813 }
701814
702815 // Shared and static libraries passed via `-l` flag.
703 var libs = std.ArrayList([]const u8).init(arena);
704816 var search_lib_names = std.ArrayList([]const u8).init(arena);
705817
706818 const system_libs = self.base.options.system_libs.keys();
......@@ -716,84 +828,15 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
716828 try search_lib_names.append(link_lib);
717829 }
718830
719 var search_lib_dirs = std.ArrayList([]const u8).init(arena);
720
721 for (self.base.options.lib_dirs) |path| {
722 if (fs.path.isAbsolute(path)) {
723 var candidates = std.ArrayList([]const u8).init(arena);
724 if (self.base.options.syslibroot) |syslibroot| {
725 const full_path = try fs.path.join(arena, &[_][]const u8{ syslibroot, path });
726 try candidates.append(full_path);
727 }
728 try candidates.append(path);
729
730 var found = false;
731 for (candidates.items) |candidate| {
732 // Verify that search path actually exists
733 var tmp = fs.cwd().openDir(candidate, .{}) catch |err| switch (err) {
734 error.FileNotFound => continue,
735 else => |e| return e,
736 };
737 defer tmp.close();
738
739 try search_lib_dirs.append(candidate);
740 found = true;
741 break;
742 }
743
744 if (!found) {
745 log.warn("directory not found for '-L{s}'", .{path});
746 }
747 } else {
748 // Verify that search path actually exists
749 var tmp = fs.cwd().openDir(path, .{}) catch |err| switch (err) {
750 error.FileNotFound => {
751 log.warn("directory not found for '-L{s}'", .{path});
752 continue;
753 },
754 else => |e| return e,
755 };
756 defer tmp.close();
757
758 try search_lib_dirs.append(path);
759 }
760 }
761
762 // Assume ld64 default: -search_paths_first
763 // Look in each directory for a dylib (next, tbd), and then for archive
764 // TODO implement alternative: -search_dylibs_first
765 const exts = &[_][]const u8{ "dylib", "tbd", "a" };
766
767 for (search_lib_names.items) |l_name| {
768 var found = false;
769
770 ext: for (exts) |ext| {
771 const l_name_ext = try std.fmt.allocPrint(arena, "lib{s}.{s}", .{ l_name, ext });
772
773 for (search_lib_dirs.items) |lib_dir| {
774 const full_path = try fs.path.join(arena, &[_][]const u8{ lib_dir, l_name_ext });
775
776 // Check if the lib file exists.
777 const tmp = fs.cwd().openFile(full_path, .{}) catch |err| switch (err) {
778 error.FileNotFound => continue,
779 else => |e| return e,
780 };
781 defer tmp.close();
782
783 try libs.append(full_path);
784 found = true;
785 break :ext;
786 }
787 }
788
789 if (!found) {
790 log.warn("library not found for '-l{s}'", .{l_name});
791 log.warn("Library search paths:", .{});
792 for (search_lib_dirs.items) |lib_dir| {
793 log.warn(" {s}", .{lib_dir});
794 }
795 }
796 }
831 var libs = std.ArrayList([]const u8).init(arena);
832 try resolvePaths(
833 arena,
834 &libs,
835 self.base.options.syslibroot,
836 self.base.options.lib_dirs,
837 search_lib_names.items,
838 .lib,
839 );
797840
798841 // rpaths
799842 var rpath_table = std.StringArrayHashMap(void).init(arena);
......@@ -809,9 +852,14 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
809852 }
810853
811854 // frameworks
812 for (self.base.options.frameworks) |framework| {
813 log.warn("frameworks not yet supported for '-framework {s}'", .{framework});
814 }
855 try resolvePaths(
856 arena,
857 &libs,
858 self.base.options.syslibroot,
859 self.base.options.framework_dirs,
860 self.base.options.frameworks,
861 .framework,
862 );
815863
816864 if (self.base.options.verbose_link) {
817865 var argv = std.ArrayList([]const u8).init(arena);
src/link/MachO/Stub.zig+33-4
......@@ -60,7 +60,7 @@ pub fn parse(self: *Stub) !void {
6060 const lib_stub = self.lib_stub orelse return error.EmptyStubFile;
6161 if (lib_stub.inner.len == 0) return error.EmptyStubFile;
6262
63 log.debug("parsing shared library from stub '{s}'", .{self.name.?});
63 log.warn("parsing shared library from stub '{s}'", .{self.name.?});
6464
6565 const umbrella_lib = lib_stub.inner[0];
6666 self.id = .{
......@@ -84,9 +84,24 @@ pub fn parse(self: *Stub) !void {
8484 for (exports) |exp| {
8585 if (!hasTarget(exp.targets, target_string)) continue;
8686
87 for (exp.symbols) |sym_name| {
88 if (self.symbols.contains(sym_name)) continue;
89 try self.symbols.putNoClobber(self.allocator, sym_name, {});
87 if (exp.symbols) |symbols| {
88 for (symbols) |sym_name| {
89 if (self.symbols.contains(sym_name)) continue;
90 try self.symbols.putNoClobber(self.allocator, sym_name, {});
91 }
92 }
93
94 if (exp.objc_classes) |classes| {
95 for (classes) |sym_name| {
96 log.warn(" | {s}", .{sym_name});
97 const actual_sym_name = try std.fmt.allocPrint(
98 self.allocator,
99 "_OBJC_CLASS_$_{s}",
100 .{sym_name},
101 );
102 if (self.symbols.contains(actual_sym_name)) continue;
103 try self.symbols.putNoClobber(self.allocator, actual_sym_name, {});
104 }
90105 }
91106 }
92107 }
......@@ -101,6 +116,20 @@ pub fn parse(self: *Stub) !void {
101116 }
102117 }
103118 }
119
120 if (stub.objc_classes) |classes| {
121 log.warn(" | objc_classes", .{});
122 for (classes) |sym_name| {
123 log.warn(" | {s}", .{sym_name});
124 const actual_sym_name = try std.fmt.allocPrint(
125 self.allocator,
126 "_OBJC_METACLASS_$_{s}",
127 .{sym_name},
128 );
129 if (self.symbols.contains(actual_sym_name)) continue;
130 try self.symbols.putNoClobber(self.allocator, actual_sym_name, {});
131 }
132 }
104133 }
105134}
106135
src/link/tapi.zig+2-1
......@@ -36,7 +36,8 @@ pub const LibStub = struct {
3636 },
3737 exports: ?[]const struct {
3838 targets: []const []const u8,
39 symbols: []const []const u8,
39 symbols: ?[]const []const u8,
40 objc_classes: ?[]const []const u8,
4041 },
4142 reexports: ?[]const struct {
4243 targets: []const []const u8,