authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-15 19:01:55-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-15 19:01:55-07:00
logccdf55310bee2dcf86b718d26a56933dc1a03443
treeb33a5cdb44395fd3ec399153213436dc3e836c48
parent2b2920f5998fc464c7ebd342c36879a17e76e4b4

stage2: properly model miscellaneous failed tasks

with error messages that go away after updates

2 files changed, 253 insertions(+), 43 deletions(-)

src/Compilation.zig+249-42
......@@ -53,6 +53,9 @@ c_object_work_queue: std.fifo.LinearFifo(*CObject, .Dynamic),
5353/// This data is accessed by multiple threads and is protected by `mutex`.
5454failed_c_objects: std.AutoArrayHashMapUnmanaged(*CObject, *CObject.ErrorMsg) = .{},
5555
56/// Miscellaneous things that can fail.
57misc_failures: std.AutoArrayHashMapUnmanaged(MiscTask, MiscError) = .{},
58
5659keep_source_files_loaded: bool,
5760use_clang: bool,
5861sanitize_c: bool,
......@@ -256,6 +259,36 @@ pub const CObject = struct {
256259 }
257260};
258261
262pub const MiscTask = enum {
263 write_builtin_zig,
264 glibc_crt_file,
265 glibc_shared_objects,
266 musl_crt_file,
267 mingw_crt_file,
268 windows_import_lib,
269 libunwind,
270 libcxx,
271 libcxxabi,
272 libtsan,
273 compiler_rt,
274 libssp,
275 zig_libc,
276};
277
278pub const MiscError = struct {
279 /// Allocated with gpa.
280 msg: []u8,
281 children: ?AllErrors = null,
282
283 pub fn deinit(misc_err: *MiscError, gpa: *Allocator) void {
284 gpa.free(misc_err.msg);
285 if (misc_err.children) |*children| {
286 children.deinit(gpa);
287 }
288 misc_err.* = undefined;
289 }
290};
291
259292/// To support incremental compilation, errors are stored in various places
260293/// so that they can be created and destroyed appropriately. This structure
261294/// is used to collect all the errors from the various places into one
......@@ -278,6 +311,7 @@ pub const AllErrors = struct {
278311 },
279312 plain: struct {
280313 msg: []const u8,
314 notes: []Message = &.{},
281315 },
282316
283317 pub fn renderToStdErr(msg: Message, ttyconf: std.debug.TTY.Config) void {
......@@ -285,7 +319,7 @@ pub const AllErrors = struct {
285319 const held = std.debug.getStderrMutex().acquire();
286320 defer held.release();
287321 const stderr = std.io.getStdErr();
288 return msg.renderToStdErrInner(ttyconf, stderr, "error:", .Red) catch return;
322 return msg.renderToStdErrInner(ttyconf, stderr, "error:", .Red, 0) catch return;
289323 }
290324
291325 fn renderToStdErrInner(
......@@ -294,6 +328,7 @@ pub const AllErrors = struct {
294328 stderr_file: std.fs.File,
295329 kind: []const u8,
296330 color: std.debug.TTY.Color,
331 indent: usize,
297332 ) anyerror!void {
298333 const stderr = stderr_file.writer();
299334 switch (msg) {
......@@ -305,6 +340,7 @@ pub const AllErrors = struct {
305340 src.column + 1,
306341 });
307342 ttyconf.setColor(stderr, color);
343 try stderr.writeByteNTimes(' ', indent);
308344 try stderr.writeAll(kind);
309345 ttyconf.setColor(stderr, .Bold);
310346 try stderr.print(" {s}\n", .{src.msg});
......@@ -318,11 +354,19 @@ pub const AllErrors = struct {
318354 ttyconf.setColor(stderr, .Reset);
319355 }
320356 for (src.notes) |note| {
321 try note.renderToStdErrInner(ttyconf, stderr_file, "note:", .Cyan);
357 try note.renderToStdErrInner(ttyconf, stderr_file, "note:", .Cyan, indent);
322358 }
323359 },
324360 .plain => |plain| {
325 try stderr.print("{s}: {s}\n", .{ kind, plain.msg });
361 ttyconf.setColor(stderr, color);
362 try stderr.writeByteNTimes(' ', indent);
363 try stderr.writeAll(kind);
364 ttyconf.setColor(stderr, .Reset);
365 try stderr.print(" {s}\n", .{plain.msg});
366 ttyconf.setColor(stderr, .Reset);
367 for (plain.notes) |note| {
368 try note.renderToStdErrInner(ttyconf, stderr_file, "error:", .Red, indent + 4);
369 }
326370 },
327371 }
328372 }
......@@ -380,6 +424,45 @@ pub const AllErrors = struct {
380424 ) !void {
381425 try errors.append(.{ .plain = .{ .msg = msg } });
382426 }
427
428 fn addPlainWithChildren(
429 arena: *std.heap.ArenaAllocator,
430 errors: *std.ArrayList(Message),
431 msg: []const u8,
432 optional_children: ?AllErrors,
433 ) !void {
434 const duped_msg = try arena.allocator.dupe(u8, msg);
435 if (optional_children) |*children| {
436 try errors.append(.{ .plain = .{
437 .msg = duped_msg,
438 .notes = try dupeList(children.list, &arena.allocator),
439 } });
440 } else {
441 try errors.append(.{ .plain = .{ .msg = duped_msg } });
442 }
443 }
444
445 fn dupeList(list: []const Message, arena: *Allocator) Allocator.Error![]Message {
446 const duped_list = try arena.alloc(Message, list.len);
447 for (list) |item, i| {
448 duped_list[i] = switch (item) {
449 .src => |src| .{ .src = .{
450 .msg = try arena.dupe(u8, src.msg),
451 .src_path = try arena.dupe(u8, src.src_path),
452 .line = src.line,
453 .column = src.column,
454 .byte_offset = src.byte_offset,
455 .source_line = if (src.source_line) |s| try arena.dupe(u8, s) else null,
456 .notes = try dupeList(src.notes, arena),
457 } },
458 .plain => |plain| .{ .plain = .{
459 .msg = try arena.dupe(u8, plain.msg),
460 .notes = try dupeList(plain.notes, arena),
461 } },
462 };
463 }
464 return duped_list;
465 }
383466};
384467
385468pub const Directory = struct {
......@@ -1357,6 +1440,8 @@ pub fn destroy(self: *Compilation) void {
13571440 }
13581441 self.failed_c_objects.deinit(gpa);
13591442
1443 self.clearMiscFailures();
1444
13601445 self.cache_parent.manifest_dir.close();
13611446 if (self.owned_link_dir) |*dir| dir.close();
13621447
......@@ -1366,6 +1451,14 @@ pub fn destroy(self: *Compilation) void {
13661451 self.arena_state.promote(gpa).deinit();
13671452}
13681453
1454pub fn clearMiscFailures(comp: *Compilation) void {
1455 for (comp.misc_failures.items()) |*entry| {
1456 entry.value.deinit(comp.gpa);
1457 }
1458 comp.misc_failures.deinit(comp.gpa);
1459 comp.misc_failures = .{};
1460}
1461
13691462pub fn getTarget(self: Compilation) Target {
13701463 return self.bin_file.options.target;
13711464}
......@@ -1375,6 +1468,7 @@ pub fn update(self: *Compilation) !void {
13751468 const tracy = trace(@src());
13761469 defer tracy.end();
13771470
1471 self.clearMiscFailures();
13781472 self.c_object_cache_digest_set.clearRetainingCapacity();
13791473
13801474 // For compiling C objects, we rely on the cache hash system to avoid duplicating work.
......@@ -1475,7 +1569,7 @@ pub fn makeBinFileWritable(self: *Compilation) !void {
14751569}
14761570
14771571pub fn totalErrorCount(self: *Compilation) usize {
1478 var total: usize = self.failed_c_objects.items().len;
1572 var total: usize = self.failed_c_objects.count() + self.misc_failures.count();
14791573
14801574 if (self.bin_file.options.module) |module| {
14811575 total += module.failed_exports.items().len +
......@@ -1539,6 +1633,9 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
15391633 },
15401634 });
15411635 }
1636 for (self.misc_failures.items()) |entry| {
1637 try AllErrors.addPlainWithChildren(&arena, &errors, entry.value.msg, entry.value.children);
1638 }
15421639 if (self.bin_file.options.module) |module| {
15431640 for (module.failed_files.items()) |entry| {
15441641 try AllErrors.add(module, &arena, &errors, entry.value.*);
......@@ -1775,89 +1872,160 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
17751872 },
17761873 .glibc_crt_file => |crt_file| {
17771874 glibc.buildCRTFile(self, crt_file) catch |err| {
1778 // TODO Expose this as a normal compile error rather than crashing here.
1779 fatal("unable to build glibc CRT file: {s}", .{@errorName(err)});
1875 // TODO Surface more error details.
1876 try self.setMiscFailure(.glibc_crt_file, "unable to build glibc CRT file: {s}", .{
1877 @errorName(err),
1878 });
17801879 };
17811880 },
17821881 .glibc_shared_objects => {
17831882 glibc.buildSharedObjects(self) catch |err| {
1784 // TODO Expose this as a normal compile error rather than crashing here.
1785 fatal("unable to build glibc shared objects: {s}", .{@errorName(err)});
1883 // TODO Surface more error details.
1884 try self.setMiscFailure(
1885 .glibc_shared_objects,
1886 "unable to build glibc shared objects: {s}",
1887 .{@errorName(err)},
1888 );
17861889 };
17871890 },
17881891 .musl_crt_file => |crt_file| {
17891892 musl.buildCRTFile(self, crt_file) catch |err| {
1790 // TODO Expose this as a normal compile error rather than crashing here.
1791 fatal("unable to build musl CRT file: {s}", .{@errorName(err)});
1893 // TODO Surface more error details.
1894 try self.setMiscFailure(
1895 .musl_crt_file,
1896 "unable to build musl CRT file: {s}",
1897 .{@errorName(err)},
1898 );
17921899 };
17931900 },
17941901 .mingw_crt_file => |crt_file| {
17951902 mingw.buildCRTFile(self, crt_file) catch |err| {
1796 // TODO Expose this as a normal compile error rather than crashing here.
1797 fatal("unable to build mingw-w64 CRT file: {s}", .{@errorName(err)});
1903 // TODO Surface more error details.
1904 try self.setMiscFailure(
1905 .mingw_crt_file,
1906 "unable to build mingw-w64 CRT file: {s}",
1907 .{@errorName(err)},
1908 );
17981909 };
17991910 },
18001911 .windows_import_lib => |index| {
18011912 const link_lib = self.bin_file.options.system_libs.items()[index].key;
18021913 mingw.buildImportLib(self, link_lib) catch |err| {
1803 // TODO Expose this as a normal compile error rather than crashing here.
1804 fatal("unable to generate DLL import .lib file: {s}", .{@errorName(err)});
1914 // TODO Surface more error details.
1915 try self.setMiscFailure(
1916 .windows_import_lib,
1917 "unable to generate DLL import .lib file: {s}",
1918 .{@errorName(err)},
1919 );
18051920 };
18061921 },
18071922 .libunwind => {
18081923 libunwind.buildStaticLib(self) catch |err| {
1809 // TODO Expose this as a normal compile error rather than crashing here.
1810 fatal("unable to build libunwind: {s}", .{@errorName(err)});
1924 // TODO Surface more error details.
1925 try self.setMiscFailure(
1926 .libunwind,
1927 "unable to build libunwind: {s}",
1928 .{@errorName(err)},
1929 );
18111930 };
18121931 },
18131932 .libcxx => {
18141933 libcxx.buildLibCXX(self) catch |err| {
1815 // TODO Expose this as a normal compile error rather than crashing here.
1816 fatal("unable to build libcxx: {s}", .{@errorName(err)});
1934 // TODO Surface more error details.
1935 try self.setMiscFailure(
1936 .libcxx,
1937 "unable to build libcxx: {s}",
1938 .{@errorName(err)},
1939 );
18171940 };
18181941 },
18191942 .libcxxabi => {
18201943 libcxx.buildLibCXXABI(self) catch |err| {
1821 // TODO Expose this as a normal compile error rather than crashing here.
1822 fatal("unable to build libcxxabi: {s}", .{@errorName(err)});
1944 // TODO Surface more error details.
1945 try self.setMiscFailure(
1946 .libcxxabi,
1947 "unable to build libcxxabi: {s}",
1948 .{@errorName(err)},
1949 );
18231950 };
18241951 },
18251952 .libtsan => {
18261953 libtsan.buildTsan(self) catch |err| {
1827 // TODO Expose this as a normal compile error rather than crashing here.
1828 fatal("unable to build TSAN library: {s}", .{@errorName(err)});
1954 // TODO Surface more error details.
1955 try self.setMiscFailure(
1956 .libtsan,
1957 "unable to build TSAN library: {s}",
1958 .{@errorName(err)},
1959 );
18291960 };
18301961 },
18311962 .compiler_rt_lib => {
1832 self.buildOutputFromZig("compiler_rt.zig", .Lib, &self.compiler_rt_static_lib) catch |err| {
1833 // TODO Expose this as a normal compile error rather than crashing here.
1834 fatal("unable to build compiler_rt: {s}", .{@errorName(err)});
1963 self.buildOutputFromZig(
1964 "compiler_rt.zig",
1965 .Lib,
1966 &self.compiler_rt_static_lib,
1967 .compiler_rt,
1968 ) catch |err| switch (err) {
1969 error.OutOfMemory => return error.OutOfMemory,
1970 error.SubCompilationFailed => continue, // error reported already
1971 else => try self.setMiscFailure(
1972 .compiler_rt,
1973 "unable to build compiler_rt: {s}",
1974 .{@errorName(err)},
1975 ),
18351976 };
18361977 },
18371978 .compiler_rt_obj => {
1838 self.buildOutputFromZig("compiler_rt.zig", .Obj, &self.compiler_rt_obj) catch |err| {
1839 // TODO Expose this as a normal compile error rather than crashing here.
1840 fatal("unable to build compiler_rt: {s}", .{@errorName(err)});
1979 self.buildOutputFromZig(
1980 "compiler_rt.zig",
1981 .Obj,
1982 &self.compiler_rt_obj,
1983 .compiler_rt,
1984 ) catch |err| switch (err) {
1985 error.OutOfMemory => return error.OutOfMemory,
1986 error.SubCompilationFailed => continue, // error reported already
1987 else => try self.setMiscFailure(
1988 .compiler_rt,
1989 "unable to build compiler_rt: {s}",
1990 .{@errorName(err)},
1991 ),
18411992 };
18421993 },
18431994 .libssp => {
1844 self.buildOutputFromZig("ssp.zig", .Lib, &self.libssp_static_lib) catch |err| {
1845 // TODO Expose this as a normal compile error rather than crashing here.
1846 fatal("unable to build libssp: {s}", .{@errorName(err)});
1995 self.buildOutputFromZig(
1996 "ssp.zig",
1997 .Lib,
1998 &self.libssp_static_lib,
1999 .libssp,
2000 ) catch |err| switch (err) {
2001 error.OutOfMemory => return error.OutOfMemory,
2002 error.SubCompilationFailed => continue, // error reported already
2003 else => try self.setMiscFailure(
2004 .libssp,
2005 "unable to build libssp: {s}",
2006 .{@errorName(err)},
2007 ),
18472008 };
18482009 },
18492010 .zig_libc => {
1850 self.buildOutputFromZig("c.zig", .Lib, &self.libc_static_lib) catch |err| {
1851 // TODO Expose this as a normal compile error rather than crashing here.
1852 fatal("unable to build zig's multitarget libc: {s}", .{@errorName(err)});
2011 self.buildOutputFromZig(
2012 "c.zig",
2013 .Lib,
2014 &self.libc_static_lib,
2015 .zig_libc,
2016 ) catch |err| switch (err) {
2017 error.OutOfMemory => return error.OutOfMemory,
2018 error.SubCompilationFailed => continue, // error reported already
2019 else => try self.setMiscFailure(
2020 .zig_libc,
2021 "unable to build zig's multitarget libc: {s}",
2022 .{@errorName(err)},
2023 ),
18532024 };
18542025 },
18552026 .generate_builtin_zig => {
18562027 // This Job is only queued up if there is a zig module.
1857 self.updateBuiltinZigFile(self.bin_file.options.module.?) catch |err| {
1858 // TODO Expose this as a normal compile error rather than crashing here.
1859 fatal("unable to update builtin.zig file: {s}", .{@errorName(err)});
1860 };
2028 try self.updateBuiltinZigFile(self.bin_file.options.module.?);
18612029 },
18622030 .stage1_module => {
18632031 if (!build_options.is_stage1)
......@@ -2858,13 +3026,31 @@ fn wantBuildLibUnwindFromSource(comp: *Compilation) bool {
28583026 target_util.libcNeedsLibUnwind(comp.getTarget());
28593027}
28603028
2861fn updateBuiltinZigFile(comp: *Compilation, mod: *Module) !void {
3029fn updateBuiltinZigFile(comp: *Compilation, mod: *Module) Allocator.Error!void {
28623030 const tracy = trace(@src());
28633031 defer tracy.end();
28643032
28653033 const source = try comp.generateBuiltinZigSource(comp.gpa);
28663034 defer comp.gpa.free(source);
2867 try mod.zig_cache_artifact_directory.handle.writeFile("builtin.zig", source);
3035
3036 mod.zig_cache_artifact_directory.handle.writeFile("builtin.zig", source) catch |err| {
3037 const dir_path: []const u8 = mod.zig_cache_artifact_directory.path orelse ".";
3038 try comp.setMiscFailure(.write_builtin_zig, "unable to write builtin.zig to {s}: {s}", .{
3039 dir_path,
3040 @errorName(err),
3041 });
3042 };
3043}
3044
3045fn setMiscFailure(
3046 comp: *Compilation,
3047 tag: MiscTask,
3048 comptime format: []const u8,
3049 args: anytype,
3050) Allocator.Error!void {
3051 try comp.misc_failures.ensureCapacity(comp.gpa, comp.misc_failures.count() + 1);
3052 const msg = try std.fmt.allocPrint(comp.gpa, format, args);
3053 comp.misc_failures.putAssumeCapacityNoClobber(tag, .{ .msg = msg });
28683054}
28693055
28703056pub fn dump_argv(argv: []const []const u8) void {
......@@ -2874,7 +3060,7 @@ pub fn dump_argv(argv: []const []const u8) void {
28743060 std.debug.print("{s}\n", .{argv[argv.len - 1]});
28753061}
28763062
2877pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8 {
3063pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) Allocator.Error![]u8 {
28783064 const tracy = trace(@src());
28793065 defer tracy.end();
28803066
......@@ -3071,6 +3257,10 @@ pub fn updateSubCompilation(sub_compilation: *Compilation) !void {
30713257 try sub_compilation.update();
30723258
30733259 // Look for compilation errors in this sub_compilation
3260 // TODO instead of logging these errors, handle them in the callsites
3261 // of updateSubCompilation and attach them as sub-errors, properly
3262 // surfacing the errors. You can see an example of this already
3263 // done inside buildOutputFromZig.
30743264 var errors = try sub_compilation.getAllErrorsAlloc();
30753265 defer errors.deinit(sub_compilation.gpa);
30763266
......@@ -3099,6 +3289,7 @@ fn buildOutputFromZig(
30993289 src_basename: []const u8,
31003290 output_mode: std.builtin.OutputMode,
31013291 out: *?CRTFile,
3292 misc_task_tag: MiscTask,
31023293) !void {
31033294 const tracy = trace(@src());
31043295 defer tracy.end();
......@@ -3173,7 +3364,23 @@ fn buildOutputFromZig(
31733364 });
31743365 defer sub_compilation.destroy();
31753366
3176 try sub_compilation.updateSubCompilation();
3367 try sub_compilation.update();
3368 // Look for compilation errors in this sub_compilation.
3369 var keep_errors = false;
3370 var errors = try sub_compilation.getAllErrorsAlloc();
3371 defer if (!keep_errors) errors.deinit(sub_compilation.gpa);
3372
3373 if (errors.list.len != 0) {
3374 try comp.misc_failures.ensureCapacity(comp.gpa, comp.misc_failures.count() + 1);
3375 comp.misc_failures.putAssumeCapacityNoClobber(misc_task_tag, .{
3376 .msg = try std.fmt.allocPrint(comp.gpa, "sub-compilation of {s} failed", .{
3377 @tagName(misc_task_tag),
3378 }),
3379 .children = errors,
3380 });
3381 keep_errors = true;
3382 return error.SubCompilationFailed;
3383 }
31773384
31783385 assert(out.* == null);
31793386 out.* = Compilation.CRTFile{
src/main.zig+4-1
......@@ -2623,7 +2623,10 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v
26232623 };
26242624 defer comp.destroy();
26252625
2626 try updateModule(gpa, comp, .none);
2626 updateModule(gpa, comp, .none) catch |err| switch (err) {
2627 error.SemanticAnalyzeFail => process.exit(1),
2628 else => |e| return e,
2629 };
26272630 try comp.makeBinFileExecutable();
26282631
26292632 child_argv.items[argv_index_exe] = try comp.bin_file.options.emit.?.directory.join(