| author | |
| committer | |
| log | cce32bd1d505ee5c5ea7878c9e9e57b6b63856f2 |
| tree | 944f136cbdd9d6662cbae2c14bbf7d8d862739bb |
| parent | ec3b5f0c7474b22dfbf2f19e0121a1f87a58efd0 |
8 files changed, 254 insertions(+), 251 deletions(-)
lib/compiler/build_runner.zig+81-68| ... | ... | @@ -12,6 +12,7 @@ const Watch = std.Build.Watch; |
| 12 | 12 | const Fuzz = std.Build.Fuzz; |
| 13 | 13 | const Allocator = std.mem.Allocator; |
| 14 | 14 | const fatal = std.process.fatal; |
| 15 | const Writer = std.io.Writer; | |
| 15 | 16 | const runner = @This(); |
| 16 | 17 | |
| 17 | 18 | pub const root = @import("@build"); |
| ... | ... | @@ -330,7 +331,7 @@ pub fn main() !void { |
| 330 | 331 | } |
| 331 | 332 | } |
| 332 | 333 | |
| 333 | const stderr = std.fs.File.stderr(); | |
| 334 | const stderr: std.fs.File = .stderr(); | |
| 334 | 335 | const ttyconf = get_tty_conf(color, stderr); |
| 335 | 336 | switch (ttyconf) { |
| 336 | 337 | .no_color => try graph.env_map.put("NO_COLOR", "1"), |
| ... | ... | @@ -378,13 +379,19 @@ pub fn main() !void { |
| 378 | 379 | |
| 379 | 380 | validateSystemLibraryOptions(builder); |
| 380 | 381 | |
| 381 | const stdout_writer = std.fs.File.stdout().deprecatedWriter(); | |
| 382 | ||
| 383 | if (help_menu) | |
| 384 | return usage(builder, stdout_writer); | |
| 382 | if (help_menu) { | |
| 383 | var w = initStdoutWriter(); | |
| 384 | printUsage(builder, w) catch return stdout_writer_allocation.err.?; | |
| 385 | w.flush() catch return stdout_writer_allocation.err.?; | |
| 386 | return; | |
| 387 | } | |
| 385 | 388 | |
| 386 | if (steps_menu) | |
| 387 | return steps(builder, stdout_writer); | |
| 389 | if (steps_menu) { | |
| 390 | var w = initStdoutWriter(); | |
| 391 | printSteps(builder, w) catch return stdout_writer_allocation.err.?; | |
| 392 | w.flush() catch return stdout_writer_allocation.err.?; | |
| 393 | return; | |
| 394 | } | |
| 388 | 395 | |
| 389 | 396 | var run: Run = .{ |
| 390 | 397 | .max_rss = max_rss, |
| ... | ... | @@ -696,24 +703,21 @@ fn runStepNames( |
| 696 | 703 | const ttyconf = run.ttyconf; |
| 697 | 704 | |
| 698 | 705 | if (run.summary != .none) { |
| 699 | std.debug.lockStdErr(); | |
| 700 | defer std.debug.unlockStdErr(); | |
| 701 | const stderr = run.stderr; | |
| 706 | const w = std.debug.lockStderrWriter(&stdio_buffer_allocation); | |
| 707 | defer std.debug.unlockStderrWriter(); | |
| 702 | 708 | |
| 703 | 709 | const total_count = success_count + failure_count + pending_count + skipped_count; |
| 704 | ttyconf.setColor(stderr, .cyan) catch {}; | |
| 705 | stderr.writeAll("Build Summary:") catch {}; | |
| 706 | ttyconf.setColor(stderr, .reset) catch {}; | |
| 707 | stderr.deprecatedWriter().print(" {d}/{d} steps succeeded", .{ success_count, total_count }) catch {}; | |
| 708 | if (skipped_count > 0) stderr.deprecatedWriter().print("; {d} skipped", .{skipped_count}) catch {}; | |
| 709 | if (failure_count > 0) stderr.deprecatedWriter().print("; {d} failed", .{failure_count}) catch {}; | |
| 710 | ||
| 711 | if (test_count > 0) stderr.deprecatedWriter().print("; {d}/{d} tests passed", .{ test_pass_count, test_count }) catch {}; | |
| 712 | if (test_skip_count > 0) stderr.deprecatedWriter().print("; {d} skipped", .{test_skip_count}) catch {}; | |
| 713 | if (test_fail_count > 0) stderr.deprecatedWriter().print("; {d} failed", .{test_fail_count}) catch {}; | |
| 714 | if (test_leak_count > 0) stderr.deprecatedWriter().print("; {d} leaked", .{test_leak_count}) catch {}; | |
| 715 | ||
| 716 | stderr.writeAll("\n") catch {}; | |
| 710 | ttyconf.setColor(w, .cyan) catch {}; | |
| 711 | w.writeAll("Build Summary:") catch {}; | |
| 712 | ttyconf.setColor(w, .reset) catch {}; | |
| 713 | w.print(" {d}/{d} steps succeeded", .{ success_count, total_count }) catch {}; | |
| 714 | if (skipped_count > 0) w.print("; {d} skipped", .{skipped_count}) catch {}; | |
| 715 | if (failure_count > 0) w.print("; {d} failed", .{failure_count}) catch {}; | |
| 716 | ||
| 717 | if (test_count > 0) w.print("; {d}/{d} tests passed", .{ test_pass_count, test_count }) catch {}; | |
| 718 | if (test_skip_count > 0) w.print("; {d} skipped", .{test_skip_count}) catch {}; | |
| 719 | if (test_fail_count > 0) w.print("; {d} failed", .{test_fail_count}) catch {}; | |
| 720 | if (test_leak_count > 0) w.print("; {d} leaked", .{test_leak_count}) catch {}; | |
| 717 | 721 | |
| 718 | 722 | // Print a fancy tree with build results. |
| 719 | 723 | var step_stack_copy = try step_stack.clone(gpa); |
| ... | ... | @@ -722,7 +726,7 @@ fn runStepNames( |
| 722 | 726 | var print_node: PrintNode = .{ .parent = null }; |
| 723 | 727 | if (step_names.len == 0) { |
| 724 | 728 | print_node.last = true; |
| 725 | printTreeStep(b, b.default_step, run, stderr, ttyconf, &print_node, &step_stack_copy) catch {}; | |
| 729 | printTreeStep(b, b.default_step, run, w, ttyconf, &print_node, &step_stack_copy) catch {}; | |
| 726 | 730 | } else { |
| 727 | 731 | const last_index = if (run.summary == .all) b.top_level_steps.count() else blk: { |
| 728 | 732 | var i: usize = step_names.len; |
| ... | ... | @@ -741,9 +745,10 @@ fn runStepNames( |
| 741 | 745 | for (step_names, 0..) |step_name, i| { |
| 742 | 746 | const tls = b.top_level_steps.get(step_name).?; |
| 743 | 747 | print_node.last = i + 1 == last_index; |
| 744 | printTreeStep(b, &tls.step, run, stderr, ttyconf, &print_node, &step_stack_copy) catch {}; | |
| 748 | printTreeStep(b, &tls.step, run, w, ttyconf, &print_node, &step_stack_copy) catch {}; | |
| 745 | 749 | } |
| 746 | 750 | } |
| 751 | w.writeByte('\n') catch {}; | |
| 747 | 752 | } |
| 748 | 753 | |
| 749 | 754 | if (failure_count == 0) { |
| ... | ... | @@ -775,7 +780,7 @@ const PrintNode = struct { |
| 775 | 780 | last: bool = false, |
| 776 | 781 | }; |
| 777 | 782 | |
| 778 | fn printPrefix(node: *PrintNode, stderr: File, ttyconf: std.io.tty.Config) !void { | |
| 783 | fn printPrefix(node: *PrintNode, stderr: *Writer, ttyconf: std.io.tty.Config) !void { | |
| 779 | 784 | const parent = node.parent orelse return; |
| 780 | 785 | if (parent.parent == null) return; |
| 781 | 786 | try printPrefix(parent, stderr, ttyconf); |
| ... | ... | @@ -789,7 +794,7 @@ fn printPrefix(node: *PrintNode, stderr: File, ttyconf: std.io.tty.Config) !void |
| 789 | 794 | } |
| 790 | 795 | } |
| 791 | 796 | |
| 792 | fn printChildNodePrefix(stderr: File, ttyconf: std.io.tty.Config) !void { | |
| 797 | fn printChildNodePrefix(stderr: *Writer, ttyconf: std.io.tty.Config) !void { | |
| 793 | 798 | try stderr.writeAll(switch (ttyconf) { |
| 794 | 799 | .no_color, .windows_api => "+- ", |
| 795 | 800 | .escape_codes => "\x1B\x28\x30\x6d\x71\x1B\x28\x42 ", // └─ |
| ... | ... | @@ -798,7 +803,7 @@ fn printChildNodePrefix(stderr: File, ttyconf: std.io.tty.Config) !void { |
| 798 | 803 | |
| 799 | 804 | fn printStepStatus( |
| 800 | 805 | s: *Step, |
| 801 | stderr: File, | |
| 806 | stderr: *Writer, | |
| 802 | 807 | ttyconf: std.io.tty.Config, |
| 803 | 808 | run: *const Run, |
| 804 | 809 | ) !void { |
| ... | ... | @@ -820,10 +825,10 @@ fn printStepStatus( |
| 820 | 825 | try stderr.writeAll(" cached"); |
| 821 | 826 | } else if (s.test_results.test_count > 0) { |
| 822 | 827 | const pass_count = s.test_results.passCount(); |
| 823 | try stderr.deprecatedWriter().print(" {d} passed", .{pass_count}); | |
| 828 | try stderr.print(" {d} passed", .{pass_count}); | |
| 824 | 829 | if (s.test_results.skip_count > 0) { |
| 825 | 830 | try ttyconf.setColor(stderr, .yellow); |
| 826 | try stderr.deprecatedWriter().print(" {d} skipped", .{s.test_results.skip_count}); | |
| 831 | try stderr.print(" {d} skipped", .{s.test_results.skip_count}); | |
| 827 | 832 | } |
| 828 | 833 | } else { |
| 829 | 834 | try stderr.writeAll(" success"); |
| ... | ... | @@ -832,15 +837,15 @@ fn printStepStatus( |
| 832 | 837 | if (s.result_duration_ns) |ns| { |
| 833 | 838 | try ttyconf.setColor(stderr, .dim); |
| 834 | 839 | if (ns >= std.time.ns_per_min) { |
| 835 | try stderr.deprecatedWriter().print(" {d}m", .{ns / std.time.ns_per_min}); | |
| 840 | try stderr.print(" {d}m", .{ns / std.time.ns_per_min}); | |
| 836 | 841 | } else if (ns >= std.time.ns_per_s) { |
| 837 | try stderr.deprecatedWriter().print(" {d}s", .{ns / std.time.ns_per_s}); | |
| 842 | try stderr.print(" {d}s", .{ns / std.time.ns_per_s}); | |
| 838 | 843 | } else if (ns >= std.time.ns_per_ms) { |
| 839 | try stderr.deprecatedWriter().print(" {d}ms", .{ns / std.time.ns_per_ms}); | |
| 844 | try stderr.print(" {d}ms", .{ns / std.time.ns_per_ms}); | |
| 840 | 845 | } else if (ns >= std.time.ns_per_us) { |
| 841 | try stderr.deprecatedWriter().print(" {d}us", .{ns / std.time.ns_per_us}); | |
| 846 | try stderr.print(" {d}us", .{ns / std.time.ns_per_us}); | |
| 842 | 847 | } else { |
| 843 | try stderr.deprecatedWriter().print(" {d}ns", .{ns}); | |
| 848 | try stderr.print(" {d}ns", .{ns}); | |
| 844 | 849 | } |
| 845 | 850 | try ttyconf.setColor(stderr, .reset); |
| 846 | 851 | } |
| ... | ... | @@ -848,13 +853,13 @@ fn printStepStatus( |
| 848 | 853 | const rss = s.result_peak_rss; |
| 849 | 854 | try ttyconf.setColor(stderr, .dim); |
| 850 | 855 | if (rss >= 1000_000_000) { |
| 851 | try stderr.deprecatedWriter().print(" MaxRSS:{d}G", .{rss / 1000_000_000}); | |
| 856 | try stderr.print(" MaxRSS:{d}G", .{rss / 1000_000_000}); | |
| 852 | 857 | } else if (rss >= 1000_000) { |
| 853 | try stderr.deprecatedWriter().print(" MaxRSS:{d}M", .{rss / 1000_000}); | |
| 858 | try stderr.print(" MaxRSS:{d}M", .{rss / 1000_000}); | |
| 854 | 859 | } else if (rss >= 1000) { |
| 855 | try stderr.deprecatedWriter().print(" MaxRSS:{d}K", .{rss / 1000}); | |
| 860 | try stderr.print(" MaxRSS:{d}K", .{rss / 1000}); | |
| 856 | 861 | } else { |
| 857 | try stderr.deprecatedWriter().print(" MaxRSS:{d}B", .{rss}); | |
| 862 | try stderr.print(" MaxRSS:{d}B", .{rss}); | |
| 858 | 863 | } |
| 859 | 864 | try ttyconf.setColor(stderr, .reset); |
| 860 | 865 | } |
| ... | ... | @@ -866,7 +871,7 @@ fn printStepStatus( |
| 866 | 871 | if (skip == .skipped_oom) { |
| 867 | 872 | try stderr.writeAll(" (not enough memory)"); |
| 868 | 873 | try ttyconf.setColor(stderr, .dim); |
| 869 | try stderr.deprecatedWriter().print(" upper bound of {d} exceeded runner limit ({d})", .{ s.max_rss, run.max_rss }); | |
| 874 | try stderr.print(" upper bound of {d} exceeded runner limit ({d})", .{ s.max_rss, run.max_rss }); | |
| 870 | 875 | try ttyconf.setColor(stderr, .yellow); |
| 871 | 876 | } |
| 872 | 877 | try stderr.writeAll("\n"); |
| ... | ... | @@ -878,23 +883,23 @@ fn printStepStatus( |
| 878 | 883 | |
| 879 | 884 | fn printStepFailure( |
| 880 | 885 | s: *Step, |
| 881 | stderr: File, | |
| 886 | stderr: *Writer, | |
| 882 | 887 | ttyconf: std.io.tty.Config, |
| 883 | 888 | ) !void { |
| 884 | 889 | if (s.result_error_bundle.errorMessageCount() > 0) { |
| 885 | 890 | try ttyconf.setColor(stderr, .red); |
| 886 | try stderr.deprecatedWriter().print(" {d} errors\n", .{ | |
| 891 | try stderr.print(" {d} errors\n", .{ | |
| 887 | 892 | s.result_error_bundle.errorMessageCount(), |
| 888 | 893 | }); |
| 889 | 894 | try ttyconf.setColor(stderr, .reset); |
| 890 | 895 | } else if (!s.test_results.isSuccess()) { |
| 891 | try stderr.deprecatedWriter().print(" {d}/{d} passed", .{ | |
| 896 | try stderr.print(" {d}/{d} passed", .{ | |
| 892 | 897 | s.test_results.passCount(), s.test_results.test_count, |
| 893 | 898 | }); |
| 894 | 899 | if (s.test_results.fail_count > 0) { |
| 895 | 900 | try stderr.writeAll(", "); |
| 896 | 901 | try ttyconf.setColor(stderr, .red); |
| 897 | try stderr.deprecatedWriter().print("{d} failed", .{ | |
| 902 | try stderr.print("{d} failed", .{ | |
| 898 | 903 | s.test_results.fail_count, |
| 899 | 904 | }); |
| 900 | 905 | try ttyconf.setColor(stderr, .reset); |
| ... | ... | @@ -902,7 +907,7 @@ fn printStepFailure( |
| 902 | 907 | if (s.test_results.skip_count > 0) { |
| 903 | 908 | try stderr.writeAll(", "); |
| 904 | 909 | try ttyconf.setColor(stderr, .yellow); |
| 905 | try stderr.deprecatedWriter().print("{d} skipped", .{ | |
| 910 | try stderr.print("{d} skipped", .{ | |
| 906 | 911 | s.test_results.skip_count, |
| 907 | 912 | }); |
| 908 | 913 | try ttyconf.setColor(stderr, .reset); |
| ... | ... | @@ -910,7 +915,7 @@ fn printStepFailure( |
| 910 | 915 | if (s.test_results.leak_count > 0) { |
| 911 | 916 | try stderr.writeAll(", "); |
| 912 | 917 | try ttyconf.setColor(stderr, .red); |
| 913 | try stderr.deprecatedWriter().print("{d} leaked", .{ | |
| 918 | try stderr.print("{d} leaked", .{ | |
| 914 | 919 | s.test_results.leak_count, |
| 915 | 920 | }); |
| 916 | 921 | try ttyconf.setColor(stderr, .reset); |
| ... | ... | @@ -932,7 +937,7 @@ fn printTreeStep( |
| 932 | 937 | b: *std.Build, |
| 933 | 938 | s: *Step, |
| 934 | 939 | run: *const Run, |
| 935 | stderr: File, | |
| 940 | stderr: *Writer, | |
| 936 | 941 | ttyconf: std.io.tty.Config, |
| 937 | 942 | parent_node: *PrintNode, |
| 938 | 943 | step_stack: *std.AutoArrayHashMapUnmanaged(*Step, void), |
| ... | ... | @@ -992,7 +997,7 @@ fn printTreeStep( |
| 992 | 997 | if (s.dependencies.items.len == 0) { |
| 993 | 998 | try stderr.writeAll(" (reused)\n"); |
| 994 | 999 | } else { |
| 995 | try stderr.deprecatedWriter().print(" (+{d} more reused dependencies)\n", .{ | |
| 1000 | try stderr.print(" (+{d} more reused dependencies)\n", .{ | |
| 996 | 1001 | s.dependencies.items.len, |
| 997 | 1002 | }); |
| 998 | 1003 | } |
| ... | ... | @@ -1129,11 +1134,11 @@ fn workerMakeOneStep( |
| 1129 | 1134 | const show_stderr = s.result_stderr.len > 0; |
| 1130 | 1135 | |
| 1131 | 1136 | if (show_error_msgs or show_compile_errors or show_stderr) { |
| 1132 | std.debug.lockStdErr(); | |
| 1133 | defer std.debug.unlockStdErr(); | |
| 1137 | const bw = std.debug.lockStderrWriter(&stdio_buffer_allocation); | |
| 1138 | defer std.debug.unlockStderrWriter(); | |
| 1134 | 1139 | |
| 1135 | 1140 | const gpa = b.allocator; |
| 1136 | printErrorMessages(gpa, s, .{ .ttyconf = run.ttyconf }, run.stderr, run.prominent_compile_errors) catch {}; | |
| 1141 | printErrorMessages(gpa, s, .{ .ttyconf = run.ttyconf }, bw, run.prominent_compile_errors) catch {}; | |
| 1137 | 1142 | } |
| 1138 | 1143 | |
| 1139 | 1144 | handle_result: { |
| ... | ... | @@ -1190,7 +1195,7 @@ pub fn printErrorMessages( |
| 1190 | 1195 | gpa: Allocator, |
| 1191 | 1196 | failing_step: *Step, |
| 1192 | 1197 | options: std.zig.ErrorBundle.RenderOptions, |
| 1193 | stderr: File, | |
| 1198 | stderr: *Writer, | |
| 1194 | 1199 | prominent_compile_errors: bool, |
| 1195 | 1200 | ) !void { |
| 1196 | 1201 | // Provide context for where these error messages are coming from by |
| ... | ... | @@ -1209,7 +1214,7 @@ pub fn printErrorMessages( |
| 1209 | 1214 | var indent: usize = 0; |
| 1210 | 1215 | while (step_stack.pop()) |s| : (indent += 1) { |
| 1211 | 1216 | if (indent > 0) { |
| 1212 | try stderr.deprecatedWriter().writeByteNTimes(' ', (indent - 1) * 3); | |
| 1217 | try stderr.splatByteAll(' ', (indent - 1) * 3); | |
| 1213 | 1218 | try printChildNodePrefix(stderr, ttyconf); |
| 1214 | 1219 | } |
| 1215 | 1220 | |
| ... | ... | @@ -1231,7 +1236,7 @@ pub fn printErrorMessages( |
| 1231 | 1236 | } |
| 1232 | 1237 | |
| 1233 | 1238 | if (!prominent_compile_errors and failing_step.result_error_bundle.errorMessageCount() > 0) { |
| 1234 | try failing_step.result_error_bundle.renderToWriter(options, stderr.deprecatedWriter()); | |
| 1239 | try failing_step.result_error_bundle.renderToWriter(options, stderr); | |
| 1235 | 1240 | } |
| 1236 | 1241 | |
| 1237 | 1242 | for (failing_step.result_error_msgs.items) |msg| { |
| ... | ... | @@ -1243,27 +1248,27 @@ pub fn printErrorMessages( |
| 1243 | 1248 | } |
| 1244 | 1249 | } |
| 1245 | 1250 | |
| 1246 | fn steps(builder: *std.Build, out_stream: anytype) !void { | |
| 1251 | fn printSteps(builder: *std.Build, w: *Writer) !void { | |
| 1247 | 1252 | const allocator = builder.allocator; |
| 1248 | 1253 | for (builder.top_level_steps.values()) |top_level_step| { |
| 1249 | 1254 | const name = if (&top_level_step.step == builder.default_step) |
| 1250 | 1255 | try fmt.allocPrint(allocator, "{s} (default)", .{top_level_step.step.name}) |
| 1251 | 1256 | else |
| 1252 | 1257 | top_level_step.step.name; |
| 1253 | try out_stream.print(" {s:<28} {s}\n", .{ name, top_level_step.description }); | |
| 1258 | try w.print(" {s:<28} {s}\n", .{ name, top_level_step.description }); | |
| 1254 | 1259 | } |
| 1255 | 1260 | } |
| 1256 | 1261 | |
| 1257 | fn usage(b: *std.Build, out_stream: anytype) !void { | |
| 1258 | try out_stream.print( | |
| 1262 | fn printUsage(b: *std.Build, w: *Writer) !void { | |
| 1263 | try w.print( | |
| 1259 | 1264 | \\Usage: {s} build [steps] [options] |
| 1260 | 1265 | \\ |
| 1261 | 1266 | \\Steps: |
| 1262 | 1267 | \\ |
| 1263 | 1268 | , .{b.graph.zig_exe}); |
| 1264 | try steps(b, out_stream); | |
| 1269 | try printSteps(b, w); | |
| 1265 | 1270 | |
| 1266 | try out_stream.writeAll( | |
| 1271 | try w.writeAll( | |
| 1267 | 1272 | \\ |
| 1268 | 1273 | \\General Options: |
| 1269 | 1274 | \\ -p, --prefix [path] Where to install files (default: zig-out) |
| ... | ... | @@ -1319,25 +1324,25 @@ fn usage(b: *std.Build, out_stream: anytype) !void { |
| 1319 | 1324 | |
| 1320 | 1325 | const arena = b.allocator; |
| 1321 | 1326 | if (b.available_options_list.items.len == 0) { |
| 1322 | try out_stream.print(" (none)\n", .{}); | |
| 1327 | try w.print(" (none)\n", .{}); | |
| 1323 | 1328 | } else { |
| 1324 | 1329 | for (b.available_options_list.items) |option| { |
| 1325 | 1330 | const name = try fmt.allocPrint(arena, " -D{s}=[{s}]", .{ |
| 1326 | 1331 | option.name, |
| 1327 | 1332 | @tagName(option.type_id), |
| 1328 | 1333 | }); |
| 1329 | try out_stream.print("{s:<30} {s}\n", .{ name, option.description }); | |
| 1334 | try w.print("{s:<30} {s}\n", .{ name, option.description }); | |
| 1330 | 1335 | if (option.enum_options) |enum_options| { |
| 1331 | 1336 | const padding = " " ** 33; |
| 1332 | try out_stream.writeAll(padding ++ "Supported Values:\n"); | |
| 1337 | try w.writeAll(padding ++ "Supported Values:\n"); | |
| 1333 | 1338 | for (enum_options) |enum_option| { |
| 1334 | try out_stream.print(padding ++ " {s}\n", .{enum_option}); | |
| 1339 | try w.print(padding ++ " {s}\n", .{enum_option}); | |
| 1335 | 1340 | } |
| 1336 | 1341 | } |
| 1337 | 1342 | } |
| 1338 | 1343 | } |
| 1339 | 1344 | |
| 1340 | try out_stream.writeAll( | |
| 1345 | try w.writeAll( | |
| 1341 | 1346 | \\ |
| 1342 | 1347 | \\System Integration Options: |
| 1343 | 1348 | \\ --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 { |
| 1352 | 1357 | \\ |
| 1353 | 1358 | ); |
| 1354 | 1359 | if (b.graph.system_library_options.entries.len == 0) { |
| 1355 | try out_stream.writeAll(" (none) -\n"); | |
| 1360 | try w.writeAll(" (none) -\n"); | |
| 1356 | 1361 | } else { |
| 1357 | 1362 | for (b.graph.system_library_options.keys(), b.graph.system_library_options.values()) |k, v| { |
| 1358 | 1363 | const status = switch (v) { |
| ... | ... | @@ -1360,11 +1365,11 @@ fn usage(b: *std.Build, out_stream: anytype) !void { |
| 1360 | 1365 | .declared_disabled => "no", |
| 1361 | 1366 | .user_enabled, .user_disabled => unreachable, // already emitted error |
| 1362 | 1367 | }; |
| 1363 | try out_stream.print(" {s:<43} {s}\n", .{ k, status }); | |
| 1368 | try w.print(" {s:<43} {s}\n", .{ k, status }); | |
| 1364 | 1369 | } |
| 1365 | 1370 | } |
| 1366 | 1371 | |
| 1367 | try out_stream.writeAll( | |
| 1372 | try w.writeAll( | |
| 1368 | 1373 | \\ |
| 1369 | 1374 | \\Advanced Options: |
| 1370 | 1375 | \\ -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 { |
| 1544 | 1549 | }; |
| 1545 | 1550 | } |
| 1546 | 1551 | } |
| 1552 | ||
| 1553 | var stdio_buffer_allocation: [256]u8 = undefined; | |
| 1554 | var stdout_writer_allocation: std.fs.File.Writer = undefined; | |
| 1555 | ||
| 1556 | fn initStdoutWriter() *Writer { | |
| 1557 | stdout_writer_allocation = std.fs.File.stdout().writerStreaming(&stdio_buffer_allocation); | |
| 1558 | return &stdout_writer_allocation.interface; | |
| 1559 | } |
lib/std/Build.zig+31-41| ... | ... | @@ -284,7 +284,7 @@ pub fn create( |
| 284 | 284 | .h_dir = undefined, |
| 285 | 285 | .dest_dir = graph.env_map.get("DESTDIR"), |
| 286 | 286 | .install_tls = .{ |
| 287 | .step = Step.init(.{ | |
| 287 | .step = .init(.{ | |
| 288 | 288 | .id = TopLevelStep.base_id, |
| 289 | 289 | .name = "install", |
| 290 | 290 | .owner = b, |
| ... | ... | @@ -292,7 +292,7 @@ pub fn create( |
| 292 | 292 | .description = "Copy build artifacts to prefix path", |
| 293 | 293 | }, |
| 294 | 294 | .uninstall_tls = .{ |
| 295 | .step = Step.init(.{ | |
| 295 | .step = .init(.{ | |
| 296 | 296 | .id = TopLevelStep.base_id, |
| 297 | 297 | .name = "uninstall", |
| 298 | 298 | .owner = b, |
| ... | ... | @@ -342,7 +342,7 @@ fn createChildOnly( |
| 342 | 342 | .graph = parent.graph, |
| 343 | 343 | .allocator = allocator, |
| 344 | 344 | .install_tls = .{ |
| 345 | .step = Step.init(.{ | |
| 345 | .step = .init(.{ | |
| 346 | 346 | .id = TopLevelStep.base_id, |
| 347 | 347 | .name = "install", |
| 348 | 348 | .owner = child, |
| ... | ... | @@ -350,7 +350,7 @@ fn createChildOnly( |
| 350 | 350 | .description = "Copy build artifacts to prefix path", |
| 351 | 351 | }, |
| 352 | 352 | .uninstall_tls = .{ |
| 353 | .step = Step.init(.{ | |
| 353 | .step = .init(.{ | |
| 354 | 354 | .id = TopLevelStep.base_id, |
| 355 | 355 | .name = "uninstall", |
| 356 | 356 | .owner = child, |
| ... | ... | @@ -1525,7 +1525,7 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw |
| 1525 | 1525 | pub fn step(b: *Build, name: []const u8, description: []const u8) *Step { |
| 1526 | 1526 | const step_info = b.allocator.create(TopLevelStep) catch @panic("OOM"); |
| 1527 | 1527 | step_info.* = .{ |
| 1528 | .step = Step.init(.{ | |
| 1528 | .step = .init(.{ | |
| 1529 | 1529 | .id = TopLevelStep.base_id, |
| 1530 | 1530 | .name = name, |
| 1531 | 1531 | .owner = b, |
| ... | ... | @@ -1824,13 +1824,13 @@ pub fn validateUserInputDidItFail(b: *Build) bool { |
| 1824 | 1824 | return b.invalid_user_input; |
| 1825 | 1825 | } |
| 1826 | 1826 | |
| 1827 | fn allocPrintCmd(ally: Allocator, opt_cwd: ?[]const u8, argv: []const []const u8) error{OutOfMemory}![]u8 { | |
| 1828 | var buf = ArrayList(u8).init(ally); | |
| 1829 | if (opt_cwd) |cwd| try buf.writer().print("cd {s} && ", .{cwd}); | |
| 1827 | fn allocPrintCmd(gpa: Allocator, opt_cwd: ?[]const u8, argv: []const []const u8) error{OutOfMemory}![]u8 { | |
| 1828 | var buf: std.ArrayListUnmanaged(u8) = .empty; | |
| 1829 | if (opt_cwd) |cwd| try buf.print(gpa, "cd {s} && ", .{cwd}); | |
| 1830 | 1830 | for (argv) |arg| { |
| 1831 | try buf.writer().print("{s} ", .{arg}); | |
| 1831 | try buf.print(gpa, "{s} ", .{arg}); | |
| 1832 | 1832 | } |
| 1833 | return buf.toOwnedSlice(); | |
| 1833 | return buf.toOwnedSlice(gpa); | |
| 1834 | 1834 | } |
| 1835 | 1835 | |
| 1836 | 1836 | fn printCmd(ally: Allocator, cwd: ?[]const u8, argv: []const []const u8) void { |
| ... | ... | @@ -2466,10 +2466,9 @@ pub const GeneratedFile = struct { |
| 2466 | 2466 | |
| 2467 | 2467 | pub fn getPath2(gen: GeneratedFile, src_builder: *Build, asking_step: ?*Step) []const u8 { |
| 2468 | 2468 | return gen.path orelse { |
| 2469 | std.debug.lockStdErr(); | |
| 2470 | const stderr = std.fs.File.stderr(); | |
| 2471 | dumpBadGetPathHelp(gen.step, stderr, src_builder, asking_step) catch {}; | |
| 2472 | std.debug.unlockStdErr(); | |
| 2469 | const w = debug.lockStderrWriter(&.{}); | |
| 2470 | dumpBadGetPathHelp(gen.step, w, .detect(.stderr()), src_builder, asking_step) catch {}; | |
| 2471 | debug.unlockStderrWriter(); | |
| 2473 | 2472 | @panic("misconfigured build script"); |
| 2474 | 2473 | }; |
| 2475 | 2474 | } |
| ... | ... | @@ -2676,10 +2675,9 @@ pub const LazyPath = union(enum) { |
| 2676 | 2675 | var file_path: Cache.Path = .{ |
| 2677 | 2676 | .root_dir = Cache.Directory.cwd(), |
| 2678 | 2677 | .sub_path = gen.file.path orelse { |
| 2679 | std.debug.lockStdErr(); | |
| 2680 | const stderr: fs.File = .stderr(); | |
| 2681 | dumpBadGetPathHelp(gen.file.step, stderr, src_builder, asking_step) catch {}; | |
| 2682 | std.debug.unlockStdErr(); | |
| 2678 | const w = debug.lockStderrWriter(&.{}); | |
| 2679 | dumpBadGetPathHelp(gen.file.step, w, .detect(.stderr()), src_builder, asking_step) catch {}; | |
| 2680 | debug.unlockStderrWriter(); | |
| 2683 | 2681 | @panic("misconfigured build script"); |
| 2684 | 2682 | }, |
| 2685 | 2683 | }; |
| ... | ... | @@ -2766,44 +2764,42 @@ fn dumpBadDirnameHelp( |
| 2766 | 2764 | comptime msg: []const u8, |
| 2767 | 2765 | args: anytype, |
| 2768 | 2766 | ) anyerror!void { |
| 2769 | debug.lockStdErr(); | |
| 2770 | defer debug.unlockStdErr(); | |
| 2767 | const w = debug.lockStderrWriter(&.{}); | |
| 2768 | defer debug.unlockStderrWriter(); | |
| 2771 | 2769 | |
| 2772 | const stderr: fs.File = .stderr(); | |
| 2773 | const w = stderr.deprecatedWriter(); | |
| 2774 | 2770 | try w.print(msg, args); |
| 2775 | 2771 | |
| 2776 | const tty_config = std.io.tty.detectConfig(stderr); | |
| 2772 | const tty_config = std.io.tty.detectConfig(.stderr()); | |
| 2777 | 2773 | |
| 2778 | 2774 | if (fail_step) |s| { |
| 2779 | 2775 | tty_config.setColor(w, .red) catch {}; |
| 2780 | try stderr.writeAll(" The step was created by this stack trace:\n"); | |
| 2776 | try w.writeAll(" The step was created by this stack trace:\n"); | |
| 2781 | 2777 | tty_config.setColor(w, .reset) catch {}; |
| 2782 | 2778 | |
| 2783 | s.dump(stderr); | |
| 2779 | s.dump(w, tty_config); | |
| 2784 | 2780 | } |
| 2785 | 2781 | |
| 2786 | 2782 | if (asking_step) |as| { |
| 2787 | 2783 | tty_config.setColor(w, .red) catch {}; |
| 2788 | 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}); | |
| 2784 | try w.print(" The step '{s}' that is missing a dependency on the above step was created by this stack trace:\n", .{as.name}); | |
| 2789 | 2785 | tty_config.setColor(w, .reset) catch {}; |
| 2790 | 2786 | |
| 2791 | as.dump(stderr); | |
| 2787 | as.dump(w, tty_config); | |
| 2792 | 2788 | } |
| 2793 | 2789 | |
| 2794 | 2790 | tty_config.setColor(w, .red) catch {}; |
| 2795 | try stderr.writeAll(" Hope that helps. Proceeding to panic.\n"); | |
| 2791 | try w.writeAll(" Hope that helps. Proceeding to panic.\n"); | |
| 2796 | 2792 | tty_config.setColor(w, .reset) catch {}; |
| 2797 | 2793 | } |
| 2798 | 2794 | |
| 2799 | 2795 | /// In this function the stderr mutex has already been locked. |
| 2800 | 2796 | pub fn dumpBadGetPathHelp( |
| 2801 | 2797 | s: *Step, |
| 2802 | stderr: fs.File, | |
| 2798 | w: *std.io.Writer, | |
| 2799 | tty_config: std.io.tty.Config, | |
| 2803 | 2800 | src_builder: *Build, |
| 2804 | 2801 | asking_step: ?*Step, |
| 2805 | 2802 | ) anyerror!void { |
| 2806 | const w = stderr.deprecatedWriter(); | |
| 2807 | 2803 | try w.print( |
| 2808 | 2804 | \\getPath() was called on a GeneratedFile that wasn't built yet. |
| 2809 | 2805 | \\ source package path: {s} |
| ... | ... | @@ -2814,21 +2810,20 @@ pub fn dumpBadGetPathHelp( |
| 2814 | 2810 | s.name, |
| 2815 | 2811 | }); |
| 2816 | 2812 | |
| 2817 | const tty_config = std.io.tty.detectConfig(stderr); | |
| 2818 | 2813 | tty_config.setColor(w, .red) catch {}; |
| 2819 | try stderr.writeAll(" The step was created by this stack trace:\n"); | |
| 2814 | try w.writeAll(" The step was created by this stack trace:\n"); | |
| 2820 | 2815 | tty_config.setColor(w, .reset) catch {}; |
| 2821 | 2816 | |
| 2822 | s.dump(stderr); | |
| 2817 | s.dump(w, tty_config); | |
| 2823 | 2818 | if (asking_step) |as| { |
| 2824 | 2819 | tty_config.setColor(w, .red) catch {}; |
| 2825 | 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}); | |
| 2820 | try w.print(" The step '{s}' that is missing a dependency on the above step was created by this stack trace:\n", .{as.name}); | |
| 2826 | 2821 | tty_config.setColor(w, .reset) catch {}; |
| 2827 | 2822 | |
| 2828 | as.dump(stderr); | |
| 2823 | as.dump(w, tty_config); | |
| 2829 | 2824 | } |
| 2830 | 2825 | tty_config.setColor(w, .red) catch {}; |
| 2831 | try stderr.writeAll(" Hope that helps. Proceeding to panic.\n"); | |
| 2826 | try w.writeAll(" Hope that helps. Proceeding to panic.\n"); | |
| 2832 | 2827 | tty_config.setColor(w, .reset) catch {}; |
| 2833 | 2828 | } |
| 2834 | 2829 | |
| ... | ... | @@ -2866,11 +2861,6 @@ pub fn makeTempPath(b: *Build) []const u8 { |
| 2866 | 2861 | return result_path; |
| 2867 | 2862 | } |
| 2868 | 2863 | |
| 2869 | /// Deprecated; use `std.fmt.hex` instead. | |
| 2870 | pub fn hex64(x: u64) [16]u8 { | |
| 2871 | return std.fmt.hex(x); | |
| 2872 | } | |
| 2873 | ||
| 2874 | 2864 | /// A pair of target query and fully resolved target. |
| 2875 | 2865 | /// This type is generally required by build system API that need to be given a |
| 2876 | 2866 | /// target. The query is kept because the Zig toolchain needs to know which parts |
lib/std/Build/Fuzz.zig+8-8| ... | ... | @@ -112,7 +112,6 @@ fn rebuildTestsWorkerRun(run: *Step.Run, ttyconf: std.io.tty.Config, parent_prog |
| 112 | 112 | |
| 113 | 113 | fn rebuildTestsWorkerRunFallible(run: *Step.Run, ttyconf: std.io.tty.Config, parent_prog_node: std.Progress.Node) !void { |
| 114 | 114 | const gpa = run.step.owner.allocator; |
| 115 | const stderr = std.fs.File.stderr(); | |
| 116 | 115 | |
| 117 | 116 | const compile = run.producer.?; |
| 118 | 117 | 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 |
| 125 | 124 | const show_stderr = compile.step.result_stderr.len > 0; |
| 126 | 125 | |
| 127 | 126 | if (show_error_msgs or show_compile_errors or show_stderr) { |
| 128 | std.debug.lockStdErr(); | |
| 129 | defer std.debug.unlockStdErr(); | |
| 130 | build_runner.printErrorMessages(gpa, &compile.step, .{ .ttyconf = ttyconf }, stderr, false) catch {}; | |
| 127 | var buf: [256]u8 = undefined; | |
| 128 | const w = std.debug.lockStderrWriter(&buf); | |
| 129 | defer std.debug.unlockStderrWriter(); | |
| 130 | build_runner.printErrorMessages(gpa, &compile.step, .{ .ttyconf = ttyconf }, w, false) catch {}; | |
| 131 | 131 | } |
| 132 | 132 | |
| 133 | 133 | const rebuilt_bin_path = result catch |err| switch (err) { |
| ... | ... | @@ -152,10 +152,10 @@ fn fuzzWorkerRun( |
| 152 | 152 | |
| 153 | 153 | run.rerunInFuzzMode(web_server, unit_test_index, prog_node) catch |err| switch (err) { |
| 154 | 154 | error.MakeFailed => { |
| 155 | const stderr = std.fs.File.stderr(); | |
| 156 | std.debug.lockStdErr(); | |
| 157 | defer std.debug.unlockStdErr(); | |
| 158 | build_runner.printErrorMessages(gpa, &run.step, .{ .ttyconf = ttyconf }, stderr, false) catch {}; | |
| 155 | var buf: [256]u8 = undefined; | |
| 156 | const w = std.debug.lockStderrWriter(&buf); | |
| 157 | defer std.debug.unlockStderrWriter(); | |
| 158 | build_runner.printErrorMessages(gpa, &run.step, .{ .ttyconf = ttyconf }, w, false) catch {}; | |
| 159 | 159 | return; |
| 160 | 160 | }, |
| 161 | 161 | else => { |
lib/std/Build/Step.zig+1-4| ... | ... | @@ -286,10 +286,7 @@ pub fn cast(step: *Step, comptime T: type) ?*T { |
| 286 | 286 | } |
| 287 | 287 | |
| 288 | 288 | /// For debugging purposes, prints identifying information about this Step. |
| 289 | pub fn dump(step: *Step, file: std.fs.File) void { | |
| 290 | var fw = file.writer(&.{}); | |
| 291 | const w = &fw.interface; | |
| 292 | const tty_config = std.io.tty.detectConfig(file); | |
| 289 | pub fn dump(step: *Step, w: *std.io.Writer, tty_config: std.io.tty.Config) void { | |
| 293 | 290 | const debug_info = std.debug.getSelfDebugInfo() catch |err| { |
| 294 | 291 | w.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{ |
| 295 | 292 | @errorName(err), |
lib/std/Build/Step/Compile.zig+30-31| ... | ... | @@ -409,7 +409,7 @@ pub fn create(owner: *std.Build, options: Options) *Compile { |
| 409 | 409 | .linkage = options.linkage, |
| 410 | 410 | .kind = options.kind, |
| 411 | 411 | .name = name, |
| 412 | .step = Step.init(.{ | |
| 412 | .step = .init(.{ | |
| 413 | 413 | .id = base_id, |
| 414 | 414 | .name = step_name, |
| 415 | 415 | .owner = owner, |
| ... | ... | @@ -1017,20 +1017,16 @@ fn getGeneratedFilePath(compile: *Compile, comptime tag_name: []const u8, asking |
| 1017 | 1017 | const maybe_path: ?*GeneratedFile = @field(compile, tag_name); |
| 1018 | 1018 | |
| 1019 | 1019 | const generated_file = maybe_path orelse { |
| 1020 | std.debug.lockStdErr(); | |
| 1021 | const stderr: fs.File = .stderr(); | |
| 1022 | ||
| 1023 | std.Build.dumpBadGetPathHelp(&compile.step, stderr, compile.step.owner, asking_step) catch {}; | |
| 1024 | ||
| 1020 | const w = std.debug.lockStderrWriter(&.{}); | |
| 1021 | std.Build.dumpBadGetPathHelp(&compile.step, w, .detect(.stderr()), compile.step.owner, asking_step) catch {}; | |
| 1022 | std.debug.unlockStderrWriter(); | |
| 1025 | 1023 | @panic("missing emit option for " ++ tag_name); |
| 1026 | 1024 | }; |
| 1027 | 1025 | |
| 1028 | 1026 | const path = generated_file.path orelse { |
| 1029 | std.debug.lockStdErr(); | |
| 1030 | const stderr: fs.File = .stderr(); | |
| 1031 | ||
| 1032 | std.Build.dumpBadGetPathHelp(&compile.step, stderr, compile.step.owner, asking_step) catch {}; | |
| 1033 | ||
| 1027 | const w = std.debug.lockStderrWriter(&.{}); | |
| 1028 | std.Build.dumpBadGetPathHelp(&compile.step, w, .detect(.stderr()), compile.step.owner, asking_step) catch {}; | |
| 1029 | std.debug.unlockStderrWriter(); | |
| 1034 | 1030 | @panic(tag_name ++ " is null. Is there a missing step dependency?"); |
| 1035 | 1031 | }; |
| 1036 | 1032 | |
| ... | ... | @@ -1768,12 +1764,12 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 { |
| 1768 | 1764 | for (arg, 0..) |c, arg_idx| { |
| 1769 | 1765 | if (c == '\\' or c == '"') { |
| 1770 | 1766 | // Slow path for arguments that need to be escaped. We'll need to allocate and copy |
| 1771 | var escaped = try ArrayList(u8).initCapacity(arena, arg.len + 1); | |
| 1772 | const writer = escaped.writer(); | |
| 1773 | try writer.writeAll(arg[0..arg_idx]); | |
| 1767 | var escaped: std.ArrayListUnmanaged(u8) = .empty; | |
| 1768 | try escaped.ensureTotalCapacityPrecise(arena, arg.len + 1); | |
| 1769 | try escaped.appendSlice(arena, arg[0..arg_idx]); | |
| 1774 | 1770 | for (arg[arg_idx..]) |to_escape| { |
| 1775 | if (to_escape == '\\' or to_escape == '"') try writer.writeByte('\\'); | |
| 1776 | try writer.writeByte(to_escape); | |
| 1771 | if (to_escape == '\\' or to_escape == '"') try escaped.append(arena, '\\'); | |
| 1772 | try escaped.append(arena, to_escape); | |
| 1777 | 1773 | } |
| 1778 | 1774 | escaped_args.appendAssumeCapacity(escaped.items); |
| 1779 | 1775 | continue :arg_blk; |
| ... | ... | @@ -1963,20 +1959,23 @@ fn addFlag(args: *ArrayList([]const u8), comptime name: []const u8, opt: ?bool) |
| 1963 | 1959 | fn checkCompileErrors(compile: *Compile) !void { |
| 1964 | 1960 | // Clear this field so that it does not get printed by the build runner. |
| 1965 | 1961 | const actual_eb = compile.step.result_error_bundle; |
| 1966 | compile.step.result_error_bundle = std.zig.ErrorBundle.empty; | |
| 1962 | compile.step.result_error_bundle = .empty; | |
| 1967 | 1963 | |
| 1968 | 1964 | const arena = compile.step.owner.allocator; |
| 1969 | 1965 | |
| 1970 | var actual_errors_list = std.ArrayList(u8).init(arena); | |
| 1971 | try actual_eb.renderToWriter(.{ | |
| 1972 | .ttyconf = .no_color, | |
| 1973 | .include_reference_trace = false, | |
| 1974 | .include_source_line = false, | |
| 1975 | }, actual_errors_list.writer()); | |
| 1976 | const actual_errors = try actual_errors_list.toOwnedSlice(); | |
| 1966 | const actual_errors = ae: { | |
| 1967 | var aw: std.io.Writer.Allocating = .init(arena); | |
| 1968 | defer aw.deinit(); | |
| 1969 | try actual_eb.renderToWriter(.{ | |
| 1970 | .ttyconf = .no_color, | |
| 1971 | .include_reference_trace = false, | |
| 1972 | .include_source_line = false, | |
| 1973 | }, &aw.writer); | |
| 1974 | break :ae try aw.toOwnedSlice(); | |
| 1975 | }; | |
| 1977 | 1976 | |
| 1978 | 1977 | // Render the expected lines into a string that we can compare verbatim. |
| 1979 | var expected_generated = std.ArrayList(u8).init(arena); | |
| 1978 | var expected_generated: std.ArrayListUnmanaged(u8) = .empty; | |
| 1980 | 1979 | const expect_errors = compile.expect_errors.?; |
| 1981 | 1980 | |
| 1982 | 1981 | var actual_line_it = mem.splitScalar(u8, actual_errors, '\n'); |
| ... | ... | @@ -2035,17 +2034,17 @@ fn checkCompileErrors(compile: *Compile) !void { |
| 2035 | 2034 | .exact => |expect_lines| { |
| 2036 | 2035 | for (expect_lines) |expect_line| { |
| 2037 | 2036 | const actual_line = actual_line_it.next() orelse { |
| 2038 | try expected_generated.appendSlice(expect_line); | |
| 2039 | try expected_generated.append('\n'); | |
| 2037 | try expected_generated.appendSlice(arena, expect_line); | |
| 2038 | try expected_generated.append(arena, '\n'); | |
| 2040 | 2039 | continue; |
| 2041 | 2040 | }; |
| 2042 | 2041 | if (matchCompileError(actual_line, expect_line)) { |
| 2043 | try expected_generated.appendSlice(actual_line); | |
| 2044 | try expected_generated.append('\n'); | |
| 2042 | try expected_generated.appendSlice(arena, actual_line); | |
| 2043 | try expected_generated.append(arena, '\n'); | |
| 2045 | 2044 | continue; |
| 2046 | 2045 | } |
| 2047 | try expected_generated.appendSlice(expect_line); | |
| 2048 | try expected_generated.append('\n'); | |
| 2046 | try expected_generated.appendSlice(arena, expect_line); | |
| 2047 | try expected_generated.append(arena, '\n'); | |
| 2049 | 2048 | } |
| 2050 | 2049 | |
| 2051 | 2050 | if (mem.eql(u8, expected_generated.items, actual_errors)) return; |
lib/std/fs/File.zig-4| ... | ... | @@ -1725,10 +1725,6 @@ pub const Writer = struct { |
| 1725 | 1725 | iovecs[len] = .{ .base = splat_buffer.ptr, .len = remaining_splat }; |
| 1726 | 1726 | len += 1; |
| 1727 | 1727 | } |
| 1728 | return std.posix.writev(handle, iovecs[0..len]) catch |err| { | |
| 1729 | w.err = err; | |
| 1730 | return error.WriteFailed; | |
| 1731 | }; | |
| 1732 | 1728 | }, |
| 1733 | 1729 | else => for (0..splat - 1) |_| { |
| 1734 | 1730 | if (iovecs.len - len == 0) break; |
lib/std/io/tty.zig+35-29| ... | ... | @@ -5,36 +5,9 @@ const process = std.process; |
| 5 | 5 | const windows = std.os.windows; |
| 6 | 6 | const native_os = builtin.os.tag; |
| 7 | 7 | |
| 8 | /// Detect suitable TTY configuration options for the given file (commonly stdout/stderr). | |
| 9 | /// This includes feature checks for ANSI escape codes and the Windows console API, as well as | |
| 10 | /// respecting the `NO_COLOR` and `CLICOLOR_FORCE` environment variables to override the default. | |
| 11 | /// Will attempt to enable ANSI escape code support if necessary/possible. | |
| 8 | /// Deprecated in favor of `Config.detect`. | |
| 12 | 9 | pub fn detectConfig(file: File) Config { |
| 13 | const force_color: ?bool = if (builtin.os.tag == .wasi) | |
| 14 | null // wasi does not support environment variables | |
| 15 | else if (process.hasNonEmptyEnvVarConstant("NO_COLOR")) | |
| 16 | false | |
| 17 | else if (process.hasNonEmptyEnvVarConstant("CLICOLOR_FORCE")) | |
| 18 | true | |
| 19 | else | |
| 20 | null; | |
| 21 | ||
| 22 | if (force_color == false) return .no_color; | |
| 23 | ||
| 24 | if (file.getOrEnableAnsiEscapeSupport()) return .escape_codes; | |
| 25 | ||
| 26 | if (native_os == .windows and file.isTty()) { | |
| 27 | var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined; | |
| 28 | if (windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) == windows.FALSE) { | |
| 29 | return if (force_color == true) .escape_codes else .no_color; | |
| 30 | } | |
| 31 | return .{ .windows_api = .{ | |
| 32 | .handle = file.handle, | |
| 33 | .reset_attributes = info.wAttributes, | |
| 34 | } }; | |
| 35 | } | |
| 36 | ||
| 37 | return if (force_color == true) .escape_codes else .no_color; | |
| 10 | return .detect(file); | |
| 38 | 11 | } |
| 39 | 12 | |
| 40 | 13 | pub const Color = enum { |
| ... | ... | @@ -66,6 +39,38 @@ pub const Config = union(enum) { |
| 66 | 39 | escape_codes, |
| 67 | 40 | windows_api: if (native_os == .windows) WindowsContext else void, |
| 68 | 41 | |
| 42 | /// Detect suitable TTY configuration options for the given file (commonly stdout/stderr). | |
| 43 | /// This includes feature checks for ANSI escape codes and the Windows console API, as well as | |
| 44 | /// respecting the `NO_COLOR` and `CLICOLOR_FORCE` environment variables to override the default. | |
| 45 | /// Will attempt to enable ANSI escape code support if necessary/possible. | |
| 46 | pub fn detect(file: File) Config { | |
| 47 | const force_color: ?bool = if (builtin.os.tag == .wasi) | |
| 48 | null // wasi does not support environment variables | |
| 49 | else if (process.hasNonEmptyEnvVarConstant("NO_COLOR")) | |
| 50 | false | |
| 51 | else if (process.hasNonEmptyEnvVarConstant("CLICOLOR_FORCE")) | |
| 52 | true | |
| 53 | else | |
| 54 | null; | |
| 55 | ||
| 56 | if (force_color == false) return .no_color; | |
| 57 | ||
| 58 | if (file.getOrEnableAnsiEscapeSupport()) return .escape_codes; | |
| 59 | ||
| 60 | if (native_os == .windows and file.isTty()) { | |
| 61 | var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined; | |
| 62 | if (windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) == windows.FALSE) { | |
| 63 | return if (force_color == true) .escape_codes else .no_color; | |
| 64 | } | |
| 65 | return .{ .windows_api = .{ | |
| 66 | .handle = file.handle, | |
| 67 | .reset_attributes = info.wAttributes, | |
| 68 | } }; | |
| 69 | } | |
| 70 | ||
| 71 | return if (force_color == true) .escape_codes else .no_color; | |
| 72 | } | |
| 73 | ||
| 69 | 74 | pub const WindowsContext = struct { |
| 70 | 75 | handle: File.Handle, |
| 71 | 76 | reset_attributes: u16, |
| ... | ... | @@ -123,6 +128,7 @@ pub const Config = union(enum) { |
| 123 | 128 | .dim => windows.FOREGROUND_INTENSITY, |
| 124 | 129 | .reset => ctx.reset_attributes, |
| 125 | 130 | }; |
| 131 | try w.flush(); | |
| 126 | 132 | try windows.SetConsoleTextAttribute(ctx.handle, attributes); |
| 127 | 133 | } else { |
| 128 | 134 | unreachable; |
lib/std/zig/ErrorBundle.zig+68-66| ... | ... | @@ -11,6 +11,7 @@ const std = @import("std"); |
| 11 | 11 | const ErrorBundle = @This(); |
| 12 | 12 | const Allocator = std.mem.Allocator; |
| 13 | 13 | const assert = std.debug.assert; |
| 14 | const Writer = std.io.Writer; | |
| 14 | 15 | |
| 15 | 16 | string_bytes: []const u8, |
| 16 | 17 | /// The first thing in this array is an `ErrorMessageList`. |
| ... | ... | @@ -162,23 +163,23 @@ pub const RenderOptions = struct { |
| 162 | 163 | }; |
| 163 | 164 | |
| 164 | 165 | pub fn renderToStdErr(eb: ErrorBundle, options: RenderOptions) void { |
| 165 | std.debug.lockStdErr(); | |
| 166 | defer std.debug.unlockStdErr(); | |
| 167 | const stderr: std.fs.File = .stderr(); | |
| 168 | return renderToWriter(eb, options, stderr.deprecatedWriter()) catch return; | |
| 166 | var buffer: [256]u8 = undefined; | |
| 167 | const w = std.debug.lockStderrWriter(&buffer); | |
| 168 | defer std.debug.unlockStderrWriter(); | |
| 169 | renderToWriter(eb, options, w) catch return; | |
| 169 | 170 | } |
| 170 | 171 | |
| 171 | pub fn renderToWriter(eb: ErrorBundle, options: RenderOptions, writer: anytype) anyerror!void { | |
| 172 | pub fn renderToWriter(eb: ErrorBundle, options: RenderOptions, w: *Writer) (Writer.Error || std.posix.UnexpectedError)!void { | |
| 172 | 173 | if (eb.extra.len == 0) return; |
| 173 | 174 | for (eb.getMessages()) |err_msg| { |
| 174 | try renderErrorMessageToWriter(eb, options, err_msg, writer, "error", .red, 0); | |
| 175 | try renderErrorMessageToWriter(eb, options, err_msg, w, "error", .red, 0); | |
| 175 | 176 | } |
| 176 | 177 | |
| 177 | 178 | if (options.include_log_text) { |
| 178 | 179 | const log_text = eb.getCompileLogOutput(); |
| 179 | 180 | if (log_text.len != 0) { |
| 180 | try writer.writeAll("\nCompile Log Output:\n"); | |
| 181 | try writer.writeAll(log_text); | |
| 181 | try w.writeAll("\nCompile Log Output:\n"); | |
| 182 | try w.writeAll(log_text); | |
| 182 | 183 | } |
| 183 | 184 | } |
| 184 | 185 | } |
| ... | ... | @@ -187,74 +188,73 @@ fn renderErrorMessageToWriter( |
| 187 | 188 | eb: ErrorBundle, |
| 188 | 189 | options: RenderOptions, |
| 189 | 190 | err_msg_index: MessageIndex, |
| 190 | stderr: anytype, | |
| 191 | w: *Writer, | |
| 191 | 192 | kind: []const u8, |
| 192 | 193 | color: std.io.tty.Color, |
| 193 | 194 | indent: usize, |
| 194 | ) anyerror!void { | |
| 195 | ) (Writer.Error || std.posix.UnexpectedError)!void { | |
| 195 | 196 | const ttyconf = options.ttyconf; |
| 196 | var counting_writer = std.io.countingWriter(stderr); | |
| 197 | const counting_stderr = counting_writer.writer(); | |
| 198 | 197 | const err_msg = eb.getErrorMessage(err_msg_index); |
| 198 | const prefix_start = w.count; | |
| 199 | 199 | if (err_msg.src_loc != .none) { |
| 200 | 200 | const src = eb.extraData(SourceLocation, @intFromEnum(err_msg.src_loc)); |
| 201 | try counting_stderr.writeByteNTimes(' ', indent); | |
| 202 | try ttyconf.setColor(stderr, .bold); | |
| 203 | try counting_stderr.print("{s}:{d}:{d}: ", .{ | |
| 201 | try w.splatByteAll(' ', indent); | |
| 202 | try ttyconf.setColor(w, .bold); | |
| 203 | try w.print("{s}:{d}:{d}: ", .{ | |
| 204 | 204 | eb.nullTerminatedString(src.data.src_path), |
| 205 | 205 | src.data.line + 1, |
| 206 | 206 | src.data.column + 1, |
| 207 | 207 | }); |
| 208 | try ttyconf.setColor(stderr, color); | |
| 209 | try counting_stderr.writeAll(kind); | |
| 210 | try counting_stderr.writeAll(": "); | |
| 208 | try ttyconf.setColor(w, color); | |
| 209 | try w.writeAll(kind); | |
| 210 | try w.writeAll(": "); | |
| 211 | 211 | // This is the length of the part before the error message: |
| 212 | 212 | // e.g. "file.zig:4:5: error: " |
| 213 | const prefix_len: usize = @intCast(counting_stderr.context.bytes_written); | |
| 214 | try ttyconf.setColor(stderr, .reset); | |
| 215 | try ttyconf.setColor(stderr, .bold); | |
| 213 | const prefix_len = w.count - prefix_start; | |
| 214 | try ttyconf.setColor(w, .reset); | |
| 215 | try ttyconf.setColor(w, .bold); | |
| 216 | 216 | if (err_msg.count == 1) { |
| 217 | try writeMsg(eb, err_msg, stderr, prefix_len); | |
| 218 | try stderr.writeByte('\n'); | |
| 217 | try writeMsg(eb, err_msg, w, prefix_len); | |
| 218 | try w.writeByte('\n'); | |
| 219 | 219 | } else { |
| 220 | try writeMsg(eb, err_msg, stderr, prefix_len); | |
| 221 | try ttyconf.setColor(stderr, .dim); | |
| 222 | try stderr.print(" ({d} times)\n", .{err_msg.count}); | |
| 220 | try writeMsg(eb, err_msg, w, prefix_len); | |
| 221 | try ttyconf.setColor(w, .dim); | |
| 222 | try w.print(" ({d} times)\n", .{err_msg.count}); | |
| 223 | 223 | } |
| 224 | try ttyconf.setColor(stderr, .reset); | |
| 224 | try ttyconf.setColor(w, .reset); | |
| 225 | 225 | if (src.data.source_line != 0 and options.include_source_line) { |
| 226 | 226 | const line = eb.nullTerminatedString(src.data.source_line); |
| 227 | 227 | for (line) |b| switch (b) { |
| 228 | '\t' => try stderr.writeByte(' '), | |
| 229 | else => try stderr.writeByte(b), | |
| 228 | '\t' => try w.writeByte(' '), | |
| 229 | else => try w.writeByte(b), | |
| 230 | 230 | }; |
| 231 | try stderr.writeByte('\n'); | |
| 231 | try w.writeByte('\n'); | |
| 232 | 232 | // TODO basic unicode code point monospace width |
| 233 | 233 | const before_caret = src.data.span_main - src.data.span_start; |
| 234 | 234 | // -1 since span.main includes the caret |
| 235 | 235 | const after_caret = src.data.span_end -| src.data.span_main -| 1; |
| 236 | try stderr.writeByteNTimes(' ', src.data.column - before_caret); | |
| 237 | try ttyconf.setColor(stderr, .green); | |
| 238 | try stderr.writeByteNTimes('~', before_caret); | |
| 239 | try stderr.writeByte('^'); | |
| 240 | try stderr.writeByteNTimes('~', after_caret); | |
| 241 | try stderr.writeByte('\n'); | |
| 242 | try ttyconf.setColor(stderr, .reset); | |
| 236 | try w.splatByteAll(' ', src.data.column - before_caret); | |
| 237 | try ttyconf.setColor(w, .green); | |
| 238 | try w.splatByteAll('~', before_caret); | |
| 239 | try w.writeByte('^'); | |
| 240 | try w.splatByteAll('~', after_caret); | |
| 241 | try w.writeByte('\n'); | |
| 242 | try ttyconf.setColor(w, .reset); | |
| 243 | 243 | } |
| 244 | 244 | for (eb.getNotes(err_msg_index)) |note| { |
| 245 | try renderErrorMessageToWriter(eb, options, note, stderr, "note", .cyan, indent); | |
| 245 | try renderErrorMessageToWriter(eb, options, note, w, "note", .cyan, indent); | |
| 246 | 246 | } |
| 247 | 247 | if (src.data.reference_trace_len > 0 and options.include_reference_trace) { |
| 248 | try ttyconf.setColor(stderr, .reset); | |
| 249 | try ttyconf.setColor(stderr, .dim); | |
| 250 | try stderr.print("referenced by:\n", .{}); | |
| 248 | try ttyconf.setColor(w, .reset); | |
| 249 | try ttyconf.setColor(w, .dim); | |
| 250 | try w.print("referenced by:\n", .{}); | |
| 251 | 251 | var ref_index = src.end; |
| 252 | 252 | for (0..src.data.reference_trace_len) |_| { |
| 253 | 253 | const ref_trace = eb.extraData(ReferenceTrace, ref_index); |
| 254 | 254 | ref_index = ref_trace.end; |
| 255 | 255 | if (ref_trace.data.src_loc != .none) { |
| 256 | 256 | const ref_src = eb.getSourceLocation(ref_trace.data.src_loc); |
| 257 | try stderr.print(" {s}: {s}:{d}:{d}\n", .{ | |
| 257 | try w.print(" {s}: {s}:{d}:{d}\n", .{ | |
| 258 | 258 | eb.nullTerminatedString(ref_trace.data.decl_name), |
| 259 | 259 | eb.nullTerminatedString(ref_src.src_path), |
| 260 | 260 | ref_src.line + 1, |
| ... | ... | @@ -262,36 +262,36 @@ fn renderErrorMessageToWriter( |
| 262 | 262 | }); |
| 263 | 263 | } else if (ref_trace.data.decl_name != 0) { |
| 264 | 264 | const count = ref_trace.data.decl_name; |
| 265 | try stderr.print( | |
| 265 | try w.print( | |
| 266 | 266 | " {d} reference(s) hidden; use '-freference-trace={d}' to see all references\n", |
| 267 | 267 | .{ count, count + src.data.reference_trace_len - 1 }, |
| 268 | 268 | ); |
| 269 | 269 | } else { |
| 270 | try stderr.print( | |
| 270 | try w.print( | |
| 271 | 271 | " remaining reference traces hidden; use '-freference-trace' to see all reference traces\n", |
| 272 | 272 | .{}, |
| 273 | 273 | ); |
| 274 | 274 | } |
| 275 | 275 | } |
| 276 | try ttyconf.setColor(stderr, .reset); | |
| 276 | try ttyconf.setColor(w, .reset); | |
| 277 | 277 | } |
| 278 | 278 | } else { |
| 279 | try ttyconf.setColor(stderr, color); | |
| 280 | try stderr.writeByteNTimes(' ', indent); | |
| 281 | try stderr.writeAll(kind); | |
| 282 | try stderr.writeAll(": "); | |
| 283 | try ttyconf.setColor(stderr, .reset); | |
| 279 | try ttyconf.setColor(w, color); | |
| 280 | try w.splatByteAll(' ', indent); | |
| 281 | try w.writeAll(kind); | |
| 282 | try w.writeAll(": "); | |
| 283 | try ttyconf.setColor(w, .reset); | |
| 284 | 284 | const msg = eb.nullTerminatedString(err_msg.msg); |
| 285 | 285 | if (err_msg.count == 1) { |
| 286 | try stderr.print("{s}\n", .{msg}); | |
| 286 | try w.print("{s}\n", .{msg}); | |
| 287 | 287 | } else { |
| 288 | try stderr.print("{s}", .{msg}); | |
| 289 | try ttyconf.setColor(stderr, .dim); | |
| 290 | try stderr.print(" ({d} times)\n", .{err_msg.count}); | |
| 288 | try w.print("{s}", .{msg}); | |
| 289 | try ttyconf.setColor(w, .dim); | |
| 290 | try w.print(" ({d} times)\n", .{err_msg.count}); | |
| 291 | 291 | } |
| 292 | try ttyconf.setColor(stderr, .reset); | |
| 292 | try ttyconf.setColor(w, .reset); | |
| 293 | 293 | for (eb.getNotes(err_msg_index)) |note| { |
| 294 | try renderErrorMessageToWriter(eb, options, note, stderr, "note", .cyan, indent + 4); | |
| 294 | try renderErrorMessageToWriter(eb, options, note, w, "note", .cyan, indent + 4); | |
| 295 | 295 | } |
| 296 | 296 | } |
| 297 | 297 | } |
| ... | ... | @@ -300,13 +300,13 @@ fn renderErrorMessageToWriter( |
| 300 | 300 | /// to allow for long, good-looking error messages. |
| 301 | 301 | /// |
| 302 | 302 | /// This is used to split the message in `@compileError("hello\nworld")` for example. |
| 303 | fn writeMsg(eb: ErrorBundle, err_msg: ErrorMessage, stderr: anytype, indent: usize) !void { | |
| 303 | fn writeMsg(eb: ErrorBundle, err_msg: ErrorMessage, w: *Writer, indent: usize) !void { | |
| 304 | 304 | var lines = std.mem.splitScalar(u8, eb.nullTerminatedString(err_msg.msg), '\n'); |
| 305 | 305 | while (lines.next()) |line| { |
| 306 | try stderr.writeAll(line); | |
| 306 | try w.writeAll(line); | |
| 307 | 307 | if (lines.index == null) break; |
| 308 | try stderr.writeByte('\n'); | |
| 309 | try stderr.writeByteNTimes(' ', indent); | |
| 308 | try w.writeByte('\n'); | |
| 309 | try w.splatByteAll(' ', indent); | |
| 310 | 310 | } |
| 311 | 311 | } |
| 312 | 312 | |
| ... | ... | @@ -398,7 +398,7 @@ pub const Wip = struct { |
| 398 | 398 | pub fn printString(wip: *Wip, comptime fmt: []const u8, args: anytype) Allocator.Error!String { |
| 399 | 399 | const gpa = wip.gpa; |
| 400 | 400 | const index: String = @intCast(wip.string_bytes.items.len); |
| 401 | try wip.string_bytes.writer(gpa).print(fmt, args); | |
| 401 | try wip.string_bytes.print(gpa, fmt, args); | |
| 402 | 402 | try wip.string_bytes.append(gpa, 0); |
| 403 | 403 | return index; |
| 404 | 404 | } |
| ... | ... | @@ -788,9 +788,10 @@ pub const Wip = struct { |
| 788 | 788 | |
| 789 | 789 | const ttyconf: std.io.tty.Config = .no_color; |
| 790 | 790 | |
| 791 | var bundle_buf = std.ArrayList(u8).init(std.testing.allocator); | |
| 791 | var bundle_buf: std.io.Writer.Allocating = .init(std.testing.allocator); | |
| 792 | const bundle_bw = &bundle_buf.interface; | |
| 792 | 793 | defer bundle_buf.deinit(); |
| 793 | try bundle.renderToWriter(.{ .ttyconf = ttyconf }, bundle_buf.writer()); | |
| 794 | try bundle.renderToWriter(.{ .ttyconf = ttyconf }, bundle_bw); | |
| 794 | 795 | |
| 795 | 796 | var copy = copy: { |
| 796 | 797 | var wip: ErrorBundle.Wip = undefined; |
| ... | ... | @@ -803,10 +804,11 @@ pub const Wip = struct { |
| 803 | 804 | }; |
| 804 | 805 | defer copy.deinit(std.testing.allocator); |
| 805 | 806 | |
| 806 | var copy_buf = std.ArrayList(u8).init(std.testing.allocator); | |
| 807 | var copy_buf: std.io.Writer.Allocating = .init(std.testing.allocator); | |
| 808 | const copy_bw = &copy_buf.interface; | |
| 807 | 809 | defer copy_buf.deinit(); |
| 808 | try copy.renderToWriter(.{ .ttyconf = ttyconf }, copy_buf.writer()); | |
| 810 | try copy.renderToWriter(.{ .ttyconf = ttyconf }, copy_bw); | |
| 809 | 811 | |
| 810 | try std.testing.expectEqualStrings(bundle_buf.items, copy_buf.items); | |
| 812 | try std.testing.expectEqualStrings(bundle_bw.getWritten(), copy_bw.getWritten()); | |
| 811 | 813 | } |
| 812 | 814 | }; |