11const root = @import ("@build" );
22const std = @import ("std" );
33const builtin = @import ("builtin" );
4+ const assert = std .debug .assert ;
45const io = std .io ;
56const fmt = std .fmt ;
67const mem = std .mem ;
@@ -71,8 +72,7 @@ pub fn main() !void {
7172 cache .addPrefix (build_root_directory );
7273 cache .addPrefix (local_cache_directory );
7374 cache .addPrefix (global_cache_directory );
74-
75- //cache.hash.addBytes(builtin.zig_version);
75+ cache .hash .addBytes (builtin .zig_version_string );
7676
7777 const builder = try std .Build .create (
7878 allocator ,
@@ -95,10 +95,8 @@ pub fn main() !void {
9595 var install_prefix : ? []const u8 = null ;
9696 var dir_list = std.Build.DirList {};
9797
98- // before arg parsing, check for the NO_COLOR environment variable
99- // if it exists, default the color setting to .off
100- // explicit --color arguments will still override this setting.
101- builder .color = if (process .hasEnvVarConstant ("NO_COLOR" )) .off else .auto ;
98+ const Color = enum { auto , off , on };
99+ var color : Color = .auto ;
102100
103101 while (nextArg (args , & arg_idx )) | arg | {
104102 if (mem .startsWith (u8 , arg , "-D" )) {
@@ -166,7 +164,7 @@ pub fn main() !void {
166164 std .debug .print ("expected [auto|on|off] after --color" , .{});
167165 usageAndErr (builder , false , stderr_stream );
168166 };
169- builder . color = std .meta .stringToEnum (@TypeOf ( builder . color ) , next_arg ) orelse {
167+ color = std .meta .stringToEnum (Color , next_arg ) orelse {
170168 std .debug .print ("expected [auto|on|off] after --color, found '{s}'" , .{next_arg });
171169 usageAndErr (builder , false , stderr_stream );
172170 };
@@ -200,8 +198,6 @@ pub fn main() !void {
200198 builder .verbose_cc = true ;
201199 } else if (mem .eql (u8 , arg , "--verbose-llvm-cpu-features" )) {
202200 builder .verbose_llvm_cpu_features = true ;
203- } else if (mem .eql (u8 , arg , "--prominent-compile-errors" )) {
204- builder .prominent_compile_errors = true ;
205201 } else if (mem .eql (u8 , arg , "-fwine" )) {
206202 builder .enable_wine = true ;
207203 } else if (mem .eql (u8 , arg , "-fno-wine" )) {
@@ -257,6 +253,12 @@ pub fn main() !void {
257253 }
258254 }
259255
256+ const ttyconf : std.debug.TTY.Config = switch (color ) {
257+ .auto = > std .debug .detectTTYConfig (std .io .getStdErr ()),
258+ .on = > .escape_codes ,
259+ .off = > .no_color ,
260+ };
261+
260262 var progress : std.Progress = .{};
261263 const main_progress_node = progress .start ("" , 0 );
262264 defer main_progress_node .end ();
@@ -272,11 +274,15 @@ pub fn main() !void {
272274 if (builder .validateUserInputDidItFail ())
273275 usageAndErr (builder , true , stderr_stream );
274276
275- runStepNames (builder , targets .items , main_progress_node , thread_pool_options ) catch | err | {
276- switch (err ) {
277- error .UncleanExit = > process .exit (1 ),
278- else = > return err ,
279- }
277+ runStepNames (
278+ builder ,
279+ targets .items ,
280+ main_progress_node ,
281+ thread_pool_options ,
282+ ttyconf ,
283+ ) catch | err | switch (err ) {
284+ error .UncleanExit = > process .exit (1 ),
285+ else = > return err ,
280286 };
281287}
282288
@@ -285,6 +291,7 @@ fn runStepNames(
285291 step_names : []const []const u8 ,
286292 parent_prog_node : * std.Progress.Node ,
287293 thread_pool_options : std.Thread.Pool.Options ,
294+ ttyconf : std.debug.TTY.Config ,
288295) ! void {
289296 var step_stack = ArrayList (* Step ).init (b .allocator );
290297 defer step_stack .deinit ();
@@ -332,12 +339,14 @@ fn runStepNames(
332339
333340 wait_group .start ();
334341 thread_pool .spawn (workerMakeOneStep , .{
335- & wait_group , & thread_pool , b , step , & step_prog ,
342+ & wait_group , & thread_pool , b , step , & step_prog , ttyconf ,
336343 }) catch @panic ("OOM" );
337344 }
338345 }
339346
340- var any_failed = false ;
347+ var success_count : usize = 0 ;
348+ var failure_count : usize = 0 ;
349+ var pending_count : usize = 0 ;
341350
342351 for (step_stack .items ) | s | {
343352 switch (s .state ) {
@@ -349,20 +358,42 @@ fn runStepNames(
349358 // A -> B -> C (failure)
350359 // B will be marked as dependency_failure, while A may never be queued, and thus
351360 // remain in the initial state of precheck_done.
352- .dependency_failure , .precheck_done = > continue ,
353- .success = > continue ,
354- .failure = > {
355- any_failed = true ;
356- std .debug .print ("{s}: {s}\n " , .{
357- s .name , @errorName (s .result .err_code ),
358- });
359- },
361+ .dependency_failure , .precheck_done = > pending_count += 1 ,
362+ .success = > success_count += 1 ,
363+ .failure = > failure_count += 1 ,
360364 }
361365 }
362366
363- if (any_failed ) {
364- process .exit (1 );
365- }
367+ const stderr = std .io .getStdErr ();
368+
369+ const total_count = success_count + failure_count + pending_count ;
370+ stderr .writer ().print ("build summary: {d}/{d} steps succeeded; {d} failed\n " , .{
371+ success_count , total_count , failure_count ,
372+ }) catch {};
373+ if (failure_count == 0 ) return cleanExit ();
374+
375+ for (step_stack .items ) | s | switch (s .state ) {
376+ .failure = > {
377+ // TODO print the dep prefix too
378+ ttyconf .setColor (stderr , .Bold ) catch break ;
379+ stderr .writeAll (s .name ) catch break ;
380+ ttyconf .setColor (stderr , .Reset ) catch break ;
381+
382+ if (s .result_error_bundle .errorMessageCount () > 0 ) {
383+ stderr .writer ().print (": {d} compilation errors:\n " , .{
384+ s .result_error_bundle .errorMessageCount (),
385+ }) catch break ;
386+ s .result_error_bundle .renderToStdErr (ttyconf );
387+ } else {
388+ stderr .writer ().print (": {d} error messages (printed above)\n " , .{
389+ s .result_error_msgs .items .len ,
390+ }) catch break ;
391+ }
392+ },
393+ else = > continue ,
394+ };
395+
396+ process .exit (1 );
366397}
367398
368399fn checkForDependencyLoop (
@@ -407,6 +438,7 @@ fn workerMakeOneStep(
407438 b : * std.Build ,
408439 s : * Step ,
409440 prog_node : * std.Progress.Node ,
441+ ttyconf : std.debug.TTY.Config ,
410442) void {
411443 defer wg .finish ();
412444
@@ -446,17 +478,26 @@ fn workerMakeOneStep(
446478 const make_result = s .make ();
447479
448480 // No matter the result, we want to display error/warning messages.
449- if (s .result . error_msgs .items .len > 0 ) {
481+ if (s .result_error_msgs .items .len > 0 ) {
450482 sub_prog_node .context .lock_stderr ();
451483 defer sub_prog_node .context .unlock_stderr ();
452484
453- for (s .result .error_msgs .items ) | msg | {
454- std .io .getStdErr ().writeAll (msg ) catch break ;
485+ const stderr = std .io .getStdErr ();
486+
487+ for (s .result_error_msgs .items ) | msg | {
488+ // TODO print the dep prefix too
489+ ttyconf .setColor (stderr , .Bold ) catch break ;
490+ stderr .writeAll (s .name ) catch break ;
491+ stderr .writeAll (": " ) catch break ;
492+ ttyconf .setColor (stderr , .Red ) catch break ;
493+ stderr .writeAll ("error: " ) catch break ;
494+ ttyconf .setColor (stderr , .Reset ) catch break ;
495+ stderr .writeAll (msg ) catch break ;
455496 }
456497 }
457498
458499 make_result catch | err | {
459- s . result . err_code = err ;
500+ assert ( err == error . MakeFailed ) ;
460501 @atomicStore (Step .State , & s .state , .failure , .SeqCst );
461502 return ;
462503 };
@@ -467,7 +508,7 @@ fn workerMakeOneStep(
467508 for (s .dependants .items ) | dep | {
468509 wg .start ();
469510 thread_pool .spawn (workerMakeOneStep , .{
470- wg , thread_pool , b , dep , prog_node ,
511+ wg , thread_pool , b , dep , prog_node , ttyconf ,
471512 }) catch @panic ("OOM" );
472513 }
473514}
@@ -601,3 +642,11 @@ fn argsRest(args: [][]const u8, idx: usize) ?[][]const u8 {
601642 if (idx >= args .len ) return null ;
602643 return args [idx .. ];
603644}
645+
646+ fn cleanExit () void {
647+ if (builtin .mode == .Debug ) {
648+ return ;
649+ } else {
650+ process .exit (0 );
651+ }
652+ }
0 commit comments