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 {...@@ -114,6 +114,7 @@ const Error = extern enum {
114 InvalidAbiVersion,114 InvalidAbiVersion,
115 InvalidOperatingSystemVersion,115 InvalidOperatingSystemVersion,
116 UnknownClangOption,116 UnknownClangOption,
117 NestedResponseFile,
117};118};
118119
119const FILE = std.c.FILE;120const FILE = std.c.FILE;
...@@ -1259,6 +1260,7 @@ pub const ClangArgIterator = extern struct {...@@ -1259,6 +1260,7 @@ pub const ClangArgIterator = extern struct {
1259 argv_ptr: [*]const [*:0]const u8,1260 argv_ptr: [*]const [*:0]const u8,
1260 argv_len: usize,1261 argv_len: usize,
1261 next_index: usize,1262 next_index: usize,
1263 root_args: ?*Args,
12621264
1263 // ABI warning1265 // ABI warning
1264 pub const ZigEquivalent = extern enum {1266 pub const ZigEquivalent = extern enum {
...@@ -1289,7 +1291,13 @@ pub const ClangArgIterator = extern struct {...@@ -1289,7 +1291,13 @@ pub const ClangArgIterator = extern struct {
1289 no_rtti,1291 no_rtti,
1290 };1292 };
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 {
1293 return .{1301 return .{
1294 .next_index = 2, // `zig cc foo` this points to `foo`1302 .next_index = 2, // `zig cc foo` this points to `foo`
1295 .has_next = argv.len > 2,1303 .has_next = argv.len > 2,
...@@ -1300,22 +1308,74 @@ pub const ClangArgIterator = extern struct {...@@ -1300,22 +1308,74 @@ pub const ClangArgIterator = extern struct {
1300 .other_args_len = undefined,1308 .other_args_len = undefined,
1301 .argv_ptr = argv.ptr,1309 .argv_ptr = argv.ptr,
1302 .argv_len = argv.len,1310 .argv_len = argv.len,
1311 .root_args = null,
1303 };1312 };
1304 }1313 }
13051314
1306 fn next(self: *ClangArgIterator) !void {1315 pub fn next(self: *ClangArgIterator) !void {
1307 assert(self.has_next);1316 assert(self.has_next);
1308 assert(self.next_index < self.argv_len);1317 assert(self.next_index < self.argv_len);
1309 // In this state we know that the parameter we are looking at is a root parameter1318 // In this state we know that the parameter we are looking at is a root parameter
1310 // rather than an argument to a parameter.1319 // rather than an argument to a parameter.
1311 self.other_args_ptr = self.argv_ptr + self.next_index;1320 self.other_args_ptr = self.argv_ptr + self.next_index;
1312 self.other_args_len = 1; // We adjust this value below when necessary.1321 self.other_args_len = 1; // We adjust this value below when necessary.
1313 const arg = mem.span(self.argv_ptr[self.next_index]);1322 var arg = mem.span(self.argv_ptr[self.next_index]);
1314 self.next_index += 1;1323 self.incrementArgIndex();
1315 defer {1324
1316 if (self.next_index >= self.argv_len) self.has_next = false;1325 if (mem.startsWith(u8, arg, "@")) {
1317 }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 }
1319 if (!mem.startsWith(u8, arg, "-")) {1379 if (!mem.startsWith(u8, arg, "-")) {
1320 self.zig_equivalent = .positional;1380 self.zig_equivalent = .positional;
1321 self.only_arg = arg.ptr;1381 self.only_arg = arg.ptr;
...@@ -1352,7 +1412,7 @@ pub const ClangArgIterator = extern struct {...@@ -1352,7 +1412,7 @@ pub const ClangArgIterator = extern struct {
1352 process.exit(1);1412 process.exit(1);
1353 }1413 }
1354 self.only_arg = self.argv_ptr[self.next_index];1414 self.only_arg = self.argv_ptr[self.next_index];
1355 self.next_index += 1;1415 self.incrementArgIndex();
1356 self.other_args_len += 1;1416 self.other_args_len += 1;
1357 self.zig_equivalent = clang_arg.zig_equivalent;1417 self.zig_equivalent = clang_arg.zig_equivalent;
13581418
...@@ -1374,7 +1434,7 @@ pub const ClangArgIterator = extern struct {...@@ -1374,7 +1434,7 @@ pub const ClangArgIterator = extern struct {
1374 process.exit(1);1434 process.exit(1);
1375 }1435 }
1376 self.second_arg = self.argv_ptr[self.next_index];1436 self.second_arg = self.argv_ptr[self.next_index];
1377 self.next_index += 1;1437 self.incrementArgIndex();
1378 self.other_args_len += 1;1438 self.other_args_len += 1;
1379 self.zig_equivalent = clang_arg.zig_equivalent;1439 self.zig_equivalent = clang_arg.zig_equivalent;
1380 break :find_clang_arg;1440 break :find_clang_arg;
...@@ -1386,7 +1446,7 @@ pub const ClangArgIterator = extern struct {...@@ -1386,7 +1446,7 @@ pub const ClangArgIterator = extern struct {
1386 process.exit(1);1446 process.exit(1);
1387 }1447 }
1388 self.only_arg = self.argv_ptr[self.next_index];1448 self.only_arg = self.argv_ptr[self.next_index];
1389 self.next_index += 1;1449 self.incrementArgIndex();
1390 self.other_args_len += 1;1450 self.other_args_len += 1;
1391 self.zig_equivalent = clang_arg.zig_equivalent;1451 self.zig_equivalent = clang_arg.zig_equivalent;
1392 break :find_clang_arg;1452 break :find_clang_arg;
...@@ -1406,6 +1466,28 @@ pub const ClangArgIterator = extern struct {...@@ -1406,6 +1466,28 @@ pub const ClangArgIterator = extern struct {
1406 process.exit(1);1466 process.exit(1);
1407 }1467 }
1408 }1468 }
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 }
1409};1491};
14101492
1411export fn stage2_clang_arg_iterator(1493export fn stage2_clang_arg_iterator(
...@@ -1418,7 +1500,8 @@ export fn stage2_clang_arg_iterator(...@@ -1418,7 +1500,8 @@ export fn stage2_clang_arg_iterator(
14181500
1419export fn stage2_clang_arg_next(it: *ClangArgIterator) Error {1501export fn stage2_clang_arg_next(it: *ClangArgIterator) Error {
1420 it.next() catch |err| switch (err) {1502 it.next() catch |err| switch (err) {
1421 error.UnknownClangOption => return .UnknownClangOption,1503 error.NestedResponseFile => return .NestedResponseFile,
1504 error.OutOfMemory => return .OutOfMemory,
1422 };1505 };
1423 return .None;1506 return .None;
1424}1507}
src/error.cpp+1
...@@ -84,6 +84,7 @@ const char *err_str(Error err) {...@@ -84,6 +84,7 @@ const char *err_str(Error err) {
84 case ErrorInvalidAbiVersion: return "invalid C ABI version";84 case ErrorInvalidAbiVersion: return "invalid C ABI version";
85 case ErrorInvalidOperatingSystemVersion: return "invalid operating system version";85 case ErrorInvalidOperatingSystemVersion: return "invalid operating system version";
86 case ErrorUnknownClangOption: return "unknown Clang option";86 case ErrorUnknownClangOption: return "unknown Clang option";
87 case ErrorNestedResponseFile: return "nested response file";
87 }88 }
88 return "(invalid error)";89 return "(invalid error)";
89}90}
src/stage2.h+2
...@@ -106,6 +106,7 @@ enum Error {...@@ -106,6 +106,7 @@ enum Error {
106 ErrorInvalidAbiVersion,106 ErrorInvalidAbiVersion,
107 ErrorInvalidOperatingSystemVersion,107 ErrorInvalidOperatingSystemVersion,
108 ErrorUnknownClangOption,108 ErrorUnknownClangOption,
109 ErrorNestedResponseFile,
109};110};
110111
111// ABI warning112// ABI warning
...@@ -361,6 +362,7 @@ struct Stage2ClangArgIterator {...@@ -361,6 +362,7 @@ struct Stage2ClangArgIterator {
361 const char **argv_ptr;362 const char **argv_ptr;
362 size_t argv_len;363 size_t argv_len;
363 size_t next_index;364 size_t next_index;
365 size_t root_args;
364};366};
365367
366// ABI warning368// ABI warning