Commit 1357790ec9

Jakub Konka <kubkon@jakubkonka.com>
2022-08-19 12:13:04
win: combine PDB fixes into one changeset
1 parent dd8df1c
Changed files (4)
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) {
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.* = .{
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;
     }
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");