diff options
| author | Jacob Young <jacobly0@users.noreply.github.com> | 2024-05-03 10:50:39 -0400 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2024-05-03 13:27:04 -0700 |
| commit | 3b5be9fb6e06f6494ca05fb087a2121e220beb3f (patch) | |
| tree | 37b4167d03236dec927ff2cb2efab35ac1e592fd /src | |
| parent | 44db92d1ca90c9cfdfb29fe46f04ff8f11c80901 (diff) | |
| download | zig-3b5be9fb6e06f6494ca05fb087a2121e220beb3f.tar.gz zig-3b5be9fb6e06f6494ca05fb087a2121e220beb3f.zip | |
lld: use a response file on `NameTooLong`
Diffstat (limited to 'src')
| -rw-r--r-- | src/Compilation.zig | 10 | ||||
| -rw-r--r-- | src/link.zig | 110 | ||||
| -rw-r--r-- | src/link/Coff/lld.zig | 70 | ||||
| -rw-r--r-- | src/link/Elf.zig | 70 |
4 files changed, 118 insertions, 142 deletions
diff --git a/src/Compilation.zig b/src/Compilation.zig index 0a6c0e2e4d..e592046850 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -5091,7 +5091,7 @@ fn spawnZigRc( } } -pub fn tmpFilePath(comp: *Compilation, ally: Allocator, suffix: []const u8) error{OutOfMemory}![]const u8 { +pub fn tmpFilePath(comp: Compilation, ally: Allocator, suffix: []const u8) error{OutOfMemory}![]const u8 { const s = std.fs.path.sep_str; const rand_int = std.crypto.random.int(u64); if (comp.local_cache_directory.path) |p| { @@ -5894,14 +5894,16 @@ pub fn lockAndSetMiscFailure( return setMiscFailure(comp, tag, format, args); } -fn parseLldStderr(comp: *Compilation, comptime prefix: []const u8, stderr: []const u8) Allocator.Error!void { +fn parseLldStderr(comp: *Compilation, prefix: []const u8, stderr: []const u8) Allocator.Error!void { var context_lines = std.ArrayList([]const u8).init(comp.gpa); defer context_lines.deinit(); var current_err: ?*LldError = null; var lines = mem.splitSequence(u8, stderr, if (builtin.os.tag == .windows) "\r\n" else "\n"); while (lines.next()) |line| { - if (mem.startsWith(u8, line, prefix ++ ":")) { + if (line.len > prefix.len + ":".len and + mem.eql(u8, line[0..prefix.len], prefix) and line[prefix.len] == ':') + { if (current_err) |err| { err.context_lines = try context_lines.toOwnedSlice(); } @@ -5933,7 +5935,7 @@ fn parseLldStderr(comp: *Compilation, comptime prefix: []const u8, stderr: []con } } -pub fn lockAndParseLldStderr(comp: *Compilation, comptime prefix: []const u8, stderr: []const u8) void { +pub fn lockAndParseLldStderr(comp: *Compilation, prefix: []const u8, stderr: []const u8) void { comp.mutex.lock(); defer comp.mutex.unlock(); diff --git a/src/link.zig b/src/link.zig index 8b28a17b9d..ae61e76ebf 100644 --- a/src/link.zig +++ b/src/link.zig @@ -19,6 +19,8 @@ const InternPool = @import("InternPool.zig"); const Type = @import("type.zig").Type; const Value = @import("Value.zig"); const LlvmObject = @import("codegen/llvm.zig").Object; +const lldMain = @import("main.zig").lldMain; +const Package = @import("Package.zig"); /// When adding a new field, remember to update `hashAddSystemLibs`. /// These are *always* dynamically linked. Static libraries will be @@ -982,3 +984,111 @@ pub const File = struct { pub const NvPtx = @import("link/NvPtx.zig"); pub const Dwarf = @import("link/Dwarf.zig"); }; + +pub fn spawnLld( + comp: *Compilation, + arena: Allocator, + argv: []const []const u8, +) !void { + if (comp.verbose_link) { + // Skip over our own name so that the LLD linker name is the first argv item. + Compilation.dump_argv(argv[1..]); + } + + // If possible, we run LLD as a child process because it does not always + // behave properly as a library, unfortunately. + // https://github.com/ziglang/zig/issues/3825 + if (!std.process.can_spawn) { + const exit_code = try lldMain(arena, argv, false); + if (exit_code == 0) return; + if (comp.clang_passthrough_mode) std.process.exit(exit_code); + return error.LLDReportedFailure; + } + + var stderr: []u8 = &.{}; + defer comp.gpa.free(stderr); + + var child = std.process.Child.init(argv, arena); + const term = (if (comp.clang_passthrough_mode) term: { + child.stdin_behavior = .Inherit; + child.stdout_behavior = .Inherit; + child.stderr_behavior = .Inherit; + + break :term child.spawnAndWait(); + } else term: { + child.stdin_behavior = .Ignore; + child.stdout_behavior = .Ignore; + child.stderr_behavior = .Pipe; + + child.spawn() catch |err| break :term err; + stderr = try child.stderr.?.reader().readAllAlloc(comp.gpa, std.math.maxInt(usize)); + break :term child.wait(); + }) catch |first_err| term: { + const err = switch (first_err) { + error.NameTooLong => err: { + const s = fs.path.sep_str; + const rand_int = std.crypto.random.int(u64); + const rsp_path = "tmp" ++ s ++ Package.Manifest.hex64(rand_int) ++ ".rsp"; + + const rsp_file = try comp.local_cache_directory.handle.createFileZ(rsp_path, .{}); + defer comp.local_cache_directory.handle.deleteFileZ(rsp_path) catch |err| + log.warn("failed to delete response file {s}: {s}", .{ rsp_path, @errorName(err) }); + { + defer rsp_file.close(); + var rsp_buf = std.io.bufferedWriter(rsp_file.writer()); + const rsp_writer = rsp_buf.writer(); + for (argv[2..]) |arg| { + try rsp_writer.writeByte('"'); + for (arg) |c| { + switch (c) { + '\"', '\\' => try rsp_writer.writeByte('\\'), + else => {}, + } + try rsp_writer.writeByte(c); + } + try rsp_writer.writeByte('"'); + try rsp_writer.writeByte('\n'); + } + try rsp_buf.flush(); + } + + var rsp_child = std.process.Child.init(&.{ argv[0], argv[1], try std.fmt.allocPrint( + arena, + "@{s}", + .{try comp.local_cache_directory.join(arena, &.{rsp_path})}, + ) }, arena); + if (comp.clang_passthrough_mode) { + rsp_child.stdin_behavior = .Inherit; + rsp_child.stdout_behavior = .Inherit; + rsp_child.stderr_behavior = .Inherit; + + break :term rsp_child.spawnAndWait() catch |err| break :err err; + } else { + rsp_child.stdin_behavior = .Ignore; + rsp_child.stdout_behavior = .Ignore; + rsp_child.stderr_behavior = .Pipe; + + rsp_child.spawn() catch |err| break :err err; + stderr = try rsp_child.stderr.?.reader().readAllAlloc(comp.gpa, std.math.maxInt(usize)); + break :term rsp_child.wait() catch |err| break :err err; + } + }, + else => first_err, + }; + log.err("unable to spawn {s}: {s}", .{ argv[0], @errorName(err) }); + return error.UnableToSpawnSelf; + }; + + switch (term) { + .Exited => |code| if (code != 0) { + comp.lockAndParseLldStderr(argv[1], stderr); + return error.LLDReportedFailure; + }, + else => { + log.err("{s} terminated with stderr:\n{s}", .{ argv[0], stderr }); + return error.LLDCrashed; + }, + } + + if (stderr.len > 0) log.warn("unexpected LLD stderr:\n{s}", .{stderr}); +} diff --git a/src/link/Coff/lld.zig b/src/link/Coff/lld.zig index cf9c06a70f..47753cbf01 100644 --- a/src/link/Coff/lld.zig +++ b/src/link/Coff/lld.zig @@ -9,7 +9,6 @@ const Cache = std.Build.Cache; const mingw = @import("../../mingw.zig"); const link = @import("../../link.zig"); -const lldMain = @import("../../main.zig").lldMain; const trace = @import("../../tracy.zig").trace; const Allocator = mem.Allocator; @@ -502,74 +501,7 @@ pub fn linkWithLLD(self: *Coff, arena: Allocator, prog_node: *std.Progress.Node) return error.DllImportLibraryNotFound; } - if (comp.verbose_link) { - // Skip over our own name so that the LLD linker name is the first argv item. - Compilation.dump_argv(argv.items[1..]); - } - - if (std.process.can_spawn) { - // If possible, we run LLD as a child process because it does not always - // behave properly as a library, unfortunately. - // https://github.com/ziglang/zig/issues/3825 - var child = std.ChildProcess.init(argv.items, arena); - if (comp.clang_passthrough_mode) { - child.stdin_behavior = .Inherit; - child.stdout_behavior = .Inherit; - child.stderr_behavior = .Inherit; - - const term = child.spawnAndWait() catch |err| { - log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); - return error.UnableToSpawnSelf; - }; - switch (term) { - .Exited => |code| { - if (code != 0) { - std.process.exit(code); - } - }, - else => std.process.abort(), - } - } else { - child.stdin_behavior = .Ignore; - child.stdout_behavior = .Ignore; - child.stderr_behavior = .Pipe; - - try child.spawn(); - - const stderr = try child.stderr.?.reader().readAllAlloc(arena, std.math.maxInt(usize)); - - const term = child.wait() catch |err| { - log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); - return error.UnableToSpawnSelf; - }; - - switch (term) { - .Exited => |code| { - if (code != 0) { - comp.lockAndParseLldStderr(linker_command, stderr); - return error.LLDReportedFailure; - } - }, - else => { - log.err("{s} terminated with stderr:\n{s}", .{ argv.items[0], stderr }); - return error.LLDCrashed; - }, - } - - if (stderr.len != 0) { - log.warn("unexpected LLD stderr:\n{s}", .{stderr}); - } - } - } else { - const exit_code = try lldMain(arena, argv.items, false); - if (exit_code != 0) { - if (comp.clang_passthrough_mode) { - std.process.exit(exit_code); - } else { - return error.LLDReportedFailure; - } - } - } + try link.spawnLld(comp, arena, argv.items); } if (!self.base.disable_lld_caching) { diff --git a/src/link/Elf.zig b/src/link/Elf.zig index c3a2daa5a4..a1e23945ee 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -2726,74 +2726,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) !voi try argv.append("-Bsymbolic"); } - if (comp.verbose_link) { - // Skip over our own name so that the LLD linker name is the first argv item. - Compilation.dump_argv(argv.items[1..]); - } - - if (std.process.can_spawn) { - // If possible, we run LLD as a child process because it does not always - // behave properly as a library, unfortunately. - // https://github.com/ziglang/zig/issues/3825 - var child = std.ChildProcess.init(argv.items, arena); - if (comp.clang_passthrough_mode) { - child.stdin_behavior = .Inherit; - child.stdout_behavior = .Inherit; - child.stderr_behavior = .Inherit; - - const term = child.spawnAndWait() catch |err| { - log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); - return error.UnableToSpawnSelf; - }; - switch (term) { - .Exited => |code| { - if (code != 0) { - std.process.exit(code); - } - }, - else => std.process.abort(), - } - } else { - child.stdin_behavior = .Ignore; - child.stdout_behavior = .Ignore; - child.stderr_behavior = .Pipe; - - try child.spawn(); - - const stderr = try child.stderr.?.reader().readAllAlloc(arena, std.math.maxInt(usize)); - - const term = child.wait() catch |err| { - log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); - return error.UnableToSpawnSelf; - }; - - switch (term) { - .Exited => |code| { - if (code != 0) { - comp.lockAndParseLldStderr(linker_command, stderr); - return error.LLDReportedFailure; - } - }, - else => { - log.err("{s} terminated with stderr:\n{s}", .{ argv.items[0], stderr }); - return error.LLDCrashed; - }, - } - - if (stderr.len != 0) { - log.warn("unexpected LLD stderr:\n{s}", .{stderr}); - } - } - } else { - const exit_code = try lldMain(arena, argv.items, false); - if (exit_code != 0) { - if (comp.clang_passthrough_mode) { - std.process.exit(exit_code); - } else { - return error.LLDReportedFailure; - } - } - } + try link.spawnLld(comp, arena, argv.items); } if (!self.base.disable_lld_caching) { @@ -6500,7 +6433,6 @@ const eh_frame = @import("Elf/eh_frame.zig"); const gc = @import("Elf/gc.zig"); const glibc = @import("../glibc.zig"); const link = @import("../link.zig"); -const lldMain = @import("../main.zig").lldMain; const merge_section = @import("Elf/merge_section.zig"); const musl = @import("../musl.zig"); const relocatable = @import("Elf/relocatable.zig"); |
