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