| ... | @@ -98,6 +98,10 @@ headerpad_max_install_names: bool, | ... | @@ -98,6 +98,10 @@ headerpad_max_install_names: bool, |
| 98 | dead_strip_dylibs: bool, | 98 | dead_strip_dylibs: bool, |
| 99 | /// Treatment of undefined symbols | 99 | /// Treatment of undefined symbols |
| 100 | undefined_treatment: UndefinedTreatment, | 100 | undefined_treatment: UndefinedTreatment, |
| | 101 | /// Resolved list of library search directories |
| | 102 | lib_dirs: []const []const u8, |
| | 103 | /// Resolved list of framework search directories |
| | 104 | framework_dirs: []const []const u8, |
| 101 | /// List of input frameworks | 105 | /// List of input frameworks |
| 102 | frameworks: []const Framework, | 106 | frameworks: []const Framework, |
| 103 | /// Install name for the dylib. | 107 | /// Install name for the dylib. |
| ... | @@ -112,6 +116,8 @@ platform: Platform, | ... | @@ -112,6 +116,8 @@ platform: Platform, |
| 112 | sdk_version: ?std.SemanticVersion, | 116 | sdk_version: ?std.SemanticVersion, |
| 113 | /// Rpath table | 117 | /// Rpath table |
| 114 | rpath_table: std.StringArrayHashMapUnmanaged(void) = .{}, | 118 | rpath_table: std.StringArrayHashMapUnmanaged(void) = .{}, |
| | 119 | /// When set to true, the linker will hoist all dylibs including system dependent dylibs. |
| | 120 | no_implicit_dylibs: bool = false, |
| 115 | | 121 | |
| 116 | /// Hot-code swapping state. | 122 | /// Hot-code swapping state. |
| 117 | hot_state: if (is_hot_update_compatible) HotUpdateState else struct {} = .{}, | 123 | hot_state: if (is_hot_update_compatible) HotUpdateState else struct {} = .{}, |
| ... | @@ -190,6 +196,8 @@ pub fn createEmpty( | ... | @@ -190,6 +196,8 @@ pub fn createEmpty( |
| 190 | .platform = Platform.fromTarget(target), | 196 | .platform = Platform.fromTarget(target), |
| 191 | .sdk_version = if (options.darwin_sdk_layout) |layout| inferSdkVersion(comp, layout) else null, | 197 | .sdk_version = if (options.darwin_sdk_layout) |layout| inferSdkVersion(comp, layout) else null, |
| 192 | .undefined_treatment = if (allow_shlib_undefined) .dynamic_lookup else .@"error", | 198 | .undefined_treatment = if (allow_shlib_undefined) .dynamic_lookup else .@"error", |
| | 199 | .lib_dirs = options.lib_dirs, |
| | 200 | .framework_dirs = options.framework_dirs, |
| 193 | }; | 201 | }; |
| 194 | if (use_llvm and comp.config.have_zcu) { | 202 | if (use_llvm and comp.config.have_zcu) { |
| 195 | self.llvm_object = try LlvmObject.create(arena, comp); | 203 | self.llvm_object = try LlvmObject.create(arena, comp); |
| ... | @@ -483,7 +491,18 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node | ... | @@ -483,7 +491,18 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node |
| 483 | self.getFile(index).?.dylib.umbrella = index; | 491 | self.getFile(index).?.dylib.umbrella = index; |
| 484 | } | 492 | } |
| 485 | | 493 | |
| 486 | // TODO: try self.parseDependentDylibs(); | 494 | if (self.dylibs.items.len > 0) { |
| | 495 | self.parseDependentDylibs() catch |err| { |
| | 496 | switch (err) { |
| | 497 | error.MissingLibraryDependencies => {}, |
| | 498 | else => |e| try self.reportUnexpectedError( |
| | 499 | "unexpected error while parsing dependent libraries: {s}", |
| | 500 | .{@errorName(e)}, |
| | 501 | ), |
| | 502 | } |
| | 503 | return error.FlushFailure; |
| | 504 | }; |
| | 505 | } |
| 487 | | 506 | |
| 488 | for (self.dylibs.items) |index| { | 507 | for (self.dylibs.items) |index| { |
| 489 | const dylib = self.getFile(index).?.dylib; | 508 | const dylib = self.getFile(index).?.dylib; |
| ... | @@ -1056,152 +1075,198 @@ fn parseTbd(self: *MachO, lib: SystemLib, explicit: bool) ParseError!File.Index | ... | @@ -1056,152 +1075,198 @@ fn parseTbd(self: *MachO, lib: SystemLib, explicit: bool) ParseError!File.Index |
| 1056 | return index; | 1075 | return index; |
| 1057 | } | 1076 | } |
| 1058 | | 1077 | |
| 1059 | // /// According to ld64's manual, public (i.e., system) dylibs/frameworks are hoisted into the final | 1078 | /// According to ld64's manual, public (i.e., system) dylibs/frameworks are hoisted into the final |
| 1060 | // /// image unless overriden by -no_implicit_dylibs. | 1079 | /// image unless overriden by -no_implicit_dylibs. |
| 1061 | // fn isHoisted(self: *MachO, install_name: []const u8) bool { | 1080 | fn isHoisted(self: *MachO, install_name: []const u8) bool { |
| 1062 | // _ = self; | 1081 | if (self.no_implicit_dylibs) return true; |
| 1063 | // // TODO: if (self.options.no_implicit_dylibs) return true; | 1082 | if (std.fs.path.dirname(install_name)) |dirname| { |
| 1064 | // if (std.fs.path.dirname(install_name)) |dirname| { | 1083 | if (mem.startsWith(u8, dirname, "/usr/lib")) return true; |
| 1065 | // if (mem.startsWith(u8, dirname, "/usr/lib")) return true; | 1084 | if (eatPrefix(dirname, "/System/Library/Frameworks/")) |path| { |
| 1066 | // if (eatPrefix(dirname, "/System/Library/Frameworks/")) |path| { | 1085 | const basename = std.fs.path.basename(install_name); |
| 1067 | // const basename = std.fs.path.basename(install_name); | 1086 | if (mem.indexOfScalar(u8, path, '.')) |index| { |
| 1068 | // if (mem.indexOfScalar(u8, path, '.')) |index| { | 1087 | if (mem.eql(u8, basename, path[0..index])) return true; |
| 1069 | // if (mem.eql(u8, basename, path[0..index])) return true; | 1088 | } |
| 1070 | // } | 1089 | } |
| 1071 | // } | 1090 | } |
| 1072 | // } | 1091 | return false; |
| 1073 | // return false; | 1092 | } |
| 1074 | // } | 1093 | |
| 1075 | | 1094 | fn accessPath(path: []const u8) !bool { |
| 1076 | // TODO: | 1095 | std.fs.cwd().access(path, .{}) catch |err| switch (err) { |
| 1077 | // fn parseDependentDylibs( | 1096 | error.FileNotFound => return false, |
| 1078 | // self: *MachO | 1097 | else => |e| return e, |
| 1079 | // ) !void { | 1098 | }; |
| 1080 | // const tracy = trace(@src()); | 1099 | return true; |
| 1081 | // defer tracy.end(); | 1100 | } |
| 1082 | | 1101 | |
| 1083 | // const gpa = self.base.comp.gpa; | 1102 | fn resolveLib(arena: Allocator, search_dirs: []const []const u8, name: []const u8) !?[]const u8 { |
| 1084 | // const lib_dirs = self.base.comp.lib_dirs; | 1103 | const path = try std.fmt.allocPrint(arena, "lib{s}", .{name}); |
| 1085 | // const framework_dirs = self.base.comp.framework_dirs; | 1104 | for (search_dirs) |dir| { |
| 1086 | | 1105 | for (&[_][]const u8{ ".tbd", ".dylib" }) |ext| { |
| 1087 | // if (self.dylibs.items.len == 0) return; | 1106 | const with_ext = try std.fmt.allocPrint(arena, "{s}{s}", .{ path, ext }); |
| 1088 | | 1107 | const full_path = try std.fs.path.join(arena, &[_][]const u8{ dir, with_ext }); |
| 1089 | // var arena = std.heap.ArenaAllocator.init(gpa); | 1108 | if (try accessPath(full_path)) return full_path; |
| 1090 | // defer arena.deinit(); | 1109 | } |
| 1091 | | 1110 | } |
| 1092 | // // TODO handle duplicate dylibs - it is not uncommon to have the same dylib loaded multiple times | 1111 | return null; |
| 1093 | // // in which case we should track that and return File.Index immediately instead re-parsing paths. | 1112 | } |
| 1094 | | 1113 | |
| 1095 | // var index: usize = 0; | 1114 | fn resolveFramework(arena: Allocator, search_dirs: []const []const u8, name: []const u8) !?[]const u8 { |
| 1096 | // while (index < self.dylibs.items.len) : (index += 1) { | 1115 | const prefix = try std.fmt.allocPrint(arena, "{s}.framework", .{name}); |
| 1097 | // const dylib_index = self.dylibs.items[index]; | 1116 | const path = try std.fs.path.join(arena, &[_][]const u8{ prefix, name }); |
| 1098 | | 1117 | for (search_dirs) |dir| { |
| 1099 | // var dependents = std.ArrayList(File.Index).init(gpa); | 1118 | for (&[_][]const u8{ ".tbd", ".dylib" }) |ext| { |
| 1100 | // defer dependents.deinit(); | 1119 | const with_ext = try std.fmt.allocPrint(arena, "{s}{s}", .{ path, ext }); |
| 1101 | // try dependents.ensureTotalCapacityPrecise(self.getFile(dylib_index).?.dylib.dependents.items.len); | 1120 | const full_path = try std.fs.path.join(arena, &[_][]const u8{ dir, with_ext }); |
| 1102 | | 1121 | if (try accessPath(full_path)) return full_path; |
| 1103 | // const is_weak = self.getFile(dylib_index).?.dylib.weak; | 1122 | } |
| 1104 | // for (self.getFile(dylib_index).?.dylib.dependents.items) |id| { | 1123 | } |
| 1105 | // // We will search for the dependent dylibs in the following order: | 1124 | return null; |
| 1106 | // // 1. Basename is in search lib directories or framework directories | 1125 | } |
| 1107 | // // 2. If name is an absolute path, search as-is optionally prepending a syslibroot | 1126 | |
| 1108 | // // if specified. | 1127 | fn parseDependentDylibs(self: *MachO) !void { |
| 1109 | // // 3. If name is a relative path, substitute @rpath, @loader_path, @executable_path with | 1128 | const tracy = trace(@src()); |
| 1110 | // // dependees list of rpaths, and search there. | 1129 | defer tracy.end(); |
| 1111 | // // 4. Finally, just search the provided relative path directly in CWD. | 1130 | |
| 1112 | // const full_path = full_path: { | 1131 | const gpa = self.base.comp.gpa; |
| 1113 | // fail: { | 1132 | const lib_dirs = self.lib_dirs; |
| 1114 | // const stem = std.fs.path.stem(id.name); | 1133 | const framework_dirs = self.framework_dirs; |
| 1115 | // const framework_name = try std.fmt.allocPrint(gpa, "{s}.framework" ++ std.fs.path.sep_str ++ "{s}", .{ | 1134 | |
| 1116 | // stem, | 1135 | var arena = std.heap.ArenaAllocator.init(gpa); |
| 1117 | // stem, | 1136 | defer arena.deinit(); |
| 1118 | // }); | 1137 | |
| 1119 | // defer gpa.free(framework_name); | 1138 | // TODO handle duplicate dylibs - it is not uncommon to have the same dylib loaded multiple times |
| 1120 | | 1139 | // in which case we should track that and return File.Index immediately instead re-parsing paths. |
| 1121 | // if (mem.endsWith(u8, id.name, framework_name)) { | 1140 | |
| 1122 | // // Framework | 1141 | var has_errors = false; |
| 1123 | // const full_path = (try self.resolveFramework(arena, framework_dirs, stem)) orelse break :fail; | 1142 | var index: usize = 0; |
| 1124 | // break :full_path full_path; | 1143 | while (index < self.dylibs.items.len) : (index += 1) { |
| 1125 | // } | 1144 | const dylib_index = self.dylibs.items[index]; |
| 1126 | | 1145 | |
| 1127 | // // Library | 1146 | var dependents = std.ArrayList(File.Index).init(gpa); |
| 1128 | // const lib_name = eatPrefix(stem, "lib") orelse stem; | 1147 | defer dependents.deinit(); |
| 1129 | // const full_path = (try self.resolveLib(arena, lib_dirs, lib_name)) orelse break :fail; | 1148 | try dependents.ensureTotalCapacityPrecise(self.getFile(dylib_index).?.dylib.dependents.items.len); |
| 1130 | // break :full_path full_path; | 1149 | |
| 1131 | // } | 1150 | const is_weak = self.getFile(dylib_index).?.dylib.weak; |
| 1132 | | 1151 | for (self.getFile(dylib_index).?.dylib.dependents.items) |id| { |
| 1133 | // if (std.fs.path.isAbsolute(id.name)) { | 1152 | // We will search for the dependent dylibs in the following order: |
| 1134 | // const path = if (self.options.syslibroot) |root| | 1153 | // 1. Basename is in search lib directories or framework directories |
| 1135 | // try std.fs.path.join(arena, &.{ root, id.name }) | 1154 | // 2. If name is an absolute path, search as-is optionally prepending a syslibroot |
| 1136 | // else | 1155 | // if specified. |
| 1137 | // id.name; | 1156 | // 3. If name is a relative path, substitute @rpath, @loader_path, @executable_path with |
| 1138 | // for (&[_][]const u8{ "", ".tbd", ".dylib" }) |ext| { | 1157 | // dependees list of rpaths, and search there. |
| 1139 | // const full_path = try std.fmt.allocPrint(arena, "{s}{s}", .{ path, ext }); | 1158 | // 4. Finally, just search the provided relative path directly in CWD. |
| 1140 | // if (try accessLibPath(full_path)) break :full_path full_path; | 1159 | const full_path = full_path: { |
| 1141 | // } | 1160 | fail: { |
| 1142 | // } | 1161 | const stem = std.fs.path.stem(id.name); |
| 1143 | | 1162 | const framework_name = try std.fmt.allocPrint(gpa, "{s}.framework" ++ std.fs.path.sep_str ++ "{s}", .{ |
| 1144 | // if (eatPrefix(id.name, "@rpath/")) |path| { | 1163 | stem, |
| 1145 | // const dylib = self.getFile(dylib_index).?.dylib; | 1164 | stem, |
| 1146 | // for (self.getFile(dylib.umbrella).?.dylib.rpaths.keys()) |rpath| { | 1165 | }); |
| 1147 | // const prefix = eatPrefix(rpath, "@loader_path/") orelse rpath; | 1166 | defer gpa.free(framework_name); |
| 1148 | // const rel_path = try std.fs.path.join(arena, &.{ prefix, path }); | 1167 | |
| 1149 | // var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined; | 1168 | if (mem.endsWith(u8, id.name, framework_name)) { |
| 1150 | // const full_path = std.fs.realpath(rel_path, &buffer) catch continue; | 1169 | // Framework |
| 1151 | // break :full_path full_path; | 1170 | const full_path = (try resolveFramework(arena.allocator(), framework_dirs, stem)) orelse break :fail; |
| 1152 | // } | 1171 | break :full_path full_path; |
| 1153 | // } else if (eatPrefix(id.name, "@loader_path/")) |_| { | 1172 | } |
| 1154 | // return self.base.fatal("{s}: TODO handle install_name '{s}'", .{ | 1173 | |
| 1155 | // self.getFile(dylib_index).?.dylib.path, id.name, | 1174 | // Library |
| 1156 | // }); | 1175 | const lib_name = eatPrefix(stem, "lib") orelse stem; |
| 1157 | // } else if (eatPrefix(id.name, "@executable_path/")) |_| { | 1176 | const full_path = (try resolveLib(arena.allocator(), lib_dirs, lib_name)) orelse break :fail; |
| 1158 | // return self.base.fatal("{s}: TODO handle install_name '{s}'", .{ | 1177 | break :full_path full_path; |
| 1159 | // self.getFile(dylib_index).?.dylib.path, id.name, | 1178 | } |
| 1160 | // }); | 1179 | |
| 1161 | // } | 1180 | if (std.fs.path.isAbsolute(id.name)) { |
| 1162 | | 1181 | const path = if (self.base.comp.sysroot) |root| |
| 1163 | // var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined; | 1182 | try std.fs.path.join(arena.allocator(), &.{ root, id.name }) |
| 1164 | // const full_path = std.fs.realpath(id.name, &buffer) catch { | 1183 | else |
| 1165 | // dependents.appendAssumeCapacity(0); | 1184 | id.name; |
| 1166 | // continue; | 1185 | for (&[_][]const u8{ "", ".tbd", ".dylib" }) |ext| { |
| 1167 | // }; | 1186 | const full_path = try std.fmt.allocPrint(arena.allocator(), "{s}{s}", .{ path, ext }); |
| 1168 | // break :full_path full_path; | 1187 | if (try accessPath(full_path)) break :full_path full_path; |
| 1169 | // }; | 1188 | } |
| 1170 | // const link_obj = LinkObject{ | 1189 | } |
| 1171 | // .path = full_path, | 1190 | |
| 1172 | // .tag = .obj, | 1191 | if (eatPrefix(id.name, "@rpath/")) |path| { |
| 1173 | // .weak = is_weak, | 1192 | const dylib = self.getFile(dylib_index).?.dylib; |
| 1174 | // }; | 1193 | for (self.getFile(dylib.umbrella).?.dylib.rpaths.keys()) |rpath| { |
| 1175 | // const file_index = file_index: { | 1194 | const prefix = eatPrefix(rpath, "@loader_path/") orelse rpath; |
| 1176 | // if (try self.parseDylib(arena, link_obj, false)) |file| break :file_index file; | 1195 | const rel_path = try std.fs.path.join(arena.allocator(), &.{ prefix, path }); |
| 1177 | // if (try self.parseTbd(link_obj, false)) |file| break :file_index file; | 1196 | var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined; |
| 1178 | // break :file_index @as(File.Index, 0); | 1197 | const full_path = std.fs.realpath(rel_path, &buffer) catch continue; |
| 1179 | // }; | 1198 | break :full_path full_path; |
| 1180 | // dependents.appendAssumeCapacity(file_index); | 1199 | } |
| 1181 | // } | 1200 | } else if (eatPrefix(id.name, "@loader_path/")) |_| { |
| 1182 | | 1201 | try self.reportParseError2(dylib_index, "TODO handle install_name '{s}'", .{id.name}); |
| 1183 | // const dylib = self.getFile(dylib_index).?.dylib; | 1202 | return error.Unhandled; |
| 1184 | // for (dylib.dependents.items, dependents.items) |id, file_index| { | 1203 | } else if (eatPrefix(id.name, "@executable_path/")) |_| { |
| 1185 | // if (self.getFile(file_index)) |file| { | 1204 | try self.reportParseError2(dylib_index, "TODO handle install_name '{s}'", .{id.name}); |
| 1186 | // const dep_dylib = file.dylib; | 1205 | return error.Unhandled; |
| 1187 | // dep_dylib.hoisted = self.isHoisted(id.name); | 1206 | } |
| 1188 | // if (self.getFile(dep_dylib.umbrella) == null) { | 1207 | |
| 1189 | // dep_dylib.umbrella = dylib.umbrella; | 1208 | var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined; |
| 1190 | // } | 1209 | const full_path = std.fs.realpath(id.name, &buffer) catch { |
| 1191 | // if (!dep_dylib.hoisted) { | 1210 | dependents.appendAssumeCapacity(0); |
| 1192 | // const umbrella = dep_dylib.getUmbrella(self); | 1211 | continue; |
| 1193 | // for (dep_dylib.exports.items(.name), dep_dylib.exports.items(.flags)) |off, flags| { | 1212 | }; |
| 1194 | // try umbrella.addExport(gpa, dep_dylib.getString(off), flags); | 1213 | break :full_path full_path; |
| 1195 | // } | 1214 | }; |
| 1196 | // try umbrella.rpaths.ensureUnusedCapacity(gpa, dep_dylib.rpaths.keys().len); | 1215 | const lib = SystemLib{ |
| 1197 | // for (dep_dylib.rpaths.keys()) |rpath| { | 1216 | .path = full_path, |
| 1198 | // umbrella.rpaths.putAssumeCapacity(rpath, {}); | 1217 | .weak = is_weak, |
| 1199 | // } | 1218 | }; |
| 1200 | // } | 1219 | const file_index = file_index: { |
| 1201 | // } else self.base.fatal("{s}: unable to resolve dependency {s}", .{ dylib.getUmbrella(self).path, id.name }); | 1220 | if (try fat.isFatLibrary(lib.path)) { |
| 1202 | // } | 1221 | const fat_arch = try self.parseFatLibrary(lib.path); |
| 1203 | // } | 1222 | if (try Dylib.isDylib(lib.path, fat_arch)) { |
| 1204 | // } | 1223 | break :file_index try self.parseDylib(lib, false, fat_arch); |
| | 1224 | } else break :file_index @as(File.Index, 0); |
| | 1225 | } else if (try Dylib.isDylib(lib.path, null)) { |
| | 1226 | break :file_index try self.parseDylib(lib, false, null); |
| | 1227 | } else { |
| | 1228 | const file_index = self.parseTbd(lib, false) catch |err| switch (err) { |
| | 1229 | error.MalformedTbd => @as(File.Index, 0), |
| | 1230 | else => |e| return e, |
| | 1231 | }; |
| | 1232 | break :file_index file_index; |
| | 1233 | } |
| | 1234 | }; |
| | 1235 | dependents.appendAssumeCapacity(file_index); |
| | 1236 | } |
| | 1237 | |
| | 1238 | const dylib = self.getFile(dylib_index).?.dylib; |
| | 1239 | for (dylib.dependents.items, dependents.items) |id, file_index| { |
| | 1240 | if (self.getFile(file_index)) |file| { |
| | 1241 | const dep_dylib = file.dylib; |
| | 1242 | dep_dylib.hoisted = self.isHoisted(id.name); |
| | 1243 | if (self.getFile(dep_dylib.umbrella) == null) { |
| | 1244 | dep_dylib.umbrella = dylib.umbrella; |
| | 1245 | } |
| | 1246 | if (!dep_dylib.hoisted) { |
| | 1247 | const umbrella = dep_dylib.getUmbrella(self); |
| | 1248 | for (dep_dylib.exports.items(.name), dep_dylib.exports.items(.flags)) |off, flags| { |
| | 1249 | try umbrella.addExport(gpa, dep_dylib.getString(off), flags); |
| | 1250 | } |
| | 1251 | try umbrella.rpaths.ensureUnusedCapacity(gpa, dep_dylib.rpaths.keys().len); |
| | 1252 | for (dep_dylib.rpaths.keys()) |rpath| { |
| | 1253 | umbrella.rpaths.putAssumeCapacity(rpath, {}); |
| | 1254 | } |
| | 1255 | } |
| | 1256 | } else { |
| | 1257 | try self.reportDependencyError( |
| | 1258 | dylib.getUmbrella(self).index, |
| | 1259 | id.name, |
| | 1260 | "unable to resolve dependency", |
| | 1261 | .{}, |
| | 1262 | ); |
| | 1263 | has_errors = true; |
| | 1264 | } |
| | 1265 | } |
| | 1266 | } |
| | 1267 | |
| | 1268 | if (has_errors) return error.MissingLibraryDependencies; |
| | 1269 | } |
| 1205 | | 1270 | |
| 1206 | pub fn addUndefinedGlobals(self: *MachO) !void { | 1271 | pub fn addUndefinedGlobals(self: *MachO) !void { |
| 1207 | const gpa = self.base.comp.gpa; | 1272 | const gpa = self.base.comp.gpa; |
| ... | @@ -3459,24 +3524,17 @@ fn reportMissingLibraryError( | ... | @@ -3459,24 +3524,17 @@ fn reportMissingLibraryError( |
| 3459 | | 3524 | |
| 3460 | fn reportDependencyError( | 3525 | fn reportDependencyError( |
| 3461 | self: *MachO, | 3526 | self: *MachO, |
| 3462 | parent: []const u8, | 3527 | parent: File.Index, |
| 3463 | path: ?[]const u8, | 3528 | path: ?[]const u8, |
| 3464 | comptime format: []const u8, | 3529 | comptime format: []const u8, |
| 3465 | args: anytype, | 3530 | args: anytype, |
| 3466 | ) error{OutOfMemory}!void { | 3531 | ) error{OutOfMemory}!void { |
| 3467 | const comp = self.base.comp; | 3532 | var err = try self.addErrorWithNotes(2); |
| 3468 | const gpa = comp.gpa; | 3533 | try err.addMsg(self, format, args); |
| 3469 | try comp.link_errors.ensureUnusedCapacity(gpa, 1); | | |
| 3470 | var notes = try std.ArrayList(link.File.ErrorMsg).initCapacity(gpa, 2); | | |
| 3471 | defer notes.deinit(); | | |
| 3472 | if (path) |p| { | 3534 | if (path) |p| { |
| 3473 | notes.appendAssumeCapacity(.{ .msg = try std.fmt.allocPrint(gpa, "while parsing {s}", .{p}) }); | 3535 | try err.addNote(self, "while parsing {s}", .{p}); |
| 3474 | } | 3536 | } |
| 3475 | notes.appendAssumeCapacity(.{ .msg = try std.fmt.allocPrint(gpa, "a dependency of {s}", .{parent}) }); | 3537 | try err.addNote(self, "a dependency of {}", .{self.getFile(parent).?.fmtPath()}); |
| 3476 | comp.link_errors.appendAssumeCapacity(.{ | | |
| 3477 | .msg = try std.fmt.allocPrint(gpa, format, args), | | |
| 3478 | .notes = try notes.toOwnedSlice(), | | |
| 3479 | }); | | |
| 3480 | } | 3538 | } |
| 3481 | | 3539 | |
| 3482 | fn reportUnexpectedError(self: *MachO, comptime format: []const u8, args: anytype) error{OutOfMemory}!void { | 3540 | fn reportUnexpectedError(self: *MachO, comptime format: []const u8, args: anytype) error{OutOfMemory}!void { |