From 1357790ec969bb6ee19ade6e8a348bd9d7cbbc4d Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Fri, 19 Aug 2022 12:13:04 +0200 Subject: [PATCH] win: combine PDB fixes into one changeset --- src/Compilation.zig | 25 +++++++++++++++++++++++++ src/link.zig | 4 ++++ src/link/Coff/lld.zig | 4 ++++ test/tests.zig | 2 +- 4 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/Compilation.zig b/src/Compilation.zig index 7903586450..35be4e86cf 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -1016,6 +1016,9 @@ pub const InitOptions = struct { /// (Darwin) remove dylibs that are unreachable by the entry point or exported symbols dead_strip_dylibs: bool = false, libcxx_abi_version: libcxx.AbiVersion = libcxx.AbiVersion.default, + /// (Windows) PDB source path prefix to instruct the linker how to resolve relative + /// paths when consolidating CodeView streams into a single PDB file. + pdb_source_path: ?[]const u8 = null, }; fn addPackageTableToCacheHash( @@ -1719,6 +1722,27 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { }; }; + const pdb_source_path: ?[]const u8 = options.pdb_source_path orelse blk: { + if (builtin.target.os.tag == .windows) { + // PDB requires all file paths to be fully resolved, and it is really the + // linker's responsibility to canonicalize any path extracted from the CodeView + // in the object file. However, LLD-link has some very questionable defaults, and + // in particular, it purposely bakes in path separator of the host system it was + // built on rather than the targets, or just throw an error. Thankfully, they have + // left a backdoor we can use via -PDBSOURCEPATH. + const mod = module orelse break :blk null; + var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined; + const resolved_path = if (mod.main_pkg.root_src_directory.path) |base_path| p: { + if (std.fs.path.isAbsolute(base_path)) break :blk base_path; + const resolved_path = std.os.realpath(base_path, &buffer) catch break :blk null; + const pos = std.mem.lastIndexOfLinear(u8, resolved_path, base_path) orelse resolved_path.len; + break :p resolved_path[0..pos]; + } else std.os.realpath(".", &buffer) catch break :blk null; + break :blk try arena.dupe(u8, resolved_path); + } + break :blk null; + }; + const implib_emit: ?link.Emit = blk: { const emit_implib = options.emit_implib orelse break :blk null; @@ -1865,6 +1889,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .headerpad_max_install_names = options.headerpad_max_install_names, .dead_strip_dylibs = options.dead_strip_dylibs, .force_undefined_symbols = .{}, + .pdb_source_path = pdb_source_path, }); errdefer bin_file.destroy(); comp.* = .{ diff --git a/src/link.zig b/src/link.zig index 3097e5cf1f..4dfcf171af 100644 --- a/src/link.zig +++ b/src/link.zig @@ -218,6 +218,10 @@ pub const Options = struct { /// (Darwin) remove dylibs that are unreachable by the entry point or exported symbols dead_strip_dylibs: bool = false, + /// (Windows) PDB source path prefix to instruct the linker how to resolve relative + /// paths when consolidating CodeView streams into a single PDB file. + pdb_source_path: ?[]const u8 = null, + pub fn effectiveOutputMode(options: Options) std.builtin.OutputMode { return if (options.use_lld) .Obj else options.output_mode; } diff --git a/src/link/Coff/lld.zig b/src/link/Coff/lld.zig index 9d9d1e4094..00e6c4d8d1 100644 --- a/src/link/Coff/lld.zig +++ b/src/link/Coff/lld.zig @@ -188,6 +188,10 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod }); try argv.append(try allocPrint(arena, "-PDB:{s}", .{out_pdb})); try argv.append(try allocPrint(arena, "-PDBALTPATH:{s}", .{out_pdb})); + + if (self.base.options.pdb_source_path) |path| { + try argv.append(try std.fmt.allocPrint(arena, "-PDBSOURCEPATH:{s}", .{path})); + } } if (self.base.options.lto) { switch (self.base.options.optimize_mode) { diff --git a/test/tests.zig b/test/tests.zig index 1d47fcddc5..26eee873bf 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -960,7 +960,7 @@ pub const StackTracesContext = struct { pos = marks[i] + delim.len; } // locate source basename - pos = mem.lastIndexOfAny(u8, line[0..marks[0]], "\\/") orelse { + pos = mem.lastIndexOfScalar(u8, line[0..marks[0]], fs.path.sep) orelse { // unexpected pattern: emit raw line and cont try buf.appendSlice(line); try buf.appendSlice("\n");