authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-03-27 22:24:40-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-03-27 22:24:40-04:00
loga25874108470f97c5c58d72b2df49a9085c79b2e
treed68193ddaeedef8dc97ea2d8436798a34e405d65
parente803490a562cdc6f0f8aa03a6d35c1b7c78379f7
signaturelock-open Commit is signed but in an unrecognized format.

initial support of response files

See #4833 It doesn't support comments or quotes yet.

3 files changed, 97 insertions(+), 11 deletions(-)

src-self-hosted/stage2.zig+94-11
......@@ -114,6 +114,7 @@ const Error = extern enum {
114114 InvalidAbiVersion,
115115 InvalidOperatingSystemVersion,
116116 UnknownClangOption,
117 NestedResponseFile,
117118};
118119
119120const FILE = std.c.FILE;
......@@ -1259,6 +1260,7 @@ pub const ClangArgIterator = extern struct {
12591260 argv_ptr: [*]const [*:0]const u8,
12601261 argv_len: usize,
12611262 next_index: usize,
1263 root_args: ?*Args,
12621264
12631265 // ABI warning
12641266 pub const ZigEquivalent = extern enum {
......@@ -1289,7 +1291,13 @@ pub const ClangArgIterator = extern struct {
12891291 no_rtti,
12901292 };
12911293
1292 fn init(argv: []const [*:0]const u8) ClangArgIterator {
1294 const Args = struct {
1295 next_index: usize,
1296 argv_ptr: [*]const [*:0]const u8,
1297 argv_len: usize,
1298 };
1299
1300 pub fn init(argv: []const [*:0]const u8) ClangArgIterator {
12931301 return .{
12941302 .next_index = 2, // `zig cc foo` this points to `foo`
12951303 .has_next = argv.len > 2,
......@@ -1300,22 +1308,74 @@ pub const ClangArgIterator = extern struct {
13001308 .other_args_len = undefined,
13011309 .argv_ptr = argv.ptr,
13021310 .argv_len = argv.len,
1311 .root_args = null,
13031312 };
13041313 }
13051314
1306 fn next(self: *ClangArgIterator) !void {
1315 pub fn next(self: *ClangArgIterator) !void {
13071316 assert(self.has_next);
13081317 assert(self.next_index < self.argv_len);
13091318 // In this state we know that the parameter we are looking at is a root parameter
13101319 // rather than an argument to a parameter.
13111320 self.other_args_ptr = self.argv_ptr + self.next_index;
13121321 self.other_args_len = 1; // We adjust this value below when necessary.
1313 const arg = mem.span(self.argv_ptr[self.next_index]);
1314 self.next_index += 1;
1315 defer {
1316 if (self.next_index >= self.argv_len) self.has_next = false;
1317 }
1322 var arg = mem.span(self.argv_ptr[self.next_index]);
1323 self.incrementArgIndex();
1324
1325 if (mem.startsWith(u8, arg, "@")) {
1326 if (self.root_args != null) return error.NestedResponseFile;
1327
1328 // This is a "compiler response file". We must parse the file and treat its
1329 // contents as command line parameters.
1330 const allocator = std.heap.c_allocator;
1331 const max_bytes = 10 * 1024 * 1024; // 10 MiB of command line arguments is a reasonable limit
1332 const resp_file_path = arg[1..];
1333 const resp_contents = fs.cwd().readFileAlloc(allocator, resp_file_path, max_bytes) catch |err| {
1334 std.debug.warn("unable to read response file '{}': {}\n", .{ resp_file_path, @errorName(err) });
1335 process.exit(1);
1336 };
1337 defer allocator.free(resp_contents);
1338 // TODO is there a specification for this file format? Let's find it and make this parsing more robust
1339 // at the very least I'm guessing this needs to handle quotes and `#` comments.
1340 var it = mem.tokenize(resp_contents, " \t\r\n");
1341 var resp_arg_list = std.ArrayList([*:0]const u8).init(allocator);
1342 defer resp_arg_list.deinit();
1343 {
1344 errdefer {
1345 for (resp_arg_list.span()) |item| {
1346 allocator.free(mem.span(item));
1347 }
1348 }
1349 while (it.next()) |token| {
1350 const dupe_token = try mem.dupeZ(allocator, u8, token);
1351 errdefer allocator.free(dupe_token);
1352 try resp_arg_list.append(dupe_token);
1353 }
1354 const args = try allocator.create(Args);
1355 errdefer allocator.destroy(args);
1356 args.* = .{
1357 .next_index = self.next_index,
1358 .argv_ptr = self.argv_ptr,
1359 .argv_len = self.argv_len,
1360 };
1361 self.root_args = args;
1362 }
1363 const resp_arg_slice = resp_arg_list.toOwnedSlice();
1364 self.next_index = 0;
1365 self.argv_ptr = resp_arg_slice.ptr;
1366 self.argv_len = resp_arg_slice.len;
1367
1368 if (resp_arg_slice.len == 0) {
1369 self.resolveRespFileArgs();
1370 return;
1371 }
13181372
1373 self.has_next = true;
1374 self.other_args_ptr = self.argv_ptr + self.next_index;
1375 self.other_args_len = 1; // We adjust this value below when necessary.
1376 arg = mem.span(self.argv_ptr[self.next_index]);
1377 self.incrementArgIndex();
1378 }
13191379 if (!mem.startsWith(u8, arg, "-")) {
13201380 self.zig_equivalent = .positional;
13211381 self.only_arg = arg.ptr;
......@@ -1352,7 +1412,7 @@ pub const ClangArgIterator = extern struct {
13521412 process.exit(1);
13531413 }
13541414 self.only_arg = self.argv_ptr[self.next_index];
1355 self.next_index += 1;
1415 self.incrementArgIndex();
13561416 self.other_args_len += 1;
13571417 self.zig_equivalent = clang_arg.zig_equivalent;
13581418
......@@ -1374,7 +1434,7 @@ pub const ClangArgIterator = extern struct {
13741434 process.exit(1);
13751435 }
13761436 self.second_arg = self.argv_ptr[self.next_index];
1377 self.next_index += 1;
1437 self.incrementArgIndex();
13781438 self.other_args_len += 1;
13791439 self.zig_equivalent = clang_arg.zig_equivalent;
13801440 break :find_clang_arg;
......@@ -1386,7 +1446,7 @@ pub const ClangArgIterator = extern struct {
13861446 process.exit(1);
13871447 }
13881448 self.only_arg = self.argv_ptr[self.next_index];
1389 self.next_index += 1;
1449 self.incrementArgIndex();
13901450 self.other_args_len += 1;
13911451 self.zig_equivalent = clang_arg.zig_equivalent;
13921452 break :find_clang_arg;
......@@ -1406,6 +1466,28 @@ pub const ClangArgIterator = extern struct {
14061466 process.exit(1);
14071467 }
14081468 }
1469
1470 fn incrementArgIndex(self: *ClangArgIterator) void {
1471 self.next_index += 1;
1472 self.resolveRespFileArgs();
1473 }
1474
1475 fn resolveRespFileArgs(self: *ClangArgIterator) void {
1476 const allocator = std.heap.c_allocator;
1477 if (self.next_index >= self.argv_len) {
1478 if (self.root_args) |root_args| {
1479 self.next_index = root_args.next_index;
1480 self.argv_ptr = root_args.argv_ptr;
1481 self.argv_len = root_args.argv_len;
1482
1483 allocator.destroy(root_args);
1484 self.root_args = null;
1485 }
1486 if (self.next_index >= self.argv_len) {
1487 self.has_next = false;
1488 }
1489 }
1490 }
14091491};
14101492
14111493export fn stage2_clang_arg_iterator(
......@@ -1418,7 +1500,8 @@ export fn stage2_clang_arg_iterator(
14181500
14191501export fn stage2_clang_arg_next(it: *ClangArgIterator) Error {
14201502 it.next() catch |err| switch (err) {
1421 error.UnknownClangOption => return .UnknownClangOption,
1503 error.NestedResponseFile => return .NestedResponseFile,
1504 error.OutOfMemory => return .OutOfMemory,
14221505 };
14231506 return .None;
14241507}
src/error.cpp+1
......@@ -84,6 +84,7 @@ const char *err_str(Error err) {
8484 case ErrorInvalidAbiVersion: return "invalid C ABI version";
8585 case ErrorInvalidOperatingSystemVersion: return "invalid operating system version";
8686 case ErrorUnknownClangOption: return "unknown Clang option";
87 case ErrorNestedResponseFile: return "nested response file";
8788 }
8889 return "(invalid error)";
8990}
src/stage2.h+2
......@@ -106,6 +106,7 @@ enum Error {
106106 ErrorInvalidAbiVersion,
107107 ErrorInvalidOperatingSystemVersion,
108108 ErrorUnknownClangOption,
109 ErrorNestedResponseFile,
109110};
110111
111112// ABI warning
......@@ -361,6 +362,7 @@ struct Stage2ClangArgIterator {
361362 const char **argv_ptr;
362363 size_t argv_len;
363364 size_t next_index;
365 size_t root_args;
364366};
365367
366368// ABI warning