authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-07-24 17:41:44-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-07-25 18:52:21-07:00
loga3c74aca99c7eaf719c745ec6e9ee7366cad1910
treeb0396505cb9623d1a906501ed97905f7cc8bb6c6
parent90dfd86ebee1639e5455ace4e34157ff9b68ac0f

add --debug-rt CLI arg to the compiler + bonus edits

The flag makes compiler_rt and libfuzzer be in debug mode. Also: * fuzzer: override debug logs and disable debug logs for frequently called functions * std.Build.Fuzz: fix bug of rerunning the old unit test binary * report errors from rebuilding the unit tests better * link.Elf: additionally add tsan lib and fuzzer lib to the hash

9 files changed, 116 insertions(+), 29 deletions(-)

lib/compiler/build_runner.zig+6-4
...@@ -208,6 +208,8 @@ pub fn main() !void {...@@ -208,6 +208,8 @@ pub fn main() !void {
208 try debug_log_scopes.append(next_arg);208 try debug_log_scopes.append(next_arg);
209 } else if (mem.eql(u8, arg, "--debug-pkg-config")) {209 } else if (mem.eql(u8, arg, "--debug-pkg-config")) {
210 builder.debug_pkg_config = true;210 builder.debug_pkg_config = true;
211 } else if (mem.eql(u8, arg, "--debug-rt")) {
212 graph.debug_compiler_runtime_libs = true;
211 } else if (mem.eql(u8, arg, "--debug-compile-errors")) {213 } else if (mem.eql(u8, arg, "--debug-compile-errors")) {
212 builder.debug_compile_errors = true;214 builder.debug_compile_errors = true;
213 } else if (mem.eql(u8, arg, "--system")) {215 } else if (mem.eql(u8, arg, "--system")) {
...@@ -1072,7 +1074,8 @@ fn workerMakeOneStep(...@@ -1072,7 +1074,8 @@ fn workerMakeOneStep(
1072 std.debug.lockStdErr();1074 std.debug.lockStdErr();
1073 defer std.debug.unlockStdErr();1075 defer std.debug.unlockStdErr();
10741076
1075 printErrorMessages(b, s, run.ttyconf, run.stderr, run.prominent_compile_errors) catch {};1077 const gpa = b.allocator;
1078 printErrorMessages(gpa, s, run.ttyconf, run.stderr, run.prominent_compile_errors) catch {};
1076 }1079 }
10771080
1078 handle_result: {1081 handle_result: {
...@@ -1126,14 +1129,12 @@ fn workerMakeOneStep(...@@ -1126,14 +1129,12 @@ fn workerMakeOneStep(
1126}1129}
11271130
1128pub fn printErrorMessages(1131pub fn printErrorMessages(
1129 b: *std.Build,1132 gpa: Allocator,
1130 failing_step: *Step,1133 failing_step: *Step,
1131 ttyconf: std.io.tty.Config,1134 ttyconf: std.io.tty.Config,
1132 stderr: File,1135 stderr: File,
1133 prominent_compile_errors: bool,1136 prominent_compile_errors: bool,
1134) !void {1137) !void {
1135 const gpa = b.allocator;
1136
1137 // Provide context for where these error messages are coming from by1138 // Provide context for where these error messages are coming from by
1138 // printing the corresponding Step subtree.1139 // printing the corresponding Step subtree.
11391140
...@@ -1313,6 +1314,7 @@ fn usage(b: *std.Build, out_stream: anytype) !void {...@@ -1313,6 +1314,7 @@ fn usage(b: *std.Build, out_stream: anytype) !void {
1313 \\ --seed [integer] For shuffling dependency traversal order (default: random)1314 \\ --seed [integer] For shuffling dependency traversal order (default: random)
1314 \\ --debug-log [scope] Enable debugging the compiler1315 \\ --debug-log [scope] Enable debugging the compiler
1315 \\ --debug-pkg-config Fail if unknown pkg-config flags encountered1316 \\ --debug-pkg-config Fail if unknown pkg-config flags encountered
1317 \\ --debug-rt Debug compiler runtime libraries
1316 \\ --verbose-link Enable compiler debug output for linking1318 \\ --verbose-link Enable compiler debug output for linking
1317 \\ --verbose-air Enable compiler debug output for Zig AIR1319 \\ --verbose-air Enable compiler debug output for Zig AIR
1318 \\ --verbose-llvm-ir[=file] Enable compiler debug output for LLVM IR1320 \\ --verbose-llvm-ir[=file] Enable compiler debug output for LLVM IR
lib/fuzzer.zig+62-10
...@@ -1,14 +1,40 @@...@@ -1,14 +1,40 @@
1const std = @import("std");1const std = @import("std");
2const Allocator = std.mem.Allocator;2const Allocator = std.mem.Allocator;
33
4pub const std_options = .{
5 .logFn = logOverride,
6};
7
8var log_file: ?std.fs.File = null;
9
10fn logOverride(
11 comptime level: std.log.Level,
12 comptime scope: @TypeOf(.EnumLiteral),
13 comptime format: []const u8,
14 args: anytype,
15) void {
16 const f = if (log_file) |f| f else f: {
17 const f = std.fs.cwd().createFile("libfuzzer.log", .{}) catch @panic("failed to open fuzzer log file");
18 log_file = f;
19 break :f f;
20 };
21 const prefix1 = comptime level.asText();
22 const prefix2 = if (scope == .default) ": " else "(" ++ @tagName(scope) ++ "): ";
23 f.writer().print(prefix1 ++ prefix2 ++ format ++ "\n", args) catch @panic("failed to write to fuzzer log");
24}
25
4export threadlocal var __sancov_lowest_stack: usize = 0;26export threadlocal var __sancov_lowest_stack: usize = 0;
527
6export fn __sanitizer_cov_8bit_counters_init(start: [*]u8, stop: [*]u8) void {28export fn __sanitizer_cov_8bit_counters_init(start: [*]u8, stop: [*]u8) void {
7 std.log.debug("__sanitizer_cov_8bit_counters_init start={*}, stop={*}", .{ start, stop });29 std.log.debug("__sanitizer_cov_8bit_counters_init start={*}, stop={*}", .{ start, stop });
8}30}
931
10export fn __sanitizer_cov_pcs_init(pcs_beg: [*]const usize, pcs_end: [*]const usize) void {32export fn __sanitizer_cov_pcs_init(pc_start: [*]const usize, pc_end: [*]const usize) void {
11 std.log.debug("__sanitizer_cov_pcs_init pcs_beg={*}, pcs_end={*}", .{ pcs_beg, pcs_end });33 std.log.debug("__sanitizer_cov_pcs_init pc_start={*}, pc_end={*}", .{ pc_start, pc_end });
34 fuzzer.pc_range = .{
35 .start = @intFromPtr(pc_start),
36 .end = @intFromPtr(pc_start),
37 };
12}38}
1339
14export fn __sanitizer_cov_trace_const_cmp1(arg1: u8, arg2: u8) void {40export fn __sanitizer_cov_trace_const_cmp1(arg1: u8, arg2: u8) void {
...@@ -48,34 +74,45 @@ export fn __sanitizer_cov_trace_switch(val: u64, cases_ptr: [*]u64) void {...@@ -48,34 +74,45 @@ export fn __sanitizer_cov_trace_switch(val: u64, cases_ptr: [*]u64) void {
48 const len = cases_ptr[0];74 const len = cases_ptr[0];
49 const val_size_in_bits = cases_ptr[1];75 const val_size_in_bits = cases_ptr[1];
50 const cases = cases_ptr[2..][0..len];76 const cases = cases_ptr[2..][0..len];
51 std.log.debug("0x{x}: switch on value {d} ({d} bits) with {d} cases", .{77 _ = val;
52 pc, val, val_size_in_bits, cases.len,78 _ = pc;
53 });79 _ = val_size_in_bits;
80 _ = cases;
81 //std.log.debug("0x{x}: switch on value {d} ({d} bits) with {d} cases", .{
82 // pc, val, val_size_in_bits, cases.len,
83 //});
54}84}
5585
56export fn __sanitizer_cov_trace_pc_indir(callee: usize) void {86export fn __sanitizer_cov_trace_pc_indir(callee: usize) void {
57 const pc = @returnAddress();87 const pc = @returnAddress();
58 std.log.debug("0x{x}: indirect call to 0x{x}", .{ pc, callee });88 _ = callee;
89 _ = pc;
90 //std.log.debug("0x{x}: indirect call to 0x{x}", .{ pc, callee });
59}91}
6092
61fn handleCmp(pc: usize, arg1: u64, arg2: u64) void {93fn handleCmp(pc: usize, arg1: u64, arg2: u64) void {
62 std.log.debug("0x{x}: comparison of {d} and {d}", .{ pc, arg1, arg2 });94 _ = pc;
95 _ = arg1;
96 _ = arg2;
97 //std.log.debug("0x{x}: comparison of {d} and {d}", .{ pc, arg1, arg2 });
63}98}
6499
65const Fuzzer = struct {100const Fuzzer = struct {
66 gpa: Allocator,101 gpa: Allocator,
67 rng: std.Random.DefaultPrng,102 rng: std.Random.DefaultPrng,
68 input: std.ArrayListUnmanaged(u8),103 input: std.ArrayListUnmanaged(u8),
104 pc_range: PcRange,
105 count: usize,
69106
70 const Slice = extern struct {107 const Slice = extern struct {
71 ptr: [*]const u8,108 ptr: [*]const u8,
72 len: usize,109 len: usize,
73110
74 fn toSlice(s: Slice) []const u8 {111 fn toZig(s: Slice) []const u8 {
75 return s.ptr[0..s.len];112 return s.ptr[0..s.len];
76 }113 }
77114
78 fn fromSlice(s: []const u8) Slice {115 fn fromZig(s: []const u8) Slice {
79 return .{116 return .{
80 .ptr = s.ptr,117 .ptr = s.ptr,
81 .len = s.len,118 .len = s.len,
...@@ -83,14 +120,27 @@ const Fuzzer = struct {...@@ -83,14 +120,27 @@ const Fuzzer = struct {
83 }120 }
84 };121 };
85122
123 const PcRange = struct {
124 start: usize,
125 end: usize,
126 };
127
86 fn next(f: *Fuzzer) ![]const u8 {128 fn next(f: *Fuzzer) ![]const u8 {
87 const gpa = f.gpa;129 const gpa = f.gpa;
130
131 // Prepare next input.
88 const rng = fuzzer.rng.random();132 const rng = fuzzer.rng.random();
89 const len = rng.uintLessThan(usize, 64);133 const len = rng.uintLessThan(usize, 64);
90 try f.input.resize(gpa, len);134 try f.input.resize(gpa, len);
91 rng.bytes(f.input.items);135 rng.bytes(f.input.items);
136 f.resetCoverage();
137 f.count += 1;
92 return f.input.items;138 return f.input.items;
93 }139 }
140
141 fn resetCoverage(f: *Fuzzer) void {
142 _ = f;
143 }
94};144};
95145
96var general_purpose_allocator: std.heap.GeneralPurposeAllocator(.{}) = .{};146var general_purpose_allocator: std.heap.GeneralPurposeAllocator(.{}) = .{};
...@@ -99,10 +149,12 @@ var fuzzer: Fuzzer = .{...@@ -99,10 +149,12 @@ var fuzzer: Fuzzer = .{
99 .gpa = general_purpose_allocator.allocator(),149 .gpa = general_purpose_allocator.allocator(),
100 .rng = std.Random.DefaultPrng.init(0),150 .rng = std.Random.DefaultPrng.init(0),
101 .input = .{},151 .input = .{},
152 .pc_range = .{ .start = 0, .end = 0 },
153 .count = 0,
102};154};
103155
104export fn fuzzer_next() Fuzzer.Slice {156export fn fuzzer_next() Fuzzer.Slice {
105 return Fuzzer.Slice.fromSlice(fuzzer.next() catch |err| switch (err) {157 return Fuzzer.Slice.fromZig(fuzzer.next() catch |err| switch (err) {
106 error.OutOfMemory => @panic("out of memory"),158 error.OutOfMemory => @panic("out of memory"),
107 });159 });
108}160}
lib/std/Build.zig+1
...@@ -113,6 +113,7 @@ pub const Graph = struct {...@@ -113,6 +113,7 @@ pub const Graph = struct {
113 arena: Allocator,113 arena: Allocator,
114 system_library_options: std.StringArrayHashMapUnmanaged(SystemLibraryMode) = .{},114 system_library_options: std.StringArrayHashMapUnmanaged(SystemLibraryMode) = .{},
115 system_package_mode: bool = false,115 system_package_mode: bool = false,
116 debug_compiler_runtime_libs: bool = false,
116 cache: Cache,117 cache: Cache,
117 zig_exe: [:0]const u8,118 zig_exe: [:0]const u8,
118 env_map: EnvMap,119 env_map: EnvMap,
lib/std/Build/Fuzz.zig+23-13
...@@ -55,22 +55,32 @@ pub fn start(...@@ -55,22 +55,32 @@ pub fn start(
55}55}
5656
57fn rebuildTestsWorkerRun(run: *Step.Run, ttyconf: std.io.tty.Config, parent_prog_node: std.Progress.Node) void {57fn rebuildTestsWorkerRun(run: *Step.Run, ttyconf: std.io.tty.Config, parent_prog_node: std.Progress.Node) void {
58 const compile_step = run.producer.?;58 const gpa = run.step.owner.allocator;
59 const prog_node = parent_prog_node.start(compile_step.step.name, 0);59 const stderr = std.io.getStdErr();
60
61 const compile = run.producer.?;
62 const prog_node = parent_prog_node.start(compile.step.name, 0);
60 defer prog_node.end();63 defer prog_node.end();
61 if (compile_step.rebuildInFuzzMode(prog_node)) |rebuilt_bin_path| {64
65 const result = compile.rebuildInFuzzMode(prog_node);
66
67 const show_compile_errors = compile.step.result_error_bundle.errorMessageCount() > 0;
68 const show_error_msgs = compile.step.result_error_msgs.items.len > 0;
69 const show_stderr = compile.step.result_stderr.len > 0;
70
71 if (show_error_msgs or show_compile_errors or show_stderr) {
72 std.debug.lockStdErr();
73 defer std.debug.unlockStdErr();
74 build_runner.printErrorMessages(gpa, &compile.step, ttyconf, stderr, false) catch {};
75 }
76
77 if (result) |rebuilt_bin_path| {
62 run.rebuilt_executable = rebuilt_bin_path;78 run.rebuilt_executable = rebuilt_bin_path;
63 } else |err| switch (err) {79 } else |err| switch (err) {
64 error.MakeFailed => {80 error.MakeFailed => {},
65 const b = run.step.owner;
66 const stderr = std.io.getStdErr();
67 std.debug.lockStdErr();
68 defer std.debug.unlockStdErr();
69 build_runner.printErrorMessages(b, &compile_step.step, ttyconf, stderr, false) catch {};
70 },
71 else => {81 else => {
72 std.debug.print("step '{s}': failed to rebuild in fuzz mode: {s}\n", .{82 std.debug.print("step '{s}': failed to rebuild in fuzz mode: {s}\n", .{
73 compile_step.step.name, @errorName(err),83 compile.step.name, @errorName(err),
74 });84 });
75 },85 },
76 }86 }
...@@ -82,6 +92,7 @@ fn fuzzWorkerRun(...@@ -82,6 +92,7 @@ fn fuzzWorkerRun(
82 ttyconf: std.io.tty.Config,92 ttyconf: std.io.tty.Config,
83 parent_prog_node: std.Progress.Node,93 parent_prog_node: std.Progress.Node,
84) void {94) void {
95 const gpa = run.step.owner.allocator;
85 const test_name = run.cached_test_metadata.?.testName(unit_test_index);96 const test_name = run.cached_test_metadata.?.testName(unit_test_index);
8697
87 const prog_node = parent_prog_node.start(test_name, 0);98 const prog_node = parent_prog_node.start(test_name, 0);
...@@ -89,11 +100,10 @@ fn fuzzWorkerRun(...@@ -89,11 +100,10 @@ fn fuzzWorkerRun(
89100
90 run.rerunInFuzzMode(unit_test_index, prog_node) catch |err| switch (err) {101 run.rerunInFuzzMode(unit_test_index, prog_node) catch |err| switch (err) {
91 error.MakeFailed => {102 error.MakeFailed => {
92 const b = run.step.owner;
93 const stderr = std.io.getStdErr();103 const stderr = std.io.getStdErr();
94 std.debug.lockStdErr();104 std.debug.lockStdErr();
95 defer std.debug.unlockStdErr();105 defer std.debug.unlockStdErr();
96 build_runner.printErrorMessages(b, &run.step, ttyconf, stderr, false) catch {};106 build_runner.printErrorMessages(gpa, &run.step, ttyconf, stderr, false) catch {};
97 },107 },
98 else => {108 else => {
99 std.debug.print("step '{s}': failed to rebuild '{s}' in fuzz mode: {s}\n", .{109 std.debug.print("step '{s}': failed to rebuild '{s}' in fuzz mode: {s}\n", .{
lib/std/Build/Step/Compile.zig+10
...@@ -1483,6 +1483,8 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 {...@@ -1483,6 +1483,8 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 {
1483 try zig_args.append("--global-cache-dir");1483 try zig_args.append("--global-cache-dir");
1484 try zig_args.append(b.graph.global_cache_root.path orelse ".");1484 try zig_args.append(b.graph.global_cache_root.path orelse ".");
14851485
1486 if (b.graph.debug_compiler_runtime_libs) try zig_args.append("--debug-rt");
1487
1486 try zig_args.append("--name");1488 try zig_args.append("--name");
1487 try zig_args.append(compile.name);1489 try zig_args.append(compile.name);
14881490
...@@ -1840,6 +1842,14 @@ fn make(step: *Step, options: Step.MakeOptions) !void {...@@ -1840,6 +1842,14 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
1840}1842}
18411843
1842pub fn rebuildInFuzzMode(c: *Compile, progress_node: std.Progress.Node) ![]const u8 {1844pub fn rebuildInFuzzMode(c: *Compile, progress_node: std.Progress.Node) ![]const u8 {
1845 const gpa = c.step.owner.allocator;
1846
1847 c.step.result_error_msgs.clearRetainingCapacity();
1848 c.step.result_stderr = "";
1849
1850 c.step.result_error_bundle.deinit(gpa);
1851 c.step.result_error_bundle = std.zig.ErrorBundle.empty;
1852
1843 const zig_args = try getZigArgs(c, true);1853 const zig_args = try getZigArgs(c, true);
1844 const maybe_output_bin_path = try c.step.evalZigProcess(zig_args, progress_node, false);1854 const maybe_output_bin_path = try c.step.evalZigProcess(zig_args, progress_node, false);
1845 return maybe_output_bin_path.?;1855 return maybe_output_bin_path.?;
lib/std/Build/Step/Run.zig+4-1
...@@ -865,7 +865,10 @@ pub fn rerunInFuzzMode(run: *Run, unit_test_index: u32, prog_node: std.Progress....@@ -865,7 +865,10 @@ pub fn rerunInFuzzMode(run: *Run, unit_test_index: u32, prog_node: std.Progress.
865 },865 },
866 .artifact => |pa| {866 .artifact => |pa| {
867 const artifact = pa.artifact;867 const artifact = pa.artifact;
868 const file_path = artifact.installed_path orelse artifact.generated_bin.?.path.?;868 const file_path = if (artifact == run.producer.?)
869 run.rebuilt_executable.?
870 else
871 (artifact.installed_path orelse artifact.generated_bin.?.path.?);
869 try argv_list.append(arena, b.fmt("{s}{s}", .{ pa.prefix, file_path }));872 try argv_list.append(arena, b.fmt("{s}{s}", .{ pa.prefix, file_path }));
870 },873 },
871 .output_file, .output_directory => unreachable,874 .output_file, .output_directory => unreachable,
src/Compilation.zig+3-1
...@@ -2180,7 +2180,9 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {...@@ -2180,7 +2180,9 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
2180 comp.bin_file = try link.File.createEmpty(arena, comp, emit, whole.lf_open_opts);2180 comp.bin_file = try link.File.createEmpty(arena, comp, emit, whole.lf_open_opts);
2181 }2181 }
2182 },2182 },
2183 .incremental => {},2183 .incremental => {
2184 log.debug("Compilation.update for {s}, CacheMode.incremental", .{comp.root_name});
2185 },
2184 }2186 }
21852187
2186 // From this point we add a preliminary set of file system inputs that2188 // From this point we add a preliminary set of file system inputs that
src/link/Elf.zig+2
...@@ -2286,6 +2286,8 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s...@@ -2286,6 +2286,8 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
2286 }2286 }
2287 try man.addOptionalFile(module_obj_path);2287 try man.addOptionalFile(module_obj_path);
2288 try man.addOptionalFile(compiler_rt_path);2288 try man.addOptionalFile(compiler_rt_path);
2289 try man.addOptionalFile(if (comp.tsan_lib) |l| l.full_object_path else null);
2290 try man.addOptionalFile(if (comp.fuzzer_lib) |l| l.full_object_path else null);
22892291
2290 // We can skip hashing libc and libc++ components that we are in charge of building from Zig2292 // We can skip hashing libc and libc++ components that we are in charge of building from Zig
2291 // installation sources because they are always a product of the compiler version + target information.2293 // installation sources because they are always a product of the compiler version + target information.
src/main.zig+5
...@@ -655,6 +655,7 @@ const usage_build_generic =...@@ -655,6 +655,7 @@ const usage_build_generic =
655 \\ --debug-log [scope] Enable printing debug/info log messages for scope655 \\ --debug-log [scope] Enable printing debug/info log messages for scope
656 \\ --debug-compile-errors Crash with helpful diagnostics at the first compile error656 \\ --debug-compile-errors Crash with helpful diagnostics at the first compile error
657 \\ --debug-link-snapshot Enable dumping of the linker's state in JSON format657 \\ --debug-link-snapshot Enable dumping of the linker's state in JSON format
658 \\ --debug-rt Debug compiler runtime libraries
658 \\659 \\
659;660;
660661
...@@ -912,6 +913,7 @@ fn buildOutputType(...@@ -912,6 +913,7 @@ fn buildOutputType(
912 var minor_subsystem_version: ?u16 = null;913 var minor_subsystem_version: ?u16 = null;
913 var mingw_unicode_entry_point: bool = false;914 var mingw_unicode_entry_point: bool = false;
914 var enable_link_snapshots: bool = false;915 var enable_link_snapshots: bool = false;
916 var debug_compiler_runtime_libs = false;
915 var opt_incremental: ?bool = null;917 var opt_incremental: ?bool = null;
916 var install_name: ?[]const u8 = null;918 var install_name: ?[]const u8 = null;
917 var hash_style: link.File.Elf.HashStyle = .both;919 var hash_style: link.File.Elf.HashStyle = .both;
...@@ -1367,6 +1369,8 @@ fn buildOutputType(...@@ -1367,6 +1369,8 @@ fn buildOutputType(
1367 } else {1369 } else {
1368 enable_link_snapshots = true;1370 enable_link_snapshots = true;
1369 }1371 }
1372 } else if (mem.eql(u8, arg, "--debug-rt")) {
1373 debug_compiler_runtime_libs = true;
1370 } else if (mem.eql(u8, arg, "-fincremental")) {1374 } else if (mem.eql(u8, arg, "-fincremental")) {
1371 dev.check(.incremental);1375 dev.check(.incremental);
1372 opt_incremental = true;1376 opt_incremental = true;
...@@ -3408,6 +3412,7 @@ fn buildOutputType(...@@ -3408,6 +3412,7 @@ fn buildOutputType(
3408 // noise when --search-prefix and --mod are combined.3412 // noise when --search-prefix and --mod are combined.
3409 .global_cc_argv = try cc_argv.toOwnedSlice(arena),3413 .global_cc_argv = try cc_argv.toOwnedSlice(arena),
3410 .file_system_inputs = &file_system_inputs,3414 .file_system_inputs = &file_system_inputs,
3415 .debug_compiler_runtime_libs = debug_compiler_runtime_libs,
3411 }) catch |err| switch (err) {3416 }) catch |err| switch (err) {
3412 error.LibCUnavailable => {3417 error.LibCUnavailable => {
3413 const triple_name = try target.zigTriple(arena);3418 const triple_name = try target.zigTriple(arena);