| ... | @@ -166,11 +166,13 @@ error_flags: File.ErrorFlags = File.ErrorFlags{}, | ... | @@ -166,11 +166,13 @@ error_flags: File.ErrorFlags = File.ErrorFlags{}, |
| 166 | | 166 | |
| 167 | load_commands_dirty: bool = false, | 167 | load_commands_dirty: bool = false, |
| 168 | sections_order_dirty: bool = false, | 168 | sections_order_dirty: bool = false, |
| 169 | | | |
| 170 | has_dices: bool = false, | 169 | has_dices: bool = false, |
| 171 | has_stabs: bool = false, | 170 | has_stabs: bool = false, |
| 172 | | 171 | /// A helper var to indicate if we are at the start of the incremental updates, or |
| 173 | args_digest: [Cache.hex_digest_len]u8 = undefined, | 172 | /// already somewhere further along the update-and-run chain. |
| | 173 | /// TODO once we add opening a prelinked output binary from file, this will become |
| | 174 | /// obsolete as we will carry on where we left off. |
| | 175 | cold_start: bool = false, |
| 174 | | 176 | |
| 175 | section_ordinals: std.AutoArrayHashMapUnmanaged(MatchingSection, void) = .{}, | 177 | section_ordinals: std.AutoArrayHashMapUnmanaged(MatchingSection, void) = .{}, |
| 176 | | 178 | |
| ... | @@ -336,6 +338,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio | ... | @@ -336,6 +338,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio |
| 336 | return self; | 338 | return self; |
| 337 | } | 339 | } |
| 338 | | 340 | |
| | 341 | // TODO Migrate DebugSymbols to the merged linker codepaths |
| 339 | // if (!options.strip and options.module != null) { | 342 | // if (!options.strip and options.module != null) { |
| 340 | // // Create dSYM bundle. | 343 | // // Create dSYM bundle. |
| 341 | // const dir = options.module.?.zig_cache_artifact_directory; | 344 | // const dir = options.module.?.zig_cache_artifact_directory; |
| ... | @@ -456,8 +459,11 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { | ... | @@ -456,8 +459,11 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { |
| 456 | defer if (!self.base.options.disable_lld_caching) man.deinit(); | 459 | defer if (!self.base.options.disable_lld_caching) man.deinit(); |
| 457 | | 460 | |
| 458 | var digest: [Cache.hex_digest_len]u8 = undefined; | 461 | var digest: [Cache.hex_digest_len]u8 = undefined; |
| | 462 | var needs_full_relink = true; |
| | 463 | |
| | 464 | cache: { |
| | 465 | if (use_stage1 and self.base.options.disable_lld_caching) break :cache; |
| 459 | | 466 | |
| 460 | if (!self.base.options.disable_lld_caching) { | | |
| 461 | man = comp.cache_parent.obtain(); | 467 | man = comp.cache_parent.obtain(); |
| 462 | | 468 | |
| 463 | // We are about to obtain this lock, so here we give other processes a chance first. | 469 | // We are about to obtain this lock, so here we give other processes a chance first. |
| ... | @@ -491,17 +497,36 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { | ... | @@ -491,17 +497,36 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { |
| 491 | id_symlink_basename, | 497 | id_symlink_basename, |
| 492 | &prev_digest_buf, | 498 | &prev_digest_buf, |
| 493 | ) catch |err| blk: { | 499 | ) catch |err| blk: { |
| 494 | log.debug("MachO Zld new_digest={s} error: {s}", .{ std.fmt.fmtSliceHexLower(&digest), @errorName(err) }); | 500 | log.debug("MachO Zld new_digest={s} error: {s}", .{ |
| | 501 | std.fmt.fmtSliceHexLower(&digest), |
| | 502 | @errorName(err), |
| | 503 | }); |
| 495 | // Handle this as a cache miss. | 504 | // Handle this as a cache miss. |
| 496 | break :blk prev_digest_buf[0..0]; | 505 | break :blk prev_digest_buf[0..0]; |
| 497 | }; | 506 | }; |
| 498 | if (mem.eql(u8, prev_digest, &digest)) { | 507 | if (mem.eql(u8, prev_digest, &digest)) { |
| 499 | log.debug("MachO Zld digest={s} match - skipping invocation", .{std.fmt.fmtSliceHexLower(&digest)}); | | |
| 500 | // Hot diggity dog! The output binary is already there. | 508 | // Hot diggity dog! The output binary is already there. |
| 501 | self.base.lock = man.toOwnedLock(); | 509 | |
| 502 | return; | 510 | if (use_stage1) { |
| | 511 | log.debug("MachO Zld digest={s} match - skipping invocation", .{std.fmt.fmtSliceHexLower(&digest)}); |
| | 512 | self.base.lock = man.toOwnedLock(); |
| | 513 | return; |
| | 514 | } else { |
| | 515 | log.debug("MachO Zld digest={s} match", .{std.fmt.fmtSliceHexLower(&digest)}); |
| | 516 | if (!self.cold_start) { |
| | 517 | log.debug(" no need to relink objects", .{}); |
| | 518 | needs_full_relink = false; |
| | 519 | } else { |
| | 520 | log.debug(" TODO parse prelinked binary and continue linking where we left off", .{}); |
| | 521 | // TODO until such time however, perform a full relink of objects. |
| | 522 | needs_full_relink = true; |
| | 523 | } |
| | 524 | } |
| 503 | } | 525 | } |
| 504 | log.debug("MachO Zld prev_digest={s} new_digest={s}", .{ std.fmt.fmtSliceHexLower(prev_digest), std.fmt.fmtSliceHexLower(&digest) }); | 526 | log.debug("MachO Zld prev_digest={s} new_digest={s}", .{ |
| | 527 | std.fmt.fmtSliceHexLower(prev_digest), |
| | 528 | std.fmt.fmtSliceHexLower(&digest), |
| | 529 | }); |
| 505 | | 530 | |
| 506 | // We are about to change the output file to be different, so we invalidate the build hash now. | 531 | // We are about to change the output file to be different, so we invalidate the build hash now. |
| 507 | directory.handle.deleteFile(id_symlink_basename) catch |err| switch (err) { | 532 | directory.handle.deleteFile(id_symlink_basename) catch |err| switch (err) { |
| ... | @@ -509,7 +534,6 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { | ... | @@ -509,7 +534,6 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { |
| 509 | else => |e| return e, | 534 | else => |e| return e, |
| 510 | }; | 535 | }; |
| 511 | } | 536 | } |
| 512 | | | |
| 513 | const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path}); | 537 | const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path}); |
| 514 | | 538 | |
| 515 | if (self.base.options.output_mode == .Obj) { | 539 | if (self.base.options.output_mode == .Obj) { |
| ... | @@ -557,34 +581,6 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { | ... | @@ -557,34 +581,6 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { |
| 557 | try self.strtab.append(self.base.allocator, 0); | 581 | try self.strtab.append(self.base.allocator, 0); |
| 558 | } | 582 | } |
| 559 | | 583 | |
| 560 | const needs_full_relink = blk: { | | |
| 561 | if (use_stage1) break :blk true; | | |
| 562 | | | |
| 563 | var hh: Cache.HashHelper = .{}; | | |
| 564 | hh.addListOfBytes(self.base.options.objects); | | |
| 565 | for (comp.c_object_table.keys()) |key| { | | |
| 566 | hh.addBytes(key.status.success.object_path); | | |
| 567 | } | | |
| 568 | hh.addOptionalBytes(module_obj_path); | | |
| 569 | if (comp.compiler_rt_static_lib) |lib| { | | |
| 570 | hh.addBytes(lib.full_object_path); | | |
| 571 | } | | |
| 572 | if (self.base.options.link_libcpp) { | | |
| 573 | hh.addBytes(comp.libcxxabi_static_lib.?.full_object_path); | | |
| 574 | hh.addBytes(comp.libcxx_static_lib.?.full_object_path); | | |
| 575 | } | | |
| 576 | hh.addListOfBytes(self.base.options.lib_dirs); | | |
| 577 | hh.addListOfBytes(self.base.options.framework_dirs); | | |
| 578 | hh.addListOfBytes(self.base.options.frameworks); | | |
| 579 | hh.addListOfBytes(self.base.options.rpath_list); | | |
| 580 | hh.addStringSet(self.base.options.system_libs); | | |
| 581 | hh.addOptionalBytes(self.base.options.sysroot); | | |
| 582 | const new_digest = hh.final(); | | |
| 583 | const needs_full_relink = !mem.eql(u8, &new_digest, &self.args_digest); | | |
| 584 | mem.copy(u8, &self.args_digest, &new_digest); | | |
| 585 | break :blk needs_full_relink; | | |
| 586 | }; | | |
| 587 | | | |
| 588 | if (needs_full_relink) { | 584 | if (needs_full_relink) { |
| 589 | self.objects.clearRetainingCapacity(); | 585 | self.objects.clearRetainingCapacity(); |
| 590 | self.archives.clearRetainingCapacity(); | 586 | self.archives.clearRetainingCapacity(); |
| ... | @@ -848,22 +844,6 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { | ... | @@ -848,22 +844,6 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { |
| 848 | try self.allocateGlobalSymbols(); | 844 | try self.allocateGlobalSymbols(); |
| 849 | try self.writeAtoms(); | 845 | try self.writeAtoms(); |
| 850 | | 846 | |
| 851 | // log.warn("Locals:", .{}); | | |
| 852 | // for (self.locals.items) |sym, i| { | | |
| 853 | // log.warn(" => {d}: {s}, {}", .{ i, self.getString(sym.n_strx), sym }); | | |
| 854 | // } | | |
| 855 | // log.warn("Globals:", .{}); | | |
| 856 | // for (self.globals.items) |sym, i| { | | |
| 857 | // log.warn(" => {d}: {s} {}", .{ i, self.getString(sym.n_strx), sym }); | | |
| 858 | // } | | |
| 859 | // { | | |
| 860 | // log.warn("Resolver:", .{}); | | |
| 861 | // var it = self.symbol_resolver.iterator(); | | |
| 862 | // while (it.next()) |entry| { | | |
| 863 | // log.warn(" => {s}: {}", .{ self.getString(entry.key_ptr.*), entry.value_ptr.* }); | | |
| 864 | // } | | |
| 865 | // } | | |
| 866 | | | |
| 867 | if (self.bss_section_index) |idx| { | 847 | if (self.bss_section_index) |idx| { |
| 868 | const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; | 848 | const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 869 | const sect = &seg.sections.items[idx]; | 849 | const sect = &seg.sections.items[idx]; |
| ... | @@ -880,7 +860,8 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { | ... | @@ -880,7 +860,8 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { |
| 880 | try self.flushModule(comp); | 860 | try self.flushModule(comp); |
| 881 | } | 861 | } |
| 882 | | 862 | |
| 883 | if (!self.base.options.disable_lld_caching) { | 863 | cache: { |
| | 864 | if (use_stage1 and self.base.options.disable_lld_caching) break :cache; |
| 884 | // Update the file with the digest. If it fails we can continue; it only | 865 | // Update the file with the digest. If it fails we can continue; it only |
| 885 | // means that the next invocation will have an unnecessary cache miss. | 866 | // means that the next invocation will have an unnecessary cache miss. |
| 886 | Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| { | 867 | Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| { |
| ... | @@ -894,6 +875,8 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { | ... | @@ -894,6 +875,8 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { |
| 894 | // other processes clobbering it. | 875 | // other processes clobbering it. |
| 895 | self.base.lock = man.toOwnedLock(); | 876 | self.base.lock = man.toOwnedLock(); |
| 896 | } | 877 | } |
| | 878 | |
| | 879 | self.cold_start = false; |
| 897 | } | 880 | } |
| 898 | | 881 | |
| 899 | pub fn flushModule(self: *MachO, comp: *Compilation) !void { | 882 | pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| ... | @@ -3929,6 +3912,8 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -3929,6 +3912,8 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 3929 | }); | 3912 | }); |
| 3930 | self.load_commands_dirty = true; | 3913 | self.load_commands_dirty = true; |
| 3931 | } | 3914 | } |
| | 3915 | |
| | 3916 | self.cold_start = true; |
| 3932 | } | 3917 | } |
| 3933 | | 3918 | |
| 3934 | const AllocateSectionOpts = struct { | 3919 | const AllocateSectionOpts = struct { |