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 {...@@ -514,6 +514,119 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
514 }514 }
515}515}
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
517fn linkWithLLD(self: *MachO, comp: *Compilation) !void {630fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
518 const tracy = trace(@src());631 const tracy = trace(@src());
519 defer tracy.end();632 defer tracy.end();
...@@ -700,7 +813,6 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {...@@ -700,7 +813,6 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
700 }813 }
701814
702 // Shared and static libraries passed via `-l` flag.815 // Shared and static libraries passed via `-l` flag.
703 var libs = std.ArrayList([]const u8).init(arena);
704 var search_lib_names = std.ArrayList([]const u8).init(arena);816 var search_lib_names = std.ArrayList([]const u8).init(arena);
705817
706 const system_libs = self.base.options.system_libs.keys();818 const system_libs = self.base.options.system_libs.keys();
...@@ -716,84 +828,15 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {...@@ -716,84 +828,15 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
716 try search_lib_names.append(link_lib);828 try search_lib_names.append(link_lib);
717 }829 }
718830
719 var search_lib_dirs = std.ArrayList([]const u8).init(arena);831 var libs = std.ArrayList([]const u8).init(arena);
720832 try resolvePaths(
721 for (self.base.options.lib_dirs) |path| {833 arena,
722 if (fs.path.isAbsolute(path)) {834 &libs,
723 var candidates = std.ArrayList([]const u8).init(arena);835 self.base.options.syslibroot,
724 if (self.base.options.syslibroot) |syslibroot| {836 self.base.options.lib_dirs,
725 const full_path = try fs.path.join(arena, &[_][]const u8{ syslibroot, path });837 search_lib_names.items,
726 try candidates.append(full_path);838 .lib,
727 }839 );
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 }
797840
798 // rpaths841 // rpaths
799 var rpath_table = std.StringArrayHashMap(void).init(arena);842 var rpath_table = std.StringArrayHashMap(void).init(arena);
...@@ -809,9 +852,14 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {...@@ -809,9 +852,14 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
809 }852 }
810853
811 // frameworks854 // frameworks
812 for (self.base.options.frameworks) |framework| {855 try resolvePaths(
813 log.warn("frameworks not yet supported for '-framework {s}'", .{framework});856 arena,
814 }857 &libs,
858 self.base.options.syslibroot,
859 self.base.options.framework_dirs,
860 self.base.options.frameworks,
861 .framework,
862 );
815863
816 if (self.base.options.verbose_link) {864 if (self.base.options.verbose_link) {
817 var argv = std.ArrayList([]const u8).init(arena);865 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 {...@@ -60,7 +60,7 @@ pub fn parse(self: *Stub) !void {
60 const lib_stub = self.lib_stub orelse return error.EmptyStubFile;60 const lib_stub = self.lib_stub orelse return error.EmptyStubFile;
61 if (lib_stub.inner.len == 0) return error.EmptyStubFile;61 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
65 const umbrella_lib = lib_stub.inner[0];65 const umbrella_lib = lib_stub.inner[0];
66 self.id = .{66 self.id = .{
...@@ -84,9 +84,24 @@ pub fn parse(self: *Stub) !void {...@@ -84,9 +84,24 @@ pub fn parse(self: *Stub) !void {
84 for (exports) |exp| {84 for (exports) |exp| {
85 if (!hasTarget(exp.targets, target_string)) continue;85 if (!hasTarget(exp.targets, target_string)) continue;
8686
87 for (exp.symbols) |sym_name| {87 if (exp.symbols) |symbols| {
88 if (self.symbols.contains(sym_name)) continue;88 for (symbols) |sym_name| {
89 try self.symbols.putNoClobber(self.allocator, 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 }
90 }105 }
91 }106 }
92 }107 }
...@@ -101,6 +116,20 @@ pub fn parse(self: *Stub) !void {...@@ -101,6 +116,20 @@ pub fn parse(self: *Stub) !void {
101 }116 }
102 }117 }
103 }118 }
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 }
104 }133 }
105}134}
106135
src/link/tapi.zig+2-1
...@@ -36,7 +36,8 @@ pub const LibStub = struct {...@@ -36,7 +36,8 @@ pub const LibStub = struct {
36 },36 },
37 exports: ?[]const struct {37 exports: ?[]const struct {
38 targets: []const []const u8,38 targets: []const []const u8,
39 symbols: []const []const u8,39 symbols: ?[]const []const u8,
40 objc_classes: ?[]const []const u8,
40 },41 },
41 reexports: ?[]const struct {42 reexports: ?[]const struct {
42 targets: []const []const u8,43 targets: []const []const u8,