authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-05-27 00:48:11+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-05-27 00:48:11+02:00
log4d56c6636251a90926467dfe65c99adf5ff7222a
tree5b5265368a236ab18def983268268f3792272d87
parent7451f5d1174c1113da50c883c7b3f7e8415cea0a
parent33680ced58de7efb5bfe18fc95d2b67fc8496aed

Merge pull request 'Maker: memory usage optimizations' (#35471) from build-runner-process into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/35471

10 files changed, 167 insertions(+), 116 deletions(-)

ci/x86_64-linux-debug-llvm.sh-1
......@@ -49,7 +49,6 @@ stage3-debug/bin/zig build \
4949 -Dno-lib
5050
5151stage3-debug/bin/zig build test docs \
52 --maker-opt=Debug \
5352 --maxrss ${ZSF_MAX_RSS:-0} \
5453 -Dlldb=$HOME/deps/lldb-zig/Debug-33ec8d3c11/bin/lldb \
5554 -Dlibc-test-path=$HOME/deps/libc-test-f2bac77 \
ci/x86_64-linux-debug.sh+1
......@@ -48,6 +48,7 @@ stage3-debug/bin/zig build \
4848 -Dno-lib
4949
5050stage3-debug/bin/zig build test docs \
51 --maker-opt=Debug \
5152 --maxrss ${ZSF_MAX_RSS:-0} \
5253 -Dlldb=$HOME/deps/lldb-zig/Debug-33ec8d3c11/bin/lldb \
5354 -fqemu \
lib/compiler/Maker.zig+54-44
......@@ -16,6 +16,7 @@ const fmt = std.fmt;
1616const log = std.log;
1717const mem = std.mem;
1818const process = std.process;
19const Color = std.zig.Color;
1920
2021const Fuzz = @import("Maker/Fuzz.zig");
2122const Graph = @import("Maker/Graph.zig");
......@@ -55,12 +56,59 @@ error_style: ErrorStyle,
5556multiline_errors: MultilineErrors,
5657summary: Summary,
5758
59var safe_allocator_instance: std.heap.SafeAllocator = .init(std.heap.page_allocator, .{});
60var stdio_buffer_allocation: [256]u8 = undefined;
61var stdout_writer_allocation: Io.File.Writer = undefined;
62var debug_maker_leaks: bool = false;
63
64const is_debug_mode = builtin.mode == .Debug;
65const use_safe_allocator = switch (builtin.mode) {
66 .Debug, .ReleaseSafe => true,
67 .ReleaseFast, .ReleaseSmall => false,
68};
69
70const InstallPaths = struct {
71 prefix: Path,
72 lib: Path,
73 bin: Path,
74 include: Path,
75};
76
77const PrintNode = struct {
78 parent: ?*PrintNode,
79 last: bool = false,
80};
81
82const ErrorStyle = enum {
83 verbose,
84 minimal,
85 verbose_clear,
86 minimal_clear,
87 fn verboseContext(s: ErrorStyle) bool {
88 return switch (s) {
89 .verbose, .verbose_clear => true,
90 .minimal, .minimal_clear => false,
91 };
92 }
93 fn clearOnUpdate(s: ErrorStyle) bool {
94 return switch (s) {
95 .verbose, .minimal => false,
96 .verbose_clear, .minimal_clear => true,
97 };
98 }
99};
100const MultilineErrors = enum { indent, newline, none };
101const Summary = enum { all, new, failures, line, none };
102
58103pub fn main(init: process.Init.Minimal) !void {
59 // The build runner is often short-lived, but thanks to `--watch` and `--webui`, that's not
60 // always the case. So, we do need a true gpa for some things.
61 var safe_gpa_state: std.heap.SafeAllocator = .init(std.heap.page_allocator, .{});
62 defer _ = safe_gpa_state.deinit();
63 const gpa = safe_gpa_state.allocator();
104 // The build runner is long-lived in the following use cases:
105 // * `--watch` mode
106 // * `--webui` mode
107 // * A project that has a large, complex build graph.
108 const gpa = if (use_safe_allocator) safe_allocator_instance.allocator() else std.heap.smp_allocator;
109 defer if (use_safe_allocator) {
110 _ = safe_allocator_instance.deinit();
111 };
64112
65113 var threaded: std.Io.Threaded = .init(gpa, .{
66114 .environ = init.environ,
......@@ -689,13 +737,6 @@ fn countSubProcesses(maker: *Maker) usize {
689737 return count;
690738}
691739
692const InstallPaths = struct {
693 prefix: Path,
694 lib: Path,
695 bin: Path,
696 include: Path,
697};
698
699740pub fn stepByIndex(maker: *const Maker, i: Configuration.Step.Index) *Step {
700741 return &maker.steps[@intFromEnum(i)];
701742}
......@@ -1018,6 +1059,7 @@ fn makeStepNames(
10181059fn deinit(maker: *Maker) void {
10191060 const gpa = maker.gpa;
10201061 for (maker.steps) |*step| {
1062 step.clearResultStderr(gpa);
10211063 step.clearFailedCommand(gpa);
10221064 step.clearErrorBundle(gpa);
10231065 step.inputs.deinit(gpa);
......@@ -1424,11 +1466,6 @@ fn printStepFailure(
14241466 }
14251467}
14261468
1427const PrintNode = struct {
1428 parent: ?*PrintNode,
1429 last: bool = false,
1430};
1431
14321469fn printPrefix(node: *PrintNode, stderr: Io.Terminal) !void {
14331470 const parent = node.parent orelse return;
14341471 const writer = stderr.writer;
......@@ -1657,28 +1694,6 @@ fn argsRest(args: []const [:0]const u8, idx: usize) ?[]const [:0]const u8 {
16571694 return args[idx..];
16581695}
16591696
1660const Color = std.zig.Color;
1661const ErrorStyle = enum {
1662 verbose,
1663 minimal,
1664 verbose_clear,
1665 minimal_clear,
1666 fn verboseContext(s: ErrorStyle) bool {
1667 return switch (s) {
1668 .verbose, .verbose_clear => true,
1669 .minimal, .minimal_clear => false,
1670 };
1671 }
1672 fn clearOnUpdate(s: ErrorStyle) bool {
1673 return switch (s) {
1674 .verbose, .minimal => false,
1675 .verbose_clear, .minimal_clear => true,
1676 };
1677 }
1678};
1679const MultilineErrors = enum { indent, newline, none };
1680const Summary = enum { all, new, failures, line, none };
1681
16821697fn fatalWithHint(comptime f: []const u8, args: anytype) noreturn {
16831698 log.info("to access the help menu: zig build -h", .{});
16841699 fatal(f, args);
......@@ -1701,9 +1716,6 @@ fn cleanTmpFiles(maker: *Maker, steps: []const Configuration.Step.Index) void {
17011716 }
17021717}
17031718
1704var stdio_buffer_allocation: [256]u8 = undefined;
1705var stdout_writer_allocation: Io.File.Writer = undefined;
1706
17071719fn initStdoutWriter(io: Io) *Writer {
17081720 stdout_writer_allocation = Io.File.stdout().writerStreaming(io, &stdio_buffer_allocation);
17091721 return &stdout_writer_allocation.interface;
......@@ -2043,8 +2055,6 @@ fn removePoisonedConfiguration(io: Io, scanned_config: *const ScannedConfig) voi
20432055 }
20442056}
20452057
2046const is_debug_mode = builtin.mode == .Debug;
2047var debug_maker_leaks: bool = false;
20482058inline fn debugMakerLeaks() bool {
20492059 if (!is_debug_mode) return false;
20502060 return debug_maker_leaks;
lib/compiler/Maker/PkgConfig.zig+14-7
......@@ -2,6 +2,7 @@ const std = @import("std");
22const Io = std.Io;
33const mem = std.mem;
44const assert = std.debug.assert;
5const Allocator = std.mem.Allocator;
56
67const Maker = @import("../Maker.zig");
78const Step = @import("Step.zig");
......@@ -23,6 +24,7 @@ pub const Result = std.zig.PkgConfig.Parsed;
2324pub fn run(
2425 maker: *Maker,
2526 step: *Step,
27 arena: Allocator,
2628 progress_node: std.Progress.Node,
2729 lib_name: []const u8,
2830 /// If true, reports failure error messages on step rather than returning
......@@ -31,7 +33,6 @@ pub fn run(
3133) RunError!Result {
3234 const pc = &maker.pkg_config;
3335 const graph = maker.graph;
34 const arena = graph.arena; // TODO don't leak into process arena
3536
3637 const pkg_config_exe = getExe(graph);
3738 const pkgs = try getPkgs(maker, step, progress_node, force);
......@@ -41,7 +42,7 @@ pub fn run(
4142 };
4243 const pkg = pkgs.all[found_index];
4344
44 const stdout = try captureChildProcess(maker, step, .{
45 const stdout = try captureChildProcess(maker, step, arena, .{
4546 .argv = &.{ pkg_config_exe, pkg.name, "--cflags", "--libs" },
4647 .progress_node = progress_node,
4748 .allow_failure = !force,
......@@ -69,11 +70,16 @@ fn getExe(graph: *const Graph) []const u8 {
6970 return std.zig.PkgConfig.exe(&graph.environ_map);
7071}
7172
72fn getPkgs(maker: *Maker, step: *Step, progress_node: std.Progress.Node, force: bool) RunError!std.zig.PkgConfig {
73fn getPkgs(
74 maker: *Maker,
75 step: *Step,
76 progress_node: std.Progress.Node,
77 force: bool,
78) RunError!std.zig.PkgConfig {
7379 const graph = maker.graph;
74 const arena = graph.arena; // TODO don't leak into process arena
7580 const io = graph.io;
7681 const pc = &maker.pkg_config;
82 const arena = graph.arena;
7783
7884 try pc.mutex.lock(io);
7985 defer pc.mutex.unlock(io);
......@@ -81,7 +87,7 @@ fn getPkgs(maker: *Maker, step: *Step, progress_node: std.Progress.Node, force:
8187 if (pc.pkgs) |pkgs| return pkgs;
8288
8389 const pkg_config_exe = getExe(graph);
84 const stdout = try captureChildProcess(maker, step, .{
90 const stdout = try captureChildProcess(maker, step, arena, .{
8591 .argv = &.{ pkg_config_exe, "--list-all" },
8692 .progress_node = progress_node,
8793 .allow_failure = !force,
......@@ -102,11 +108,12 @@ fn getPkgs(maker: *Maker, step: *Step, progress_node: std.Progress.Node, force:
102108 return result;
103109}
104110
105fn captureChildProcess(maker: *Maker, step: *Step, options: Step.CaptureChildProcessOptions) ![]const u8 {
106 const captured = step.captureChildProcess(maker, options) catch |err| switch (err) {
111fn captureChildProcess(maker: *Maker, step: *Step, arena: Allocator, options: Step.CaptureChildProcessOptions) ![]const u8 {
112 const captured = step.captureChildProcess(maker, arena, options) catch |err| switch (err) {
107113 error.FileNotFound => return error.PkgConfigUnavailable,
108114 else => |e| return e,
109115 };
116 if (captured.stderr.len != 0) try step.setResultStderr(maker.gpa, captured.stderr);
110117 assert(step.result_failed_command != null);
111118 if (captured.term.success()) return captured.stdout;
112119 if (!options.allow_failure) return step.fail(maker, "{s} {f}", .{ options.argv[0], captured.term });
lib/compiler/Maker/Step.zig+47-16
......@@ -54,8 +54,10 @@ dependants: std.ArrayList(Configuration.Step.Index) = .empty,
5454inputs: Inputs = .init,
5555pending_deps: u32 = undefined,
5656
57/// Array list and internal memory owned by process arena.
5758result_error_msgs: std.ArrayList([]const u8) = .empty,
5859result_error_bundle: std.zig.ErrorBundle = .empty,
60/// Owned by `Maker.gpa`.
5961result_stderr: []const u8 = "",
6062result_cached: bool = false,
6163/// Indicates error information is missing due to allocation failure.
......@@ -310,9 +312,8 @@ pub fn reset(step: *Step, maker: *Maker) void {
310312 const gpa = maker.gpa;
311313
312314 clearFailedCommand(step, gpa);
313
315 clearResultStderr(step, gpa);
314316 step.result_error_msgs.clearRetainingCapacity();
315 step.result_stderr = "";
316317 step.result_cached = false;
317318 step.result_duration_ns = null;
318319 step.result_peak_rss = 0;
......@@ -332,20 +333,23 @@ pub const CaptureChildProcessOptions = struct {
332333 allow_failure: bool = false,
333334};
334335
335/// Populates `s.result_failed_command`.
336pub fn captureChildProcess(s: *Step, maker: *Maker, options: CaptureChildProcessOptions) !std.process.RunResult {
336/// Populates `s.result_failed_command` unconditionally.
337pub fn captureChildProcess(
338 s: *Step,
339 maker: *Maker,
340 allocator: Allocator,
341 options: CaptureChildProcessOptions,
342) !std.process.RunResult {
337343 const gpa = maker.gpa;
338344 const graph = maker.graph;
339 const arena = graph.arena; // TODO stop leaking into process arena
340345 const io = graph.io;
341346
342 clearFailedCommand(s, gpa);
343 s.result_failed_command = try std.zig.allocPrintCmd(gpa, options.argv, .{});
347 s.setFailedCommand(gpa, options.argv, .{});
344348
345349 try handleChildProcUnsupported(s, maker);
346350 try graph.handleVerbose(null, null, options.argv);
347351
348 const result = std.process.run(arena, io, .{
352 const result = std.process.run(allocator, io, .{
349353 .argv = options.argv,
350354 .environ_map = options.environ_map orelse &graph.environ_map,
351355 .progress_node = options.progress_node,
......@@ -358,7 +362,7 @@ pub fn captureChildProcess(s: *Step, maker: *Maker, options: CaptureChildProcess
358362 return s.fail(maker, "failed to run {s}: {t}", .{ options.argv[0], err });
359363 };
360364
361 if (result.stderr.len > 0) try s.result_error_msgs.append(arena, result.stderr);
365 if (result.stderr.len > 0) try s.result_error_msgs.append(graph.arena, result.stderr);
362366
363367 return result;
364368}
......@@ -375,6 +379,21 @@ pub fn clearFailedCommand(s: *Step, gpa: Allocator) void {
375379 }
376380}
377381
382pub fn setFailedCommand(
383 s: *Step,
384 gpa: Allocator,
385 argv: []const []const u8,
386 options: std.zig.AllocPrintCmdOptions,
387) void {
388 s.clearFailedCommand(gpa);
389 s.result_failed_command = std.zig.allocPrintCmd(gpa, argv, options) catch |err| switch (err) {
390 error.OutOfMemory => {
391 s.result_oom = true;
392 return;
393 },
394 };
395}
396
378397pub const FailError = error{ OutOfMemory, MakeFailed };
379398
380399pub fn fail(step: *Step, maker: *const Maker, comptime fmt: []const u8, args: anytype) FailError {
......@@ -410,7 +429,8 @@ pub const ZigProcess = struct {
410429
411430/// Assumes that argv contains `--listen=-` and that the process being spawned
412431/// is the zig compiler - the same version that compiled the build runner.
413/// Populates `s.result_failed_command`.
432///
433/// Populates `s.result_failed_command` on failure.
414434pub fn evalZigProcess(
415435 step_index: Configuration.Step.Index,
416436 maker: *Maker,
......@@ -424,8 +444,7 @@ pub fn evalZigProcess(
424444 const io = graph.io;
425445
426446 // If an error occurs, it's happened in this command:
427 clearFailedCommand(s, gpa);
428 s.result_failed_command = try std.zig.allocPrintCmd(gpa, argv, .{});
447 errdefer s.setFailedCommand(gpa, argv, .{});
429448
430449 if (s.getZigProcess()) |zp| update: {
431450 assert(watch);
......@@ -683,16 +702,12 @@ fn sendMessage(io: Io, file: Io.File, tag: std.zig.Client.Message.Tag) !void {
683702 };
684703}
685704
686/// Asserts that the caller has already populated `s.result_failed_command`.
687705pub inline fn handleChildProcUnsupported(s: *Step, maker: *Maker) FailError!void {
688 assert(s.result_failed_command != null);
689706 if (!std.process.can_spawn)
690707 return s.fail(maker, "unable to spawn process: host cannot spawn child processes", .{});
691708}
692709
693/// Asserts that the caller has already populated `s.result_failed_command`.
694710pub fn handleChildProcessTerm(s: *Step, maker: *Maker, term: std.process.Child.Term) FailError!void {
695 assert(s.result_failed_command != null);
696711 if (!term.success()) return s.fail(maker, "process {f}", .{term});
697712}
698713
......@@ -861,3 +876,19 @@ fn oomWrap(s: *Step, result: error{OutOfMemory}!void) void {
861876 s.result_oom = true;
862877 };
863878}
879
880pub fn clearResultStderr(step: *Step, gpa: Allocator) void {
881 if (step.result_stderr.len != 0) {
882 gpa.free(step.result_stderr);
883 step.result_stderr = "";
884 }
885}
886
887pub fn setResultStderr(step: *Step, gpa: Allocator, bytes: []const u8) Allocator.Error!void {
888 takeResultStderr(step, gpa, try gpa.dupe(u8, bytes));
889}
890
891pub fn takeResultStderr(step: *Step, gpa: Allocator, owned: []const u8) void {
892 clearResultStderr(step, gpa);
893 step.result_stderr = owned;
894}
lib/compiler/Maker/Step/Compile.zig+6-6
......@@ -328,10 +328,10 @@ fn lowerZigArgs(
328328 const pkg_conf_node = progress_node.start("pkg-config", 0);
329329 defer pkg_conf_node.end();
330330
331 if (PkgConfig.run(maker, step, pkg_conf_node, system_lib_name, force)) |result| {
332 try zig_args.appendSlice(gpa, result.cflags);
333 try zig_args.appendSlice(gpa, result.libs);
334 try seen_system_libs.put(arena, system_lib.name, result.cflags);
331 if (PkgConfig.run(maker, step, arena, pkg_conf_node, system_lib_name, force)) |pc| {
332 try zig_args.appendSlice(gpa, pc.cflags);
333 try zig_args.appendSlice(gpa, pc.libs);
334 try seen_system_libs.put(arena, system_lib.name, pc.cflags);
335335 break :l;
336336 } else |err| switch (err) {
337337 error.PkgConfigUnavailable,
......@@ -960,8 +960,8 @@ pub fn rebuildInFuzzMode(
960960 const arena = arena_allocator.allocator();
961961
962962 step.result_error_msgs.clearRetainingCapacity();
963 step.result_stderr = "";
964
963 step.clearResultStderr(gpa);
964 step.clearErrorBundle(gpa);
965965 step.result_error_bundle.deinit(gpa);
966966 step.result_error_bundle = std.zig.ErrorBundle.empty;
967967
lib/compiler/Maker/Step/Fmt.zig+1-1
......@@ -43,7 +43,7 @@ pub fn make(
4343 argv.appendAssumeCapacity(try maker.resolveLazyPathIndexAbs(arena, lp, step_index));
4444 }
4545
46 const run_result = step.captureChildProcess(maker, .{
46 const run_result = step.captureChildProcess(maker, arena, .{
4747 .progress_node = progress_node,
4848 .argv = argv.items,
4949 .allow_failure = false,
lib/compiler/Maker/Step/Run.zig+42-39
......@@ -713,7 +713,7 @@ const FuzzTestRunner = struct {
713713 }
714714 }
715715
716 fn listen(f: *FuzzTestRunner, arena: Allocator) !void {
716 fn listen(f: *FuzzTestRunner) !void {
717717 const maker = f.ctx.fuzz.maker;
718718 const graph = maker.graph;
719719 const io = graph.io;
......@@ -737,7 +737,7 @@ const FuzzTestRunner = struct {
737737 else => |read_e| return read_e,
738738 }),
739739 2 => try f.completeStderrRead(id, result.file_read_streaming catch |e| switch (e) {
740 error.EndOfStream => return f.instanceEos(arena, id),
740 error.EndOfStream => return f.instanceEos(id),
741741 else => |read_e| return read_e,
742742 }),
743743 else => unreachable,
......@@ -899,8 +899,9 @@ const FuzzTestRunner = struct {
899899 } });
900900 }
901901
902 fn instanceEos(f: *FuzzTestRunner, arena: Allocator, id: u32) !void {
902 fn instanceEos(f: *FuzzTestRunner, id: u32) !void {
903903 const maker = f.ctx.fuzz.maker;
904 const gpa = maker.gpa;
904905 const instance = &f.instances[id];
905906 const run_index = f.run_index;
906907
......@@ -912,7 +913,7 @@ const FuzzTestRunner = struct {
912913 instance.child.stdin = null;
913914 const term = try instance.child.wait(io);
914915 if (!termMatches(.{ .exited = 0 }, term)) {
915 step.result_stderr = try f.mergedStderr(arena);
916 step.takeResultStderr(gpa, try f.mergedStderr(gpa));
916917 try f.saveCrash(id, term);
917918 return step.fail(maker, "test process unexpectedly {f}", .{fmtTerm(term)});
918919 }
......@@ -1055,7 +1056,7 @@ const FuzzTestRunner = struct {
10551056 }
10561057 }
10571058
1058 fn mergedStderr(f: *FuzzTestRunner, arena: Allocator) Allocator.Error![]const u8 {
1059 fn mergedStderr(f: *FuzzTestRunner, gpa: Allocator) Allocator.Error![]const u8 {
10591060 // Collect any available stderr
10601061 while (f.batch.next()) |completion| {
10611062 if (completion.index % 3 != 2) continue;
......@@ -1065,7 +1066,7 @@ const FuzzTestRunner = struct {
10651066
10661067 var stderr_len: usize = 0;
10671068 for (f.instances) |*instance| stderr_len += instance.stderr.items.len;
1068 const stderr = try arena.alloc(u8, stderr_len);
1069 const stderr = try gpa.alloc(u8, stderr_len);
10691070
10701071 stderr_len = 0;
10711072 for (f.instances) |*instance| {
......@@ -1086,13 +1087,12 @@ fn evalFuzzTest(
10861087 var f: FuzzTestRunner = try .init(run, run_index, fuzz_context, progress_node, spawn_options);
10871088 defer f.deinit();
10881089 try f.startInstances();
1089 try f.listen(fuzz_context.fuzz.maker.graph.arena);
1090 try f.listen();
10901091}
10911092
10921093const StdioPollEnum = enum { stdout, stderr };
10931094
10941095fn evalZigTest(
1095 arena: Allocator,
10961096 run: *Run,
10971097 run_index: Configuration.Step.Index,
10981098 maker: *Maker,
......@@ -1140,7 +1140,7 @@ fn evalZigTest(
11401140 };
11411141
11421142 switch (try waitZigTest(
1143 arena,
1143 graph.arena,
11441144 run,
11451145 run_index,
11461146 maker,
......@@ -1158,7 +1158,7 @@ fn evalZigTest(
11581158 error.ReadFailed => return stderr_fr.err.?,
11591159 error.EndOfStream => {},
11601160 }
1161 step.result_stderr = try arena.dupe(u8, stderr_fr.interface.buffered());
1161 step.takeResultStderr(gpa, try multi_reader.toOwnedSlice(1));
11621162
11631163 // Clean up everything and wait for the child to exit.
11641164 child.stdin.?.close(io);
......@@ -1180,8 +1180,9 @@ fn evalZigTest(
11801180 .no_poll => |no_poll| {
11811181 // This might be a success (we requested exit and the child dutifully closed stdout) or
11821182 // a crash of some kind. Either way, the child will terminate by itself -- wait for it.
1183 const stderr_reader = multi_reader.reader(1);
1184 const stderr_owned = try arena.dupe(u8, stderr_reader.buffered());
1183 const stderr_owned = try multi_reader.toOwnedSlice(1);
1184 var keep_stderr_owned = false;
1185 defer if (!keep_stderr_owned) gpa.free(stderr_owned);
11851186
11861187 // Clean up everything and wait for the child to exit.
11871188 child.stdin.?.close(io);
......@@ -1209,7 +1210,9 @@ fn evalZigTest(
12091210 }
12101211
12111212 // Report an error if the child terminated uncleanly or if we were still trying to run more tests.
1212 step.result_stderr = stderr_owned;
1213 step.takeResultStderr(gpa, stderr_owned);
1214 keep_stderr_owned = true;
1215
12131216 const tests_done = test_metadata != null and test_metadata.?.next_index == std.math.maxInt(u32);
12141217 if (!tests_done or !termMatches(.{ .exited = 0 }, term)) {
12151218 // The individual unit test results are irrelevant: the test runner itself broke!
......@@ -1234,9 +1237,10 @@ fn evalZigTest(
12341237 return;
12351238 },
12361239 .timeout => |timeout| {
1237 const stderr_reader = multi_reader.reader(1);
1238 const stderr = stderr_reader.buffered();
1239 stderr_reader.tossBuffered();
1240 const stderr_owned = try multi_reader.toOwnedSlice(1);
1241 var keep_stderr_owned = false;
1242 defer if (!keep_stderr_owned) gpa.free(stderr_owned);
1243
12401244 if (timeout.active_test_index) |test_index| {
12411245 // A test was running. Report the timeout against that test, and continue on to
12421246 // the next test.
......@@ -1245,16 +1249,20 @@ fn evalZigTest(
12451249 try step.addError(maker, "'{s}' timed out after {f}{s}{s}", .{
12461250 test_metadata.?.testName(test_index),
12471251 Io.Duration{ .nanoseconds = timeout.ns_elapsed },
1248 if (stderr.len != 0) " with stderr:\n" else "",
1249 std.mem.trim(u8, stderr, "\n"),
1252 if (stderr_owned.len != 0) " with stderr:\n" else "",
1253 std.mem.trim(u8, stderr_owned, "\n"),
12501254 });
12511255 continue;
12521256 }
12531257 // Just log an error and let the child be killed.
1254 step.result_stderr = try arena.dupe(u8, stderr);
1258 step.takeResultStderr(gpa, stderr_owned);
1259 keep_stderr_owned = true;
1260
12551261 // The individual unit test results in `results` are irrelevant: the test runner
12561262 // is broken! Fail immediately without populating `s.test_results`.
1257 return step.fail(maker, "test runner failed to respond for {f}", .{Io.Duration{ .nanoseconds = timeout.ns_elapsed }});
1263 return step.fail(maker, "test runner failed to respond for {f}", .{
1264 Io.Duration{ .nanoseconds = timeout.ns_elapsed },
1265 });
12581266 },
12591267 }
12601268 comptime unreachable;
......@@ -1456,8 +1464,8 @@ fn evalGeneric(
14561464
14571465 try multi_reader.checkAnyError();
14581466
1459 stdout_bytes = try multi_reader.toOwnedSlice(0);
1460 stderr_bytes = try multi_reader.toOwnedSlice(1);
1467 stdout_bytes = multi_reader.reader(0).buffered();
1468 stderr_bytes = multi_reader.reader(1).buffered();
14611469 } else {
14621470 var stdout_reader = stdout.readerStreaming(io, &.{});
14631471 const stdio_limit: Io.Limit = if (conf_run.stdio_limit.value) |x| .limited64(x) else .unlimited;
......@@ -1484,7 +1492,7 @@ fn evalGeneric(
14841492 else => true,
14851493 };
14861494 if (stderr_is_diagnostic) {
1487 step.result_stderr = bytes;
1495 try step.setResultStderr(maker.gpa, bytes);
14881496 }
14891497 };
14901498
......@@ -2084,16 +2092,11 @@ fn runCommand(
20842092 },
20852093 else => {
20862094 // On failure, report captured stderr like normal standard error output.
2087 const bad_exit = switch (generic_result.term) {
2088 .exited => |code| code != 0,
2089 .signal, .stopped, .unknown => true,
2090 };
2091 if (bad_exit) {
2095 if (!generic_result.term.success()) {
20922096 if (generic_result.stderr) |bytes| {
2093 step.result_stderr = bytes;
2097 try step.setResultStderr(gpa, bytes);
20942098 }
20952099 }
2096
20972100 try step.handleChildProcessTerm(maker, generic_result.term);
20982101 },
20992102 }
......@@ -2135,13 +2138,13 @@ fn spawnChildAndCollect(
21352138 .inherit;
21362139
21372140 // If an error occurs, it's caused by this command:
2138 step.clearFailedCommand(gpa);
2139 step.result_failed_command = try std.zig.allocPrintCmd(gpa, argv, .{
2140 .cwd = switch (child_cwd) {
2141 .path => |p| p,
2142 .dir => unreachable,
2143 .inherit => null,
2144 },
2141 const cwd_string = switch (child_cwd) {
2142 .path => |p| p,
2143 .dir => unreachable,
2144 .inherit => null,
2145 };
2146 errdefer step.setFailedCommand(gpa, argv, .{
2147 .cwd = cwd_string,
21452148 .child_env = environ_map,
21462149 .parent_env = &graph.environ_map,
21472150 });
......@@ -2178,7 +2181,7 @@ fn spawnChildAndCollect(
21782181
21792182 if (conf_run.flags.stdio == .zig_test) {
21802183 const started: Io.Clock.Timestamp = .now(io, .awake);
2181 const result = evalZigTest(graph.arena, run, run_index, maker, progress_node, spawn_options, fuzz_context) catch |err| switch (err) {
2184 const result = evalZigTest(run, run_index, maker, progress_node, spawn_options, fuzz_context) catch |err| switch (err) {
21822185 error.Canceled => |e| return e,
21832186 else => |e| e,
21842187 };
......@@ -2198,7 +2201,7 @@ fn spawnChildAndCollect(
21982201 try setColorEnvironmentVariables(&conf_run, environ_map, terminal_mode);
21992202
22002203 const started: Io.Clock.Timestamp = .now(io, .awake);
2201 const result = evalGeneric(graph.arena, run_index, maker, spawn_options) catch |err| switch (err) {
2204 const result = evalGeneric(arena, run_index, maker, spawn_options) catch |err| switch (err) {
22022205 error.Canceled => |e| return e,
22032206 else => |e| e,
22042207 };
lib/compiler/Maker/Step/TranslateC.zig+1-1
......@@ -112,7 +112,7 @@ pub fn make(
112112 const pkg_conf_node = progress_node.start("pkg-config", 0);
113113 defer pkg_conf_node.end();
114114
115 if (PkgConfig.run(maker, step, pkg_conf_node, system_lib_name, force)) |result| {
115 if (PkgConfig.run(maker, step, arena, pkg_conf_node, system_lib_name, force)) |result| {
116116 try argv.appendSlice(arena, result.cflags);
117117 try argv.appendSlice(arena, result.libs);
118118 try seen_system_libs.put(arena, system_lib.name, result.cflags);
src/main.zig+1-1
......@@ -5810,7 +5810,7 @@ const MakeRunner = struct {
58105810};
58115811
58125812fn compileMakeRunner(gpa: Allocator, arena: Allocator, io: Io, options: MakeRunner.Options) !MakeRunner {
5813 const compile_prog_node = options.parent_prog_node.start("Compile Maker", 0);
5813 const compile_prog_node = options.parent_prog_node.start("Compiling maker (first time setup)", 0);
58145814 defer compile_prog_node.end();
58155815
58165816 const strip = options.optimize_mode != .Debug;