| ... | ... | @@ -679,10 +679,20 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 679 | 679 | // the relocatable object files. |
| 680 | 680 | self.invalidate_relocs = true; |
| 681 | 681 | |
| 682 | // Unpack must-link archives |
| 683 | var must_link_archives = std.StringArrayHashMap(void).init(arena); |
| 684 | try must_link_archives.ensureTotalCapacity(@intCast(u32, self.base.options.must_link_objects.len)); |
| 685 | for (self.base.options.must_link_objects) |lib| { |
| 686 | _ = must_link_archives.getOrPutAssumeCapacity(lib); |
| 687 | } |
| 688 | |
| 682 | 689 | // Positional arguments to the linker such as object files and static archives. |
| 683 | 690 | var positionals = std.ArrayList([]const u8).init(arena); |
| 684 | | |
| 685 | | try positionals.appendSlice(self.base.options.objects); |
| 691 | try positionals.ensureUnusedCapacity(self.base.options.objects.len); |
| 692 | for (self.base.options.objects) |obj| { |
| 693 | if (must_link_archives.contains(obj)) continue; |
| 694 | _ = positionals.appendAssumeCapacity(obj); |
| 695 | } |
| 686 | 696 | |
| 687 | 697 | for (comp.c_object_table.keys()) |key| { |
| 688 | 698 | try positionals.append(key.status.success.object_path); |
| ... | ... | @@ -889,12 +899,17 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 889 | 899 | try argv.append("dynamic_lookup"); |
| 890 | 900 | } |
| 891 | 901 | |
| 902 | for (self.base.options.must_link_objects) |lib| { |
| 903 | try argv.append(try std.fmt.allocPrint(arena, "-force_load {s}", .{lib})); |
| 904 | } |
| 905 | |
| 892 | 906 | Compilation.dump_argv(argv.items); |
| 893 | 907 | } |
| 894 | 908 | |
| 895 | 909 | var dependent_libs = std.fifo.LinearFifo(Dylib.Id, .Dynamic).init(self.base.allocator); |
| 896 | 910 | defer dependent_libs.deinit(); |
| 897 | 911 | try self.parseInputFiles(positionals.items, self.base.options.sysroot, &dependent_libs); |
| 912 | try self.parseAndForceLoadStaticArchives(must_link_archives.keys()); |
| 898 | 913 | try self.parseLibs(libs.items, self.base.options.sysroot, &dependent_libs); |
| 899 | 914 | try self.parseDependentLibs(self.base.options.sysroot, &dependent_libs); |
| 900 | 915 | } |
| ... | ... | @@ -1203,7 +1218,7 @@ fn parseObject(self: *MachO, path: []const u8) !bool { |
| 1203 | 1218 | return true; |
| 1204 | 1219 | } |
| 1205 | 1220 | |
| 1206 | | fn parseArchive(self: *MachO, path: []const u8) !bool { |
| 1221 | fn parseArchive(self: *MachO, path: []const u8, force_load: bool) !bool { |
| 1207 | 1222 | const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) { |
| 1208 | 1223 | error.FileNotFound => return false, |
| 1209 | 1224 | else => |e| return e, |
| ... | ... | @@ -1226,7 +1241,23 @@ fn parseArchive(self: *MachO, path: []const u8) !bool { |
| 1226 | 1241 | else => |e| return e, |
| 1227 | 1242 | }; |
| 1228 | 1243 | |
| 1229 | | try self.archives.append(self.base.allocator, archive); |
| 1244 | if (force_load) { |
| 1245 | defer archive.deinit(self.base.allocator); |
| 1246 | // Get all offsets from the ToC |
| 1247 | var offsets = std.AutoArrayHashMap(u32, void).init(self.base.allocator); |
| 1248 | defer offsets.deinit(); |
| 1249 | for (archive.toc.values()) |offs| { |
| 1250 | for (offs.items) |off| { |
| 1251 | _ = try offsets.getOrPut(off); |
| 1252 | } |
| 1253 | } |
| 1254 | for (offsets.keys()) |off| { |
| 1255 | const object = try self.objects.addOne(self.base.allocator); |
| 1256 | object.* = try archive.parseObject(self.base.allocator, self.base.options.target, off); |
| 1257 | } |
| 1258 | } else { |
| 1259 | try self.archives.append(self.base.allocator, archive); |
| 1260 | } |
| 1230 | 1261 | |
| 1231 | 1262 | return true; |
| 1232 | 1263 | } |
| ... | ... | @@ -1311,7 +1342,7 @@ fn parseInputFiles(self: *MachO, files: []const []const u8, syslibroot: ?[]const |
| 1311 | 1342 | log.debug("parsing input file path '{s}'", .{full_path}); |
| 1312 | 1343 | |
| 1313 | 1344 | if (try self.parseObject(full_path)) continue; |
| 1314 | | if (try self.parseArchive(full_path)) continue; |
| 1345 | if (try self.parseArchive(full_path, false)) continue; |
| 1315 | 1346 | if (try self.parseDylib(full_path, .{ |
| 1316 | 1347 | .syslibroot = syslibroot, |
| 1317 | 1348 | .dependent_libs = dependent_libs, |
| ... | ... | @@ -1321,6 +1352,21 @@ fn parseInputFiles(self: *MachO, files: []const []const u8, syslibroot: ?[]const |
| 1321 | 1352 | } |
| 1322 | 1353 | } |
| 1323 | 1354 | |
| 1355 | fn parseAndForceLoadStaticArchives(self: *MachO, files: []const []const u8) !void { |
| 1356 | for (files) |file_name| { |
| 1357 | const full_path = full_path: { |
| 1358 | var buffer: [fs.MAX_PATH_BYTES]u8 = undefined; |
| 1359 | const path = try fs.realpath(file_name, &buffer); |
| 1360 | break :full_path try self.base.allocator.dupe(u8, path); |
| 1361 | }; |
| 1362 | defer self.base.allocator.free(full_path); |
| 1363 | log.debug("parsing and force loading static archive '{s}'", .{full_path}); |
| 1364 | |
| 1365 | if (try self.parseArchive(full_path, true)) continue; |
| 1366 | log.warn("unknown filetype: expected static archive: '{s}'", .{file_name}); |
| 1367 | } |
| 1368 | } |
| 1369 | |
| 1324 | 1370 | fn parseLibs(self: *MachO, libs: []const []const u8, syslibroot: ?[]const u8, dependent_libs: anytype) !void { |
| 1325 | 1371 | for (libs) |lib| { |
| 1326 | 1372 | log.debug("parsing lib path '{s}'", .{lib}); |
| ... | ... | @@ -1328,7 +1374,7 @@ fn parseLibs(self: *MachO, libs: []const []const u8, syslibroot: ?[]const u8, de |
| 1328 | 1374 | .syslibroot = syslibroot, |
| 1329 | 1375 | .dependent_libs = dependent_libs, |
| 1330 | 1376 | })) continue; |
| 1331 | | if (try self.parseArchive(lib)) continue; |
| 1377 | if (try self.parseArchive(lib, false)) continue; |
| 1332 | 1378 | |
| 1333 | 1379 | log.warn("unknown filetype for a library: '{s}'", .{lib}); |
| 1334 | 1380 | } |