authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-08-08 09:01:25+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-08-08 09:01:25+02:00
log5152987072ef2d030a704d2b4ca9cebd757d4cec
treeb203a8bed0888cc490f2c524975446755a9ce485
parent2597da02544c05f7de6c209d9d4d509b74e63f73
parent8b2949e372e615886b9087b06187878452421724

Merge pull request 'finish incomplete rework of build system integration with qemu, wine, darling, wasmtime, and rosetta' (#36409) from build-third-party-toggles into master

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

15 files changed, 577 insertions(+), 416 deletions(-)

lib/compiler/Maker.zig+18-6
......@@ -2119,7 +2119,7 @@ fn markFailedStepsDirty(maker: *Maker) void {
21192119 for (all_steps) |step_index| {
21202120 const step = maker.stepByIndex(step_index);
21212121 switch (step.state) {
2122 .dependency_failure, .failure, .skipped => _ = maker.invalidateResult(step),
2122 .dependency_failure, .dependency_skipped, .failure, .skipped => _ = maker.invalidateResult(step),
21232123 else => continue,
21242124 }
21252125 }
......@@ -2334,7 +2334,7 @@ fn makeSteps(
23342334 .precheck_unstarted => unreachable,
23352335 .precheck_started => unreachable,
23362336 .precheck_done => unreachable,
2337 .dependency_failure => pending_count += 1,
2337 .dependency_failure, .dependency_skipped => pending_count += 1,
23382338 .success => success_count += 1,
23392339 .skipped, .skipped_oom => skipped_count += 1,
23402340 .failure => {
......@@ -2580,10 +2580,14 @@ fn makeStep(
25802580
25812581 .failure,
25822582 .dependency_failure,
2583 .skipped_oom,
25842583 => break .dependency_failure,
25852584
2586 .success, .skipped => {},
2585 .dependency_skipped,
2586 .skipped_oom,
2587 .skipped,
2588 => break .dependency_skipped,
2589
2590 .success => {},
25872591 }
25882592 } else if (Step.make(step_index, maker, step_prog_node)) state: {
25892593 break :state .success;
......@@ -2602,11 +2606,12 @@ fn makeStep(
26022606
26032607 .failure,
26042608 .dependency_failure,
2609 .dependency_skipped,
26052610 .skipped_oom,
2611 .skipped,
26062612 => false,
26072613
26082614 .success,
2609 .skipped,
26102615 => true,
26112616 };
26122617
......@@ -2623,7 +2628,7 @@ fn makeStep(
26232628 .precheck_done => unreachable,
26242629 .success => .success,
26252630 .failure, .dependency_failure => .failure,
2626 .skipped => .skipped,
2631 .dependency_skipped, .skipped => .skipped,
26272632 .skipped_oom => .skipped_oom,
26282633 };
26292634 serveBuildStepCompleted(
......@@ -2777,6 +2782,12 @@ fn printStepStatus(maker: *Maker, step_index: Configuration.Step.Index, stderr:
27772782 try stderr.setColor(.reset);
27782783 },
27792784
2785 .dependency_skipped => {
2786 try stderr.setColor(.dim);
2787 try writer.writeAll(" transitive skip\n");
2788 try stderr.setColor(.reset);
2789 },
2790
27802791 .success => {
27812792 try stderr.setColor(.green);
27822793 if (s.result_cached) {
......@@ -3023,6 +3034,7 @@ fn constructGraphAndCheckForDependencyLoop(
30233034
30243035 // These don't happen until we actually run the step graph.
30253036 .dependency_failure => unreachable,
3037 .dependency_skipped => unreachable,
30263038 .success => unreachable,
30273039 .failure => unreachable,
30283040 .skipped => unreachable,
lib/compiler/Maker/Step.zig+3
......@@ -163,6 +163,9 @@ pub const State = enum {
163163 /// be re-evaluated.
164164 precheck_done,
165165 dependency_failure,
166 /// Handled exactly the same as `dependency_failure` except communicates
167 /// that the dependency didn't fail but rather was skipped.
168 dependency_skipped,
166169 success,
167170 failure,
168171 /// This state indicates that the step did not complete, however, it also did not fail,
lib/compiler/Maker/Step/Run.zig+33
......@@ -187,6 +187,11 @@ pub fn make(
187187 man.hash.addListOfBytes(run_args);
188188 }
189189 },
190 .enable_darling => thirdPartyToggle(&man.hash, &argv_list, conf, graph.enable_darling, arg.prefix.value, arg.suffix.value),
191 .enable_qemu => thirdPartyToggle(&man.hash, &argv_list, conf, graph.enable_qemu, arg.prefix.value, arg.suffix.value),
192 .enable_rosetta => thirdPartyToggle(&man.hash, &argv_list, conf, graph.enable_rosetta, arg.prefix.value, arg.suffix.value),
193 .enable_wasmtime => thirdPartyToggle(&man.hash, &argv_list, conf, graph.enable_wasmtime, arg.prefix.value, arg.suffix.value),
194 .enable_wine => thirdPartyToggle(&man.hash, &argv_list, conf, graph.enable_wine, arg.prefix.value, arg.suffix.value),
190195 }
191196 }
192197
......@@ -351,6 +356,29 @@ pub fn make(
351356 step.clearFailedCommand(gpa);
352357}
353358
359fn thirdPartyToggle(
360 man_hash: ?*Cache.HashHelper,
361 argv_list: *std.ArrayList([]const u8),
362 conf: *const Configuration,
363 setting: bool,
364 enable: ?Configuration.String,
365 disable: ?Configuration.String,
366) void {
367 if (setting) {
368 if (enable) |string| {
369 const slice = string.slice(conf);
370 if (man_hash) |h| h.addBytesZ(slice);
371 argv_list.appendAssumeCapacity(slice);
372 }
373 } else {
374 if (disable) |string| {
375 const slice = string.slice(conf);
376 if (man_hash) |h| h.addBytesZ(slice);
377 argv_list.appendAssumeCapacity(slice);
378 }
379 }
380}
381
354382/// Reads stdout of a Zig test process until a termination condition is reached:
355383/// * A write fails, indicating the child unexpectedly closed stdin
356384/// * A test (or a response from the test runner) times out
......@@ -1535,6 +1563,11 @@ pub fn rerunInFuzzMode(
15351563 .output_file => unreachable,
15361564 .output_directory => unreachable,
15371565 .passthru => unreachable,
1566 .enable_darling => thirdPartyToggle(null, &argv_list, conf, graph.enable_darling, arg.prefix.value, arg.suffix.value),
1567 .enable_qemu => thirdPartyToggle(null, &argv_list, conf, graph.enable_qemu, arg.prefix.value, arg.suffix.value),
1568 .enable_rosetta => thirdPartyToggle(null, &argv_list, conf, graph.enable_rosetta, arg.prefix.value, arg.suffix.value),
1569 .enable_wasmtime => thirdPartyToggle(null, &argv_list, conf, graph.enable_wasmtime, arg.prefix.value, arg.suffix.value),
1570 .enable_wine => thirdPartyToggle(null, &argv_list, conf, graph.enable_wine, arg.prefix.value, arg.suffix.value),
15381571 }
15391572 }
15401573
lib/std/Build.zig-16
......@@ -45,17 +45,6 @@ debug_log_scopes: []const []const u8 = &.{},
4545/// Set to 0 to disable stack collection.
4646debug_stack_frames_count: u8 = 8,
4747
48/// Experimental. Use system Darling installation to run cross compiled macOS build artifacts.
49enable_darling: bool = false,
50/// Use system QEMU installation to run cross compiled foreign architecture build artifacts.
51enable_qemu: bool = false,
52/// Darwin. Use Rosetta to run x86_64 macOS build artifacts on arm64 macOS.
53enable_rosetta: bool = false,
54/// Use system Wasmtime installation to run cross compiled wasm/wasi build artifacts.
55enable_wasmtime: bool = false,
56/// Use system Wine installation to run cross compiled Windows build artifacts.
57enable_wine: bool = false,
58
5948dep_prefix: []const u8 = "",
6049
6150modules: std.array_hash_map.String(*Module),
......@@ -388,11 +377,6 @@ fn createChild(
388377 .default_step = undefined,
389378 .top_level_steps = .{},
390379 .debug_log_scopes = parent.debug_log_scopes,
391 .enable_darling = parent.enable_darling,
392 .enable_qemu = parent.enable_qemu,
393 .enable_rosetta = parent.enable_rosetta,
394 .enable_wasmtime = parent.enable_wasmtime,
395 .enable_wine = parent.enable_wine,
396380 .dep_prefix = parent.fmt("{s}{s}.", .{ parent.dep_prefix, dep_name }),
397381 .modules = .empty,
398382 .named_writefiles = .empty,
lib/std/Build/Configuration.zig+7
......@@ -626,6 +626,13 @@ pub const Step = extern struct {
626626 output_file,
627627 output_directory,
628628 passthru,
629 /// `prefix` contains the enabled string.
630 /// `suffix` contains the disabled string.
631 enable_darling,
632 enable_qemu,
633 enable_rosetta,
634 enable_wasmtime,
635 enable_wine,
629636 };
630637
631638 pub const Index = IndexType(@This());
lib/std/Build/Serialize.zig+95
......@@ -1017,6 +1017,101 @@ fn initArgsList(s: *Serialize, args: []const Step.Run.Arg) ![]const Configuratio
10171017 .producer = .{ .value = null },
10181018 .generated = .{ .value = null },
10191019 },
1020 .enable_darling => |a| .{
1021 .flags = .{
1022 .tag = .enable_darling,
1023 .prefix = a.enabled != null,
1024 .suffix = a.disabled != null,
1025 .basename = false,
1026 .path = false,
1027 .producer = false,
1028 .generated = false,
1029 .dep_file = false,
1030 .make_absolute = false,
1031 },
1032 .prefix = .{ .value = try s.addOptionalString(a.enabled) },
1033 .suffix = .{ .value = try s.addOptionalString(a.disabled) },
1034 .basename = .{ .value = null },
1035 .path = .{ .value = null },
1036 .producer = .{ .value = null },
1037 .generated = .{ .value = null },
1038 },
1039 .enable_qemu => |a| .{
1040 .flags = .{
1041 .tag = .enable_qemu,
1042 .prefix = a.enabled != null,
1043 .suffix = a.disabled != null,
1044 .basename = false,
1045 .path = false,
1046 .producer = false,
1047 .generated = false,
1048 .dep_file = false,
1049 .make_absolute = false,
1050 },
1051 .prefix = .{ .value = try s.addOptionalString(a.enabled) },
1052 .suffix = .{ .value = try s.addOptionalString(a.disabled) },
1053 .basename = .{ .value = null },
1054 .path = .{ .value = null },
1055 .producer = .{ .value = null },
1056 .generated = .{ .value = null },
1057 },
1058 .enable_rosetta => |a| .{
1059 .flags = .{
1060 .tag = .enable_rosetta,
1061 .prefix = a.enabled != null,
1062 .suffix = a.disabled != null,
1063 .basename = false,
1064 .path = false,
1065 .producer = false,
1066 .generated = false,
1067 .dep_file = false,
1068 .make_absolute = false,
1069 },
1070 .prefix = .{ .value = try s.addOptionalString(a.enabled) },
1071 .suffix = .{ .value = try s.addOptionalString(a.disabled) },
1072 .basename = .{ .value = null },
1073 .path = .{ .value = null },
1074 .producer = .{ .value = null },
1075 .generated = .{ .value = null },
1076 },
1077 .enable_wasmtime => |a| .{
1078 .flags = .{
1079 .tag = .enable_wasmtime,
1080 .prefix = a.enabled != null,
1081 .suffix = a.disabled != null,
1082 .basename = false,
1083 .path = false,
1084 .producer = false,
1085 .generated = false,
1086 .dep_file = false,
1087 .make_absolute = false,
1088 },
1089 .prefix = .{ .value = try s.addOptionalString(a.enabled) },
1090 .suffix = .{ .value = try s.addOptionalString(a.disabled) },
1091 .basename = .{ .value = null },
1092 .path = .{ .value = null },
1093 .producer = .{ .value = null },
1094 .generated = .{ .value = null },
1095 },
1096 .enable_wine => |a| .{
1097 .flags = .{
1098 .tag = .enable_wine,
1099 .prefix = a.enabled != null,
1100 .suffix = a.disabled != null,
1101 .basename = false,
1102 .path = false,
1103 .producer = false,
1104 .generated = false,
1105 .dep_file = false,
1106 .make_absolute = false,
1107 },
1108 .prefix = .{ .value = try s.addOptionalString(a.enabled) },
1109 .suffix = .{ .value = try s.addOptionalString(a.disabled) },
1110 .basename = .{ .value = null },
1111 .path = .{ .value = null },
1112 .producer = .{ .value = null },
1113 .generated = .{ .value = null },
1114 },
10201115 });
10211116 }
10221117 return result;
lib/std/Build/Step/Run.zig+55
......@@ -68,9 +68,11 @@ rename_step_with_output_arg: bool,
6868/// executed binary will not fail the build if the binary cannot be executed
6969/// due to being for a foreign binary to the host system which is running the
7070/// build graph.
71///
7172/// Command-line arguments such as -fqemu and -fwasmtime may affect whether a
7273/// binary is detected as foreign, as well as system configuration such as
7374/// Rosetta (macOS) and binfmt_misc (Linux).
75///
7476/// If this Run step is considered to have side-effects, then this flag does
7577/// nothing.
7678skip_foreign_checks: bool,
......@@ -149,6 +151,19 @@ pub const Arg = union(enum) {
149151 output_directory: *Output,
150152 /// The arguments passed after "--" on the "zig build" CLI.
151153 passthru,
154
155 enable_darling: ToggleFlags,
156 enable_qemu: ToggleFlags,
157 enable_rosetta: ToggleFlags,
158 enable_wasmtime: ToggleFlags,
159 enable_wine: ToggleFlags,
160};
161
162pub const ToggleFlags = struct {
163 /// The string to pass when enabled, or null to omit the arg.
164 enabled: ?[]const u8 = null,
165 /// The string to pass when disabled, or null to omit the arg.
166 disabled: ?[]const u8 = null,
152167};
153168
154169pub const DecoratedArtifact = struct {
......@@ -576,6 +591,46 @@ pub fn addPassthruArgs(run: *Run) void {
576591 run.argv.append(arena, .passthru) catch @panic("OOM");
577592}
578593
594/// Appends a custom string to the command line depending on the `-fdarling`
595/// value passed to `zig build`.
596pub fn addThirdPartyEnabledArgDarling(run: *Run, toggle_flags: ToggleFlags) void {
597 const graph = run.step.owner.graph;
598 const arena = graph.arena;
599 run.argv.append(arena, .{ .enable_darling = toggle_flags }) catch @panic("OOM");
600}
601
602/// Appends a custom string to the command line depending on the `-fqemu`
603/// value passed to `zig build`.
604pub fn addThirdPartyEnabledArgQemu(run: *Run, toggle_flags: ToggleFlags) void {
605 const graph = run.step.owner.graph;
606 const arena = graph.arena;
607 run.argv.append(arena, .{ .enable_qemu = toggle_flags }) catch @panic("OOM");
608}
609
610/// Appends a custom string to the command line depending on the `-frosetta`
611/// value passed to `zig build`.
612pub fn addThirdPartyEnabledArgRosetta(run: *Run, toggle_flags: ToggleFlags) void {
613 const graph = run.step.owner.graph;
614 const arena = graph.arena;
615 run.argv.append(arena, .{ .enable_rosetta = toggle_flags }) catch @panic("OOM");
616}
617
618/// Appends a custom string to the command line depending on the `-fwasmtime`
619/// value passed to `zig build`.
620pub fn addThirdPartyEnabledArgWasmtime(run: *Run, toggle_flags: ToggleFlags) void {
621 const graph = run.step.owner.graph;
622 const arena = graph.arena;
623 run.argv.append(arena, .{ .enable_wasmtime = toggle_flags }) catch @panic("OOM");
624}
625
626/// Appends a custom string to the command line depending on the `-fwine`
627/// value passed to `zig build`.
628pub fn addThirdPartyEnabledArgWine(run: *Run, toggle_flags: ToggleFlags) void {
629 const graph = run.step.owner.graph;
630 const arena = graph.arena;
631 run.argv.append(arena, .{ .enable_wine = toggle_flags }) catch @panic("OOM");
632}
633
579634pub fn setStdIn(run: *Run, stdin: StdIn) void {
580635 switch (stdin) {
581636 .lazy_path => |lazy_path| lazy_path.addStepDependencies(&run.step),
test/error_traces.zig+41-2
......@@ -1,7 +1,10 @@
11const std = @import("std");
2const Context = @import("tests.zig").ErrorTracesContext;
23
3pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.Os.Tag) void {
4pub fn addCases(cases: *Context, params: *const Context.CaseParameters, target: *const std.Target) void {
45 cases.addCase(.{
6 .params = params,
7 .target = target,
58 .name = "return",
69 .source =
710 \\pub fn main() !void {
......@@ -17,6 +20,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
1720 });
1821
1922 cases.addCase(.{
23 .params = params,
24 .target = target,
2025 .name = "try return",
2126 .source =
2227 \\fn foo() !void {
......@@ -44,6 +49,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
4449 },
4550 });
4651 cases.addCase(.{
52 .params = params,
53 .target = target,
4754 .name = "non-error return pops error trace",
4855 .source =
4956 \\fn bar() !void {
......@@ -70,6 +77,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
7077 });
7178
7279 cases.addCase(.{
80 .params = params,
81 .target = target,
7382 .name = "continue in while loop",
7483 .source =
7584 \\fn foo() !void {
......@@ -93,6 +102,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
93102 });
94103
95104 cases.addCase(.{
105 .params = params,
106 .target = target,
96107 .name = "for loop pops error return trace",
97108 .source =
98109 \\fn foo() !void { return error.FooError; }
......@@ -123,6 +134,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
123134 });
124135
125136 cases.addCase(.{
137 .params = params,
138 .target = target,
126139 .name = "implicit continue in for loop pops stale error return trace",
127140 .source =
128141 \\fn foo() !void { return error.FooError; }
......@@ -154,6 +167,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
154167 });
155168
156169 cases.addCase(.{
170 .params = params,
171 .target = target,
157172 .name = "while loop pops error return trace",
158173 .source =
159174 \\fn foo() !void { return error.FooError; }
......@@ -186,6 +201,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
186201 });
187202
188203 cases.addCase(.{
204 .params = params,
205 .target = target,
189206 .name = "implicit continue in while loop pops stale error return trace",
190207 .source =
191208 \\fn foo() !void { return error.FooError; }
......@@ -219,6 +236,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
219236 });
220237
221238 cases.addCase(.{
239 .params = params,
240 .target = target,
222241 .name = "try return + handled catch/if-else",
223242 .source =
224243 \\fn foo() !void {
......@@ -251,6 +270,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
251270 });
252271
253272 cases.addCase(.{
273 .params = params,
274 .target = target,
254275 .name = "break from inline loop pops error return trace",
255276 .source =
256277 \\fn foo() !void { return error.FooBar; }
......@@ -276,6 +297,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
276297 });
277298
278299 cases.addCase(.{
300 .params = params,
301 .target = target,
279302 .name = "catch and re-throw error",
280303 .source =
281304 \\fn foo() !void {
......@@ -304,6 +327,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
304327 });
305328
306329 cases.addCase(.{
330 .params = params,
331 .target = target,
307332 .name = "errors stored in var do not contribute to error trace",
308333 .source =
309334 \\fn foo() !void {
......@@ -328,6 +353,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
328353 });
329354
330355 cases.addCase(.{
356 .params = params,
357 .target = target,
331358 .name = "error stored in const has trace preserved for duration of block",
332359 .source =
333360 \\fn foo() !void { return error.TheSkyIsFalling; }
......@@ -376,6 +403,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
376403 });
377404
378405 cases.addCase(.{
406 .params = params,
407 .target = target,
379408 .name = "error passed to function has its trace preserved for duration of the call",
380409 .source =
381410 \\pub fn expectError(expected_error: anyerror, actual_error: anyerror!void) !void {
......@@ -418,6 +447,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
418447 });
419448
420449 cases.addCase(.{
450 .params = params,
451 .target = target,
421452 .name = "try return from within catch",
422453 .source =
423454 \\fn foo() !void {
......@@ -455,6 +486,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
455486 });
456487
457488 cases.addCase(.{
489 .params = params,
490 .target = target,
458491 .name = "try return from within if-else",
459492 .source =
460493 \\fn foo() !void {
......@@ -492,6 +525,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
492525 });
493526
494527 cases.addCase(.{
528 .params = params,
529 .target = target,
495530 .name = "try try return return",
496531 .source =
497532 \\fn foo() !void {
......@@ -534,6 +569,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
534569 });
535570
536571 cases.addCase(.{
572 .params = params,
573 .target = target,
537574 .name = "error union switch with call operand",
538575 .source =
539576 \\pub fn main() !void {
......@@ -579,6 +616,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
579616 });
580617
581618 cases.addCase(.{
619 .params = params,
620 .target = target,
582621 .name = "trace through inline call",
583622 // The main function has two inline calls to ensure
584623 // that inlinees in PDBs are properly deduplicated.
......@@ -595,7 +634,7 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
595634 \\}
596635 ,
597636 .expect_error = "ThisIsSoSad",
598 .expect_trace = switch (os) {
637 .expect_trace = switch (target.os.tag) {
599638 // LLVM doesn't emit column info in the binary annotations for inlinee callees in PDBs,
600639 // so our expected result is slightly different for Windows than on other operating
601640 // systems.
test/src/ErrorTrace.zig+119-52
......@@ -1,11 +1,81 @@
1const ErrorTrace = @This();
2
3const builtin = @import("builtin");
4
5const std = @import("std");
6const Step = std.Build.Step;
7const OptimizeMode = std.lang.Optimize;
8const mem = std.mem;
9
10const error_traces_cases = @import("../error_traces.zig");
11
112b: *std.Build,
213step: *Step,
314test_filters: []const []const u8,
4targets: []const std.Build.ResolvedTarget,
15skip_non_native: bool,
516optimize_modes: []const OptimizeMode,
617convert_exe: *std.Build.Step.Compile,
718
19pub const CaseParameters = @import("StackTrace.zig").CaseParameters;
20
21const param_sets = [_]CaseParameters{
22 .{},
23 .{
24 .link_libc = true,
25 },
26 .{
27 .use_llvm = true,
28 .use_lld = true,
29 },
30 .{
31 .pie = true,
32 },
33 .{
34 .target = .{
35 .cpu_arch = .aarch64,
36 .os_tag = .windows,
37 .abi = .msvc,
38 },
39 },
40 .{
41 .target = .{
42 .cpu_arch = .x86_64,
43 .os_tag = .windows,
44 .abi = .gnu,
45 },
46 },
47 .{
48 .target = .{
49 .cpu_arch = .x86,
50 .os_tag = .windows,
51 .abi = .msvc,
52 },
53 },
54 .{
55 .target = .{
56 .cpu_arch = .aarch64,
57 .os_tag = .macos,
58 },
59 },
60 .{
61 .target = .{
62 .cpu_arch = .s390x,
63 .os_tag = .linux,
64 .abi = .none,
65 },
66 },
67 .{
68 .target = .{
69 .cpu_arch = .loongarch32,
70 .os_tag = .linux,
71 .abi = .none,
72 },
73 },
74};
75
876pub const Case = struct {
77 params: *const CaseParameters,
78 target: *const std.Target,
979 name: []const u8,
1080 source: []const u8,
1181 expect_error: []const u8,
......@@ -22,50 +92,47 @@ pub const Case = struct {
2292 pub const Backend = enum { llvm, selfhosted };
2393};
2494
25pub fn addCase(self: *ErrorTrace, case: Case) void {
26 for (self.targets) |*target| {
27 const triple: ?[]const u8 = if (target.query.isNative()) null else t: {
28 break :t target.query.zigTriple(self.b.graph.arena) catch @panic("OOM");
29 };
30 for (self.optimize_modes) |optimize| {
31 self.addCaseConfig(case, target, triple, optimize, .llvm);
32 }
33 if (shouldTestNonLlvm(&target.result)) {
34 for (self.optimize_modes) |optimize| {
35 self.addCaseConfig(case, target, triple, optimize, .selfhosted);
36 }
95pub fn addCases(self: *ErrorTrace) void {
96 const b = self.b;
97
98 for (&param_sets) |*params| {
99 const resolved_target = b.resolveTargetQuery(params.target);
100
101 if (self.skip_non_native and !resolved_target.query.isNative()) continue;
102
103 // To avoid redundant testing, skip cross-compilation targets matching the host.
104 if (resolved_target.result.os.tag == builtin.target.os.tag and
105 resolved_target.result.cpu.arch == builtin.target.cpu.arch)
106 {
107 continue;
37108 }
38 }
39}
40109
41fn shouldTestNonLlvm(target: *const std.Target) bool {
42 if (comptime builtin.cpu.arch.endian() == .big) return false; // https://github.com/ziglang/zig/issues/25961
43 return switch (target.cpu.arch) {
44 .x86_64 => switch (target.ofmt) {
45 .elf => !target.os.tag.isBSD() and target.os.tag != .illumos,
46 else => false,
47 },
48 else => false,
49 };
110 for (self.optimize_modes) |optimize| {
111 if (optimize == params.optimize) break;
112 } else return;
113
114 error_traces_cases.addCases(self, params, &resolved_target.result);
115 }
50116}
51117
52fn addCaseConfig(
53 self: *ErrorTrace,
54 case: Case,
55 target: *const std.Build.ResolvedTarget,
56 triple: ?[]const u8,
57 optimize: OptimizeMode,
58 backend: Case.Backend,
59) void {
118/// Called from test/error_traces.zig
119pub fn addCase(self: *ErrorTrace, case: Case) void {
60120 const b = self.b;
121 const params = case.params;
122 const target = case.target;
123 const target_query = params.target;
124
125 const triple: ?[]const u8 = if (target_query.isNative()) null else t: {
126 break :t target_query.zigTriple(self.b.graph.arena) catch @panic("OOM");
127 };
61128
62129 const error_tracing: bool = tracing: {
63 if (optimize == .debug) break :tracing true;
64 if (backend != .llvm) break :tracing true;
65 if (optimize == .small) break :tracing false;
130 if (params.optimize == .debug) break :tracing true;
131 if (params.use_llvm == false) break :tracing true;
132 if (params.optimize == .small) break :tracing false;
66133 for (case.disable_trace_optimized) |disable| {
67134 const d_arch, const d_os = disable;
68 if (target.result.cpu.arch == d_arch and target.result.os.tag == d_os) {
135 if (target.cpu.arch == d_arch and target.os.tag == d_os) {
69136 // This particular configuration cannot do error tracing in optimized LLVM builds.
70137 break :tracing false;
71138 }
......@@ -73,12 +140,19 @@ fn addCaseConfig(
73140 break :tracing true;
74141 };
75142
76 const annotated_case_name = b.fmt("check {s} ({s}{s}{s} {s})", .{
143 const backend_string = if (params.use_llvm == true)
144 "-llvm"
145 else if (params.use_llvm == false)
146 "-selfhosted"
147 else
148 "";
149
150 const annotated_case_name = b.fmt("check {s} ({s}{s}{t}{s})", .{
77151 case.name,
78152 triple orelse "",
79153 if (triple != null) " " else "",
80 @tagName(optimize),
81 @tagName(backend),
154 params.optimize,
155 backend_string,
82156 });
83157 if (self.test_filters.len > 0) {
84158 for (self.test_filters) |test_filter| {
......@@ -92,19 +166,18 @@ fn addCaseConfig(
92166 .name = "test",
93167 .root_module = b.createModule(.{
94168 .root_source_file = source_zig,
95 .optimize = optimize,
96 .target = target.*,
169 .optimize = params.optimize,
170 .target = .{ .result = target.*, .query = target_query },
97171 .error_tracing = error_tracing,
98172 .strip = false,
99173 }),
100 .use_llvm = switch (backend) {
101 .llvm => true,
102 .selfhosted => false,
103 },
174 .use_llvm = params.use_llvm,
175 .use_lld = params.use_lld,
104176 });
105177 exe.bundle_ubsan_rt = false;
106178
107179 const run = b.addRunArtifact(exe);
180 run.skip_foreign_checks = true;
108181 run.removeEnvironmentVariable("CLICOLOR_FORCE");
109182 run.setEnvironmentVariable("NO_COLOR", "1");
110183 run.expectExitCode(1);
......@@ -116,16 +189,10 @@ fn addCaseConfig(
116189 };
117190
118191 const check_run = b.addRunArtifact(self.convert_exe);
192 check_run.skip_foreign_checks = true;
119193 check_run.setName(annotated_case_name);
120194 check_run.addFileArg(run.captureStdErr(.{}));
121195 check_run.expectStdOutEqual(expected_stderr);
122196
123197 self.step.dependOn(&check_run.step);
124198}
125
126const ErrorTrace = @This();
127const std = @import("std");
128const builtin = @import("builtin");
129const Step = std.Build.Step;
130const OptimizeMode = std.builtin.OptimizeMode;
131const mem = std.mem;
test/src/StackTrace.zig+155-92
......@@ -1,10 +1,91 @@
1const StackTrace = @This();
2
3const builtin = @import("builtin");
4
5const std = @import("std");
6const Step = std.Build.Step;
7const OptimizeMode = std.lang.Optimize;
8const mem = std.mem;
9
10const stack_traces_cases = @import("../stack_traces.zig");
11
112b: *std.Build,
213step: *Step,
314test_filters: []const []const u8,
4targets: []const std.Build.ResolvedTarget,
15skip_non_native: bool,
516convert_exe: *std.Build.Step.Compile,
617
18pub const CaseParameters = struct {
19 target: std.Target.Query = .{},
20 optimize: std.builtin.OptimizeMode = .debug,
21 link_libc: ?bool = null,
22 use_llvm: ?bool = null,
23 use_lld: ?bool = null,
24 pie: ?bool = null,
25 /// To enable this coverage, one of two things needs to happen:
26 /// * The compiler needs to gain the ability to strip only debug info (not symbols)
27 /// * `std.Build.Step.ObjCopy` needs to be un-regressed
28 strip: ?bool = false,
29};
30
31const param_sets = [_]CaseParameters{
32 .{},
33 .{
34 .link_libc = true,
35 },
36 .{
37 .use_llvm = true,
38 .use_lld = true,
39 },
40 .{
41 .pie = true,
42 },
43 .{
44 .target = .{
45 .cpu_arch = .aarch64,
46 .os_tag = .windows,
47 .abi = .msvc,
48 },
49 },
50 .{
51 .target = .{
52 .cpu_arch = .x86_64,
53 .os_tag = .windows,
54 .abi = .gnu,
55 },
56 },
57 .{
58 .target = .{
59 .cpu_arch = .x86,
60 .os_tag = .windows,
61 .abi = .msvc,
62 },
63 },
64 .{
65 .target = .{
66 .cpu_arch = .aarch64,
67 .os_tag = .macos,
68 },
69 },
70 .{
71 .target = .{
72 .cpu_arch = .s390x,
73 .os_tag = .linux,
74 .abi = .none,
75 },
76 },
77 .{
78 .target = .{
79 .cpu_arch = .loongarch32,
80 .os_tag = .linux,
81 .abi = .none,
82 },
83 },
84};
85
786const Config = struct {
87 params: *const CaseParameters,
88 target: *const std.Target,
889 name: []const u8,
990 source: []const u8,
1091 /// Whether this test case expects to have unwind tables / frame pointers.
......@@ -26,42 +107,37 @@ const Config = struct {
26107 expect_strip: []const u8,
27108};
28109
29pub fn addCase(self: *StackTrace, config: Config) void {
30 for (self.targets) |*target| {
31 addCaseTarget(
32 self,
33 config,
34 target,
35 if (target.query.isNative()) null else t: {
36 break :t target.query.zigTriple(self.b.graph.arena) catch @panic("OOM");
37 },
38 );
110pub fn addCases(self: *StackTrace) void {
111 const b = self.b;
112
113 for (&param_sets) |*params| {
114 const resolved_target = b.resolveTargetQuery(params.target);
115
116 if (self.skip_non_native and !resolved_target.query.isNative()) continue;
117
118 // To avoid redundant testing, skip cross-compilation targets matching the host.
119 if (resolved_target.result.os.tag == builtin.target.os.tag and
120 resolved_target.result.cpu.arch == builtin.target.cpu.arch)
121 {
122 continue;
123 }
124
125 stack_traces_cases.addCases(self, params, &resolved_target.result);
39126 }
40127}
41fn addCaseTarget(
42 self: *StackTrace,
43 config: Config,
44 target: *const std.Build.ResolvedTarget,
45 triple: ?[]const u8,
46) void {
47 const both_backends = b: {
48 if (comptime builtin.cpu.arch.endian() == .big) break :b false; // https://github.com/ziglang/zig/issues/25961
49 break :b switch (target.result.cpu.arch) {
50 .x86_64 => switch (target.result.ofmt) {
51 .elf => !target.result.os.tag.isBSD() and target.result.os.tag != .illumos,
52 else => false,
53 },
54 else => false,
55 };
56 };
57 const both_pie = switch (target.result.os.tag) {
58 .fuchsia => false,
59 else => true,
128
129/// Called from test/stack_traces.zig
130pub fn addCase(self: *StackTrace, config: Config) void {
131 const params = config.params;
132 const target = config.target;
133 const target_query = config.params.target;
134
135 const triple: ?[]const u8 = if (target_query.isNative()) null else t: {
136 break :t target_query.zigTriple(self.b.graph.arena) catch @panic("OOM");
60137 };
61 const both_libc = !std.os.targetRequiresLibC(&target.result);
62138
63139 // See `std.debug.StackIterator.fp_usability` logic.
64 const fp_usability: enum { useless, unsafe, safe, ideal } = switch (target.result.cpu.arch) {
140 const fp_usability: enum { useless, unsafe, safe, ideal } = switch (target.cpu.arch) {
65141 .alpha,
66142 .csky,
67143 .microblaze,
......@@ -83,20 +159,15 @@ fn addCaseTarget(
83159 .sparc,
84160 .sparc64,
85161 => .ideal,
86 .aarch64 => if (target.result.os.tag.isDarwin()) .safe else .unsafe,
162 .aarch64 => if (target.os.tag.isDarwin()) .safe else .unsafe,
87163 else => .unsafe,
88164 };
89 const supports_unwind_tables = switch (target.result.os.tag) {
165 const supports_unwind_tables = switch (target.os.tag) {
90166 // x86-windows just has no way to do stack unwinding other then using frame pointers.
91 .windows => target.result.cpu.arch != .x86,
167 .windows => target.cpu.arch != .x86,
92168 else => true,
93169 };
94170
95 const use_llvm_vals: []const bool = if (both_backends) &.{ true, false } else &.{true};
96 const pie_vals: []const ?bool = if (both_pie) &.{ true, false } else &.{null};
97 const link_libc_vals: []const ?bool = if (both_libc) &.{ true, false } else &.{null};
98 const strip_debug_vals: []const bool = &.{ true, false };
99
100171 const UnwindInfo = packed struct(u2) {
101172 tables: bool,
102173 fp: bool,
......@@ -126,43 +197,33 @@ fn addCaseTarget(
126197 },
127198 };
128199
129 for (use_llvm_vals) |use_llvm| {
130 for (pie_vals) |pie| {
131 for (link_libc_vals) |link_libc| {
132 for (strip_debug_vals) |strip_debug| {
133 for (unwind_info_vals) |unwind_info| {
134 if (unwind_info.tables and !supports_unwind_tables) continue;
135 self.addCaseInstance(
136 target,
137 triple,
138 config.name,
139 config.source,
140 use_llvm,
141 pie,
142 link_libc,
143 strip_debug,
144 !unwind_info.tables and supports_unwind_tables,
145 !unwind_info.fp,
146 config.expect_panic,
147 if (strip_debug) config.expect_strip else config.expect,
148 );
149 }
150 }
151 }
152 }
200 for (unwind_info_vals) |unwind_info| {
201 if (unwind_info.tables and !supports_unwind_tables) continue;
202 const strip = params.strip orelse switch (params.optimize) {
203 .debug, .fast, .safe => false,
204 .small => true,
205 };
206 self.addCaseInstance(
207 .{ .result = target.*, .query = target_query },
208 triple,
209 config.name,
210 config.source,
211 params,
212 !unwind_info.tables and supports_unwind_tables,
213 !unwind_info.fp,
214 config.expect_panic,
215 if (strip) config.expect_strip else config.expect,
216 );
153217 }
154218}
155219
156220fn addCaseInstance(
157221 self: *StackTrace,
158 target: *const std.Build.ResolvedTarget,
222 resolved_target: std.Build.ResolvedTarget,
159223 triple: ?[]const u8,
160224 name: []const u8,
161225 source: []const u8,
162 use_llvm: bool,
163 pie: ?bool,
164 link_libc: ?bool,
165 strip_debug: bool,
226 params: *const CaseParameters,
166227 strip_unwind: bool,
167228 omit_frame_pointer: bool,
168229 expect_panic: bool,
......@@ -170,13 +231,6 @@ fn addCaseInstance(
170231) void {
171232 const b = self.b;
172233
173 if (strip_debug) {
174 // To enable this coverage, one of two things needs to happen:
175 // * The compiler needs to gain the ability to strip only debug info (not symbols)
176 // * `std.Build.Step.ObjCopy` needs to be un-regressed
177 return;
178 }
179
180234 if (strip_unwind) {
181235 // To enable this coverage, `std.Build.Step.ObjCopy` needs to be un-regressed and gain the
182236 // ability to remove individual sections. `-fno-unwind-tables` is insufficient because it
......@@ -187,14 +241,28 @@ fn addCaseInstance(
187241 return;
188242 }
189243
244 const backend_string = if (params.use_llvm == true)
245 " llvm"
246 else if (params.use_llvm == false)
247 " selfhosted"
248 else
249 "";
250
251 const strip_string = if (params.strip == true)
252 " strip"
253 else if (params.strip == false)
254 " unstripped"
255 else
256 "";
257
190258 const annotated_case_name = b.fmt("check {s} ({s}{s}{s}{s}{s}{s}{s}{s})", .{
191259 name,
192260 triple orelse "",
193261 if (triple != null) " " else "",
194 if (use_llvm) "llvm" else "selfhosted",
195 if (pie == true) " pie" else "",
196 if (link_libc == true) " libc" else "",
197 if (strip_debug) " strip" else "",
262 backend_string,
263 if (params.pie == true) " pie" else "",
264 if (params.link_libc == true) " libc" else "",
265 strip_string,
198266 if (strip_unwind) " no_unwind" else "",
199267 if (omit_frame_pointer) " no_fp" else "",
200268 });
......@@ -211,24 +279,26 @@ fn addCaseInstance(
211279 .root_module = b.createModule(.{
212280 .root_source_file = source_zig,
213281 .optimize = .Debug,
214 .target = target.*,
282 .target = resolved_target,
215283 .omit_frame_pointer = omit_frame_pointer,
216 .link_libc = link_libc,
284 .link_libc = params.link_libc,
217285 .unwind_tables = if (strip_unwind) .none else null,
218286 // make panics single-threaded so that they don't include a thread ID
219287 .single_threaded = expect_panic,
220288 }),
221 .use_llvm = use_llvm,
289 .use_llvm = params.use_llvm,
290 .use_lld = params.use_lld,
222291 });
223 exe.pie = pie;
292 exe.pie = params.pie;
224293 exe.bundle_ubsan_rt = false;
225294
226295 const run = b.addRunArtifact(exe);
296 run.skip_foreign_checks = true;
227297 run.removeEnvironmentVariable("CLICOLOR_FORCE");
228298 run.setEnvironmentVariable("NO_COLOR", "1");
229299 run.addCheck(.{ .expect_term = term: {
230300 if (!expect_panic) break :term .{ .exited = 0 };
231 if (target.result.os.tag == .windows) break :term .{ .exited = 3 };
301 if (resolved_target.result.os.tag == .windows) break :term .{ .exited = 3 };
232302 break :term .{ .signal = @fromBackingInt(@intCast(6)) };
233303 } });
234304 run.expectStdOutEqual("");
......@@ -241,10 +311,3 @@ fn addCaseInstance(
241311
242312 self.step.dependOn(&check_run.step);
243313}
244
245const StackTrace = @This();
246const std = @import("std");
247const builtin = @import("builtin");
248const Step = std.Build.Step;
249const OptimizeMode = std.builtin.OptimizeMode;
250const mem = std.mem;
test/stack_traces.zig+24-5
......@@ -1,7 +1,10 @@
11const std = @import("std");
2const Context = @import("tests.zig").StackTracesContext;
23
3pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target.Os.Tag) void {
4pub fn addCases(cases: *Context, params: *const Context.CaseParameters, target: *const std.Target) void {
45 cases.addCase(.{
6 .params = params,
7 .target = target,
58 .name = "simple panic",
69 .source =
710 \\pub fn main() void {
......@@ -33,6 +36,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target.
3336 });
3437
3538 cases.addCase(.{
39 .params = params,
40 .target = target,
3641 .name = "simple panic with no unwind strategy",
3742 .source =
3843 \\pub fn main() void {
......@@ -50,6 +55,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target.
5055 });
5156
5257 cases.addCase(.{
58 .params = params,
59 .target = target,
5360 .name = "dump current trace",
5461 .source =
5562 \\pub fn main() void {
......@@ -89,6 +96,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target.
8996 });
9097
9198 cases.addCase(.{
99 .params = params,
100 .target = target,
92101 .name = "dump current trace with no unwind strategy",
93102 .source =
94103 \\pub fn main() void {
......@@ -114,6 +123,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target.
114123 });
115124
116125 cases.addCase(.{
126 .params = params,
127 .target = target,
117128 .name = "dump captured trace",
118129 .source =
119130 \\pub fn main() void {
......@@ -155,6 +166,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target.
155166 });
156167
157168 cases.addCase(.{
169 .params = params,
170 .target = target,
158171 .name = "dump captured trace with no unwind strategy",
159172 .source =
160173 \\pub fn main() void {
......@@ -180,6 +193,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target.
180193 });
181194
182195 cases.addCase(.{
196 .params = params,
197 .target = target,
183198 .name = "dump captured trace on thread",
184199 .source =
185200 \\pub fn main() !void {
......@@ -225,6 +240,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target.
225240 });
226241
227242 cases.addCase(.{
243 .params = params,
244 .target = target,
228245 .name = "simple inline panic",
229246 // The main function has two inline calls to ensure
230247 // that inlinees in PDBs are properly deduplicated.
......@@ -240,7 +257,7 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target.
240257 ,
241258 .unwind = .any,
242259 .expect_panic = true,
243 .expect = switch (os) {
260 .expect = switch (target.os.tag) {
244261 // LLVM doesn't emit column info in the binary annotations for inlinee callees in PDBs,
245262 // so the first location has only a row.
246263 .windows =>
......@@ -262,7 +279,7 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target.
262279 \\ ^
263280 ,
264281 },
265 .expect_strip = switch (os) {
282 .expect_strip = switch (target.os.tag) {
266283 .windows =>
267284 \\panic: oh no
268285 \\???:?:?: [address] in source.foo
......@@ -279,6 +296,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target.
279296
280297 // Make sure all inline calls are resolved and in the right order!
281298 cases.addCase(.{
299 .params = params,
300 .target = target,
282301 .name = "nested inline panic",
283302 .source =
284303 \\pub fn main() void {
......@@ -298,7 +317,7 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target.
298317 .unwind = .any,
299318 .expect_panic = true,
300319 // This switch serves a similar purpose as in "inline panic".
301 .expect = switch (os) {
320 .expect = switch (target.os.tag) {
302321 .windows =>
303322 \\panic: oh no
304323 \\source.zig:11: [address] in baz
......@@ -322,7 +341,7 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target.
322341 \\ ^
323342 ,
324343 },
325 .expect_strip = switch (os) {
344 .expect_strip = switch (target.os.tag) {
326345 .windows =>
327346 \\panic: oh no
328347 \\???:?:?: [address] in baz
test/standalone/build.zig.zon-3
......@@ -187,9 +187,6 @@
187187 .posix = .{
188188 .path = "posix",
189189 },
190 .debug_io_color = .{
191 .path = "debug_io_color",
192 },
193190 .elf2 = .{
194191 .path = "elf2",
195192 },
test/standalone/debug_io_color/build.zig deleted-95
......@@ -1,95 +0,0 @@
1const std = @import("std");
2
3pub fn build(b: *std.Build) void {
4 const test_step = b.step("test", "Test");
5 b.default_step = test_step;
6
7 // Most targets handle color the same way, regardless of whether libc is linked.
8 const native_target = b.graph.host;
9 addTestCases(test_step, native_target, false);
10 addTestCases(test_step, native_target, true);
11
12 // WASI behaves differently depending on whether libc is linked.
13 if (b.enable_wasmtime) {
14 const wasi_target = b.resolveTargetQuery(.{ .cpu_arch = .wasm32, .os_tag = .wasi });
15 addTestCases(test_step, wasi_target, false);
16 addTestCases(test_step, wasi_target, true);
17 }
18}
19
20fn addTestCases(
21 test_step: *std.Build.Step,
22 target: std.Build.ResolvedTarget,
23 link_libc: bool,
24) void {
25 const b = test_step.owner;
26 const exe = b.addExecutable(.{
27 .name = b.fmt("{s}{s}", .{ @tagName(target.result.os.tag), if (link_libc) "-libc" else "" }),
28 .root_module = b.createModule(.{
29 .root_source_file = b.path("main.zig"),
30 .target = target,
31 .link_libc = link_libc,
32 }),
33 });
34
35 // Should reflect 'std.process.Environ.Block' and 'std.Io.Threaded.init_single_threaded'.
36 const debug_io_can_read_environ = switch (target.result.os.tag) {
37 .windows => true,
38 .wasi, .emscripten => link_libc,
39 .freestanding, .other => false,
40 else => true,
41 };
42
43 // Don't forget to account for whether the build process's stderr supports color.
44 const parent_stderr_color_enabled = (std.Io.Terminal.Mode.detect(b.graph.io, .stderr(), false, false) catch unreachable) != .no_color;
45
46 _ = addTestCase(test_step, exe, "neither", .inherit, .manual, parent_stderr_color_enabled);
47 _ = addTestCase(test_step, exe, "neither", .redirect, .manual, false);
48 _ = addTestCase(test_step, exe, "no_color", .inherit, .disable, if (debug_io_can_read_environ) false else parent_stderr_color_enabled);
49 _ = addTestCase(test_step, exe, "no_color", .redirect, .disable, false);
50 _ = addTestCase(test_step, exe, "clicolor_force", .inherit, .enable, if (debug_io_can_read_environ) true else parent_stderr_color_enabled);
51 _ = addTestCase(test_step, exe, "clicolor_force", .redirect, .enable, debug_io_can_read_environ);
52
53 const both = addTestCase(test_step, exe, "both", .inherit, .manual, if (debug_io_can_read_environ) false else parent_stderr_color_enabled);
54 both.setEnvironmentVariable("NO_COLOR", "1");
55 both.setEnvironmentVariable("CLICOLOR_FORCE", "1");
56
57 const both_redirected = addTestCase(test_step, exe, "both", .redirect, .manual, false);
58 both_redirected.setEnvironmentVariable("NO_COLOR", "1");
59 both_redirected.setEnvironmentVariable("CLICOLOR_FORCE", "1");
60}
61
62fn addTestCase(
63 test_step: *std.Build.Step,
64 exe: *std.Build.Step.Compile,
65 test_case_name: []const u8,
66 stderr: enum { inherit, redirect },
67 run_step_color: std.Build.Step.Run.Color,
68 expected_color_enabled: bool,
69) *std.Build.Step.Run {
70 const b = test_step.owner;
71 const step_name = b.fmt("{s} {s}{s}", .{
72 exe.name,
73 test_case_name,
74 if (stderr == .redirect) "-redirect" else "",
75 });
76 const run_exe = b.addRunArtifact(exe);
77 run_exe.setName(b.fmt("run {s}", .{step_name}));
78
79 run_exe.failing_to_execute_foreign_is_an_error = false;
80 if (stderr == .redirect) run_exe.expectStdErrMatch("");
81
82 run_exe.clearEnvironment();
83 run_exe.color = run_step_color;
84
85 // Build system quirk: Currently, Run step stdout checks will also redirect stderr, so as a
86 // workaround we use a CheckFile step instead. We must also mark the Run step as having side
87 // effects, to ensure the parent stderr is inherited when not explicitly redirected.
88 run_exe.has_side_effects = true;
89 const stdout = run_exe.captureStdOut(.{});
90 const check_file = b.addCheckFile(stdout, .{ .expected_exact = if (expected_color_enabled) "true" else "false" });
91 check_file.setName(b.fmt("check {s}", .{step_name}));
92 test_step.dependOn(&check_file.step);
93
94 return run_exe;
95}
test/standalone/debug_io_color/main.zig deleted-7
......@@ -1,7 +0,0 @@
1const std = @import("std");
2
3pub fn main() !void {
4 const stderr = std.debug.lockStderr(&.{});
5 defer std.debug.unlockStderr();
6 try std.Io.File.stdout().writeStreamingAll(std.Options.debug_io, if (stderr.terminal_mode != .no_color) "true" else "false");
7}
test/tests.zig+27-138
......@@ -6,8 +6,6 @@ const OptimizeMode = std.builtin.OptimizeMode;
66const Step = std.Build.Step;
77
88// Cases
9const error_traces = @import("error_traces.zig");
10const stack_traces = @import("stack_traces.zig");
119const llvm_ir = @import("llvm_ir.zig");
1210const libc = @import("libc.zig");
1311const link = @import("link.zig");
......@@ -2381,59 +2379,7 @@ pub fn isNative(actual_target: *const std.Build.ResolvedTarget, host: *const std
23812379 return true;
23822380}
23832381
2384/// For stack trace tests, we only test native by default, because external executors are pretty
2385/// unreliable at stack tracing. However, if there's a 32-bit equivalent target which the host can
2386/// trivially run, we may as well at least test that!
2387fn nativeAndCompatible32bit(b: *std.Build, skip_non_native: bool) []const std.Build.ResolvedTarget {
2388 const host = b.graph.host.result;
2389 const only_native = (&b.graph.host)[0..1];
2390 if (skip_non_native) return only_native;
2391 const arch32 = compatible32bitArch(&b.graph.host.result) orelse return only_native;
2392 return b.graph.arena.dupe(std.Build.ResolvedTarget, &.{
2393 b.graph.host,
2394 b.resolveTargetQuery(.{ .cpu_arch = arch32, .os_tag = host.os.tag }),
2395 }) catch @panic("OOM");
2396}
2397
2398fn wineAndCompatible32bit(b: *std.Build, skip_non_native: bool) []const std.Build.ResolvedTarget {
2399 var targets: std.ArrayList(std.Build.ResolvedTarget) = .empty;
2400
2401 const host = b.graph.host.result;
2402
2403 targets.append(b.graph.arena, b.resolveTargetQuery(.{
2404 .cpu_arch = host.cpu.arch,
2405 .os_tag = .windows,
2406 })) catch @panic("OOM");
2407 if (!skip_non_native) {
2408 if (compatible32bitArch(&b.graph.host.result)) |arch| {
2409 targets.append(b.graph.arena, b.resolveTargetQuery(.{
2410 .cpu_arch = arch,
2411 .os_tag = .windows,
2412 })) catch @panic("OOM");
2413 }
2414 }
2415
2416 return targets.toOwnedSlice(b.graph.arena) catch @panic("OOM");
2417}
2418
2419fn darlingTargets(b: *std.Build) []const std.Build.ResolvedTarget {
2420 var targets: std.ArrayList(std.Build.ResolvedTarget) = .empty;
2421
2422 const host = b.graph.host.result;
2423
2424 targets.append(b.graph.arena, b.resolveTargetQuery(.{
2425 .cpu_arch = host.cpu.arch,
2426 .os_tag = .macos,
2427 })) catch @panic("OOM");
2428
2429 return targets.toOwnedSlice(b.graph.arena) catch @panic("OOM");
2430}
2431
2432pub fn addStackTraceTests(
2433 b: *std.Build,
2434 test_filters: []const []const u8,
2435 skip_non_native: bool,
2436) *Step {
2382pub fn addStackTraceTests(b: *std.Build, test_filters: []const []const u8, skip_non_native: bool) *Step {
24372383 const step = b.step("test-stack-traces", "Run the stack trace tests");
24382384
24392385 const convert_exe = b.addExecutable(.{
......@@ -2445,39 +2391,15 @@ pub fn addStackTraceTests(
24452391 }),
24462392 });
24472393
2448 const host_cases = b.allocator.create(StackTracesContext) catch @panic("OOM");
2449 host_cases.* = .{
2394 const stack_traces_context = b.allocator.create(StackTracesContext) catch @panic("OOM");
2395 stack_traces_context.* = .{
24502396 .b = b,
24512397 .step = step,
24522398 .test_filters = test_filters,
2453 .targets = nativeAndCompatible32bit(b, skip_non_native),
2399 .skip_non_native = skip_non_native,
24542400 .convert_exe = convert_exe,
24552401 };
2456 stack_traces.addCases(host_cases, b.graph.host.result.os.tag);
2457
2458 if (b.enable_wine) {
2459 const wine_cases = b.allocator.create(StackTracesContext) catch @panic("OOM");
2460 wine_cases.* = .{
2461 .b = b,
2462 .step = step,
2463 .test_filters = test_filters,
2464 .targets = wineAndCompatible32bit(b, skip_non_native),
2465 .convert_exe = convert_exe,
2466 };
2467 stack_traces.addCases(wine_cases, .windows);
2468 }
2469
2470 if (b.enable_darling) {
2471 const darling_cases = b.allocator.create(StackTracesContext) catch @panic("OOM");
2472 darling_cases.* = .{
2473 .b = b,
2474 .step = step,
2475 .test_filters = test_filters,
2476 .targets = darlingTargets(b),
2477 .convert_exe = convert_exe,
2478 };
2479 stack_traces.addCases(darling_cases, .macos);
2480 }
2402 stack_traces_context.addCases();
24812403
24822404 return step;
24832405}
......@@ -2499,52 +2421,20 @@ pub fn addErrorTraceTests(
24992421 }),
25002422 });
25012423
2502 const host_cases = b.allocator.create(ErrorTracesContext) catch @panic("OOM");
2503 host_cases.* = .{
2424 const error_traces_context = b.allocator.create(ErrorTracesContext) catch @panic("OOM");
2425 error_traces_context.* = .{
25042426 .b = b,
25052427 .step = step,
25062428 .test_filters = test_filters,
2507 .targets = nativeAndCompatible32bit(b, skip_non_native),
2429 .skip_non_native = skip_non_native,
25082430 .optimize_modes = optimize_modes,
25092431 .convert_exe = convert_exe,
25102432 };
2511 error_traces.addCases(host_cases, b.graph.host.result.os.tag);
2512
2513 if (b.enable_wine) {
2514 const wine_cases = b.allocator.create(ErrorTracesContext) catch @panic("OOM");
2515 wine_cases.* = .{
2516 .b = b,
2517 .step = step,
2518 .test_filters = test_filters,
2519 .targets = wineAndCompatible32bit(b, skip_non_native),
2520 .optimize_modes = optimize_modes,
2521 .convert_exe = convert_exe,
2522 };
2523 error_traces.addCases(wine_cases, .windows);
2524 }
2525
2526 if (b.enable_darling) {
2527 const darling_cases = b.allocator.create(ErrorTracesContext) catch @panic("OOM");
2528 darling_cases.* = .{
2529 .b = b,
2530 .step = step,
2531 .test_filters = test_filters,
2532 .targets = darlingTargets(b),
2533 .optimize_modes = optimize_modes,
2534 .convert_exe = convert_exe,
2535 };
2536 error_traces.addCases(darling_cases, .macos);
2537 }
2433 error_traces_context.addCases();
25382434
25392435 return step;
25402436}
25412437
2542fn compilerHasPackageManager(b: *std.Build) bool {
2543 // We can only use dependencies if the compiler was built with support for package management.
2544 // (zig2 doesn't support it, but we still need to construct a build graph to build stage3.)
2545 return b.available_deps.len != 0;
2546}
2547
25482438pub fn addStandaloneTests(
25492439 b: *std.Build,
25502440 optimize_modes: []const OptimizeMode,
......@@ -2553,21 +2443,19 @@ pub fn addStandaloneTests(
25532443 enable_symlinks_windows: bool,
25542444) *Step {
25552445 const step = b.step("test-standalone", "Run the standalone tests");
2556 if (compilerHasPackageManager(b)) {
2557 const test_cases_dep_name = "standalone_test_cases";
2558 const test_cases_dep = b.dependency(test_cases_dep_name, .{
2559 .enable_ios_sdk = enable_ios_sdk,
2560 .enable_macos_sdk = enable_macos_sdk,
2561 .enable_symlinks_windows = enable_symlinks_windows,
2562 .simple_skip_debug = mem.findScalar(OptimizeMode, optimize_modes, .debug) == null,
2563 .simple_skip_release_safe = mem.findScalar(OptimizeMode, optimize_modes, .safe) == null,
2564 .simple_skip_release_fast = mem.findScalar(OptimizeMode, optimize_modes, .fast) == null,
2565 .simple_skip_release_small = mem.findScalar(OptimizeMode, optimize_modes, .small) == null,
2566 });
2567 const test_cases_dep_step = test_cases_dep.builder.default_step;
2568 test_cases_dep_step.name = b.graph.dupeString(test_cases_dep_name);
2569 step.dependOn(test_cases_dep.builder.default_step);
2570 }
2446 const test_cases_dep_name = "standalone_test_cases";
2447 const test_cases_dep = b.dependency(test_cases_dep_name, .{
2448 .enable_ios_sdk = enable_ios_sdk,
2449 .enable_macos_sdk = enable_macos_sdk,
2450 .enable_symlinks_windows = enable_symlinks_windows,
2451 .simple_skip_debug = mem.findScalar(OptimizeMode, optimize_modes, .debug) == null,
2452 .simple_skip_release_safe = mem.findScalar(OptimizeMode, optimize_modes, .safe) == null,
2453 .simple_skip_release_fast = mem.findScalar(OptimizeMode, optimize_modes, .fast) == null,
2454 .simple_skip_release_small = mem.findScalar(OptimizeMode, optimize_modes, .small) == null,
2455 });
2456 const test_cases_dep_step = test_cases_dep.builder.default_step;
2457 test_cases_dep_step.name = b.graph.dupeString(test_cases_dep_name);
2458 step.dependOn(test_cases_dep.builder.default_step);
25712459 return step;
25722460}
25732461
......@@ -3417,10 +3305,11 @@ pub fn addIncrementalTests(b: *std.Build, test_step: *Step, test_filters: []cons
34173305
34183306 run.addArg("--quiet"); // don't fill stderr telling us about skipped tests etc
34193307
3420 if (b.enable_qemu) run.addArg("-fqemu");
3421 if (b.enable_wine) run.addArg("-fwine");
3422 if (b.enable_wasmtime) run.addArg("-fwasmtime");
3423 if (b.enable_darling) run.addArg("-fdarling");
3308 run.addThirdPartyEnabledArgDarling(.{ .enabled = "-fdarling" });
3309 run.addThirdPartyEnabledArgQemu(.{ .enabled = "-fqemu" });
3310 run.addThirdPartyEnabledArgRosetta(.{ .enabled = "-frosetta" });
3311 run.addThirdPartyEnabledArgWasmtime(.{ .enabled = "-fwasmtime" });
3312 run.addThirdPartyEnabledArgWine(.{ .enabled = "-fwine" });
34243313
34253314 run.addCheck(.{ .expect_term = .{ .exited = 0 } });
34263315 test_step.dependOn(&run.step);