Commit 45ec851733

Andrew Kelley <andrew@ziglang.org>
2024-01-10 20:26:54
zig build: handle stderr more elegantly
* Specifically recognize stderr as a different concept than an error message in Step results. * Display it differently when only stderr occurs but the build proceeds successfully. closes #18473
1 parent df6aed0
Changed files (3)
lib/std/Build/Step/Run.zig
@@ -1214,7 +1214,7 @@ fn evalZigTest(
 
     if (stderr.readableLength() > 0) {
         const msg = std.mem.trim(u8, try stderr.toOwnedSlice(), "\n");
-        if (msg.len > 0) try self.step.result_error_msgs.append(arena, msg);
+        if (msg.len > 0) self.step.result_stderr = msg;
     }
 
     // Send EOF to stdin.
@@ -1344,7 +1344,7 @@ fn evalGeneric(self: *Run, child: *std.process.Child) !StdIoResult {
             else => true,
         };
         if (stderr_is_diagnostic) {
-            try self.step.result_error_msgs.append(arena, bytes);
+            self.step.result_stderr = bytes;
         }
     };
 
lib/std/Build/Step.zig
@@ -31,6 +31,7 @@ max_rss: usize,
 
 result_error_msgs: std.ArrayListUnmanaged([]const u8),
 result_error_bundle: std.zig.ErrorBundle,
+result_stderr: []const u8,
 result_cached: bool,
 result_duration_ns: ?u64,
 /// 0 means unavailable or not reported.
@@ -164,6 +165,7 @@ pub fn init(options: StepOptions) Step {
         },
         .result_error_msgs = .{},
         .result_error_bundle = std.zig.ErrorBundle.empty,
+        .result_stderr = "",
         .result_cached = false,
         .result_duration_ns = null,
         .result_peak_rss = 0,
lib/build_runner.zig
@@ -728,10 +728,15 @@ fn printStepFailure(
             try ttyconf.setColor(stderr, .reset);
         }
         try stderr.writeAll("\n");
-    } else {
+    } else if (s.result_error_msgs.items.len > 0) {
         try ttyconf.setColor(stderr, .red);
         try stderr.writeAll(" failure\n");
         try ttyconf.setColor(stderr, .reset);
+    } else {
+        assert(s.result_stderr.len > 0);
+        try ttyconf.setColor(stderr, .red);
+        try stderr.writeAll(" stderr\n");
+        try ttyconf.setColor(stderr, .reset);
     }
 }
 
@@ -918,8 +923,9 @@ fn workerMakeOneStep(
     const show_compile_errors = !run.prominent_compile_errors and
         s.result_error_bundle.errorMessageCount() > 0;
     const show_error_msgs = s.result_error_msgs.items.len > 0;
+    const show_stderr = s.result_stderr.len > 0;
 
-    if (show_error_msgs or show_compile_errors) {
+    if (show_error_msgs or show_compile_errors or show_stderr) {
         sub_prog_node.context.lock_stderr();
         defer sub_prog_node.context.unlock_stderr();
 
@@ -1012,11 +1018,16 @@ fn printErrorMessages(b: *std.Build, failing_step: *Step, run: *const Run) !void
     }
     try ttyconf.setColor(stderr, .reset);
 
-    // Penultimately, the compilation errors.
+    if (failing_step.result_stderr.len > 0) {
+        try stderr.writeAll(failing_step.result_stderr);
+        if (!mem.endsWith(u8, failing_step.result_stderr, "\n")) {
+            try stderr.writeAll("\n");
+        }
+    }
+
     if (!run.prominent_compile_errors and failing_step.result_error_bundle.errorMessageCount() > 0)
         try failing_step.result_error_bundle.renderToWriter(renderOptions(ttyconf), stderr.writer());
 
-    // Finally, generic error messages.
     for (failing_step.result_error_msgs.items) |msg| {
         try ttyconf.setColor(stderr, .red);
         try stderr.writeAll("error: ");