authorgravatar for hadrien.dorio@gmail.comHadrien Dorio <hadrien.dorio@gmail.com> 2022-08-20 21:08:02+00:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-10-26 23:50:51+02:00
log9db293492bbbc5b8d70638bd9c59dea19d13596c
treedd8792aba7ec1d131c21988c7a40014ed52bd504
parent875e98a57d99c1b6ce8a4a2f9f103b8fe417b8be

make a .rsp file for `zig clang`

same as std.build.LibExeObjStep.make() for `zig build-exe` closes #12419

2 files changed, 68 insertions(+), 4 deletions(-)

src/Compilation.zig+67
......@@ -7,6 +7,9 @@ const Allocator = std.mem.Allocator;
77const assert = std.debug.assert;
88const log = std.log.scoped(.compilation);
99const Target = std.Target;
10const ArrayList = std.ArrayList;
11const Sha256 = std.crypto.hash.sha2.Sha256;
12const fs = std.fs;
1013
1114const Value = @import("value.zig").Value;
1215const Type = @import("type.zig").Type;
......@@ -3915,6 +3918,70 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P
39153918 }
39163919 }
39173920
3921 // Windows has an argument length limit of 32,766 characters, macOS 262,144 and Linux
3922 // 2,097,152. If our args exceed 30 KiB, we instead write them to a "response file" and
3923 // pass that to zig, e.g. via 'zig build-lib @args.rsp'
3924 // See @file syntax here: https://gcc.gnu.org/onlinedocs/gcc/Overall-Options.html
3925 var args_length: usize = 0;
3926 for (argv.items) |arg| {
3927 args_length += arg.len + 1; // +1 to account for null terminator
3928 }
3929 if (args_length >= 30 * 1024) {
3930 const allocator = comp.gpa;
3931 const input_args = argv.items[2..];
3932 const output_dir = comp.local_cache_directory;
3933
3934 var args_arena = std.heap.ArenaAllocator.init(allocator);
3935 defer args_arena.deinit();
3936
3937 const args_to_escape = input_args;
3938 var escaped_args = try ArrayList([]const u8).initCapacity(args_arena.allocator(), args_to_escape.len);
3939
3940 arg_blk: for (args_to_escape) |arg| {
3941 for (arg) |c, arg_idx| {
3942 if (c == '\\' or c == '"') {
3943 // Slow path for arguments that need to be escaped. We'll need to allocate and copy
3944 var escaped = try ArrayList(u8).initCapacity(args_arena.allocator(), arg.len + 1);
3945 const writer = escaped.writer();
3946 writer.writeAll(arg[0..arg_idx]) catch unreachable;
3947 for (arg[arg_idx..]) |to_escape| {
3948 if (to_escape == '\\' or to_escape == '"') try writer.writeByte('\\');
3949 try writer.writeByte(to_escape);
3950 }
3951 escaped_args.appendAssumeCapacity(escaped.items);
3952 continue :arg_blk;
3953 }
3954 }
3955 escaped_args.appendAssumeCapacity(arg); // no escaping needed so just use original argument
3956 }
3957
3958 const partially_quoted = try std.mem.join(allocator, "\" \"", escaped_args.items);
3959 const args = try std.mem.concat(allocator, u8, &[_][]const u8{ "\"", partially_quoted, "\"" });
3960
3961 // Write the args to zig-cache/args/<SHA256 hash of args> to avoid conflicts with
3962 // other zig build commands running in parallel.
3963
3964 var args_hash: [Sha256.digest_length]u8 = undefined;
3965 Sha256.hash(args, &args_hash, .{});
3966 var args_hex_hash: [Sha256.digest_length * 2]u8 = undefined;
3967 _ = try std.fmt.bufPrint(
3968 &args_hex_hash,
3969 "{s}",
3970 .{std.fmt.fmtSliceHexLower(&args_hash)},
3971 );
3972
3973 const args_dir = "args";
3974 try output_dir.handle.makePath(args_dir);
3975 const args_file = try fs.path.join(allocator, &[_][]const u8{
3976 args_dir, args_hex_hash[0..],
3977 });
3978 try output_dir.handle.writeFile(args_file, args);
3979 const args_file_path = try output_dir.handle.realpathAlloc(allocator, args_file);
3980
3981 argv.shrinkRetainingCapacity(2);
3982 try argv.append(try std.mem.concat(allocator, u8, &[_][]const u8{ "@", args_file_path }));
3983 }
3984
39183985 if (comp.verbose_cc) {
39193986 dump_argv(argv.items);
39203987 }
test/standalone.zig+1-4
......@@ -37,10 +37,7 @@ pub fn addCases(cases: *tests.StandaloneContext) void {
3737 if (builtin.zig_backend == .stage1) { // https://github.com/ziglang/zig/issues/12194
3838 cases.addBuildFile("test/standalone/issue_9812/build.zig", .{});
3939 }
40 if (builtin.os.tag != .windows) {
41 // https://github.com/ziglang/zig/issues/12419
42 cases.addBuildFile("test/standalone/issue_11595/build.zig", .{});
43 }
40 cases.addBuildFile("test/standalone/issue_11595/build.zig", .{});
4441 if (builtin.os.tag != .wasi) {
4542 cases.addBuildFile("test/standalone/load_dynamic_library/build.zig", .{});
4643 }