| author | |
| committer | |
| log | 94b9bcd034960f0467ca789217064b17f2ca7a49 |
| tree | fb9bc675814214ad303f41bce4c8b3ca75f2c3c8 |
| parent | d7f8368da86241f47e97257e737b6fb14bf5f773 |
Fixes #115955 files changed, 94 insertions(+), 1 deletions(-)
lib/std/build.zig+26-1| ... | @@ -3009,6 +3009,7 @@ pub const LibExeObjStep = struct { | ... | @@ -3009,6 +3009,7 @@ pub const LibExeObjStep = struct { |
| 3009 | // Windows has an argument length limit of 32,766 characters, macOS 262,144 and Linux | 3009 | // Windows has an argument length limit of 32,766 characters, macOS 262,144 and Linux |
| 3010 | // 2,097,152. If our args exceed 30 KiB, we instead write them to a "response file" and | 3010 | // 2,097,152. If our args exceed 30 KiB, we instead write them to a "response file" and |
| 3011 | // pass that to zig, e.g. via 'zig build-lib @args.rsp' | 3011 | // pass that to zig, e.g. via 'zig build-lib @args.rsp' |
| 3012 | // See @file syntax here: https://gcc.gnu.org/onlinedocs/gcc/Overall-Options.html | ||
| 3012 | var args_length: usize = 0; | 3013 | var args_length: usize = 0; |
| 3013 | for (zig_args.items) |arg| { | 3014 | for (zig_args.items) |arg| { |
| 3014 | args_length += arg.len + 1; // +1 to account for null terminator | 3015 | args_length += arg.len + 1; // +1 to account for null terminator |
| ... | @@ -3020,9 +3021,33 @@ pub const LibExeObjStep = struct { | ... | @@ -3020,9 +3021,33 @@ pub const LibExeObjStep = struct { |
| 3020 | ); | 3021 | ); |
| 3021 | try std.fs.cwd().makePath(args_dir); | 3022 | try std.fs.cwd().makePath(args_dir); |
| 3022 | 3023 | ||
| 3024 | var args_arena = std.heap.ArenaAllocator.init(builder.allocator); | ||
| 3025 | defer args_arena.deinit(); | ||
| 3026 | |||
| 3027 | const args_to_escape = zig_args.items[2..]; | ||
| 3028 | var escaped_args = try ArrayList([]const u8).initCapacity(args_arena.allocator(), args_to_escape.len); | ||
| 3029 | |||
| 3030 | arg_blk: for (args_to_escape) |arg| { | ||
| 3031 | for (arg) |c, arg_idx| { | ||
| 3032 | if (c == '\\' or c == '"') { | ||
| 3033 | // Slow path for arguments that need to be escaped. We'll need to allocate and copy | ||
| 3034 | var escaped = try ArrayList(u8).initCapacity(args_arena.allocator(), arg.len + 1); | ||
| 3035 | const writer = escaped.writer(); | ||
| 3036 | writer.writeAll(arg[0..arg_idx]) catch unreachable; | ||
| 3037 | for (arg[arg_idx..]) |to_escape| { | ||
| 3038 | if (to_escape == '\\' or to_escape == '"') try writer.writeByte('\\'); | ||
| 3039 | try writer.writeByte(to_escape); | ||
| 3040 | } | ||
| 3041 | escaped_args.appendAssumeCapacity(escaped.items); | ||
| 3042 | continue :arg_blk; | ||
| 3043 | } | ||
| 3044 | } | ||
| 3045 | escaped_args.appendAssumeCapacity(arg); // no escaping needed so just use original argument | ||
| 3046 | } | ||
| 3047 | |||
| 3023 | // Write the args to zig-cache/args/<SHA256 hash of args> to avoid conflicts with | 3048 | // Write the args to zig-cache/args/<SHA256 hash of args> to avoid conflicts with |
| 3024 | // other zig build commands running in parallel. | 3049 | // other zig build commands running in parallel. |
| 3025 | const partially_quoted = try std.mem.join(builder.allocator, "\" \"", zig_args.items[2..]); | 3050 | const partially_quoted = try std.mem.join(builder.allocator, "\" \"", escaped_args.items); |
| 3026 | const args = try std.mem.concat(builder.allocator, u8, &[_][]const u8{ "\"", partially_quoted, "\"" }); | 3051 | const args = try std.mem.concat(builder.allocator, u8, &[_][]const u8{ "\"", partially_quoted, "\"" }); |
| 3027 | 3052 | ||
| 3028 | var args_hash: [Sha256.digest_length]u8 = undefined; | 3053 | var args_hash: [Sha256.digest_length]u8 = undefined; |
test/standalone.zig+1| ... | @@ -49,6 +49,7 @@ pub fn addCases(cases: *tests.StandaloneContext) void { | ... | @@ -49,6 +49,7 @@ pub fn addCases(cases: *tests.StandaloneContext) void { |
| 49 | cases.addBuildFile("test/standalone/issue_7030/build.zig", .{}); | 49 | cases.addBuildFile("test/standalone/issue_7030/build.zig", .{}); |
| 50 | cases.addBuildFile("test/standalone/install_raw_hex/build.zig", .{}); | 50 | cases.addBuildFile("test/standalone/install_raw_hex/build.zig", .{}); |
| 51 | cases.addBuildFile("test/standalone/issue_9812/build.zig", .{}); | 51 | cases.addBuildFile("test/standalone/issue_9812/build.zig", .{}); |
| 52 | cases.addBuildFile("test/standalone/issue_11595/build.zig", .{}); | ||
| 52 | if (builtin.os.tag != .wasi) { | 53 | if (builtin.os.tag != .wasi) { |
| 53 | cases.addBuildFile("test/standalone/load_dynamic_library/build.zig", .{}); | 54 | cases.addBuildFile("test/standalone/load_dynamic_library/build.zig", .{}); |
| 54 | } | 55 | } |
test/standalone/issue_11595/build.zig created+52| ... | @@ -0,0 +1,52 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const Builder = std.build.Builder; | ||
| 4 | const CrossTarget = std.zig.CrossTarget; | ||
| 5 | |||
| 6 | // TODO integrate this with the std.build executor API | ||
| 7 | fn isRunnableTarget(t: CrossTarget) bool { | ||
| 8 | if (t.isNative()) return true; | ||
| 9 | |||
| 10 | return (t.getOsTag() == builtin.os.tag and | ||
| 11 | t.getCpuArch() == builtin.cpu.arch); | ||
| 12 | } | ||
| 13 | |||
| 14 | pub fn build(b: *Builder) void { | ||
| 15 | const mode = b.standardReleaseOptions(); | ||
| 16 | const target = b.standardTargetOptions(.{}); | ||
| 17 | |||
| 18 | const exe = b.addExecutable("zigtest", "main.zig"); | ||
| 19 | exe.setBuildMode(mode); | ||
| 20 | exe.install(); | ||
| 21 | |||
| 22 | const c_sources = [_][]const u8{ | ||
| 23 | "test.c", | ||
| 24 | }; | ||
| 25 | |||
| 26 | exe.addCSourceFiles(&c_sources, &.{}); | ||
| 27 | exe.linkLibC(); | ||
| 28 | |||
| 29 | var i: i32 = 0; | ||
| 30 | while (i < 1000) : (i += 1) { | ||
| 31 | exe.defineCMacro("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); | ||
| 32 | } | ||
| 33 | |||
| 34 | exe.defineCMacro("FOO", "42"); | ||
| 35 | exe.defineCMacro("BAR", "\"BAR\""); | ||
| 36 | exe.defineCMacro("BAZ", | ||
| 37 | \\"\"BAZ\"" | ||
| 38 | ); | ||
| 39 | exe.defineCMacro("QUX", "\"Q\" \"UX\""); | ||
| 40 | exe.defineCMacro("QUUX", "\"QU\\\"UX\""); | ||
| 41 | |||
| 42 | exe.setTarget(target); | ||
| 43 | b.default_step.dependOn(&exe.step); | ||
| 44 | |||
| 45 | const test_step = b.step("test", "Test the program"); | ||
| 46 | if (isRunnableTarget(target)) { | ||
| 47 | const run_cmd = exe.run(); | ||
| 48 | test_step.dependOn(&run_cmd.step); | ||
| 49 | } else { | ||
| 50 | test_step.dependOn(&exe.step); | ||
| 51 | } | ||
| 52 | } | ||
test/standalone/issue_11595/main.zig created+5| ... | @@ -0,0 +1,5 @@ | ||
| 1 | extern fn check() c_int; | ||
| 2 | |||
| 3 | pub fn main() u8 { | ||
| 4 | return @intCast(u8, check()); | ||
| 5 | } | ||
test/standalone/issue_11595/test.c created+10| ... | @@ -0,0 +1,10 @@ | ||
| 1 | #include <string.h> | ||
| 2 | |||
| 3 | int check(void) { | ||
| 4 | if (FOO != 42) return 1; | ||
| 5 | if (strcmp(BAR, "BAR")) return 2; | ||
| 6 | if (strcmp(BAZ, "\"BAZ\"")) return 3; | ||
| 7 | if (strcmp(QUX, "QUX")) return 4; | ||
| 8 | if (strcmp(QUUX, "QU\"UX")) return 5; | ||
| 9 | return 0; | ||
| 10 | } | ||