Commit d09afc08da
2024-05-03 16:50:39
1 parent
ddde99bChanged files (4)
src
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) {
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");
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();
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});
+}