Commit d65e248ed1

Andrew Kelley <andrew@ziglang.org>
2022-07-04 23:06:00
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.
1 parent 9c50567
Changed files (3)
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;
                 }
             }
         }
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,
             },
         });
     }
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");