diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 3e7e3a4e8a..11127495ab 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -919,7 +919,16 @@ fn addObject(self: *MachO, path: Path, handle: File.HandleIndex, offset: u64) !v const tracy = trace(@src()); defer tracy.end(); - const gpa = self.base.comp.gpa; + const comp = self.base.comp; + const gpa = comp.gpa; + + const abs_path = try std.fs.path.resolvePosix(gpa, &.{ + comp.dirs.cwd, + path.root_dir.path orelse ".", + path.sub_path, + }); + errdefer gpa.free(abs_path); + const mtime: u64 = mtime: { const file = self.getFileHandle(handle); const stat = file.stat() catch break :mtime 0; @@ -928,10 +937,7 @@ fn addObject(self: *MachO, path: Path, handle: File.HandleIndex, offset: u64) !v const index = @as(File.Index, @intCast(try self.files.addOne(gpa))); self.files.set(index, .{ .object = .{ .offset = offset, - .path = .{ - .root_dir = path.root_dir, - .sub_path = try gpa.dupe(u8, path.sub_path), - }, + .path = abs_path, .file_handle = handle, .mtime = mtime, .index = index, diff --git a/src/link/MachO/Archive.zig b/src/link/MachO/Archive.zig index 007e630bfb..058efdbafc 100644 --- a/src/link/MachO/Archive.zig +++ b/src/link/MachO/Archive.zig @@ -5,8 +5,9 @@ pub fn deinit(self: *Archive, allocator: Allocator) void { } pub fn unpack(self: *Archive, macho_file: *MachO, path: Path, handle_index: File.HandleIndex, fat_arch: ?fat.Arch) !void { - const gpa = macho_file.base.comp.gpa; - const diags = &macho_file.base.comp.link_diags; + const comp = macho_file.base.comp; + const gpa = comp.gpa; + const diags = &comp.link_diags; var arena = std.heap.ArenaAllocator.init(gpa); defer arena.deinit(); @@ -55,23 +56,30 @@ pub fn unpack(self: *Archive, macho_file: *MachO, path: Path, handle_index: File mem.eql(u8, name, SYMDEF_SORTED) or mem.eql(u8, name, SYMDEF64_SORTED)) continue; + const abs_path = try std.fs.path.resolvePosix(gpa, &.{ + comp.dirs.cwd, + path.root_dir.path orelse ".", + path.sub_path, + }); + errdefer gpa.free(abs_path); + + const o_basename = try gpa.dupe(u8, name); + errdefer gpa.free(o_basename); + const object: Object = .{ .offset = pos, .in_archive = .{ - .path = .{ - .root_dir = path.root_dir, - .sub_path = try gpa.dupe(u8, path.sub_path), - }, + .path = abs_path, .size = hdr_size, }, - .path = Path.initCwd(try gpa.dupe(u8, name)), + .path = o_basename, .file_handle = handle_index, .index = undefined, .alive = false, .mtime = hdr.date() catch 0, }; - log.debug("extracting object '{f}' from archive '{f}'", .{ object.path, path }); + log.debug("extracting object '{s}' from archive '{f}'", .{ o_basename, path }); try self.objects.append(gpa, object); } diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig index 90d96b85d9..7cec09ba91 100644 --- a/src/link/MachO/Object.zig +++ b/src/link/MachO/Object.zig @@ -1,8 +1,9 @@ /// Non-zero for fat object files or archives offset: u64, -/// Archive files cannot contain subdirectories, so only the basename is needed -/// for output. However, the full path is kept for error reporting. -path: Path, +/// If `in_archive` is not `null`, this is the basename of the object in the archive. Otherwise, +/// this is a fully-resolved absolute path, because that is the path we need to embed in stabs to +/// ensure the output does not depend on its cwd. +path: []u8, file_handle: File.HandleIndex, mtime: u64, index: File.Index, @@ -41,8 +42,8 @@ output_symtab_ctx: MachO.SymtabCtx = .{}, output_ar_state: Archive.ArState = .{}, pub fn deinit(self: *Object, allocator: Allocator) void { - if (self.in_archive) |*ar| allocator.free(ar.path.sub_path); - allocator.free(self.path.sub_path); + if (self.in_archive) |*ar| allocator.free(ar.path); + allocator.free(self.path); for (self.sections.items(.relocs), self.sections.items(.subsections)) |*relocs, *sub| { relocs.deinit(allocator); sub.deinit(allocator); @@ -1703,7 +1704,7 @@ pub fn updateArSize(self: *Object, macho_file: *MachO) !void { pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writer: anytype) !void { // Header const size = try macho_file.cast(usize, self.output_ar_state.size); - const basename = std.fs.path.basename(self.path.sub_path); + const basename = std.fs.path.basename(self.path); try Archive.writeHeader(basename, size, ar_format, writer); // Data const file = macho_file.getFileHandle(self.file_handle); @@ -1756,12 +1757,7 @@ pub fn calcSymtabSize(self: *Object, macho_file: *MachO) void { self.calcStabsSize(macho_file); } -fn pathLen(path: Path) usize { - // +1 for the path separator - return (if (path.root_dir.path) |p| p.len + @intFromBool(path.sub_path.len != 0) else 0) + path.sub_path.len; -} - -pub fn calcStabsSize(self: *Object, macho_file: *MachO) void { +fn calcStabsSize(self: *Object, macho_file: *MachO) void { if (self.compile_unit) |cu| { const comp_dir = cu.getCompDir(self.*); const tu_name = cu.getTuName(self.*); @@ -1771,9 +1767,11 @@ pub fn calcStabsSize(self: *Object, macho_file: *MachO) void { self.output_symtab_ctx.strsize += @as(u32, @intCast(tu_name.len + 1)); // tu_name if (self.in_archive) |ar| { - self.output_symtab_ctx.strsize += @intCast(pathLen(ar.path) + 1 + self.path.basename().len + 1 + 1); + // "/path/to/archive.a(object.o)\x00" + self.output_symtab_ctx.strsize += @intCast(ar.path.len + self.path.len + 3); } else { - self.output_symtab_ctx.strsize += @intCast(pathLen(self.path) + 1); + // "/path/to/object.o\x00" + self.output_symtab_ctx.strsize += @intCast(self.path.len + 1); } for (self.symbols.items, 0..) |sym, i| { @@ -2018,7 +2016,7 @@ pub fn writeSymtab(self: Object, macho_file: *MachO, ctx: anytype) void { self.writeStabs(n_strx, macho_file, ctx); } -pub fn writeStabs(self: Object, stroff: u32, macho_file: *MachO, ctx: anytype) void { +fn writeStabs(self: Object, stroff: u32, macho_file: *MachO, ctx: anytype) void { const writeFuncStab = struct { inline fn writeFuncStab( n_strx: u32, @@ -2103,38 +2101,20 @@ pub fn writeStabs(self: Object, stroff: u32, macho_file: *MachO, ctx: anytype) v }; index += 1; if (self.in_archive) |ar| { - if (ar.path.root_dir.path) |p| { - @memcpy(ctx.strtab.items[n_strx..][0..p.len], p); - n_strx += @intCast(p.len); - if (ar.path.sub_path.len != 0) { - ctx.strtab.items[n_strx] = '/'; - n_strx += 1; - } - } - @memcpy(ctx.strtab.items[n_strx..][0..ar.path.sub_path.len], ar.path.sub_path); - n_strx += @intCast(ar.path.sub_path.len); - ctx.strtab.items[n_strx] = '('; - n_strx += 1; - const basename = self.path.basename(); - @memcpy(ctx.strtab.items[n_strx..][0..basename.len], basename); - n_strx += @intCast(basename.len); - ctx.strtab.items[n_strx] = ')'; - n_strx += 1; - ctx.strtab.items[n_strx] = 0; + // "/path/to/archive.a(object.o)\x00" + @memcpy(ctx.strtab.items[n_strx..][0..ar.path.len], ar.path); + n_strx += @intCast(ar.path.len); + ctx.strtab.items[n_strx..][0] = '('; n_strx += 1; + @memcpy(ctx.strtab.items[n_strx..][0..self.path.len], self.path); + n_strx += @intCast(self.path.len); + ctx.strtab.items[n_strx..][0..2].* = ")\x00".*; + n_strx += 2; } else { - if (self.path.root_dir.path) |p| { - @memcpy(ctx.strtab.items[n_strx..][0..p.len], p); - n_strx += @intCast(p.len); - if (self.path.sub_path.len != 0) { - ctx.strtab.items[n_strx] = '/'; - n_strx += 1; - } - } - @memcpy(ctx.strtab.items[n_strx..][0..self.path.sub_path.len], self.path.sub_path); - n_strx += @intCast(self.path.sub_path.len); - ctx.strtab.items[n_strx] = 0; - n_strx += 1; + // "/path/to/object.o\x00" + @memcpy(ctx.strtab.items[n_strx..][0..self.path.len], self.path); + ctx.strtab.items[n_strx..][self.path.len] = 0; + n_strx += @intCast(self.path.len + 1); } for (self.symbols.items, 0..) |sym, i| { @@ -2621,11 +2601,9 @@ pub fn fmtPath(self: Object) std.fmt.Alt(Object, formatPath) { fn formatPath(object: Object, w: *Writer) Writer.Error!void { if (object.in_archive) |ar| { - try w.print("{f}({s})", .{ - ar.path, object.path.basename(), - }); + try w.print("{s}({s})", .{ ar.path, object.path }); } else { - try w.print("{f}", .{object.path}); + try w.writeAll(object.path); } } @@ -2716,7 +2694,9 @@ const CompileUnit = struct { }; const InArchive = struct { - path: Path, + /// This is a fully-resolved absolute path, because that is the path we need to embed in stabs + /// to ensure the output does not depend on its cwd. + path: []u8, size: u32, }; @@ -3094,7 +3074,6 @@ const log = std.log.scoped(.link); const macho = std.macho; const math = std.math; const mem = std.mem; -const Path = std.Build.Cache.Path; const Allocator = std.mem.Allocator; const Writer = std.Io.Writer; diff --git a/src/link/MachO/relocatable.zig b/src/link/MachO/relocatable.zig index 920125136b..09807a2845 100644 --- a/src/link/MachO/relocatable.zig +++ b/src/link/MachO/relocatable.zig @@ -191,7 +191,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ? pos = mem.alignForward(usize, pos, 2); state.file_off = pos; pos += @sizeOf(Archive.ar_hdr); - pos += mem.alignForward(usize, o.path.basename().len + 1, ptr_width); + pos += mem.alignForward(usize, std.fs.path.basename(o.path).len + 1, ptr_width); pos += try macho_file.cast(usize, state.size); }, else => unreachable,