authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-05-03 10:50:39-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-05-22 06:59:22-07:00
logd09afc08da86b4391f1dda6162621d29075cb8a2
tree610f838891db1a1cb268730cb69a70db0467fe06
parentddde99bdfa5b2fa9b49c39a0f00a8c232a9576b6

lld: use a response file on `NameTooLong`


4 files changed, 118 insertions(+), 142 deletions(-)

src/Compilation.zig+6-4
...@@ -5091,7 +5091,7 @@ fn spawnZigRc(...@@ -5091,7 +5091,7 @@ fn spawnZigRc(
5091 }5091 }
5092}5092}
50935093
5094pub fn tmpFilePath(comp: *Compilation, ally: Allocator, suffix: []const u8) error{OutOfMemory}![]const u8 {5094pub fn tmpFilePath(comp: Compilation, ally: Allocator, suffix: []const u8) error{OutOfMemory}![]const u8 {
5095 const s = std.fs.path.sep_str;5095 const s = std.fs.path.sep_str;
5096 const rand_int = std.crypto.random.int(u64);5096 const rand_int = std.crypto.random.int(u64);
5097 if (comp.local_cache_directory.path) |p| {5097 if (comp.local_cache_directory.path) |p| {
...@@ -5894,14 +5894,16 @@ pub fn lockAndSetMiscFailure(...@@ -5894,14 +5894,16 @@ pub fn lockAndSetMiscFailure(
5894 return setMiscFailure(comp, tag, format, args);5894 return setMiscFailure(comp, tag, format, args);
5895}5895}
58965896
5897fn parseLldStderr(comp: *Compilation, comptime prefix: []const u8, stderr: []const u8) Allocator.Error!void {5897fn parseLldStderr(comp: *Compilation, prefix: []const u8, stderr: []const u8) Allocator.Error!void {
5898 var context_lines = std.ArrayList([]const u8).init(comp.gpa);5898 var context_lines = std.ArrayList([]const u8).init(comp.gpa);
5899 defer context_lines.deinit();5899 defer context_lines.deinit();
59005900
5901 var current_err: ?*LldError = null;5901 var current_err: ?*LldError = null;
5902 var lines = mem.splitSequence(u8, stderr, if (builtin.os.tag == .windows) "\r\n" else "\n");5902 var lines = mem.splitSequence(u8, stderr, if (builtin.os.tag == .windows) "\r\n" else "\n");
5903 while (lines.next()) |line| {5903 while (lines.next()) |line| {
5904 if (mem.startsWith(u8, line, prefix ++ ":")) {5904 if (line.len > prefix.len + ":".len and
5905 mem.eql(u8, line[0..prefix.len], prefix) and line[prefix.len] == ':')
5906 {
5905 if (current_err) |err| {5907 if (current_err) |err| {
5906 err.context_lines = try context_lines.toOwnedSlice();5908 err.context_lines = try context_lines.toOwnedSlice();
5907 }5909 }
...@@ -5933,7 +5935,7 @@ fn parseLldStderr(comp: *Compilation, comptime prefix: []const u8, stderr: []con...@@ -5933,7 +5935,7 @@ fn parseLldStderr(comp: *Compilation, comptime prefix: []const u8, stderr: []con
5933 }5935 }
5934}5936}
59355937
5936pub fn lockAndParseLldStderr(comp: *Compilation, comptime prefix: []const u8, stderr: []const u8) void {5938pub fn lockAndParseLldStderr(comp: *Compilation, prefix: []const u8, stderr: []const u8) void {
5937 comp.mutex.lock();5939 comp.mutex.lock();
5938 defer comp.mutex.unlock();5940 defer comp.mutex.unlock();
59395941
src/link.zig+110
...@@ -19,6 +19,8 @@ const InternPool = @import("InternPool.zig");...@@ -19,6 +19,8 @@ const InternPool = @import("InternPool.zig");
19const Type = @import("type.zig").Type;19const Type = @import("type.zig").Type;
20const Value = @import("Value.zig");20const Value = @import("Value.zig");
21const LlvmObject = @import("codegen/llvm.zig").Object;21const LlvmObject = @import("codegen/llvm.zig").Object;
22const lldMain = @import("main.zig").lldMain;
23const Package = @import("Package.zig");
2224
23/// When adding a new field, remember to update `hashAddSystemLibs`.25/// When adding a new field, remember to update `hashAddSystemLibs`.
24/// These are *always* dynamically linked. Static libraries will be26/// These are *always* dynamically linked. Static libraries will be
...@@ -982,3 +984,111 @@ pub const File = struct {...@@ -982,3 +984,111 @@ pub const File = struct {
982 pub const NvPtx = @import("link/NvPtx.zig");984 pub const NvPtx = @import("link/NvPtx.zig");
983 pub const Dwarf = @import("link/Dwarf.zig");985 pub const Dwarf = @import("link/Dwarf.zig");
984};986};
987
988pub fn spawnLld(
989 comp: *Compilation,
990 arena: Allocator,
991 argv: []const []const u8,
992) !void {
993 if (comp.verbose_link) {
994 // Skip over our own name so that the LLD linker name is the first argv item.
995 Compilation.dump_argv(argv[1..]);
996 }
997
998 // If possible, we run LLD as a child process because it does not always
999 // behave properly as a library, unfortunately.
1000 // https://github.com/ziglang/zig/issues/3825
1001 if (!std.process.can_spawn) {
1002 const exit_code = try lldMain(arena, argv, false);
1003 if (exit_code == 0) return;
1004 if (comp.clang_passthrough_mode) std.process.exit(exit_code);
1005 return error.LLDReportedFailure;
1006 }
1007
1008 var stderr: []u8 = &.{};
1009 defer comp.gpa.free(stderr);
1010
1011 var child = std.process.Child.init(argv, arena);
1012 const term = (if (comp.clang_passthrough_mode) term: {
1013 child.stdin_behavior = .Inherit;
1014 child.stdout_behavior = .Inherit;
1015 child.stderr_behavior = .Inherit;
1016
1017 break :term child.spawnAndWait();
1018 } else term: {
1019 child.stdin_behavior = .Ignore;
1020 child.stdout_behavior = .Ignore;
1021 child.stderr_behavior = .Pipe;
1022
1023 child.spawn() catch |err| break :term err;
1024 stderr = try child.stderr.?.reader().readAllAlloc(comp.gpa, std.math.maxInt(usize));
1025 break :term child.wait();
1026 }) catch |first_err| term: {
1027 const err = switch (first_err) {
1028 error.NameTooLong => err: {
1029 const s = fs.path.sep_str;
1030 const rand_int = std.crypto.random.int(u64);
1031 const rsp_path = "tmp" ++ s ++ Package.Manifest.hex64(rand_int) ++ ".rsp";
1032
1033 const rsp_file = try comp.local_cache_directory.handle.createFileZ(rsp_path, .{});
1034 defer comp.local_cache_directory.handle.deleteFileZ(rsp_path) catch |err|
1035 log.warn("failed to delete response file {s}: {s}", .{ rsp_path, @errorName(err) });
1036 {
1037 defer rsp_file.close();
1038 var rsp_buf = std.io.bufferedWriter(rsp_file.writer());
1039 const rsp_writer = rsp_buf.writer();
1040 for (argv[2..]) |arg| {
1041 try rsp_writer.writeByte('"');
1042 for (arg) |c| {
1043 switch (c) {
1044 '\"', '\\' => try rsp_writer.writeByte('\\'),
1045 else => {},
1046 }
1047 try rsp_writer.writeByte(c);
1048 }
1049 try rsp_writer.writeByte('"');
1050 try rsp_writer.writeByte('\n');
1051 }
1052 try rsp_buf.flush();
1053 }
1054
1055 var rsp_child = std.process.Child.init(&.{ argv[0], argv[1], try std.fmt.allocPrint(
1056 arena,
1057 "@{s}",
1058 .{try comp.local_cache_directory.join(arena, &.{rsp_path})},
1059 ) }, arena);
1060 if (comp.clang_passthrough_mode) {
1061 rsp_child.stdin_behavior = .Inherit;
1062 rsp_child.stdout_behavior = .Inherit;
1063 rsp_child.stderr_behavior = .Inherit;
1064
1065 break :term rsp_child.spawnAndWait() catch |err| break :err err;
1066 } else {
1067 rsp_child.stdin_behavior = .Ignore;
1068 rsp_child.stdout_behavior = .Ignore;
1069 rsp_child.stderr_behavior = .Pipe;
1070
1071 rsp_child.spawn() catch |err| break :err err;
1072 stderr = try rsp_child.stderr.?.reader().readAllAlloc(comp.gpa, std.math.maxInt(usize));
1073 break :term rsp_child.wait() catch |err| break :err err;
1074 }
1075 },
1076 else => first_err,
1077 };
1078 log.err("unable to spawn {s}: {s}", .{ argv[0], @errorName(err) });
1079 return error.UnableToSpawnSelf;
1080 };
1081
1082 switch (term) {
1083 .Exited => |code| if (code != 0) {
1084 comp.lockAndParseLldStderr(argv[1], stderr);
1085 return error.LLDReportedFailure;
1086 },
1087 else => {
1088 log.err("{s} terminated with stderr:\n{s}", .{ argv[0], stderr });
1089 return error.LLDCrashed;
1090 },
1091 }
1092
1093 if (stderr.len > 0) log.warn("unexpected LLD stderr:\n{s}", .{stderr});
1094}
src/link/Coff/lld.zig+1-69
...@@ -9,7 +9,6 @@ const Cache = std.Build.Cache;...@@ -9,7 +9,6 @@ const Cache = std.Build.Cache;
99
10const mingw = @import("../../mingw.zig");10const mingw = @import("../../mingw.zig");
11const link = @import("../../link.zig");11const link = @import("../../link.zig");
12const lldMain = @import("../../main.zig").lldMain;
13const trace = @import("../../tracy.zig").trace;12const trace = @import("../../tracy.zig").trace;
1413
15const Allocator = mem.Allocator;14const Allocator = mem.Allocator;
...@@ -502,74 +501,7 @@ pub fn linkWithLLD(self: *Coff, arena: Allocator, prog_node: *std.Progress.Node)...@@ -502,74 +501,7 @@ pub fn linkWithLLD(self: *Coff, arena: Allocator, prog_node: *std.Progress.Node)
502 return error.DllImportLibraryNotFound;501 return error.DllImportLibraryNotFound;
503 }502 }
504503
505 if (comp.verbose_link) {504 try link.spawnLld(comp, arena, argv.items);
506 // Skip over our own name so that the LLD linker name is the first argv item.
507 Compilation.dump_argv(argv.items[1..]);
508 }
509
510 if (std.process.can_spawn) {
511 // If possible, we run LLD as a child process because it does not always
512 // behave properly as a library, unfortunately.
513 // https://github.com/ziglang/zig/issues/3825
514 var child = std.ChildProcess.init(argv.items, arena);
515 if (comp.clang_passthrough_mode) {
516 child.stdin_behavior = .Inherit;
517 child.stdout_behavior = .Inherit;
518 child.stderr_behavior = .Inherit;
519
520 const term = child.spawnAndWait() catch |err| {
521 log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) });
522 return error.UnableToSpawnSelf;
523 };
524 switch (term) {
525 .Exited => |code| {
526 if (code != 0) {
527 std.process.exit(code);
528 }
529 },
530 else => std.process.abort(),
531 }
532 } else {
533 child.stdin_behavior = .Ignore;
534 child.stdout_behavior = .Ignore;
535 child.stderr_behavior = .Pipe;
536
537 try child.spawn();
538
539 const stderr = try child.stderr.?.reader().readAllAlloc(arena, std.math.maxInt(usize));
540
541 const term = child.wait() catch |err| {
542 log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) });
543 return error.UnableToSpawnSelf;
544 };
545
546 switch (term) {
547 .Exited => |code| {
548 if (code != 0) {
549 comp.lockAndParseLldStderr(linker_command, stderr);
550 return error.LLDReportedFailure;
551 }
552 },
553 else => {
554 log.err("{s} terminated with stderr:\n{s}", .{ argv.items[0], stderr });
555 return error.LLDCrashed;
556 },
557 }
558
559 if (stderr.len != 0) {
560 log.warn("unexpected LLD stderr:\n{s}", .{stderr});
561 }
562 }
563 } else {
564 const exit_code = try lldMain(arena, argv.items, false);
565 if (exit_code != 0) {
566 if (comp.clang_passthrough_mode) {
567 std.process.exit(exit_code);
568 } else {
569 return error.LLDReportedFailure;
570 }
571 }
572 }
573 }505 }
574506
575 if (!self.base.disable_lld_caching) {507 if (!self.base.disable_lld_caching) {
src/link/Elf.zig+1-69
...@@ -2726,74 +2726,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) !voi...@@ -2726,74 +2726,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) !voi
2726 try argv.append("-Bsymbolic");2726 try argv.append("-Bsymbolic");
2727 }2727 }
27282728
2729 if (comp.verbose_link) {2729 try link.spawnLld(comp, arena, argv.items);
2730 // Skip over our own name so that the LLD linker name is the first argv item.
2731 Compilation.dump_argv(argv.items[1..]);
2732 }
2733
2734 if (std.process.can_spawn) {
2735 // If possible, we run LLD as a child process because it does not always
2736 // behave properly as a library, unfortunately.
2737 // https://github.com/ziglang/zig/issues/3825
2738 var child = std.ChildProcess.init(argv.items, arena);
2739 if (comp.clang_passthrough_mode) {
2740 child.stdin_behavior = .Inherit;
2741 child.stdout_behavior = .Inherit;
2742 child.stderr_behavior = .Inherit;
2743
2744 const term = child.spawnAndWait() catch |err| {
2745 log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) });
2746 return error.UnableToSpawnSelf;
2747 };
2748 switch (term) {
2749 .Exited => |code| {
2750 if (code != 0) {
2751 std.process.exit(code);
2752 }
2753 },
2754 else => std.process.abort(),
2755 }
2756 } else {
2757 child.stdin_behavior = .Ignore;
2758 child.stdout_behavior = .Ignore;
2759 child.stderr_behavior = .Pipe;
2760
2761 try child.spawn();
2762
2763 const stderr = try child.stderr.?.reader().readAllAlloc(arena, std.math.maxInt(usize));
2764
2765 const term = child.wait() catch |err| {
2766 log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) });
2767 return error.UnableToSpawnSelf;
2768 };
2769
2770 switch (term) {
2771 .Exited => |code| {
2772 if (code != 0) {
2773 comp.lockAndParseLldStderr(linker_command, stderr);
2774 return error.LLDReportedFailure;
2775 }
2776 },
2777 else => {
2778 log.err("{s} terminated with stderr:\n{s}", .{ argv.items[0], stderr });
2779 return error.LLDCrashed;
2780 },
2781 }
2782
2783 if (stderr.len != 0) {
2784 log.warn("unexpected LLD stderr:\n{s}", .{stderr});
2785 }
2786 }
2787 } else {
2788 const exit_code = try lldMain(arena, argv.items, false);
2789 if (exit_code != 0) {
2790 if (comp.clang_passthrough_mode) {
2791 std.process.exit(exit_code);
2792 } else {
2793 return error.LLDReportedFailure;
2794 }
2795 }
2796 }
2797 }2730 }
27982731
2799 if (!self.base.disable_lld_caching) {2732 if (!self.base.disable_lld_caching) {
...@@ -6500,7 +6433,6 @@ const eh_frame = @import("Elf/eh_frame.zig");...@@ -6500,7 +6433,6 @@ const eh_frame = @import("Elf/eh_frame.zig");
6500const gc = @import("Elf/gc.zig");6433const gc = @import("Elf/gc.zig");
6501const glibc = @import("../glibc.zig");6434const glibc = @import("../glibc.zig");
6502const link = @import("../link.zig");6435const link = @import("../link.zig");
6503const lldMain = @import("../main.zig").lldMain;
6504const merge_section = @import("Elf/merge_section.zig");6436const merge_section = @import("Elf/merge_section.zig");
6505const musl = @import("../musl.zig");6437const musl = @import("../musl.zig");
6506const relocatable = @import("Elf/relocatable.zig");6438const relocatable = @import("Elf/relocatable.zig");