@@ -68,7 +68,13 @@ pub const TestResults = struct {
6868 }
6969};
7070
71- pub const MakeFn = * const fn (step : * Step , prog_node : std.Progress.Node ) anyerror ! void ;
71+ pub const MakeOptions = struct {
72+ progress_node : std.Progress.Node ,
73+ thread_pool : * std.Thread.Pool ,
74+ watch : bool ,
75+ };
76+
77+ pub const MakeFn = * const fn (step : * Step , options : MakeOptions ) anyerror ! void ;
7278
7379pub const State = enum {
7480 precheck_unstarted ,
@@ -219,10 +225,10 @@ pub fn init(options: StepOptions) Step {
219225/// If the Step's `make` function reports `error.MakeFailed`, it indicates they
220226/// have already reported the error. Otherwise, we add a simple error report
221227/// here.
222- pub fn make (s : * Step , prog_node : std.Progress.Node ) error { MakeFailed , MakeSkipped }! void {
228+ pub fn make (s : * Step , options : MakeOptions ) error { MakeFailed , MakeSkipped }! void {
223229 const arena = s .owner .allocator ;
224230
225- s .makeFn (s , prog_node ) catch | err | switch (err ) {
231+ s .makeFn (s , options ) catch | err | switch (err ) {
226232 error .MakeFailed = > return error .MakeFailed ,
227233 error .MakeSkipped = > return error .MakeSkipped ,
228234 else = > {
@@ -260,8 +266,8 @@ pub fn getStackTrace(s: *Step) ?std.builtin.StackTrace {
260266 };
261267}
262268
263- fn makeNoOp (step : * Step , prog_node : std.Progress.Node ) anyerror ! void {
264- _ = prog_node ;
269+ fn makeNoOp (step : * Step , options : MakeOptions ) anyerror ! void {
270+ _ = options ;
265271
266272 var all_cached = true ;
267273
@@ -352,13 +358,25 @@ pub fn addError(step: *Step, comptime fmt: []const u8, args: anytype) error{OutO
352358 try step .result_error_msgs .append (arena , msg );
353359}
354360
361+ pub const ZigProcess = struct {
362+ child : std.process.Child ,
363+ poller : std .io .Poller (StreamEnum ),
364+
365+ pub const StreamEnum = enum { stdout , stderr };
366+ };
367+
355368/// Assumes that argv contains `--listen=-` and that the process being spawned
356369/// is the zig compiler - the same version that compiled the build runner.
357370pub fn evalZigProcess (
358371 s : * Step ,
359372 argv : []const []const u8 ,
360373 prog_node : std.Progress.Node ,
374+ watch : bool ,
361375) ! ? []const u8 {
376+ if (s .getZigProcess ()) | zp | {
377+ assert (watch );
378+ return zigProcessUpdate (s , zp , watch );
379+ }
362380 assert (argv .len != 0 );
363381 const b = s .owner ;
364382 const arena = b .allocator ;
@@ -378,29 +396,76 @@ pub fn evalZigProcess(
378396 child .spawn () catch | err | return s .fail ("unable to spawn {s}: {s}" , .{
379397 argv [0 ], @errorName (err ),
380398 });
381- var timer = try std .time .Timer .start ();
382399
383- var poller = std .io .poll (gpa , enum { stdout , stderr }, .{
384- .stdout = child .stdout .? ,
385- .stderr = child .stderr .? ,
386- });
387- defer poller .deinit ();
400+ const zp = try arena .create (ZigProcess );
401+ zp .* = .{
402+ .child = child ,
403+ .poller = std .io .poll (gpa , ZigProcess .StreamEnum , .{
404+ .stdout = child .stdout .? ,
405+ .stderr = child .stderr .? ,
406+ }),
407+ };
408+ if (watch ) s .setZigProcess (zp );
409+ defer if (! watch ) zp .poller .deinit ();
410+
411+ const result = try zigProcessUpdate (s , zp , watch );
412+
413+ if (! watch ) {
414+ // Send EOF to stdin.
415+ zp .child .stdin .? .close ();
416+ zp .child .stdin = null ;
417+
418+ const term = zp .child .wait () catch | err | {
419+ return s .fail ("unable to wait for {s}: {s}" , .{ argv [0 ], @errorName (err ) });
420+ };
421+ s .result_peak_rss = zp .child .resource_usage_statistics .getMaxRss () orelse 0 ;
422+
423+ // Special handling for Compile step that is expecting compile errors.
424+ if (s .cast (Compile )) | compile | switch (term ) {
425+ .Exited = > {
426+ // Note that the exit code may be 0 in this case due to the
427+ // compiler server protocol.
428+ if (compile .expect_errors != null ) {
429+ return error .NeedCompileErrorCheck ;
430+ }
431+ },
432+ else = > {},
433+ };
434+
435+ try handleChildProcessTerm (s , term , null , argv );
436+ }
437+
438+ if (s .result_error_bundle .errorMessageCount () > 0 ) {
439+ return s .fail ("the following command failed with {d} compilation errors:\n {s}" , .{
440+ s .result_error_bundle .errorMessageCount (),
441+ try allocPrintCmd (arena , null , argv ),
442+ });
443+ }
444+
445+ return result ;
446+ }
388447
389- try sendMessage (child .stdin .? , .update );
390- try sendMessage (child .stdin .? , .exit );
448+ fn zigProcessUpdate (s : * Step , zp : * ZigProcess , watch : bool ) ! ? []const u8 {
449+ const b = s .owner ;
450+ const arena = b .allocator ;
451+
452+ var timer = try std .time .Timer .start ();
453+
454+ try sendMessage (zp .child .stdin .? , .update );
455+ if (! watch ) try sendMessage (zp .child .stdin .? , .exit );
391456
392457 const Header = std .zig .Server .Message .Header ;
393458 var result : ? []const u8 = null ;
394459
395- const stdout = poller .fifo (.stdout );
460+ const stdout = zp . poller .fifo (.stdout );
396461
397462 poll : while (true ) {
398463 while (stdout .readableLength () < @sizeOf (Header )) {
399- if (! (try poller .poll ())) break :poll ;
464+ if (! (try zp . poller .poll ())) break :poll ;
400465 }
401466 const header = stdout .reader ().readStruct (Header ) catch unreachable ;
402467 while (stdout .readableLength () < header .bytes_len ) {
403- if (! (try poller .poll ())) break :poll ;
468+ if (! (try zp . poller .poll ())) break :poll ;
404469 }
405470 const body = stdout .readableSliceOfLen (header .bytes_len );
406471
@@ -428,12 +493,22 @@ pub fn evalZigProcess(
428493 .string_bytes = try arena .dupe (u8 , string_bytes ),
429494 .extra = extra_array ,
430495 };
496+ if (watch ) {
497+ // This message indicates the end of the update.
498+ stdout .discard (body .len );
499+ break ;
500+ }
431501 },
432502 .emit_bin_path = > {
433503 const EbpHdr = std .zig .Server .Message .EmitBinPath ;
434504 const ebp_hdr = @as (* align (1 ) const EbpHdr , @ptrCast (body ));
435505 s .result_cached = ebp_hdr .flags .cache_hit ;
436506 result = try arena .dupe (u8 , body [@sizeOf (EbpHdr ).. ]);
507+ if (watch ) {
508+ // This message indicates the end of the update.
509+ stdout .discard (body .len );
510+ break ;
511+ }
437512 },
438513 .file_system_inputs = > {
439514 s .clearWatchInputs ();
@@ -470,6 +545,13 @@ pub fn evalZigProcess(
470545 };
471546 try addWatchInputFromPath (s , path , std .fs .path .basename (sub_path ));
472547 },
548+ .global_cache = > {
549+ const path : Build.Cache.Path = .{
550+ .root_dir = s .owner .graph .global_cache_root ,
551+ .sub_path = sub_path_dirname ,
552+ };
553+ try addWatchInputFromPath (s , path , std .fs .path .basename (sub_path ));
554+ },
473555 }
474556 }
475557 },
@@ -479,43 +561,28 @@ pub fn evalZigProcess(
479561 stdout .discard (body .len );
480562 }
481563
482- const stderr = poller .fifo (.stderr );
564+ s .result_duration_ns = timer .read ();
565+
566+ const stderr = zp .poller .fifo (.stderr );
483567 if (stderr .readableLength () > 0 ) {
484568 try s .result_error_msgs .append (arena , try stderr .toOwnedSlice ());
485569 }
486570
487- // Send EOF to stdin.
488- child .stdin .? .close ();
489- child .stdin = null ;
571+ return result ;
572+ }
490573
491- const term = child .wait () catch | err | {
492- return s .fail ("unable to wait for {s}: {s}" , .{ argv [0 ], @errorName (err ) });
574+ fn getZigProcess (s : * Step ) ? * ZigProcess {
575+ return switch (s .id ) {
576+ .compile = > s .cast (Compile ).? .zig_process ,
577+ else = > null ,
493578 };
494- s .result_duration_ns = timer .read ();
495- s .result_peak_rss = child .resource_usage_statistics .getMaxRss () orelse 0 ;
496-
497- // Special handling for Compile step that is expecting compile errors.
498- if (s .cast (Compile )) | compile | switch (term ) {
499- .Exited = > {
500- // Note that the exit code may be 0 in this case due to the
501- // compiler server protocol.
502- if (compile .expect_errors != null ) {
503- return error .NeedCompileErrorCheck ;
504- }
505- },
506- else = > {},
507- };
508-
509- try handleChildProcessTerm (s , term , null , argv );
579+ }
510580
511- if (s .result_error_bundle .errorMessageCount () > 0 ) {
512- return s .fail ("the following command failed with {d} compilation errors:\n {s}" , .{
513- s .result_error_bundle .errorMessageCount (),
514- try allocPrintCmd (arena , null , argv ),
515- });
581+ fn setZigProcess (s : * Step , zp : * ZigProcess ) void {
582+ switch (s .id ) {
583+ .compile = > s .cast (Compile ).? .zig_process = zp ,
584+ else = > unreachable ,
516585 }
517-
518- return result ;
519586}
520587
521588fn sendMessage (file : std.fs.File , tag : std.zig.Client.Message.Tag ) ! void {
0 commit comments