| ... | @@ -47,6 +47,11 @@ pub const DebugSymbols = @import("MachO/DebugSymbols.zig"); | ... | @@ -47,6 +47,11 @@ pub const DebugSymbols = @import("MachO/DebugSymbols.zig"); |
| 47 | | 47 | |
| 48 | pub const base_tag: File.Tag = File.Tag.macho; | 48 | pub const base_tag: File.Tag = File.Tag.macho; |
| 49 | | 49 | |
| | 50 | pub const SearchStrategy = enum { |
| | 51 | paths_first, |
| | 52 | dylibs_first, |
| | 53 | }; |
| | 54 | |
| 50 | base: File, | 55 | base: File, |
| 51 | | 56 | |
| 52 | /// If this is not null, an object file is created by LLVM and linked with LLD afterwards. | 57 | /// If this is not null, an object file is created by LLVM and linked with LLD afterwards. |
| ... | @@ -784,18 +789,43 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No | ... | @@ -784,18 +789,43 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 784 | } | 789 | } |
| 785 | | 790 | |
| 786 | var libs = std.ArrayList([]const u8).init(arena); | 791 | var libs = std.ArrayList([]const u8).init(arena); |
| 787 | for (search_lib_names.items) |lib_name| { | 792 | |
| 788 | // Assume ld64 default: -search_paths_first | 793 | // Assume ld64 default -search_paths_first if no strategy specified. |
| 789 | // Look in each directory for a dylib (stub first), and then for archive | 794 | const search_strategy = self.base.options.search_strategy orelse .paths_first; |
| 790 | // TODO implement alternative: -search_dylibs_first | 795 | outer: for (search_lib_names.items) |lib_name| { |
| 791 | for (&[_][]const u8{ ".tbd", ".dylib", ".a" }) |ext| { | 796 | switch (search_strategy) { |
| 792 | if (try resolveLib(arena, lib_dirs.items, lib_name, ext)) |full_path| { | 797 | .paths_first => { |
| 793 | try libs.append(full_path); | 798 | // Look in each directory for a dylib (stub first), and then for archive |
| 794 | break; | 799 | for (lib_dirs.items) |dir| { |
| 795 | } | 800 | for (&[_][]const u8{ ".tbd", ".dylib", ".a" }) |ext| { |
| 796 | } else { | 801 | if (try resolveLib(arena, dir, lib_name, ext)) |full_path| { |
| 797 | log.warn("library not found for '-l{s}'", .{lib_name}); | 802 | try libs.append(full_path); |
| 798 | lib_not_found = true; | 803 | continue :outer; |
| | 804 | } |
| | 805 | } |
| | 806 | } else { |
| | 807 | log.warn("library not found for '-l{s}'", .{lib_name}); |
| | 808 | lib_not_found = true; |
| | 809 | } |
| | 810 | }, |
| | 811 | .dylibs_first => { |
| | 812 | // First, look for a dylib in each search dir |
| | 813 | for (lib_dirs.items) |dir| { |
| | 814 | for (&[_][]const u8{ ".tbd", ".dylib" }) |ext| { |
| | 815 | if (try resolveLib(arena, dir, lib_name, ext)) |full_path| { |
| | 816 | try libs.append(full_path); |
| | 817 | continue :outer; |
| | 818 | } |
| | 819 | } |
| | 820 | } else for (lib_dirs.items) |dir| { |
| | 821 | if (try resolveLib(arena, dir, lib_name, ".a")) |full_path| { |
| | 822 | try libs.append(full_path); |
| | 823 | } else { |
| | 824 | log.warn("library not found for '-l{s}'", .{lib_name}); |
| | 825 | lib_not_found = true; |
| | 826 | } |
| | 827 | } |
| | 828 | }, |
| 799 | } | 829 | } |
| 800 | } | 830 | } |
| 801 | | 831 | |
| ... | @@ -811,19 +841,23 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No | ... | @@ -811,19 +841,23 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 811 | if (self.base.options.sysroot != null) blk: { | 841 | if (self.base.options.sysroot != null) blk: { |
| 812 | // Try stub file first. If we hit it, then we're done as the stub file | 842 | // Try stub file first. If we hit it, then we're done as the stub file |
| 813 | // re-exports every single symbol definition. | 843 | // re-exports every single symbol definition. |
| 814 | if (try resolveLib(arena, lib_dirs.items, "System", ".tbd")) |full_path| { | 844 | for (lib_dirs.items) |dir| { |
| 815 | try libs.append(full_path); | 845 | if (try resolveLib(arena, dir, "System", ".tbd")) |full_path| { |
| 816 | libsystem_available = true; | 846 | try libs.append(full_path); |
| 817 | break :blk; | 847 | libsystem_available = true; |
| | 848 | break :blk; |
| | 849 | } |
| 818 | } | 850 | } |
| 819 | // If we didn't hit the stub file, try .dylib next. However, libSystem.dylib | 851 | // If we didn't hit the stub file, try .dylib next. However, libSystem.dylib |
| 820 | // doesn't export libc.dylib which we'll need to resolve subsequently also. | 852 | // doesn't export libc.dylib which we'll need to resolve subsequently also. |
| 821 | if (try resolveLib(arena, lib_dirs.items, "System", ".dylib")) |libsystem_path| { | 853 | for (lib_dirs.items) |dir| { |
| 822 | if (try resolveLib(arena, lib_dirs.items, "c", ".dylib")) |libc_path| { | 854 | if (try resolveLib(arena, dir, "System", ".dylib")) |libsystem_path| { |
| 823 | try libs.append(libsystem_path); | 855 | if (try resolveLib(arena, dir, "c", ".dylib")) |libc_path| { |
| 824 | try libs.append(libc_path); | 856 | try libs.append(libsystem_path); |
| 825 | libsystem_available = true; | 857 | try libs.append(libc_path); |
| 826 | break :blk; | 858 | libsystem_available = true; |
| | 859 | break :blk; |
| | 860 | } |
| 827 | } | 861 | } |
| 828 | } | 862 | } |
| 829 | } | 863 | } |
| ... | @@ -847,11 +881,13 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No | ... | @@ -847,11 +881,13 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 847 | } | 881 | } |
| 848 | } | 882 | } |
| 849 | | 883 | |
| 850 | for (self.base.options.frameworks) |framework| { | 884 | outer: for (self.base.options.frameworks) |framework| { |
| 851 | for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| { | 885 | for (framework_dirs.items) |dir| { |
| 852 | if (try resolveFramework(arena, framework_dirs.items, framework, ext)) |full_path| { | 886 | for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| { |
| 853 | try libs.append(full_path); | 887 | if (try resolveFramework(arena, dir, framework, ext)) |full_path| { |
| 854 | break; | 888 | try libs.append(full_path); |
| | 889 | continue :outer; |
| | 890 | } |
| 855 | } | 891 | } |
| 856 | } else { | 892 | } else { |
| 857 | log.warn("framework not found for '-framework {s}'", .{framework}); | 893 | log.warn("framework not found for '-framework {s}'", .{framework}); |
| ... | @@ -934,6 +970,11 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No | ... | @@ -934,6 +970,11 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 934 | try argv.append(try std.fmt.allocPrint(arena, "0x{x}", .{pagezero_size})); | 970 | try argv.append(try std.fmt.allocPrint(arena, "0x{x}", .{pagezero_size})); |
| 935 | } | 971 | } |
| 936 | | 972 | |
| | 973 | if (self.base.options.search_strategy) |strat| switch (strat) { |
| | 974 | .paths_first => try argv.append("-search_paths_first"), |
| | 975 | .dylibs_first => try argv.append("-search_dylibs_first"), |
| | 976 | }; |
| | 977 | |
| 937 | if (self.base.options.entry) |entry| { | 978 | if (self.base.options.entry) |entry| { |
| 938 | try argv.append("-e"); | 979 | try argv.append("-e"); |
| 939 | try argv.append(entry); | 980 | try argv.append(entry); |
| ... | @@ -1183,51 +1224,41 @@ fn resolveSearchDir( | ... | @@ -1183,51 +1224,41 @@ fn resolveSearchDir( |
| 1183 | | 1224 | |
| 1184 | fn resolveLib( | 1225 | fn resolveLib( |
| 1185 | arena: Allocator, | 1226 | arena: Allocator, |
| 1186 | search_dirs: []const []const u8, | 1227 | search_dir: []const u8, |
| 1187 | name: []const u8, | 1228 | name: []const u8, |
| 1188 | ext: []const u8, | 1229 | ext: []const u8, |
| 1189 | ) !?[]const u8 { | 1230 | ) !?[]const u8 { |
| 1190 | const search_name = try std.fmt.allocPrint(arena, "lib{s}{s}", .{ name, ext }); | 1231 | const search_name = try std.fmt.allocPrint(arena, "lib{s}{s}", .{ name, ext }); |
| | 1232 | const full_path = try fs.path.join(arena, &[_][]const u8{ search_dir, search_name }); |
| 1191 | | 1233 | |
| 1192 | for (search_dirs) |dir| { | 1234 | // Check if the file exists. |
| 1193 | const full_path = try fs.path.join(arena, &[_][]const u8{ dir, search_name }); | 1235 | const tmp = fs.cwd().openFile(full_path, .{}) catch |err| switch (err) { |
| 1194 | | 1236 | error.FileNotFound => return null, |
| 1195 | // Check if the file exists. | 1237 | else => |e| return e, |
| 1196 | const tmp = fs.cwd().openFile(full_path, .{}) catch |err| switch (err) { | 1238 | }; |
| 1197 | error.FileNotFound => continue, | 1239 | defer tmp.close(); |
| 1198 | else => |e| return e, | | |
| 1199 | }; | | |
| 1200 | defer tmp.close(); | | |
| 1201 | | | |
| 1202 | return full_path; | | |
| 1203 | } | | |
| 1204 | | 1240 | |
| 1205 | return null; | 1241 | return full_path; |
| 1206 | } | 1242 | } |
| 1207 | | 1243 | |
| 1208 | fn resolveFramework( | 1244 | fn resolveFramework( |
| 1209 | arena: Allocator, | 1245 | arena: Allocator, |
| 1210 | search_dirs: []const []const u8, | 1246 | search_dir: []const u8, |
| 1211 | name: []const u8, | 1247 | name: []const u8, |
| 1212 | ext: []const u8, | 1248 | ext: []const u8, |
| 1213 | ) !?[]const u8 { | 1249 | ) !?[]const u8 { |
| 1214 | const search_name = try std.fmt.allocPrint(arena, "{s}{s}", .{ name, ext }); | 1250 | const search_name = try std.fmt.allocPrint(arena, "{s}{s}", .{ name, ext }); |
| 1215 | const prefix_path = try std.fmt.allocPrint(arena, "{s}.framework", .{name}); | 1251 | const prefix_path = try std.fmt.allocPrint(arena, "{s}.framework", .{name}); |
| | 1252 | const full_path = try fs.path.join(arena, &[_][]const u8{ search_dir, prefix_path, search_name }); |
| 1216 | | 1253 | |
| 1217 | for (search_dirs) |dir| { | 1254 | // Check if the file exists. |
| 1218 | const full_path = try fs.path.join(arena, &[_][]const u8{ dir, prefix_path, search_name }); | 1255 | const tmp = fs.cwd().openFile(full_path, .{}) catch |err| switch (err) { |
| 1219 | | 1256 | error.FileNotFound => return null, |
| 1220 | // Check if the file exists. | 1257 | else => |e| return e, |
| 1221 | const tmp = fs.cwd().openFile(full_path, .{}) catch |err| switch (err) { | 1258 | }; |
| 1222 | error.FileNotFound => continue, | 1259 | defer tmp.close(); |
| 1223 | else => |e| return e, | | |
| 1224 | }; | | |
| 1225 | defer tmp.close(); | | |
| 1226 | | | |
| 1227 | return full_path; | | |
| 1228 | } | | |
| 1229 | | 1260 | |
| 1230 | return null; | 1261 | return full_path; |
| 1231 | } | 1262 | } |
| 1232 | | 1263 | |
| 1233 | fn parseObject(self: *MachO, path: []const u8) !bool { | 1264 | fn parseObject(self: *MachO, path: []const u8) !bool { |