From d65e248ed130da21e554807c8ce6add9773e0670 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 4 Jul 2022 14:06:00 -0700 Subject: [PATCH] stage2: ELF: improve error reporting when libc is missing Future improvement: make plain error notes actually render as notes rather than errors, but keep them as errors for the case of sub-compilation errors, e.g. when compiler-rt has compilation errors. --- src/Compilation.zig | 34 ++++++++++++++++++++++++++++++---- src/link.zig | 1 + src/link/Elf.zig | 4 +++- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/Compilation.zig b/src/Compilation.zig index 99b502dbd7..feb9fedceb 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -2321,7 +2321,12 @@ pub fn update(comp: *Compilation) !void { } fn flush(comp: *Compilation, prog_node: *std.Progress.Node) !void { - try comp.bin_file.flush(comp, prog_node); // This is needed before reading the error flags. + // This is needed before reading the error flags. + comp.bin_file.flush(comp, prog_node) catch |err| switch (err) { + error.FlushFailure => {}, // error reported through link_error_flags + error.LLDReportedFailure => {}, // error reported through log.err + else => |e| return e, + }; comp.link_error_flags = comp.bin_file.errorFlags(); const use_stage1 = build_options.omit_stage2 or @@ -2593,10 +2598,11 @@ pub fn totalErrorCount(self: *Compilation) usize { } } - // The "no entry point found" error only counts if there are no other errors. + // The "no entry point found" error only counts if there are no semantic analysis errors. if (total == 0) { total += @boolToInt(self.link_error_flags.no_entry_point_found); } + total += @boolToInt(self.link_error_flags.missing_libc); // Compile log errors only count if there are no other errors. if (total == 0) { @@ -2693,10 +2699,30 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors { } } - if (errors.items.len == 0 and self.link_error_flags.no_entry_point_found) { + if (errors.items.len == 0) { + if (self.link_error_flags.no_entry_point_found) { + try errors.append(.{ + .plain = .{ + .msg = try std.fmt.allocPrint(arena_allocator, "no entry point found", .{}), + }, + }); + } + } + + if (self.link_error_flags.missing_libc) { + const notes = try arena_allocator.create([2]AllErrors.Message); + notes.* = .{ + .{ .plain = .{ + .msg = try arena_allocator.dupe(u8, "run 'zig libc -h' to learn about libc installations"), + } }, + .{ .plain = .{ + .msg = try arena_allocator.dupe(u8, "run 'zig targets' to see the targets for which zig can always provide libc"), + } }, + }; try errors.append(.{ .plain = .{ - .msg = try std.fmt.allocPrint(arena_allocator, "no entry point found", .{}), + .msg = try std.fmt.allocPrint(arena_allocator, "libc not available", .{}), + .notes = notes, }, }); } diff --git a/src/link.zig b/src/link.zig index 6c5e876022..97eb9f8876 100644 --- a/src/link.zig +++ b/src/link.zig @@ -951,6 +951,7 @@ pub const File = struct { pub const ErrorFlags = struct { no_entry_point_found: bool = false, + missing_libc: bool = false, }; pub const C = @import("link/C.zig"); diff --git a/src/link/Elf.zig b/src/link/Elf.zig index faeb7c9d27..f7d582bae7 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1719,6 +1719,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v } // libc dep + self.error_flags.missing_libc = false; if (self.base.options.link_libc) { if (self.base.options.libc_installation != null) { const needs_grouping = self.base.options.link_mode == .Static; @@ -1739,7 +1740,8 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v .Dynamic => "libc.so", })); } else { - unreachable; // Compiler was supposed to emit an error for not being able to provide libc. + self.error_flags.missing_libc = true; + return error.FlushFailure; } } }