aboutsummaryrefslogtreecommitdiff
path: root/src/link.zig
diff options
context:
space:
mode:
authorJacob Young <jacobly0@users.noreply.github.com>2024-05-03 10:50:39 -0400
committerAndrew Kelley <andrew@ziglang.org>2024-05-03 13:27:04 -0700
commit3b5be9fb6e06f6494ca05fb087a2121e220beb3f (patch)
tree37b4167d03236dec927ff2cb2efab35ac1e592fd /src/link.zig
parent44db92d1ca90c9cfdfb29fe46f04ff8f11c80901 (diff)
downloadzig-3b5be9fb6e06f6494ca05fb087a2121e220beb3f.tar.gz
zig-3b5be9fb6e06f6494ca05fb087a2121e220beb3f.zip
lld: use a response file on `NameTooLong`
Diffstat (limited to 'src/link.zig')
-rw-r--r--src/link.zig110
1 files changed, 110 insertions, 0 deletions
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});
+}