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 {...@@ -2119,7 +2119,7 @@ fn markFailedStepsDirty(maker: *Maker) void {
2119 for (all_steps) |step_index| {2119 for (all_steps) |step_index| {
2120 const step = maker.stepByIndex(step_index);2120 const step = maker.stepByIndex(step_index);
2121 switch (step.state) {2121 switch (step.state) {
2122 .dependency_failure, .failure, .skipped => _ = maker.invalidateResult(step),2122 .dependency_failure, .dependency_skipped, .failure, .skipped => _ = maker.invalidateResult(step),
2123 else => continue,2123 else => continue,
2124 }2124 }
2125 }2125 }
...@@ -2334,7 +2334,7 @@ fn makeSteps(...@@ -2334,7 +2334,7 @@ fn makeSteps(
2334 .precheck_unstarted => unreachable,2334 .precheck_unstarted => unreachable,
2335 .precheck_started => unreachable,2335 .precheck_started => unreachable,
2336 .precheck_done => unreachable,2336 .precheck_done => unreachable,
2337 .dependency_failure => pending_count += 1,2337 .dependency_failure, .dependency_skipped => pending_count += 1,
2338 .success => success_count += 1,2338 .success => success_count += 1,
2339 .skipped, .skipped_oom => skipped_count += 1,2339 .skipped, .skipped_oom => skipped_count += 1,
2340 .failure => {2340 .failure => {
...@@ -2580,10 +2580,14 @@ fn makeStep(...@@ -2580,10 +2580,14 @@ fn makeStep(
25802580
2581 .failure,2581 .failure,
2582 .dependency_failure,2582 .dependency_failure,
2583 .skipped_oom,
2584 => break .dependency_failure,2583 => break .dependency_failure,
25852584
2586 .success, .skipped => {},2585 .dependency_skipped,
2586 .skipped_oom,
2587 .skipped,
2588 => break .dependency_skipped,
2589
2590 .success => {},
2587 }2591 }
2588 } else if (Step.make(step_index, maker, step_prog_node)) state: {2592 } else if (Step.make(step_index, maker, step_prog_node)) state: {
2589 break :state .success;2593 break :state .success;
...@@ -2602,11 +2606,12 @@ fn makeStep(...@@ -2602,11 +2606,12 @@ fn makeStep(
26022606
2603 .failure,2607 .failure,
2604 .dependency_failure,2608 .dependency_failure,
2609 .dependency_skipped,
2605 .skipped_oom,2610 .skipped_oom,
2611 .skipped,
2606 => false,2612 => false,
26072613
2608 .success,2614 .success,
2609 .skipped,
2610 => true,2615 => true,
2611 };2616 };
26122617
...@@ -2623,7 +2628,7 @@ fn makeStep(...@@ -2623,7 +2628,7 @@ fn makeStep(
2623 .precheck_done => unreachable,2628 .precheck_done => unreachable,
2624 .success => .success,2629 .success => .success,
2625 .failure, .dependency_failure => .failure,2630 .failure, .dependency_failure => .failure,
2626 .skipped => .skipped,2631 .dependency_skipped, .skipped => .skipped,
2627 .skipped_oom => .skipped_oom,2632 .skipped_oom => .skipped_oom,
2628 };2633 };
2629 serveBuildStepCompleted(2634 serveBuildStepCompleted(
...@@ -2777,6 +2782,12 @@ fn printStepStatus(maker: *Maker, step_index: Configuration.Step.Index, stderr:...@@ -2777,6 +2782,12 @@ fn printStepStatus(maker: *Maker, step_index: Configuration.Step.Index, stderr:
2777 try stderr.setColor(.reset);2782 try stderr.setColor(.reset);
2778 },2783 },
27792784
2785 .dependency_skipped => {
2786 try stderr.setColor(.dim);
2787 try writer.writeAll(" transitive skip\n");
2788 try stderr.setColor(.reset);
2789 },
2790
2780 .success => {2791 .success => {
2781 try stderr.setColor(.green);2792 try stderr.setColor(.green);
2782 if (s.result_cached) {2793 if (s.result_cached) {
...@@ -3023,6 +3034,7 @@ fn constructGraphAndCheckForDependencyLoop(...@@ -3023,6 +3034,7 @@ fn constructGraphAndCheckForDependencyLoop(
30233034
3024 // These don't happen until we actually run the step graph.3035 // These don't happen until we actually run the step graph.
3025 .dependency_failure => unreachable,3036 .dependency_failure => unreachable,
3037 .dependency_skipped => unreachable,
3026 .success => unreachable,3038 .success => unreachable,
3027 .failure => unreachable,3039 .failure => unreachable,
3028 .skipped => unreachable,3040 .skipped => unreachable,
lib/compiler/Maker/Step.zig+3
...@@ -163,6 +163,9 @@ pub const State = enum {...@@ -163,6 +163,9 @@ pub const State = enum {
163 /// be re-evaluated.163 /// be re-evaluated.
164 precheck_done,164 precheck_done,
165 dependency_failure,165 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,
166 success,169 success,
167 failure,170 failure,
168 /// This state indicates that the step did not complete, however, it also did not fail,171 /// 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(...@@ -187,6 +187,11 @@ pub fn make(
187 man.hash.addListOfBytes(run_args);187 man.hash.addListOfBytes(run_args);
188 }188 }
189 },189 },
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),
190 }195 }
191 }196 }
192197
...@@ -351,6 +356,29 @@ pub fn make(...@@ -351,6 +356,29 @@ pub fn make(
351 step.clearFailedCommand(gpa);356 step.clearFailedCommand(gpa);
352}357}
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
354/// Reads stdout of a Zig test process until a termination condition is reached:382/// Reads stdout of a Zig test process until a termination condition is reached:
355/// * A write fails, indicating the child unexpectedly closed stdin383/// * A write fails, indicating the child unexpectedly closed stdin
356/// * A test (or a response from the test runner) times out384/// * A test (or a response from the test runner) times out
...@@ -1535,6 +1563,11 @@ pub fn rerunInFuzzMode(...@@ -1535,6 +1563,11 @@ pub fn rerunInFuzzMode(
1535 .output_file => unreachable,1563 .output_file => unreachable,
1536 .output_directory => unreachable,1564 .output_directory => unreachable,
1537 .passthru => unreachable,1565 .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),
1538 }1571 }
1539 }1572 }
15401573
lib/std/Build.zig-16
...@@ -45,17 +45,6 @@ debug_log_scopes: []const []const u8 = &.{},...@@ -45,17 +45,6 @@ debug_log_scopes: []const []const u8 = &.{},
45/// Set to 0 to disable stack collection.45/// Set to 0 to disable stack collection.
46debug_stack_frames_count: u8 = 8,46debug_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
59dep_prefix: []const u8 = "",48dep_prefix: []const u8 = "",
6049
61modules: std.array_hash_map.String(*Module),50modules: std.array_hash_map.String(*Module),
...@@ -388,11 +377,6 @@ fn createChild(...@@ -388,11 +377,6 @@ fn createChild(
388 .default_step = undefined,377 .default_step = undefined,
389 .top_level_steps = .{},378 .top_level_steps = .{},
390 .debug_log_scopes = parent.debug_log_scopes,379 .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,
396 .dep_prefix = parent.fmt("{s}{s}.", .{ parent.dep_prefix, dep_name }),380 .dep_prefix = parent.fmt("{s}{s}.", .{ parent.dep_prefix, dep_name }),
397 .modules = .empty,381 .modules = .empty,
398 .named_writefiles = .empty,382 .named_writefiles = .empty,
lib/std/Build/Configuration.zig+7
...@@ -626,6 +626,13 @@ pub const Step = extern struct {...@@ -626,6 +626,13 @@ pub const Step = extern struct {
626 output_file,626 output_file,
627 output_directory,627 output_directory,
628 passthru,628 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,
629 };636 };
630637
631 pub const Index = IndexType(@This());638 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...@@ -1017,6 +1017,101 @@ fn initArgsList(s: *Serialize, args: []const Step.Run.Arg) ![]const Configuratio
1017 .producer = .{ .value = null },1017 .producer = .{ .value = null },
1018 .generated = .{ .value = null },1018 .generated = .{ .value = null },
1019 },1019 },
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 },
1020 });1115 });
1021 }1116 }
1022 return result;1117 return result;
lib/std/Build/Step/Run.zig+55
...@@ -68,9 +68,11 @@ rename_step_with_output_arg: bool,...@@ -68,9 +68,11 @@ rename_step_with_output_arg: bool,
68/// executed binary will not fail the build if the binary cannot be executed68/// executed binary will not fail the build if the binary cannot be executed
69/// due to being for a foreign binary to the host system which is running the69/// due to being for a foreign binary to the host system which is running the
70/// build graph.70/// build graph.
71///
71/// Command-line arguments such as -fqemu and -fwasmtime may affect whether a72/// Command-line arguments such as -fqemu and -fwasmtime may affect whether a
72/// binary is detected as foreign, as well as system configuration such as73/// binary is detected as foreign, as well as system configuration such as
73/// Rosetta (macOS) and binfmt_misc (Linux).74/// Rosetta (macOS) and binfmt_misc (Linux).
75///
74/// If this Run step is considered to have side-effects, then this flag does76/// If this Run step is considered to have side-effects, then this flag does
75/// nothing.77/// nothing.
76skip_foreign_checks: bool,78skip_foreign_checks: bool,
...@@ -149,6 +151,19 @@ pub const Arg = union(enum) {...@@ -149,6 +151,19 @@ pub const Arg = union(enum) {
149 output_directory: *Output,151 output_directory: *Output,
150 /// The arguments passed after "--" on the "zig build" CLI.152 /// The arguments passed after "--" on the "zig build" CLI.
151 passthru,153 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,
152};167};
153168
154pub const DecoratedArtifact = struct {169pub const DecoratedArtifact = struct {
...@@ -576,6 +591,46 @@ pub fn addPassthruArgs(run: *Run) void {...@@ -576,6 +591,46 @@ pub fn addPassthruArgs(run: *Run) void {
576 run.argv.append(arena, .passthru) catch @panic("OOM");591 run.argv.append(arena, .passthru) catch @panic("OOM");
577}592}
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
579pub fn setStdIn(run: *Run, stdin: StdIn) void {634pub fn setStdIn(run: *Run, stdin: StdIn) void {
580 switch (stdin) {635 switch (stdin) {
581 .lazy_path => |lazy_path| lazy_path.addStepDependencies(&run.step),636 .lazy_path => |lazy_path| lazy_path.addStepDependencies(&run.step),
test/error_traces.zig+41-2
...@@ -1,7 +1,10 @@...@@ -1,7 +1,10 @@
1const std = @import("std");1const 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 {
4 cases.addCase(.{5 cases.addCase(.{
6 .params = params,
7 .target = target,
5 .name = "return",8 .name = "return",
6 .source =9 .source =
7 \\pub fn main() !void {10 \\pub fn main() !void {
...@@ -17,6 +20,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target....@@ -17,6 +20,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
17 });20 });
1821
19 cases.addCase(.{22 cases.addCase(.{
23 .params = params,
24 .target = target,
20 .name = "try return",25 .name = "try return",
21 .source =26 .source =
22 \\fn foo() !void {27 \\fn foo() !void {
...@@ -44,6 +49,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target....@@ -44,6 +49,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
44 },49 },
45 });50 });
46 cases.addCase(.{51 cases.addCase(.{
52 .params = params,
53 .target = target,
47 .name = "non-error return pops error trace",54 .name = "non-error return pops error trace",
48 .source =55 .source =
49 \\fn bar() !void {56 \\fn bar() !void {
...@@ -70,6 +77,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target....@@ -70,6 +77,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
70 });77 });
7178
72 cases.addCase(.{79 cases.addCase(.{
80 .params = params,
81 .target = target,
73 .name = "continue in while loop",82 .name = "continue in while loop",
74 .source =83 .source =
75 \\fn foo() !void {84 \\fn foo() !void {
...@@ -93,6 +102,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target....@@ -93,6 +102,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
93 });102 });
94103
95 cases.addCase(.{104 cases.addCase(.{
105 .params = params,
106 .target = target,
96 .name = "for loop pops error return trace",107 .name = "for loop pops error return trace",
97 .source =108 .source =
98 \\fn foo() !void { return error.FooError; }109 \\fn foo() !void { return error.FooError; }
...@@ -123,6 +134,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target....@@ -123,6 +134,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
123 });134 });
124135
125 cases.addCase(.{136 cases.addCase(.{
137 .params = params,
138 .target = target,
126 .name = "implicit continue in for loop pops stale error return trace",139 .name = "implicit continue in for loop pops stale error return trace",
127 .source =140 .source =
128 \\fn foo() !void { return error.FooError; }141 \\fn foo() !void { return error.FooError; }
...@@ -154,6 +167,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target....@@ -154,6 +167,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
154 });167 });
155168
156 cases.addCase(.{169 cases.addCase(.{
170 .params = params,
171 .target = target,
157 .name = "while loop pops error return trace",172 .name = "while loop pops error return trace",
158 .source =173 .source =
159 \\fn foo() !void { return error.FooError; }174 \\fn foo() !void { return error.FooError; }
...@@ -186,6 +201,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target....@@ -186,6 +201,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
186 });201 });
187202
188 cases.addCase(.{203 cases.addCase(.{
204 .params = params,
205 .target = target,
189 .name = "implicit continue in while loop pops stale error return trace",206 .name = "implicit continue in while loop pops stale error return trace",
190 .source =207 .source =
191 \\fn foo() !void { return error.FooError; }208 \\fn foo() !void { return error.FooError; }
...@@ -219,6 +236,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target....@@ -219,6 +236,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
219 });236 });
220237
221 cases.addCase(.{238 cases.addCase(.{
239 .params = params,
240 .target = target,
222 .name = "try return + handled catch/if-else",241 .name = "try return + handled catch/if-else",
223 .source =242 .source =
224 \\fn foo() !void {243 \\fn foo() !void {
...@@ -251,6 +270,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target....@@ -251,6 +270,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
251 });270 });
252271
253 cases.addCase(.{272 cases.addCase(.{
273 .params = params,
274 .target = target,
254 .name = "break from inline loop pops error return trace",275 .name = "break from inline loop pops error return trace",
255 .source =276 .source =
256 \\fn foo() !void { return error.FooBar; }277 \\fn foo() !void { return error.FooBar; }
...@@ -276,6 +297,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target....@@ -276,6 +297,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
276 });297 });
277298
278 cases.addCase(.{299 cases.addCase(.{
300 .params = params,
301 .target = target,
279 .name = "catch and re-throw error",302 .name = "catch and re-throw error",
280 .source =303 .source =
281 \\fn foo() !void {304 \\fn foo() !void {
...@@ -304,6 +327,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target....@@ -304,6 +327,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
304 });327 });
305328
306 cases.addCase(.{329 cases.addCase(.{
330 .params = params,
331 .target = target,
307 .name = "errors stored in var do not contribute to error trace",332 .name = "errors stored in var do not contribute to error trace",
308 .source =333 .source =
309 \\fn foo() !void {334 \\fn foo() !void {
...@@ -328,6 +353,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target....@@ -328,6 +353,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
328 });353 });
329354
330 cases.addCase(.{355 cases.addCase(.{
356 .params = params,
357 .target = target,
331 .name = "error stored in const has trace preserved for duration of block",358 .name = "error stored in const has trace preserved for duration of block",
332 .source =359 .source =
333 \\fn foo() !void { return error.TheSkyIsFalling; }360 \\fn foo() !void { return error.TheSkyIsFalling; }
...@@ -376,6 +403,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target....@@ -376,6 +403,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
376 });403 });
377404
378 cases.addCase(.{405 cases.addCase(.{
406 .params = params,
407 .target = target,
379 .name = "error passed to function has its trace preserved for duration of the call",408 .name = "error passed to function has its trace preserved for duration of the call",
380 .source =409 .source =
381 \\pub fn expectError(expected_error: anyerror, actual_error: anyerror!void) !void {410 \\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....@@ -418,6 +447,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
418 });447 });
419448
420 cases.addCase(.{449 cases.addCase(.{
450 .params = params,
451 .target = target,
421 .name = "try return from within catch",452 .name = "try return from within catch",
422 .source =453 .source =
423 \\fn foo() !void {454 \\fn foo() !void {
...@@ -455,6 +486,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target....@@ -455,6 +486,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
455 });486 });
456487
457 cases.addCase(.{488 cases.addCase(.{
489 .params = params,
490 .target = target,
458 .name = "try return from within if-else",491 .name = "try return from within if-else",
459 .source =492 .source =
460 \\fn foo() !void {493 \\fn foo() !void {
...@@ -492,6 +525,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target....@@ -492,6 +525,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
492 });525 });
493526
494 cases.addCase(.{527 cases.addCase(.{
528 .params = params,
529 .target = target,
495 .name = "try try return return",530 .name = "try try return return",
496 .source =531 .source =
497 \\fn foo() !void {532 \\fn foo() !void {
...@@ -534,6 +569,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target....@@ -534,6 +569,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
534 });569 });
535570
536 cases.addCase(.{571 cases.addCase(.{
572 .params = params,
573 .target = target,
537 .name = "error union switch with call operand",574 .name = "error union switch with call operand",
538 .source =575 .source =
539 \\pub fn main() !void {576 \\pub fn main() !void {
...@@ -579,6 +616,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target....@@ -579,6 +616,8 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
579 });616 });
580617
581 cases.addCase(.{618 cases.addCase(.{
619 .params = params,
620 .target = target,
582 .name = "trace through inline call",621 .name = "trace through inline call",
583 // The main function has two inline calls to ensure622 // The main function has two inline calls to ensure
584 // that inlinees in PDBs are properly deduplicated.623 // that inlinees in PDBs are properly deduplicated.
...@@ -595,7 +634,7 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target....@@ -595,7 +634,7 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
595 \\}634 \\}
596 ,635 ,
597 .expect_error = "ThisIsSoSad",636 .expect_error = "ThisIsSoSad",
598 .expect_trace = switch (os) {637 .expect_trace = switch (target.os.tag) {
599 // LLVM doesn't emit column info in the binary annotations for inlinee callees in PDBs,638 // LLVM doesn't emit column info in the binary annotations for inlinee callees in PDBs,
600 // so our expected result is slightly different for Windows than on other operating639 // so our expected result is slightly different for Windows than on other operating
601 // systems.640 // systems.
test/src/ErrorTrace.zig+119-52
...@@ -1,11 +1,81 @@...@@ -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
1b: *std.Build,12b: *std.Build,
2step: *Step,13step: *Step,
3test_filters: []const []const u8,14test_filters: []const []const u8,
4targets: []const std.Build.ResolvedTarget,15skip_non_native: bool,
5optimize_modes: []const OptimizeMode,16optimize_modes: []const OptimizeMode,
6convert_exe: *std.Build.Step.Compile,17convert_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
8pub const Case = struct {76pub const Case = struct {
77 params: *const CaseParameters,
78 target: *const std.Target,
9 name: []const u8,79 name: []const u8,
10 source: []const u8,80 source: []const u8,
11 expect_error: []const u8,81 expect_error: []const u8,
...@@ -22,50 +92,47 @@ pub const Case = struct {...@@ -22,50 +92,47 @@ pub const Case = struct {
22 pub const Backend = enum { llvm, selfhosted };92 pub const Backend = enum { llvm, selfhosted };
23};93};
2494
25pub fn addCase(self: *ErrorTrace, case: Case) void {95pub fn addCases(self: *ErrorTrace) void {
26 for (self.targets) |*target| {96 const b = self.b;
27 const triple: ?[]const u8 = if (target.query.isNative()) null else t: {97
28 break :t target.query.zigTriple(self.b.graph.arena) catch @panic("OOM");98 for (&param_sets) |*params| {
29 };99 const resolved_target = b.resolveTargetQuery(params.target);
30 for (self.optimize_modes) |optimize| {100
31 self.addCaseConfig(case, target, triple, optimize, .llvm);101 if (self.skip_non_native and !resolved_target.query.isNative()) continue;
32 }102
33 if (shouldTestNonLlvm(&target.result)) {103 // To avoid redundant testing, skip cross-compilation targets matching the host.
34 for (self.optimize_modes) |optimize| {104 if (resolved_target.result.os.tag == builtin.target.os.tag and
35 self.addCaseConfig(case, target, triple, optimize, .selfhosted);105 resolved_target.result.cpu.arch == builtin.target.cpu.arch)
36 }106 {
107 continue;
37 }108 }
38 }
39}
40109
41fn shouldTestNonLlvm(target: *const std.Target) bool {110 for (self.optimize_modes) |optimize| {
42 if (comptime builtin.cpu.arch.endian() == .big) return false; // https://github.com/ziglang/zig/issues/25961111 if (optimize == params.optimize) break;
43 return switch (target.cpu.arch) {112 } else return;
44 .x86_64 => switch (target.ofmt) {113
45 .elf => !target.os.tag.isBSD() and target.os.tag != .illumos,114 error_traces_cases.addCases(self, params, &resolved_target.result);
46 else => false,115 }
47 },
48 else => false,
49 };
50}116}
51117
52fn addCaseConfig(118/// Called from test/error_traces.zig
53 self: *ErrorTrace,119pub fn addCase(self: *ErrorTrace, case: Case) void {
54 case: Case,
55 target: *const std.Build.ResolvedTarget,
56 triple: ?[]const u8,
57 optimize: OptimizeMode,
58 backend: Case.Backend,
59) void {
60 const b = self.b;120 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
62 const error_tracing: bool = tracing: {129 const error_tracing: bool = tracing: {
63 if (optimize == .debug) break :tracing true;130 if (params.optimize == .debug) break :tracing true;
64 if (backend != .llvm) break :tracing true;131 if (params.use_llvm == false) break :tracing true;
65 if (optimize == .small) break :tracing false;132 if (params.optimize == .small) break :tracing false;
66 for (case.disable_trace_optimized) |disable| {133 for (case.disable_trace_optimized) |disable| {
67 const d_arch, const d_os = disable;134 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) {
69 // This particular configuration cannot do error tracing in optimized LLVM builds.136 // This particular configuration cannot do error tracing in optimized LLVM builds.
70 break :tracing false;137 break :tracing false;
71 }138 }
...@@ -73,12 +140,19 @@ fn addCaseConfig(...@@ -73,12 +140,19 @@ fn addCaseConfig(
73 break :tracing true;140 break :tracing true;
74 };141 };
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})", .{
77 case.name,151 case.name,
78 triple orelse "",152 triple orelse "",
79 if (triple != null) " " else "",153 if (triple != null) " " else "",
80 @tagName(optimize),154 params.optimize,
81 @tagName(backend),155 backend_string,
82 });156 });
83 if (self.test_filters.len > 0) {157 if (self.test_filters.len > 0) {
84 for (self.test_filters) |test_filter| {158 for (self.test_filters) |test_filter| {
...@@ -92,19 +166,18 @@ fn addCaseConfig(...@@ -92,19 +166,18 @@ fn addCaseConfig(
92 .name = "test",166 .name = "test",
93 .root_module = b.createModule(.{167 .root_module = b.createModule(.{
94 .root_source_file = source_zig,168 .root_source_file = source_zig,
95 .optimize = optimize,169 .optimize = params.optimize,
96 .target = target.*,170 .target = .{ .result = target.*, .query = target_query },
97 .error_tracing = error_tracing,171 .error_tracing = error_tracing,
98 .strip = false,172 .strip = false,
99 }),173 }),
100 .use_llvm = switch (backend) {174 .use_llvm = params.use_llvm,
101 .llvm => true,175 .use_lld = params.use_lld,
102 .selfhosted => false,
103 },
104 });176 });
105 exe.bundle_ubsan_rt = false;177 exe.bundle_ubsan_rt = false;
106178
107 const run = b.addRunArtifact(exe);179 const run = b.addRunArtifact(exe);
180 run.skip_foreign_checks = true;
108 run.removeEnvironmentVariable("CLICOLOR_FORCE");181 run.removeEnvironmentVariable("CLICOLOR_FORCE");
109 run.setEnvironmentVariable("NO_COLOR", "1");182 run.setEnvironmentVariable("NO_COLOR", "1");
110 run.expectExitCode(1);183 run.expectExitCode(1);
...@@ -116,16 +189,10 @@ fn addCaseConfig(...@@ -116,16 +189,10 @@ fn addCaseConfig(
116 };189 };
117190
118 const check_run = b.addRunArtifact(self.convert_exe);191 const check_run = b.addRunArtifact(self.convert_exe);
192 check_run.skip_foreign_checks = true;
119 check_run.setName(annotated_case_name);193 check_run.setName(annotated_case_name);
120 check_run.addFileArg(run.captureStdErr(.{}));194 check_run.addFileArg(run.captureStdErr(.{}));
121 check_run.expectStdOutEqual(expected_stderr);195 check_run.expectStdOutEqual(expected_stderr);
122196
123 self.step.dependOn(&check_run.step);197 self.step.dependOn(&check_run.step);
124}198}
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 @@...@@ -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
1b: *std.Build,12b: *std.Build,
2step: *Step,13step: *Step,
3test_filters: []const []const u8,14test_filters: []const []const u8,
4targets: []const std.Build.ResolvedTarget,15skip_non_native: bool,
5convert_exe: *std.Build.Step.Compile,16convert_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
7const Config = struct {86const Config = struct {
87 params: *const CaseParameters,
88 target: *const std.Target,
8 name: []const u8,89 name: []const u8,
9 source: []const u8,90 source: []const u8,
10 /// Whether this test case expects to have unwind tables / frame pointers.91 /// Whether this test case expects to have unwind tables / frame pointers.
...@@ -26,42 +107,37 @@ const Config = struct {...@@ -26,42 +107,37 @@ const Config = struct {
26 expect_strip: []const u8,107 expect_strip: []const u8,
27};108};
28109
29pub fn addCase(self: *StackTrace, config: Config) void {110pub fn addCases(self: *StackTrace) void {
30 for (self.targets) |*target| {111 const b = self.b;
31 addCaseTarget(112
32 self,113 for (&param_sets) |*params| {
33 config,114 const resolved_target = b.resolveTargetQuery(params.target);
34 target,115
35 if (target.query.isNative()) null else t: {116 if (self.skip_non_native and !resolved_target.query.isNative()) continue;
36 break :t target.query.zigTriple(self.b.graph.arena) catch @panic("OOM");117
37 },118 // To avoid redundant testing, skip cross-compilation targets matching the host.
38 );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);
39 }126 }
40}127}
41fn addCaseTarget(128
42 self: *StackTrace,129/// Called from test/stack_traces.zig
43 config: Config,130pub fn addCase(self: *StackTrace, config: Config) void {
44 target: *const std.Build.ResolvedTarget,131 const params = config.params;
45 triple: ?[]const u8,132 const target = config.target;
46) void {133 const target_query = config.params.target;
47 const both_backends = b: {134
48 if (comptime builtin.cpu.arch.endian() == .big) break :b false; // https://github.com/ziglang/zig/issues/25961135 const triple: ?[]const u8 = if (target_query.isNative()) null else t: {
49 break :b switch (target.result.cpu.arch) {136 break :t target_query.zigTriple(self.b.graph.arena) catch @panic("OOM");
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,
60 };137 };
61 const both_libc = !std.os.targetRequiresLibC(&target.result);
62138
63 // See `std.debug.StackIterator.fp_usability` logic.139 // 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) {
65 .alpha,141 .alpha,
66 .csky,142 .csky,
67 .microblaze,143 .microblaze,
...@@ -83,20 +159,15 @@ fn addCaseTarget(...@@ -83,20 +159,15 @@ fn addCaseTarget(
83 .sparc,159 .sparc,
84 .sparc64,160 .sparc64,
85 => .ideal,161 => .ideal,
86 .aarch64 => if (target.result.os.tag.isDarwin()) .safe else .unsafe,162 .aarch64 => if (target.os.tag.isDarwin()) .safe else .unsafe,
87 else => .unsafe,163 else => .unsafe,
88 };164 };
89 const supports_unwind_tables = switch (target.result.os.tag) {165 const supports_unwind_tables = switch (target.os.tag) {
90 // x86-windows just has no way to do stack unwinding other then using frame pointers.166 // 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,
92 else => true,168 else => true,
93 };169 };
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
100 const UnwindInfo = packed struct(u2) {171 const UnwindInfo = packed struct(u2) {
101 tables: bool,172 tables: bool,
102 fp: bool,173 fp: bool,
...@@ -126,43 +197,33 @@ fn addCaseTarget(...@@ -126,43 +197,33 @@ fn addCaseTarget(
126 },197 },
127 };198 };
128199
129 for (use_llvm_vals) |use_llvm| {200 for (unwind_info_vals) |unwind_info| {
130 for (pie_vals) |pie| {201 if (unwind_info.tables and !supports_unwind_tables) continue;
131 for (link_libc_vals) |link_libc| {202 const strip = params.strip orelse switch (params.optimize) {
132 for (strip_debug_vals) |strip_debug| {203 .debug, .fast, .safe => false,
133 for (unwind_info_vals) |unwind_info| {204 .small => true,
134 if (unwind_info.tables and !supports_unwind_tables) continue;205 };
135 self.addCaseInstance(206 self.addCaseInstance(
136 target,207 .{ .result = target.*, .query = target_query },
137 triple,208 triple,
138 config.name,209 config.name,
139 config.source,210 config.source,
140 use_llvm,211 params,
141 pie,212 !unwind_info.tables and supports_unwind_tables,
142 link_libc,213 !unwind_info.fp,
143 strip_debug,214 config.expect_panic,
144 !unwind_info.tables and supports_unwind_tables,215 if (strip) config.expect_strip else config.expect,
145 !unwind_info.fp,216 );
146 config.expect_panic,
147 if (strip_debug) config.expect_strip else config.expect,
148 );
149 }
150 }
151 }
152 }
153 }217 }
154}218}
155219
156fn addCaseInstance(220fn addCaseInstance(
157 self: *StackTrace,221 self: *StackTrace,
158 target: *const std.Build.ResolvedTarget,222 resolved_target: std.Build.ResolvedTarget,
159 triple: ?[]const u8,223 triple: ?[]const u8,
160 name: []const u8,224 name: []const u8,
161 source: []const u8,225 source: []const u8,
162 use_llvm: bool,226 params: *const CaseParameters,
163 pie: ?bool,
164 link_libc: ?bool,
165 strip_debug: bool,
166 strip_unwind: bool,227 strip_unwind: bool,
167 omit_frame_pointer: bool,228 omit_frame_pointer: bool,
168 expect_panic: bool,229 expect_panic: bool,
...@@ -170,13 +231,6 @@ fn addCaseInstance(...@@ -170,13 +231,6 @@ fn addCaseInstance(
170) void {231) void {
171 const b = self.b;232 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
180 if (strip_unwind) {234 if (strip_unwind) {
181 // To enable this coverage, `std.Build.Step.ObjCopy` needs to be un-regressed and gain the235 // To enable this coverage, `std.Build.Step.ObjCopy` needs to be un-regressed and gain the
182 // ability to remove individual sections. `-fno-unwind-tables` is insufficient because it236 // ability to remove individual sections. `-fno-unwind-tables` is insufficient because it
...@@ -187,14 +241,28 @@ fn addCaseInstance(...@@ -187,14 +241,28 @@ fn addCaseInstance(
187 return;241 return;
188 }242 }
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
190 const annotated_case_name = b.fmt("check {s} ({s}{s}{s}{s}{s}{s}{s}{s})", .{258 const annotated_case_name = b.fmt("check {s} ({s}{s}{s}{s}{s}{s}{s}{s})", .{
191 name,259 name,
192 triple orelse "",260 triple orelse "",
193 if (triple != null) " " else "",261 if (triple != null) " " else "",
194 if (use_llvm) "llvm" else "selfhosted",262 backend_string,
195 if (pie == true) " pie" else "",263 if (params.pie == true) " pie" else "",
196 if (link_libc == true) " libc" else "",264 if (params.link_libc == true) " libc" else "",
197 if (strip_debug) " strip" else "",265 strip_string,
198 if (strip_unwind) " no_unwind" else "",266 if (strip_unwind) " no_unwind" else "",
199 if (omit_frame_pointer) " no_fp" else "",267 if (omit_frame_pointer) " no_fp" else "",
200 });268 });
...@@ -211,24 +279,26 @@ fn addCaseInstance(...@@ -211,24 +279,26 @@ fn addCaseInstance(
211 .root_module = b.createModule(.{279 .root_module = b.createModule(.{
212 .root_source_file = source_zig,280 .root_source_file = source_zig,
213 .optimize = .Debug,281 .optimize = .Debug,
214 .target = target.*,282 .target = resolved_target,
215 .omit_frame_pointer = omit_frame_pointer,283 .omit_frame_pointer = omit_frame_pointer,
216 .link_libc = link_libc,284 .link_libc = params.link_libc,
217 .unwind_tables = if (strip_unwind) .none else null,285 .unwind_tables = if (strip_unwind) .none else null,
218 // make panics single-threaded so that they don't include a thread ID286 // make panics single-threaded so that they don't include a thread ID
219 .single_threaded = expect_panic,287 .single_threaded = expect_panic,
220 }),288 }),
221 .use_llvm = use_llvm,289 .use_llvm = params.use_llvm,
290 .use_lld = params.use_lld,
222 });291 });
223 exe.pie = pie;292 exe.pie = params.pie;
224 exe.bundle_ubsan_rt = false;293 exe.bundle_ubsan_rt = false;
225294
226 const run = b.addRunArtifact(exe);295 const run = b.addRunArtifact(exe);
296 run.skip_foreign_checks = true;
227 run.removeEnvironmentVariable("CLICOLOR_FORCE");297 run.removeEnvironmentVariable("CLICOLOR_FORCE");
228 run.setEnvironmentVariable("NO_COLOR", "1");298 run.setEnvironmentVariable("NO_COLOR", "1");
229 run.addCheck(.{ .expect_term = term: {299 run.addCheck(.{ .expect_term = term: {
230 if (!expect_panic) break :term .{ .exited = 0 };300 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 };
232 break :term .{ .signal = @fromBackingInt(@intCast(6)) };302 break :term .{ .signal = @fromBackingInt(@intCast(6)) };
233 } });303 } });
234 run.expectStdOutEqual("");304 run.expectStdOutEqual("");
...@@ -241,10 +311,3 @@ fn addCaseInstance(...@@ -241,10 +311,3 @@ fn addCaseInstance(
241311
242 self.step.dependOn(&check_run.step);312 self.step.dependOn(&check_run.step);
243}313}
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 @@...@@ -1,7 +1,10 @@
1const std = @import("std");1const 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 {
4 cases.addCase(.{5 cases.addCase(.{
6 .params = params,
7 .target = target,
5 .name = "simple panic",8 .name = "simple panic",
6 .source =9 .source =
7 \\pub fn main() void {10 \\pub fn main() void {
...@@ -33,6 +36,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target....@@ -33,6 +36,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target.
33 });36 });
3437
35 cases.addCase(.{38 cases.addCase(.{
39 .params = params,
40 .target = target,
36 .name = "simple panic with no unwind strategy",41 .name = "simple panic with no unwind strategy",
37 .source =42 .source =
38 \\pub fn main() void {43 \\pub fn main() void {
...@@ -50,6 +55,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target....@@ -50,6 +55,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target.
50 });55 });
5156
52 cases.addCase(.{57 cases.addCase(.{
58 .params = params,
59 .target = target,
53 .name = "dump current trace",60 .name = "dump current trace",
54 .source =61 .source =
55 \\pub fn main() void {62 \\pub fn main() void {
...@@ -89,6 +96,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target....@@ -89,6 +96,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target.
89 });96 });
9097
91 cases.addCase(.{98 cases.addCase(.{
99 .params = params,
100 .target = target,
92 .name = "dump current trace with no unwind strategy",101 .name = "dump current trace with no unwind strategy",
93 .source =102 .source =
94 \\pub fn main() void {103 \\pub fn main() void {
...@@ -114,6 +123,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target....@@ -114,6 +123,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target.
114 });123 });
115124
116 cases.addCase(.{125 cases.addCase(.{
126 .params = params,
127 .target = target,
117 .name = "dump captured trace",128 .name = "dump captured trace",
118 .source =129 .source =
119 \\pub fn main() void {130 \\pub fn main() void {
...@@ -155,6 +166,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target....@@ -155,6 +166,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target.
155 });166 });
156167
157 cases.addCase(.{168 cases.addCase(.{
169 .params = params,
170 .target = target,
158 .name = "dump captured trace with no unwind strategy",171 .name = "dump captured trace with no unwind strategy",
159 .source =172 .source =
160 \\pub fn main() void {173 \\pub fn main() void {
...@@ -180,6 +193,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target....@@ -180,6 +193,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target.
180 });193 });
181194
182 cases.addCase(.{195 cases.addCase(.{
196 .params = params,
197 .target = target,
183 .name = "dump captured trace on thread",198 .name = "dump captured trace on thread",
184 .source =199 .source =
185 \\pub fn main() !void {200 \\pub fn main() !void {
...@@ -225,6 +240,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target....@@ -225,6 +240,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target.
225 });240 });
226241
227 cases.addCase(.{242 cases.addCase(.{
243 .params = params,
244 .target = target,
228 .name = "simple inline panic",245 .name = "simple inline panic",
229 // The main function has two inline calls to ensure246 // The main function has two inline calls to ensure
230 // that inlinees in PDBs are properly deduplicated.247 // that inlinees in PDBs are properly deduplicated.
...@@ -240,7 +257,7 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target....@@ -240,7 +257,7 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target.
240 ,257 ,
241 .unwind = .any,258 .unwind = .any,
242 .expect_panic = true,259 .expect_panic = true,
243 .expect = switch (os) {260 .expect = switch (target.os.tag) {
244 // LLVM doesn't emit column info in the binary annotations for inlinee callees in PDBs,261 // LLVM doesn't emit column info in the binary annotations for inlinee callees in PDBs,
245 // so the first location has only a row.262 // so the first location has only a row.
246 .windows =>263 .windows =>
...@@ -262,7 +279,7 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target....@@ -262,7 +279,7 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target.
262 \\ ^279 \\ ^
263 ,280 ,
264 },281 },
265 .expect_strip = switch (os) {282 .expect_strip = switch (target.os.tag) {
266 .windows =>283 .windows =>
267 \\panic: oh no284 \\panic: oh no
268 \\???:?:?: [address] in source.foo285 \\???:?:?: [address] in source.foo
...@@ -279,6 +296,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target....@@ -279,6 +296,8 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target.
279296
280 // Make sure all inline calls are resolved and in the right order!297 // Make sure all inline calls are resolved and in the right order!
281 cases.addCase(.{298 cases.addCase(.{
299 .params = params,
300 .target = target,
282 .name = "nested inline panic",301 .name = "nested inline panic",
283 .source =302 .source =
284 \\pub fn main() void {303 \\pub fn main() void {
...@@ -298,7 +317,7 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target....@@ -298,7 +317,7 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target.
298 .unwind = .any,317 .unwind = .any,
299 .expect_panic = true,318 .expect_panic = true,
300 // This switch serves a similar purpose as in "inline panic".319 // This switch serves a similar purpose as in "inline panic".
301 .expect = switch (os) {320 .expect = switch (target.os.tag) {
302 .windows =>321 .windows =>
303 \\panic: oh no322 \\panic: oh no
304 \\source.zig:11: [address] in baz323 \\source.zig:11: [address] in baz
...@@ -322,7 +341,7 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target....@@ -322,7 +341,7 @@ pub fn addCases(cases: *@import("tests.zig").StackTracesContext, os: std.Target.
322 \\ ^341 \\ ^
323 ,342 ,
324 },343 },
325 .expect_strip = switch (os) {344 .expect_strip = switch (target.os.tag) {
326 .windows =>345 .windows =>
327 \\panic: oh no346 \\panic: oh no
328 \\???:?:?: [address] in baz347 \\???:?:?: [address] in baz
test/standalone/build.zig.zon-3
...@@ -187,9 +187,6 @@...@@ -187,9 +187,6 @@
187 .posix = .{187 .posix = .{
188 .path = "posix",188 .path = "posix",
189 },189 },
190 .debug_io_color = .{
191 .path = "debug_io_color",
192 },
193 .elf2 = .{190 .elf2 = .{
194 .path = "elf2",191 .path = "elf2",
195 },192 },
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;...@@ -6,8 +6,6 @@ const OptimizeMode = std.builtin.OptimizeMode;
6const Step = std.Build.Step;6const Step = std.Build.Step;
77
8// Cases8// Cases
9const error_traces = @import("error_traces.zig");
10const stack_traces = @import("stack_traces.zig");
11const llvm_ir = @import("llvm_ir.zig");9const llvm_ir = @import("llvm_ir.zig");
12const libc = @import("libc.zig");10const libc = @import("libc.zig");
13const link = @import("link.zig");11const link = @import("link.zig");
...@@ -2381,59 +2379,7 @@ pub fn isNative(actual_target: *const std.Build.ResolvedTarget, host: *const std...@@ -2381,59 +2379,7 @@ pub fn isNative(actual_target: *const std.Build.ResolvedTarget, host: *const std
2381 return true;2379 return true;
2382}2380}
23832381
2384/// For stack trace tests, we only test native by default, because external executors are pretty2382pub fn addStackTraceTests(b: *std.Build, test_filters: []const []const u8, skip_non_native: bool) *Step {
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 {
2437 const step = b.step("test-stack-traces", "Run the stack trace tests");2383 const step = b.step("test-stack-traces", "Run the stack trace tests");
24382384
2439 const convert_exe = b.addExecutable(.{2385 const convert_exe = b.addExecutable(.{
...@@ -2445,39 +2391,15 @@ pub fn addStackTraceTests(...@@ -2445,39 +2391,15 @@ pub fn addStackTraceTests(
2445 }),2391 }),
2446 });2392 });
24472393
2448 const host_cases = b.allocator.create(StackTracesContext) catch @panic("OOM");2394 const stack_traces_context = b.allocator.create(StackTracesContext) catch @panic("OOM");
2449 host_cases.* = .{2395 stack_traces_context.* = .{
2450 .b = b,2396 .b = b,
2451 .step = step,2397 .step = step,
2452 .test_filters = test_filters,2398 .test_filters = test_filters,
2453 .targets = nativeAndCompatible32bit(b, skip_non_native),2399 .skip_non_native = skip_non_native,
2454 .convert_exe = convert_exe,2400 .convert_exe = convert_exe,
2455 };2401 };
2456 stack_traces.addCases(host_cases, b.graph.host.result.os.tag);2402 stack_traces_context.addCases();
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 }
24812403
2482 return step;2404 return step;
2483}2405}
...@@ -2499,52 +2421,20 @@ pub fn addErrorTraceTests(...@@ -2499,52 +2421,20 @@ pub fn addErrorTraceTests(
2499 }),2421 }),
2500 });2422 });
25012423
2502 const host_cases = b.allocator.create(ErrorTracesContext) catch @panic("OOM");2424 const error_traces_context = b.allocator.create(ErrorTracesContext) catch @panic("OOM");
2503 host_cases.* = .{2425 error_traces_context.* = .{
2504 .b = b,2426 .b = b,
2505 .step = step,2427 .step = step,
2506 .test_filters = test_filters,2428 .test_filters = test_filters,
2507 .targets = nativeAndCompatible32bit(b, skip_non_native),2429 .skip_non_native = skip_non_native,
2508 .optimize_modes = optimize_modes,2430 .optimize_modes = optimize_modes,
2509 .convert_exe = convert_exe,2431 .convert_exe = convert_exe,
2510 };2432 };
2511 error_traces.addCases(host_cases, b.graph.host.result.os.tag);2433 error_traces_context.addCases();
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 }
25382434
2539 return step;2435 return step;
2540}2436}
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
2548pub fn addStandaloneTests(2438pub fn addStandaloneTests(
2549 b: *std.Build,2439 b: *std.Build,
2550 optimize_modes: []const OptimizeMode,2440 optimize_modes: []const OptimizeMode,
...@@ -2553,21 +2443,19 @@ pub fn addStandaloneTests(...@@ -2553,21 +2443,19 @@ pub fn addStandaloneTests(
2553 enable_symlinks_windows: bool,2443 enable_symlinks_windows: bool,
2554) *Step {2444) *Step {
2555 const step = b.step("test-standalone", "Run the standalone tests");2445 const step = b.step("test-standalone", "Run the standalone tests");
2556 if (compilerHasPackageManager(b)) {2446 const test_cases_dep_name = "standalone_test_cases";
2557 const test_cases_dep_name = "standalone_test_cases";2447 const test_cases_dep = b.dependency(test_cases_dep_name, .{
2558 const test_cases_dep = b.dependency(test_cases_dep_name, .{2448 .enable_ios_sdk = enable_ios_sdk,
2559 .enable_ios_sdk = enable_ios_sdk,2449 .enable_macos_sdk = enable_macos_sdk,
2560 .enable_macos_sdk = enable_macos_sdk,2450 .enable_symlinks_windows = enable_symlinks_windows,
2561 .enable_symlinks_windows = enable_symlinks_windows,2451 .simple_skip_debug = mem.findScalar(OptimizeMode, optimize_modes, .debug) == null,
2562 .simple_skip_debug = mem.findScalar(OptimizeMode, optimize_modes, .debug) == null,2452 .simple_skip_release_safe = mem.findScalar(OptimizeMode, optimize_modes, .safe) == null,
2563 .simple_skip_release_safe = mem.findScalar(OptimizeMode, optimize_modes, .safe) == null,2453 .simple_skip_release_fast = mem.findScalar(OptimizeMode, optimize_modes, .fast) == null,
2564 .simple_skip_release_fast = mem.findScalar(OptimizeMode, optimize_modes, .fast) == null,2454 .simple_skip_release_small = mem.findScalar(OptimizeMode, optimize_modes, .small) == null,
2565 .simple_skip_release_small = mem.findScalar(OptimizeMode, optimize_modes, .small) == null,2455 });
2566 });2456 const test_cases_dep_step = test_cases_dep.builder.default_step;
2567 const test_cases_dep_step = test_cases_dep.builder.default_step;2457 test_cases_dep_step.name = b.graph.dupeString(test_cases_dep_name);
2568 test_cases_dep_step.name = b.graph.dupeString(test_cases_dep_name);2458 step.dependOn(test_cases_dep.builder.default_step);
2569 step.dependOn(test_cases_dep.builder.default_step);
2570 }
2571 return step;2459 return step;
2572}2460}
25732461
...@@ -3417,10 +3305,11 @@ pub fn addIncrementalTests(b: *std.Build, test_step: *Step, test_filters: []cons...@@ -3417,10 +3305,11 @@ pub fn addIncrementalTests(b: *std.Build, test_step: *Step, test_filters: []cons
34173305
3418 run.addArg("--quiet"); // don't fill stderr telling us about skipped tests etc3306 run.addArg("--quiet"); // don't fill stderr telling us about skipped tests etc
34193307
3420 if (b.enable_qemu) run.addArg("-fqemu");3308 run.addThirdPartyEnabledArgDarling(.{ .enabled = "-fdarling" });
3421 if (b.enable_wine) run.addArg("-fwine");3309 run.addThirdPartyEnabledArgQemu(.{ .enabled = "-fqemu" });
3422 if (b.enable_wasmtime) run.addArg("-fwasmtime");3310 run.addThirdPartyEnabledArgRosetta(.{ .enabled = "-frosetta" });
3423 if (b.enable_darling) run.addArg("-fdarling");3311 run.addThirdPartyEnabledArgWasmtime(.{ .enabled = "-fwasmtime" });
3312 run.addThirdPartyEnabledArgWine(.{ .enabled = "-fwine" });
34243313
3425 run.addCheck(.{ .expect_term = .{ .exited = 0 } });3314 run.addCheck(.{ .expect_term = .{ .exited = 0 } });
3426 test_step.dependOn(&run.step);3315 test_step.dependOn(&run.step);