Commit cce32bd1d5
Changed files (8)
lib
compiler
std
lib/compiler/build_runner.zig
@@ -12,6 +12,7 @@ const Watch = std.Build.Watch;
const Fuzz = std.Build.Fuzz;
const Allocator = std.mem.Allocator;
const fatal = std.process.fatal;
+const Writer = std.io.Writer;
const runner = @This();
pub const root = @import("@build");
@@ -330,7 +331,7 @@ pub fn main() !void {
}
}
- const stderr = std.fs.File.stderr();
+ const stderr: std.fs.File = .stderr();
const ttyconf = get_tty_conf(color, stderr);
switch (ttyconf) {
.no_color => try graph.env_map.put("NO_COLOR", "1"),
@@ -378,13 +379,19 @@ pub fn main() !void {
validateSystemLibraryOptions(builder);
- const stdout_writer = std.fs.File.stdout().deprecatedWriter();
-
- if (help_menu)
- return usage(builder, stdout_writer);
+ if (help_menu) {
+ var w = initStdoutWriter();
+ printUsage(builder, w) catch return stdout_writer_allocation.err.?;
+ w.flush() catch return stdout_writer_allocation.err.?;
+ return;
+ }
- if (steps_menu)
- return steps(builder, stdout_writer);
+ if (steps_menu) {
+ var w = initStdoutWriter();
+ printSteps(builder, w) catch return stdout_writer_allocation.err.?;
+ w.flush() catch return stdout_writer_allocation.err.?;
+ return;
+ }
var run: Run = .{
.max_rss = max_rss,
@@ -696,24 +703,21 @@ fn runStepNames(
const ttyconf = run.ttyconf;
if (run.summary != .none) {
- std.debug.lockStdErr();
- defer std.debug.unlockStdErr();
- const stderr = run.stderr;
+ const w = std.debug.lockStderrWriter(&stdio_buffer_allocation);
+ defer std.debug.unlockStderrWriter();
const total_count = success_count + failure_count + pending_count + skipped_count;
- ttyconf.setColor(stderr, .cyan) catch {};
- stderr.writeAll("Build Summary:") catch {};
- ttyconf.setColor(stderr, .reset) catch {};
- stderr.deprecatedWriter().print(" {d}/{d} steps succeeded", .{ success_count, total_count }) catch {};
- if (skipped_count > 0) stderr.deprecatedWriter().print("; {d} skipped", .{skipped_count}) catch {};
- if (failure_count > 0) stderr.deprecatedWriter().print("; {d} failed", .{failure_count}) catch {};
-
- if (test_count > 0) stderr.deprecatedWriter().print("; {d}/{d} tests passed", .{ test_pass_count, test_count }) catch {};
- if (test_skip_count > 0) stderr.deprecatedWriter().print("; {d} skipped", .{test_skip_count}) catch {};
- if (test_fail_count > 0) stderr.deprecatedWriter().print("; {d} failed", .{test_fail_count}) catch {};
- if (test_leak_count > 0) stderr.deprecatedWriter().print("; {d} leaked", .{test_leak_count}) catch {};
-
- stderr.writeAll("\n") catch {};
+ ttyconf.setColor(w, .cyan) catch {};
+ w.writeAll("Build Summary:") catch {};
+ ttyconf.setColor(w, .reset) catch {};
+ w.print(" {d}/{d} steps succeeded", .{ success_count, total_count }) catch {};
+ if (skipped_count > 0) w.print("; {d} skipped", .{skipped_count}) catch {};
+ if (failure_count > 0) w.print("; {d} failed", .{failure_count}) catch {};
+
+ if (test_count > 0) w.print("; {d}/{d} tests passed", .{ test_pass_count, test_count }) catch {};
+ if (test_skip_count > 0) w.print("; {d} skipped", .{test_skip_count}) catch {};
+ if (test_fail_count > 0) w.print("; {d} failed", .{test_fail_count}) catch {};
+ if (test_leak_count > 0) w.print("; {d} leaked", .{test_leak_count}) catch {};
// Print a fancy tree with build results.
var step_stack_copy = try step_stack.clone(gpa);
@@ -722,7 +726,7 @@ fn runStepNames(
var print_node: PrintNode = .{ .parent = null };
if (step_names.len == 0) {
print_node.last = true;
- printTreeStep(b, b.default_step, run, stderr, ttyconf, &print_node, &step_stack_copy) catch {};
+ printTreeStep(b, b.default_step, run, w, ttyconf, &print_node, &step_stack_copy) catch {};
} else {
const last_index = if (run.summary == .all) b.top_level_steps.count() else blk: {
var i: usize = step_names.len;
@@ -741,9 +745,10 @@ fn runStepNames(
for (step_names, 0..) |step_name, i| {
const tls = b.top_level_steps.get(step_name).?;
print_node.last = i + 1 == last_index;
- printTreeStep(b, &tls.step, run, stderr, ttyconf, &print_node, &step_stack_copy) catch {};
+ printTreeStep(b, &tls.step, run, w, ttyconf, &print_node, &step_stack_copy) catch {};
}
}
+ w.writeByte('\n') catch {};
}
if (failure_count == 0) {
@@ -775,7 +780,7 @@ const PrintNode = struct {
last: bool = false,
};
-fn printPrefix(node: *PrintNode, stderr: File, ttyconf: std.io.tty.Config) !void {
+fn printPrefix(node: *PrintNode, stderr: *Writer, ttyconf: std.io.tty.Config) !void {
const parent = node.parent orelse return;
if (parent.parent == null) return;
try printPrefix(parent, stderr, ttyconf);
@@ -789,7 +794,7 @@ fn printPrefix(node: *PrintNode, stderr: File, ttyconf: std.io.tty.Config) !void
}
}
-fn printChildNodePrefix(stderr: File, ttyconf: std.io.tty.Config) !void {
+fn printChildNodePrefix(stderr: *Writer, ttyconf: std.io.tty.Config) !void {
try stderr.writeAll(switch (ttyconf) {
.no_color, .windows_api => "+- ",
.escape_codes => "\x1B\x28\x30\x6d\x71\x1B\x28\x42 ", // └─
@@ -798,7 +803,7 @@ fn printChildNodePrefix(stderr: File, ttyconf: std.io.tty.Config) !void {
fn printStepStatus(
s: *Step,
- stderr: File,
+ stderr: *Writer,
ttyconf: std.io.tty.Config,
run: *const Run,
) !void {
@@ -820,10 +825,10 @@ fn printStepStatus(
try stderr.writeAll(" cached");
} else if (s.test_results.test_count > 0) {
const pass_count = s.test_results.passCount();
- try stderr.deprecatedWriter().print(" {d} passed", .{pass_count});
+ try stderr.print(" {d} passed", .{pass_count});
if (s.test_results.skip_count > 0) {
try ttyconf.setColor(stderr, .yellow);
- try stderr.deprecatedWriter().print(" {d} skipped", .{s.test_results.skip_count});
+ try stderr.print(" {d} skipped", .{s.test_results.skip_count});
}
} else {
try stderr.writeAll(" success");
@@ -832,15 +837,15 @@ fn printStepStatus(
if (s.result_duration_ns) |ns| {
try ttyconf.setColor(stderr, .dim);
if (ns >= std.time.ns_per_min) {
- try stderr.deprecatedWriter().print(" {d}m", .{ns / std.time.ns_per_min});
+ try stderr.print(" {d}m", .{ns / std.time.ns_per_min});
} else if (ns >= std.time.ns_per_s) {
- try stderr.deprecatedWriter().print(" {d}s", .{ns / std.time.ns_per_s});
+ try stderr.print(" {d}s", .{ns / std.time.ns_per_s});
} else if (ns >= std.time.ns_per_ms) {
- try stderr.deprecatedWriter().print(" {d}ms", .{ns / std.time.ns_per_ms});
+ try stderr.print(" {d}ms", .{ns / std.time.ns_per_ms});
} else if (ns >= std.time.ns_per_us) {
- try stderr.deprecatedWriter().print(" {d}us", .{ns / std.time.ns_per_us});
+ try stderr.print(" {d}us", .{ns / std.time.ns_per_us});
} else {
- try stderr.deprecatedWriter().print(" {d}ns", .{ns});
+ try stderr.print(" {d}ns", .{ns});
}
try ttyconf.setColor(stderr, .reset);
}
@@ -848,13 +853,13 @@ fn printStepStatus(
const rss = s.result_peak_rss;
try ttyconf.setColor(stderr, .dim);
if (rss >= 1000_000_000) {
- try stderr.deprecatedWriter().print(" MaxRSS:{d}G", .{rss / 1000_000_000});
+ try stderr.print(" MaxRSS:{d}G", .{rss / 1000_000_000});
} else if (rss >= 1000_000) {
- try stderr.deprecatedWriter().print(" MaxRSS:{d}M", .{rss / 1000_000});
+ try stderr.print(" MaxRSS:{d}M", .{rss / 1000_000});
} else if (rss >= 1000) {
- try stderr.deprecatedWriter().print(" MaxRSS:{d}K", .{rss / 1000});
+ try stderr.print(" MaxRSS:{d}K", .{rss / 1000});
} else {
- try stderr.deprecatedWriter().print(" MaxRSS:{d}B", .{rss});
+ try stderr.print(" MaxRSS:{d}B", .{rss});
}
try ttyconf.setColor(stderr, .reset);
}
@@ -866,7 +871,7 @@ fn printStepStatus(
if (skip == .skipped_oom) {
try stderr.writeAll(" (not enough memory)");
try ttyconf.setColor(stderr, .dim);
- try stderr.deprecatedWriter().print(" upper bound of {d} exceeded runner limit ({d})", .{ s.max_rss, run.max_rss });
+ try stderr.print(" upper bound of {d} exceeded runner limit ({d})", .{ s.max_rss, run.max_rss });
try ttyconf.setColor(stderr, .yellow);
}
try stderr.writeAll("\n");
@@ -878,23 +883,23 @@ fn printStepStatus(
fn printStepFailure(
s: *Step,
- stderr: File,
+ stderr: *Writer,
ttyconf: std.io.tty.Config,
) !void {
if (s.result_error_bundle.errorMessageCount() > 0) {
try ttyconf.setColor(stderr, .red);
- try stderr.deprecatedWriter().print(" {d} errors\n", .{
+ try stderr.print(" {d} errors\n", .{
s.result_error_bundle.errorMessageCount(),
});
try ttyconf.setColor(stderr, .reset);
} else if (!s.test_results.isSuccess()) {
- try stderr.deprecatedWriter().print(" {d}/{d} passed", .{
+ try stderr.print(" {d}/{d} passed", .{
s.test_results.passCount(), s.test_results.test_count,
});
if (s.test_results.fail_count > 0) {
try stderr.writeAll(", ");
try ttyconf.setColor(stderr, .red);
- try stderr.deprecatedWriter().print("{d} failed", .{
+ try stderr.print("{d} failed", .{
s.test_results.fail_count,
});
try ttyconf.setColor(stderr, .reset);
@@ -902,7 +907,7 @@ fn printStepFailure(
if (s.test_results.skip_count > 0) {
try stderr.writeAll(", ");
try ttyconf.setColor(stderr, .yellow);
- try stderr.deprecatedWriter().print("{d} skipped", .{
+ try stderr.print("{d} skipped", .{
s.test_results.skip_count,
});
try ttyconf.setColor(stderr, .reset);
@@ -910,7 +915,7 @@ fn printStepFailure(
if (s.test_results.leak_count > 0) {
try stderr.writeAll(", ");
try ttyconf.setColor(stderr, .red);
- try stderr.deprecatedWriter().print("{d} leaked", .{
+ try stderr.print("{d} leaked", .{
s.test_results.leak_count,
});
try ttyconf.setColor(stderr, .reset);
@@ -932,7 +937,7 @@ fn printTreeStep(
b: *std.Build,
s: *Step,
run: *const Run,
- stderr: File,
+ stderr: *Writer,
ttyconf: std.io.tty.Config,
parent_node: *PrintNode,
step_stack: *std.AutoArrayHashMapUnmanaged(*Step, void),
@@ -992,7 +997,7 @@ fn printTreeStep(
if (s.dependencies.items.len == 0) {
try stderr.writeAll(" (reused)\n");
} else {
- try stderr.deprecatedWriter().print(" (+{d} more reused dependencies)\n", .{
+ try stderr.print(" (+{d} more reused dependencies)\n", .{
s.dependencies.items.len,
});
}
@@ -1129,11 +1134,11 @@ fn workerMakeOneStep(
const show_stderr = s.result_stderr.len > 0;
if (show_error_msgs or show_compile_errors or show_stderr) {
- std.debug.lockStdErr();
- defer std.debug.unlockStdErr();
+ const bw = std.debug.lockStderrWriter(&stdio_buffer_allocation);
+ defer std.debug.unlockStderrWriter();
const gpa = b.allocator;
- printErrorMessages(gpa, s, .{ .ttyconf = run.ttyconf }, run.stderr, run.prominent_compile_errors) catch {};
+ printErrorMessages(gpa, s, .{ .ttyconf = run.ttyconf }, bw, run.prominent_compile_errors) catch {};
}
handle_result: {
@@ -1190,7 +1195,7 @@ pub fn printErrorMessages(
gpa: Allocator,
failing_step: *Step,
options: std.zig.ErrorBundle.RenderOptions,
- stderr: File,
+ stderr: *Writer,
prominent_compile_errors: bool,
) !void {
// Provide context for where these error messages are coming from by
@@ -1209,7 +1214,7 @@ pub fn printErrorMessages(
var indent: usize = 0;
while (step_stack.pop()) |s| : (indent += 1) {
if (indent > 0) {
- try stderr.deprecatedWriter().writeByteNTimes(' ', (indent - 1) * 3);
+ try stderr.splatByteAll(' ', (indent - 1) * 3);
try printChildNodePrefix(stderr, ttyconf);
}
@@ -1231,7 +1236,7 @@ pub fn printErrorMessages(
}
if (!prominent_compile_errors and failing_step.result_error_bundle.errorMessageCount() > 0) {
- try failing_step.result_error_bundle.renderToWriter(options, stderr.deprecatedWriter());
+ try failing_step.result_error_bundle.renderToWriter(options, stderr);
}
for (failing_step.result_error_msgs.items) |msg| {
@@ -1243,27 +1248,27 @@ pub fn printErrorMessages(
}
}
-fn steps(builder: *std.Build, out_stream: anytype) !void {
+fn printSteps(builder: *std.Build, w: *Writer) !void {
const allocator = builder.allocator;
for (builder.top_level_steps.values()) |top_level_step| {
const name = if (&top_level_step.step == builder.default_step)
try fmt.allocPrint(allocator, "{s} (default)", .{top_level_step.step.name})
else
top_level_step.step.name;
- try out_stream.print(" {s:<28} {s}\n", .{ name, top_level_step.description });
+ try w.print(" {s:<28} {s}\n", .{ name, top_level_step.description });
}
}
-fn usage(b: *std.Build, out_stream: anytype) !void {
- try out_stream.print(
+fn printUsage(b: *std.Build, w: *Writer) !void {
+ try w.print(
\\Usage: {s} build [steps] [options]
\\
\\Steps:
\\
, .{b.graph.zig_exe});
- try steps(b, out_stream);
+ try printSteps(b, w);
- try out_stream.writeAll(
+ try w.writeAll(
\\
\\General Options:
\\ -p, --prefix [path] Where to install files (default: zig-out)
@@ -1319,25 +1324,25 @@ fn usage(b: *std.Build, out_stream: anytype) !void {
const arena = b.allocator;
if (b.available_options_list.items.len == 0) {
- try out_stream.print(" (none)\n", .{});
+ try w.print(" (none)\n", .{});
} else {
for (b.available_options_list.items) |option| {
const name = try fmt.allocPrint(arena, " -D{s}=[{s}]", .{
option.name,
@tagName(option.type_id),
});
- try out_stream.print("{s:<30} {s}\n", .{ name, option.description });
+ try w.print("{s:<30} {s}\n", .{ name, option.description });
if (option.enum_options) |enum_options| {
const padding = " " ** 33;
- try out_stream.writeAll(padding ++ "Supported Values:\n");
+ try w.writeAll(padding ++ "Supported Values:\n");
for (enum_options) |enum_option| {
- try out_stream.print(padding ++ " {s}\n", .{enum_option});
+ try w.print(padding ++ " {s}\n", .{enum_option});
}
}
}
}
- try out_stream.writeAll(
+ try w.writeAll(
\\
\\System Integration Options:
\\ --search-prefix [path] Add a path to look for binaries, libraries, headers
@@ -1352,7 +1357,7 @@ fn usage(b: *std.Build, out_stream: anytype) !void {
\\
);
if (b.graph.system_library_options.entries.len == 0) {
- try out_stream.writeAll(" (none) -\n");
+ try w.writeAll(" (none) -\n");
} else {
for (b.graph.system_library_options.keys(), b.graph.system_library_options.values()) |k, v| {
const status = switch (v) {
@@ -1360,11 +1365,11 @@ fn usage(b: *std.Build, out_stream: anytype) !void {
.declared_disabled => "no",
.user_enabled, .user_disabled => unreachable, // already emitted error
};
- try out_stream.print(" {s:<43} {s}\n", .{ k, status });
+ try w.print(" {s:<43} {s}\n", .{ k, status });
}
}
- try out_stream.writeAll(
+ try w.writeAll(
\\
\\Advanced Options:
\\ -freference-trace[=num] How many lines of reference trace should be shown per compile error
@@ -1544,3 +1549,11 @@ fn createModuleDependenciesForStep(step: *Step) Allocator.Error!void {
};
}
}
+
+var stdio_buffer_allocation: [256]u8 = undefined;
+var stdout_writer_allocation: std.fs.File.Writer = undefined;
+
+fn initStdoutWriter() *Writer {
+ stdout_writer_allocation = std.fs.File.stdout().writerStreaming(&stdio_buffer_allocation);
+ return &stdout_writer_allocation.interface;
+}
lib/std/Build/Step/Compile.zig
@@ -409,7 +409,7 @@ pub fn create(owner: *std.Build, options: Options) *Compile {
.linkage = options.linkage,
.kind = options.kind,
.name = name,
- .step = Step.init(.{
+ .step = .init(.{
.id = base_id,
.name = step_name,
.owner = owner,
@@ -1017,20 +1017,16 @@ fn getGeneratedFilePath(compile: *Compile, comptime tag_name: []const u8, asking
const maybe_path: ?*GeneratedFile = @field(compile, tag_name);
const generated_file = maybe_path orelse {
- std.debug.lockStdErr();
- const stderr: fs.File = .stderr();
-
- std.Build.dumpBadGetPathHelp(&compile.step, stderr, compile.step.owner, asking_step) catch {};
-
+ const w = std.debug.lockStderrWriter(&.{});
+ std.Build.dumpBadGetPathHelp(&compile.step, w, .detect(.stderr()), compile.step.owner, asking_step) catch {};
+ std.debug.unlockStderrWriter();
@panic("missing emit option for " ++ tag_name);
};
const path = generated_file.path orelse {
- std.debug.lockStdErr();
- const stderr: fs.File = .stderr();
-
- std.Build.dumpBadGetPathHelp(&compile.step, stderr, compile.step.owner, asking_step) catch {};
-
+ const w = std.debug.lockStderrWriter(&.{});
+ std.Build.dumpBadGetPathHelp(&compile.step, w, .detect(.stderr()), compile.step.owner, asking_step) catch {};
+ std.debug.unlockStderrWriter();
@panic(tag_name ++ " is null. Is there a missing step dependency?");
};
@@ -1768,12 +1764,12 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 {
for (arg, 0..) |c, arg_idx| {
if (c == '\\' or c == '"') {
// Slow path for arguments that need to be escaped. We'll need to allocate and copy
- var escaped = try ArrayList(u8).initCapacity(arena, arg.len + 1);
- const writer = escaped.writer();
- try writer.writeAll(arg[0..arg_idx]);
+ var escaped: std.ArrayListUnmanaged(u8) = .empty;
+ try escaped.ensureTotalCapacityPrecise(arena, arg.len + 1);
+ try escaped.appendSlice(arena, arg[0..arg_idx]);
for (arg[arg_idx..]) |to_escape| {
- if (to_escape == '\\' or to_escape == '"') try writer.writeByte('\\');
- try writer.writeByte(to_escape);
+ if (to_escape == '\\' or to_escape == '"') try escaped.append(arena, '\\');
+ try escaped.append(arena, to_escape);
}
escaped_args.appendAssumeCapacity(escaped.items);
continue :arg_blk;
@@ -1963,20 +1959,23 @@ fn addFlag(args: *ArrayList([]const u8), comptime name: []const u8, opt: ?bool)
fn checkCompileErrors(compile: *Compile) !void {
// Clear this field so that it does not get printed by the build runner.
const actual_eb = compile.step.result_error_bundle;
- compile.step.result_error_bundle = std.zig.ErrorBundle.empty;
+ compile.step.result_error_bundle = .empty;
const arena = compile.step.owner.allocator;
- var actual_errors_list = std.ArrayList(u8).init(arena);
- try actual_eb.renderToWriter(.{
- .ttyconf = .no_color,
- .include_reference_trace = false,
- .include_source_line = false,
- }, actual_errors_list.writer());
- const actual_errors = try actual_errors_list.toOwnedSlice();
+ const actual_errors = ae: {
+ var aw: std.io.Writer.Allocating = .init(arena);
+ defer aw.deinit();
+ try actual_eb.renderToWriter(.{
+ .ttyconf = .no_color,
+ .include_reference_trace = false,
+ .include_source_line = false,
+ }, &aw.writer);
+ break :ae try aw.toOwnedSlice();
+ };
// Render the expected lines into a string that we can compare verbatim.
- var expected_generated = std.ArrayList(u8).init(arena);
+ var expected_generated: std.ArrayListUnmanaged(u8) = .empty;
const expect_errors = compile.expect_errors.?;
var actual_line_it = mem.splitScalar(u8, actual_errors, '\n');
@@ -2035,17 +2034,17 @@ fn checkCompileErrors(compile: *Compile) !void {
.exact => |expect_lines| {
for (expect_lines) |expect_line| {
const actual_line = actual_line_it.next() orelse {
- try expected_generated.appendSlice(expect_line);
- try expected_generated.append('\n');
+ try expected_generated.appendSlice(arena, expect_line);
+ try expected_generated.append(arena, '\n');
continue;
};
if (matchCompileError(actual_line, expect_line)) {
- try expected_generated.appendSlice(actual_line);
- try expected_generated.append('\n');
+ try expected_generated.appendSlice(arena, actual_line);
+ try expected_generated.append(arena, '\n');
continue;
}
- try expected_generated.appendSlice(expect_line);
- try expected_generated.append('\n');
+ try expected_generated.appendSlice(arena, expect_line);
+ try expected_generated.append(arena, '\n');
}
if (mem.eql(u8, expected_generated.items, actual_errors)) return;
lib/std/Build/Fuzz.zig
@@ -112,7 +112,6 @@ fn rebuildTestsWorkerRun(run: *Step.Run, ttyconf: std.io.tty.Config, parent_prog
fn rebuildTestsWorkerRunFallible(run: *Step.Run, ttyconf: std.io.tty.Config, parent_prog_node: std.Progress.Node) !void {
const gpa = run.step.owner.allocator;
- const stderr = std.fs.File.stderr();
const compile = run.producer.?;
const prog_node = parent_prog_node.start(compile.step.name, 0);
@@ -125,9 +124,10 @@ fn rebuildTestsWorkerRunFallible(run: *Step.Run, ttyconf: std.io.tty.Config, par
const show_stderr = compile.step.result_stderr.len > 0;
if (show_error_msgs or show_compile_errors or show_stderr) {
- std.debug.lockStdErr();
- defer std.debug.unlockStdErr();
- build_runner.printErrorMessages(gpa, &compile.step, .{ .ttyconf = ttyconf }, stderr, false) catch {};
+ var buf: [256]u8 = undefined;
+ const w = std.debug.lockStderrWriter(&buf);
+ defer std.debug.unlockStderrWriter();
+ build_runner.printErrorMessages(gpa, &compile.step, .{ .ttyconf = ttyconf }, w, false) catch {};
}
const rebuilt_bin_path = result catch |err| switch (err) {
@@ -152,10 +152,10 @@ fn fuzzWorkerRun(
run.rerunInFuzzMode(web_server, unit_test_index, prog_node) catch |err| switch (err) {
error.MakeFailed => {
- const stderr = std.fs.File.stderr();
- std.debug.lockStdErr();
- defer std.debug.unlockStdErr();
- build_runner.printErrorMessages(gpa, &run.step, .{ .ttyconf = ttyconf }, stderr, false) catch {};
+ var buf: [256]u8 = undefined;
+ const w = std.debug.lockStderrWriter(&buf);
+ defer std.debug.unlockStderrWriter();
+ build_runner.printErrorMessages(gpa, &run.step, .{ .ttyconf = ttyconf }, w, false) catch {};
return;
},
else => {
lib/std/Build/Step.zig
@@ -286,10 +286,7 @@ pub fn cast(step: *Step, comptime T: type) ?*T {
}
/// For debugging purposes, prints identifying information about this Step.
-pub fn dump(step: *Step, file: std.fs.File) void {
- var fw = file.writer(&.{});
- const w = &fw.interface;
- const tty_config = std.io.tty.detectConfig(file);
+pub fn dump(step: *Step, w: *std.io.Writer, tty_config: std.io.tty.Config) void {
const debug_info = std.debug.getSelfDebugInfo() catch |err| {
w.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{
@errorName(err),
lib/std/fs/File.zig
@@ -1725,10 +1725,6 @@ pub const Writer = struct {
iovecs[len] = .{ .base = splat_buffer.ptr, .len = remaining_splat };
len += 1;
}
- return std.posix.writev(handle, iovecs[0..len]) catch |err| {
- w.err = err;
- return error.WriteFailed;
- };
},
else => for (0..splat - 1) |_| {
if (iovecs.len - len == 0) break;
lib/std/io/tty.zig
@@ -5,36 +5,9 @@ const process = std.process;
const windows = std.os.windows;
const native_os = builtin.os.tag;
-/// Detect suitable TTY configuration options for the given file (commonly stdout/stderr).
-/// This includes feature checks for ANSI escape codes and the Windows console API, as well as
-/// respecting the `NO_COLOR` and `CLICOLOR_FORCE` environment variables to override the default.
-/// Will attempt to enable ANSI escape code support if necessary/possible.
+/// Deprecated in favor of `Config.detect`.
pub fn detectConfig(file: File) Config {
- const force_color: ?bool = if (builtin.os.tag == .wasi)
- null // wasi does not support environment variables
- else if (process.hasNonEmptyEnvVarConstant("NO_COLOR"))
- false
- else if (process.hasNonEmptyEnvVarConstant("CLICOLOR_FORCE"))
- true
- else
- null;
-
- if (force_color == false) return .no_color;
-
- if (file.getOrEnableAnsiEscapeSupport()) return .escape_codes;
-
- if (native_os == .windows and file.isTty()) {
- var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
- if (windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) == windows.FALSE) {
- return if (force_color == true) .escape_codes else .no_color;
- }
- return .{ .windows_api = .{
- .handle = file.handle,
- .reset_attributes = info.wAttributes,
- } };
- }
-
- return if (force_color == true) .escape_codes else .no_color;
+ return .detect(file);
}
pub const Color = enum {
@@ -66,6 +39,38 @@ pub const Config = union(enum) {
escape_codes,
windows_api: if (native_os == .windows) WindowsContext else void,
+ /// Detect suitable TTY configuration options for the given file (commonly stdout/stderr).
+ /// This includes feature checks for ANSI escape codes and the Windows console API, as well as
+ /// respecting the `NO_COLOR` and `CLICOLOR_FORCE` environment variables to override the default.
+ /// Will attempt to enable ANSI escape code support if necessary/possible.
+ pub fn detect(file: File) Config {
+ const force_color: ?bool = if (builtin.os.tag == .wasi)
+ null // wasi does not support environment variables
+ else if (process.hasNonEmptyEnvVarConstant("NO_COLOR"))
+ false
+ else if (process.hasNonEmptyEnvVarConstant("CLICOLOR_FORCE"))
+ true
+ else
+ null;
+
+ if (force_color == false) return .no_color;
+
+ if (file.getOrEnableAnsiEscapeSupport()) return .escape_codes;
+
+ if (native_os == .windows and file.isTty()) {
+ var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
+ if (windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) == windows.FALSE) {
+ return if (force_color == true) .escape_codes else .no_color;
+ }
+ return .{ .windows_api = .{
+ .handle = file.handle,
+ .reset_attributes = info.wAttributes,
+ } };
+ }
+
+ return if (force_color == true) .escape_codes else .no_color;
+ }
+
pub const WindowsContext = struct {
handle: File.Handle,
reset_attributes: u16,
@@ -123,6 +128,7 @@ pub const Config = union(enum) {
.dim => windows.FOREGROUND_INTENSITY,
.reset => ctx.reset_attributes,
};
+ try w.flush();
try windows.SetConsoleTextAttribute(ctx.handle, attributes);
} else {
unreachable;
lib/std/zig/ErrorBundle.zig
@@ -11,6 +11,7 @@ const std = @import("std");
const ErrorBundle = @This();
const Allocator = std.mem.Allocator;
const assert = std.debug.assert;
+const Writer = std.io.Writer;
string_bytes: []const u8,
/// The first thing in this array is an `ErrorMessageList`.
@@ -162,23 +163,23 @@ pub const RenderOptions = struct {
};
pub fn renderToStdErr(eb: ErrorBundle, options: RenderOptions) void {
- std.debug.lockStdErr();
- defer std.debug.unlockStdErr();
- const stderr: std.fs.File = .stderr();
- return renderToWriter(eb, options, stderr.deprecatedWriter()) catch return;
+ var buffer: [256]u8 = undefined;
+ const w = std.debug.lockStderrWriter(&buffer);
+ defer std.debug.unlockStderrWriter();
+ renderToWriter(eb, options, w) catch return;
}
-pub fn renderToWriter(eb: ErrorBundle, options: RenderOptions, writer: anytype) anyerror!void {
+pub fn renderToWriter(eb: ErrorBundle, options: RenderOptions, w: *Writer) (Writer.Error || std.posix.UnexpectedError)!void {
if (eb.extra.len == 0) return;
for (eb.getMessages()) |err_msg| {
- try renderErrorMessageToWriter(eb, options, err_msg, writer, "error", .red, 0);
+ try renderErrorMessageToWriter(eb, options, err_msg, w, "error", .red, 0);
}
if (options.include_log_text) {
const log_text = eb.getCompileLogOutput();
if (log_text.len != 0) {
- try writer.writeAll("\nCompile Log Output:\n");
- try writer.writeAll(log_text);
+ try w.writeAll("\nCompile Log Output:\n");
+ try w.writeAll(log_text);
}
}
}
@@ -187,74 +188,73 @@ fn renderErrorMessageToWriter(
eb: ErrorBundle,
options: RenderOptions,
err_msg_index: MessageIndex,
- stderr: anytype,
+ w: *Writer,
kind: []const u8,
color: std.io.tty.Color,
indent: usize,
-) anyerror!void {
+) (Writer.Error || std.posix.UnexpectedError)!void {
const ttyconf = options.ttyconf;
- var counting_writer = std.io.countingWriter(stderr);
- const counting_stderr = counting_writer.writer();
const err_msg = eb.getErrorMessage(err_msg_index);
+ const prefix_start = w.count;
if (err_msg.src_loc != .none) {
const src = eb.extraData(SourceLocation, @intFromEnum(err_msg.src_loc));
- try counting_stderr.writeByteNTimes(' ', indent);
- try ttyconf.setColor(stderr, .bold);
- try counting_stderr.print("{s}:{d}:{d}: ", .{
+ try w.splatByteAll(' ', indent);
+ try ttyconf.setColor(w, .bold);
+ try w.print("{s}:{d}:{d}: ", .{
eb.nullTerminatedString(src.data.src_path),
src.data.line + 1,
src.data.column + 1,
});
- try ttyconf.setColor(stderr, color);
- try counting_stderr.writeAll(kind);
- try counting_stderr.writeAll(": ");
+ try ttyconf.setColor(w, color);
+ try w.writeAll(kind);
+ try w.writeAll(": ");
// This is the length of the part before the error message:
// e.g. "file.zig:4:5: error: "
- const prefix_len: usize = @intCast(counting_stderr.context.bytes_written);
- try ttyconf.setColor(stderr, .reset);
- try ttyconf.setColor(stderr, .bold);
+ const prefix_len = w.count - prefix_start;
+ try ttyconf.setColor(w, .reset);
+ try ttyconf.setColor(w, .bold);
if (err_msg.count == 1) {
- try writeMsg(eb, err_msg, stderr, prefix_len);
- try stderr.writeByte('\n');
+ try writeMsg(eb, err_msg, w, prefix_len);
+ try w.writeByte('\n');
} else {
- try writeMsg(eb, err_msg, stderr, prefix_len);
- try ttyconf.setColor(stderr, .dim);
- try stderr.print(" ({d} times)\n", .{err_msg.count});
+ try writeMsg(eb, err_msg, w, prefix_len);
+ try ttyconf.setColor(w, .dim);
+ try w.print(" ({d} times)\n", .{err_msg.count});
}
- try ttyconf.setColor(stderr, .reset);
+ try ttyconf.setColor(w, .reset);
if (src.data.source_line != 0 and options.include_source_line) {
const line = eb.nullTerminatedString(src.data.source_line);
for (line) |b| switch (b) {
- '\t' => try stderr.writeByte(' '),
- else => try stderr.writeByte(b),
+ '\t' => try w.writeByte(' '),
+ else => try w.writeByte(b),
};
- try stderr.writeByte('\n');
+ try w.writeByte('\n');
// TODO basic unicode code point monospace width
const before_caret = src.data.span_main - src.data.span_start;
// -1 since span.main includes the caret
const after_caret = src.data.span_end -| src.data.span_main -| 1;
- try stderr.writeByteNTimes(' ', src.data.column - before_caret);
- try ttyconf.setColor(stderr, .green);
- try stderr.writeByteNTimes('~', before_caret);
- try stderr.writeByte('^');
- try stderr.writeByteNTimes('~', after_caret);
- try stderr.writeByte('\n');
- try ttyconf.setColor(stderr, .reset);
+ try w.splatByteAll(' ', src.data.column - before_caret);
+ try ttyconf.setColor(w, .green);
+ try w.splatByteAll('~', before_caret);
+ try w.writeByte('^');
+ try w.splatByteAll('~', after_caret);
+ try w.writeByte('\n');
+ try ttyconf.setColor(w, .reset);
}
for (eb.getNotes(err_msg_index)) |note| {
- try renderErrorMessageToWriter(eb, options, note, stderr, "note", .cyan, indent);
+ try renderErrorMessageToWriter(eb, options, note, w, "note", .cyan, indent);
}
if (src.data.reference_trace_len > 0 and options.include_reference_trace) {
- try ttyconf.setColor(stderr, .reset);
- try ttyconf.setColor(stderr, .dim);
- try stderr.print("referenced by:\n", .{});
+ try ttyconf.setColor(w, .reset);
+ try ttyconf.setColor(w, .dim);
+ try w.print("referenced by:\n", .{});
var ref_index = src.end;
for (0..src.data.reference_trace_len) |_| {
const ref_trace = eb.extraData(ReferenceTrace, ref_index);
ref_index = ref_trace.end;
if (ref_trace.data.src_loc != .none) {
const ref_src = eb.getSourceLocation(ref_trace.data.src_loc);
- try stderr.print(" {s}: {s}:{d}:{d}\n", .{
+ try w.print(" {s}: {s}:{d}:{d}\n", .{
eb.nullTerminatedString(ref_trace.data.decl_name),
eb.nullTerminatedString(ref_src.src_path),
ref_src.line + 1,
@@ -262,36 +262,36 @@ fn renderErrorMessageToWriter(
});
} else if (ref_trace.data.decl_name != 0) {
const count = ref_trace.data.decl_name;
- try stderr.print(
+ try w.print(
" {d} reference(s) hidden; use '-freference-trace={d}' to see all references\n",
.{ count, count + src.data.reference_trace_len - 1 },
);
} else {
- try stderr.print(
+ try w.print(
" remaining reference traces hidden; use '-freference-trace' to see all reference traces\n",
.{},
);
}
}
- try ttyconf.setColor(stderr, .reset);
+ try ttyconf.setColor(w, .reset);
}
} else {
- try ttyconf.setColor(stderr, color);
- try stderr.writeByteNTimes(' ', indent);
- try stderr.writeAll(kind);
- try stderr.writeAll(": ");
- try ttyconf.setColor(stderr, .reset);
+ try ttyconf.setColor(w, color);
+ try w.splatByteAll(' ', indent);
+ try w.writeAll(kind);
+ try w.writeAll(": ");
+ try ttyconf.setColor(w, .reset);
const msg = eb.nullTerminatedString(err_msg.msg);
if (err_msg.count == 1) {
- try stderr.print("{s}\n", .{msg});
+ try w.print("{s}\n", .{msg});
} else {
- try stderr.print("{s}", .{msg});
- try ttyconf.setColor(stderr, .dim);
- try stderr.print(" ({d} times)\n", .{err_msg.count});
+ try w.print("{s}", .{msg});
+ try ttyconf.setColor(w, .dim);
+ try w.print(" ({d} times)\n", .{err_msg.count});
}
- try ttyconf.setColor(stderr, .reset);
+ try ttyconf.setColor(w, .reset);
for (eb.getNotes(err_msg_index)) |note| {
- try renderErrorMessageToWriter(eb, options, note, stderr, "note", .cyan, indent + 4);
+ try renderErrorMessageToWriter(eb, options, note, w, "note", .cyan, indent + 4);
}
}
}
@@ -300,13 +300,13 @@ fn renderErrorMessageToWriter(
/// to allow for long, good-looking error messages.
///
/// This is used to split the message in `@compileError("hello\nworld")` for example.
-fn writeMsg(eb: ErrorBundle, err_msg: ErrorMessage, stderr: anytype, indent: usize) !void {
+fn writeMsg(eb: ErrorBundle, err_msg: ErrorMessage, w: *Writer, indent: usize) !void {
var lines = std.mem.splitScalar(u8, eb.nullTerminatedString(err_msg.msg), '\n');
while (lines.next()) |line| {
- try stderr.writeAll(line);
+ try w.writeAll(line);
if (lines.index == null) break;
- try stderr.writeByte('\n');
- try stderr.writeByteNTimes(' ', indent);
+ try w.writeByte('\n');
+ try w.splatByteAll(' ', indent);
}
}
@@ -398,7 +398,7 @@ pub const Wip = struct {
pub fn printString(wip: *Wip, comptime fmt: []const u8, args: anytype) Allocator.Error!String {
const gpa = wip.gpa;
const index: String = @intCast(wip.string_bytes.items.len);
- try wip.string_bytes.writer(gpa).print(fmt, args);
+ try wip.string_bytes.print(gpa, fmt, args);
try wip.string_bytes.append(gpa, 0);
return index;
}
@@ -788,9 +788,10 @@ pub const Wip = struct {
const ttyconf: std.io.tty.Config = .no_color;
- var bundle_buf = std.ArrayList(u8).init(std.testing.allocator);
+ var bundle_buf: std.io.Writer.Allocating = .init(std.testing.allocator);
+ const bundle_bw = &bundle_buf.interface;
defer bundle_buf.deinit();
- try bundle.renderToWriter(.{ .ttyconf = ttyconf }, bundle_buf.writer());
+ try bundle.renderToWriter(.{ .ttyconf = ttyconf }, bundle_bw);
var copy = copy: {
var wip: ErrorBundle.Wip = undefined;
@@ -803,10 +804,11 @@ pub const Wip = struct {
};
defer copy.deinit(std.testing.allocator);
- var copy_buf = std.ArrayList(u8).init(std.testing.allocator);
+ var copy_buf: std.io.Writer.Allocating = .init(std.testing.allocator);
+ const copy_bw = ©_buf.interface;
defer copy_buf.deinit();
- try copy.renderToWriter(.{ .ttyconf = ttyconf }, copy_buf.writer());
+ try copy.renderToWriter(.{ .ttyconf = ttyconf }, copy_bw);
- try std.testing.expectEqualStrings(bundle_buf.items, copy_buf.items);
+ try std.testing.expectEqualStrings(bundle_bw.getWritten(), copy_bw.getWritten());
}
};
lib/std/Build.zig
@@ -284,7 +284,7 @@ pub fn create(
.h_dir = undefined,
.dest_dir = graph.env_map.get("DESTDIR"),
.install_tls = .{
- .step = Step.init(.{
+ .step = .init(.{
.id = TopLevelStep.base_id,
.name = "install",
.owner = b,
@@ -292,7 +292,7 @@ pub fn create(
.description = "Copy build artifacts to prefix path",
},
.uninstall_tls = .{
- .step = Step.init(.{
+ .step = .init(.{
.id = TopLevelStep.base_id,
.name = "uninstall",
.owner = b,
@@ -342,7 +342,7 @@ fn createChildOnly(
.graph = parent.graph,
.allocator = allocator,
.install_tls = .{
- .step = Step.init(.{
+ .step = .init(.{
.id = TopLevelStep.base_id,
.name = "install",
.owner = child,
@@ -350,7 +350,7 @@ fn createChildOnly(
.description = "Copy build artifacts to prefix path",
},
.uninstall_tls = .{
- .step = Step.init(.{
+ .step = .init(.{
.id = TopLevelStep.base_id,
.name = "uninstall",
.owner = child,
@@ -1525,7 +1525,7 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw
pub fn step(b: *Build, name: []const u8, description: []const u8) *Step {
const step_info = b.allocator.create(TopLevelStep) catch @panic("OOM");
step_info.* = .{
- .step = Step.init(.{
+ .step = .init(.{
.id = TopLevelStep.base_id,
.name = name,
.owner = b,
@@ -1824,13 +1824,13 @@ pub fn validateUserInputDidItFail(b: *Build) bool {
return b.invalid_user_input;
}
-fn allocPrintCmd(ally: Allocator, opt_cwd: ?[]const u8, argv: []const []const u8) error{OutOfMemory}![]u8 {
- var buf = ArrayList(u8).init(ally);
- if (opt_cwd) |cwd| try buf.writer().print("cd {s} && ", .{cwd});
+fn allocPrintCmd(gpa: Allocator, opt_cwd: ?[]const u8, argv: []const []const u8) error{OutOfMemory}![]u8 {
+ var buf: std.ArrayListUnmanaged(u8) = .empty;
+ if (opt_cwd) |cwd| try buf.print(gpa, "cd {s} && ", .{cwd});
for (argv) |arg| {
- try buf.writer().print("{s} ", .{arg});
+ try buf.print(gpa, "{s} ", .{arg});
}
- return buf.toOwnedSlice();
+ return buf.toOwnedSlice(gpa);
}
fn printCmd(ally: Allocator, cwd: ?[]const u8, argv: []const []const u8) void {
@@ -2466,10 +2466,9 @@ pub const GeneratedFile = struct {
pub fn getPath2(gen: GeneratedFile, src_builder: *Build, asking_step: ?*Step) []const u8 {
return gen.path orelse {
- std.debug.lockStdErr();
- const stderr = std.fs.File.stderr();
- dumpBadGetPathHelp(gen.step, stderr, src_builder, asking_step) catch {};
- std.debug.unlockStdErr();
+ const w = debug.lockStderrWriter(&.{});
+ dumpBadGetPathHelp(gen.step, w, .detect(.stderr()), src_builder, asking_step) catch {};
+ debug.unlockStderrWriter();
@panic("misconfigured build script");
};
}
@@ -2676,10 +2675,9 @@ pub const LazyPath = union(enum) {
var file_path: Cache.Path = .{
.root_dir = Cache.Directory.cwd(),
.sub_path = gen.file.path orelse {
- std.debug.lockStdErr();
- const stderr: fs.File = .stderr();
- dumpBadGetPathHelp(gen.file.step, stderr, src_builder, asking_step) catch {};
- std.debug.unlockStdErr();
+ const w = debug.lockStderrWriter(&.{});
+ dumpBadGetPathHelp(gen.file.step, w, .detect(.stderr()), src_builder, asking_step) catch {};
+ debug.unlockStderrWriter();
@panic("misconfigured build script");
},
};
@@ -2766,44 +2764,42 @@ fn dumpBadDirnameHelp(
comptime msg: []const u8,
args: anytype,
) anyerror!void {
- debug.lockStdErr();
- defer debug.unlockStdErr();
+ const w = debug.lockStderrWriter(&.{});
+ defer debug.unlockStderrWriter();
- const stderr: fs.File = .stderr();
- const w = stderr.deprecatedWriter();
try w.print(msg, args);
- const tty_config = std.io.tty.detectConfig(stderr);
+ const tty_config = std.io.tty.detectConfig(.stderr());
if (fail_step) |s| {
tty_config.setColor(w, .red) catch {};
- try stderr.writeAll(" The step was created by this stack trace:\n");
+ try w.writeAll(" The step was created by this stack trace:\n");
tty_config.setColor(w, .reset) catch {};
- s.dump(stderr);
+ s.dump(w, tty_config);
}
if (asking_step) |as| {
tty_config.setColor(w, .red) catch {};
- try stderr.deprecatedWriter().print(" The step '{s}' that is missing a dependency on the above step was created by this stack trace:\n", .{as.name});
+ try w.print(" The step '{s}' that is missing a dependency on the above step was created by this stack trace:\n", .{as.name});
tty_config.setColor(w, .reset) catch {};
- as.dump(stderr);
+ as.dump(w, tty_config);
}
tty_config.setColor(w, .red) catch {};
- try stderr.writeAll(" Hope that helps. Proceeding to panic.\n");
+ try w.writeAll(" Hope that helps. Proceeding to panic.\n");
tty_config.setColor(w, .reset) catch {};
}
/// In this function the stderr mutex has already been locked.
pub fn dumpBadGetPathHelp(
s: *Step,
- stderr: fs.File,
+ w: *std.io.Writer,
+ tty_config: std.io.tty.Config,
src_builder: *Build,
asking_step: ?*Step,
) anyerror!void {
- const w = stderr.deprecatedWriter();
try w.print(
\\getPath() was called on a GeneratedFile that wasn't built yet.
\\ source package path: {s}
@@ -2814,21 +2810,20 @@ pub fn dumpBadGetPathHelp(
s.name,
});
- const tty_config = std.io.tty.detectConfig(stderr);
tty_config.setColor(w, .red) catch {};
- try stderr.writeAll(" The step was created by this stack trace:\n");
+ try w.writeAll(" The step was created by this stack trace:\n");
tty_config.setColor(w, .reset) catch {};
- s.dump(stderr);
+ s.dump(w, tty_config);
if (asking_step) |as| {
tty_config.setColor(w, .red) catch {};
- try stderr.deprecatedWriter().print(" The step '{s}' that is missing a dependency on the above step was created by this stack trace:\n", .{as.name});
+ try w.print(" The step '{s}' that is missing a dependency on the above step was created by this stack trace:\n", .{as.name});
tty_config.setColor(w, .reset) catch {};
- as.dump(stderr);
+ as.dump(w, tty_config);
}
tty_config.setColor(w, .red) catch {};
- try stderr.writeAll(" Hope that helps. Proceeding to panic.\n");
+ try w.writeAll(" Hope that helps. Proceeding to panic.\n");
tty_config.setColor(w, .reset) catch {};
}
@@ -2866,11 +2861,6 @@ pub fn makeTempPath(b: *Build) []const u8 {
return result_path;
}
-/// Deprecated; use `std.fmt.hex` instead.
-pub fn hex64(x: u64) [16]u8 {
- return std.fmt.hex(x);
-}
-
/// A pair of target query and fully resolved target.
/// This type is generally required by build system API that need to be given a
/// target. The query is kept because the Zig toolchain needs to know which parts