authorgravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2025-10-06 22:02:14-04:00
committergravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2025-10-09 01:06:09-04:00
log4aa4d80ec640b869939111f35d7bf2509a227793
tree1908ca29e6ddb56801d0c885ed277e2712c5f0f5
parent328ae41468f3514251ac1b0726c41eca9fbc3fb5

- Rework translate-c to integrate with the build system (by outputing error bundles on stdout) via --zig-integration

- Revive some of the removed cache integration logic in `cmdTranslateC` now that `translate-c` can return error bundles - Fixup inconsistent path separators (on Windows) when building the aro include path - Move some error bundle logic from resinator into aro.Diagnostics - Add `ErrorBundle.addRootErrorMessageWithNotes` (extracted from resinator)

6 files changed, 275 insertions(+), 131 deletions(-)

lib/compiler/aro/aro/Diagnostics.zig+76
...@@ -562,3 +562,79 @@ fn addMessage(d: *Diagnostics, msg: Message) Compilation.Error!void {...@@ -562,3 +562,79 @@ fn addMessage(d: *Diagnostics, msg: Message) Compilation.Error!void {
562 },562 },
563 }563 }
564}564}
565
566const ErrorBundle = std.zig.ErrorBundle;
567
568pub fn toErrorBundle(
569 d: *const Diagnostics,
570 gpa: std.mem.Allocator,
571 fail_msg: ?[]const u8,
572) !ErrorBundle {
573 @branchHint(.cold);
574
575 var bundle: ErrorBundle.Wip = undefined;
576 try bundle.init(gpa);
577 errdefer bundle.deinit();
578
579 if (fail_msg) |msg| {
580 try bundle.addRootErrorMessage(.{
581 .msg = try bundle.addString(msg),
582 });
583 }
584
585 var cur_err: ?ErrorBundle.ErrorMessage = null;
586 var cur_notes: std.ArrayList(ErrorBundle.ErrorMessage) = .empty;
587 defer cur_notes.deinit(gpa);
588 for (d.output.to_list.messages.items) |msg| {
589 switch (msg.kind) {
590 // Clear the current error so that notes don't bleed into unassociated errors
591 .off, .warning => {
592 cur_err = null;
593 continue;
594 },
595 .note => if (cur_err == null) continue,
596 .@"fatal error", .@"error" => {},
597 }
598
599 const src_loc = src_loc: {
600 if (msg.location) |location| {
601 break :src_loc try bundle.addSourceLocation(.{
602 .src_path = try bundle.addString(location.path),
603 .line = location.line_no - 1, // 1-based -> 0-based
604 .column = location.col - 1, // 1-based -> 0-based
605 .span_start = location.width,
606 .span_main = location.width,
607 .span_end = location.width,
608 .source_line = try bundle.addString(location.line),
609 });
610 }
611 break :src_loc ErrorBundle.SourceLocationIndex.none;
612 };
613
614 switch (msg.kind) {
615 .@"fatal error", .@"error" => {
616 if (cur_err) |err| {
617 try bundle.addRootErrorMessageWithNotes(err, cur_notes.items);
618 }
619 cur_err = .{
620 .msg = try bundle.addString(msg.text),
621 .src_loc = src_loc,
622 };
623 cur_notes.clearRetainingCapacity();
624 },
625 .note => {
626 cur_err.?.notes_len += 1;
627 try cur_notes.append(gpa, .{
628 .msg = try bundle.addString(msg.text),
629 .src_loc = src_loc,
630 });
631 },
632 .off, .warning => unreachable,
633 }
634 }
635 if (cur_err) |err| {
636 try bundle.addRootErrorMessageWithNotes(err, cur_notes.items);
637 }
638
639 return try bundle.toOwnedBundle("");
640}
lib/compiler/resinator/main.zig+5-85
...@@ -671,7 +671,7 @@ const ErrorHandler = union(enum) {...@@ -671,7 +671,7 @@ const ErrorHandler = union(enum) {
671 ) !void {671 ) !void {
672 switch (self.*) {672 switch (self.*) {
673 .server => |*server| {673 .server => |*server| {
674 var error_bundle = try aroDiagnosticsToErrorBundle(allocator, fail_msg, comp);674 var error_bundle = try comp.diagnostics.toErrorBundle(allocator, fail_msg);
675 defer error_bundle.deinit(allocator);675 defer error_bundle.deinit(allocator);
676676
677 try server.serveErrorBundle(error_bundle);677 try server.serveErrorBundle(error_bundle);
...@@ -753,7 +753,7 @@ fn cliDiagnosticsToErrorBundle(...@@ -753,7 +753,7 @@ fn cliDiagnosticsToErrorBundle(
753 switch (err_details.type) {753 switch (err_details.type) {
754 .err => {754 .err => {
755 if (cur_err) |err| {755 if (cur_err) |err| {
756 try flushErrorMessageIntoBundle(&bundle, err, cur_notes.items);756 try bundle.addRootErrorMessageWithNotes(err, cur_notes.items);
757 }757 }
758 cur_err = .{758 cur_err = .{
759 .msg = try bundle.addString(err_details.msg.items),759 .msg = try bundle.addString(err_details.msg.items),
...@@ -771,7 +771,7 @@ fn cliDiagnosticsToErrorBundle(...@@ -771,7 +771,7 @@ fn cliDiagnosticsToErrorBundle(
771 }771 }
772 }772 }
773 if (cur_err) |err| {773 if (cur_err) |err| {
774 try flushErrorMessageIntoBundle(&bundle, err, cur_notes.items);774 try bundle.addRootErrorMessageWithNotes(err, cur_notes.items);
775 }775 }
776776
777 return try bundle.toOwnedBundle("");777 return try bundle.toOwnedBundle("");
...@@ -840,7 +840,7 @@ fn diagnosticsToErrorBundle(...@@ -840,7 +840,7 @@ fn diagnosticsToErrorBundle(
840 switch (err_details.type) {840 switch (err_details.type) {
841 .err => {841 .err => {
842 if (cur_err) |err| {842 if (cur_err) |err| {
843 try flushErrorMessageIntoBundle(&bundle, err, cur_notes.items);843 try bundle.addRootErrorMessageWithNotes(err, cur_notes.items);
844 }844 }
845 cur_err = .{845 cur_err = .{
846 .msg = try bundle.addString(msg_buf.written()),846 .msg = try bundle.addString(msg_buf.written()),
...@@ -859,20 +859,12 @@ fn diagnosticsToErrorBundle(...@@ -859,20 +859,12 @@ fn diagnosticsToErrorBundle(
859 }859 }
860 }860 }
861 if (cur_err) |err| {861 if (cur_err) |err| {
862 try flushErrorMessageIntoBundle(&bundle, err, cur_notes.items);862 try bundle.addRootErrorMessageWithNotes(err, cur_notes.items);
863 }863 }
864864
865 return try bundle.toOwnedBundle("");865 return try bundle.toOwnedBundle("");
866}866}
867867
868fn flushErrorMessageIntoBundle(wip: *ErrorBundle.Wip, msg: ErrorBundle.ErrorMessage, notes: []const ErrorBundle.ErrorMessage) !void {
869 try wip.addRootErrorMessage(msg);
870 const notes_start = try wip.reserveNotes(@intCast(notes.len));
871 for (notes_start.., notes) |i, note| {
872 wip.extra.items[i] = @intFromEnum(wip.addErrorMessageAssumeCapacity(note));
873 }
874}
875
876fn errorStringToErrorBundle(allocator: std.mem.Allocator, comptime format: []const u8, args: anytype) !ErrorBundle {868fn errorStringToErrorBundle(allocator: std.mem.Allocator, comptime format: []const u8, args: anytype) !ErrorBundle {
877 @branchHint(.cold);869 @branchHint(.cold);
878 var bundle: ErrorBundle.Wip = undefined;870 var bundle: ErrorBundle.Wip = undefined;
...@@ -883,75 +875,3 @@ fn errorStringToErrorBundle(allocator: std.mem.Allocator, comptime format: []con...@@ -883,75 +875,3 @@ fn errorStringToErrorBundle(allocator: std.mem.Allocator, comptime format: []con
883 });875 });
884 return try bundle.toOwnedBundle("");876 return try bundle.toOwnedBundle("");
885}877}
886
887fn aroDiagnosticsToErrorBundle(
888 gpa: std.mem.Allocator,
889 fail_msg: []const u8,
890 comp: *aro.Compilation,
891) !ErrorBundle {
892 @branchHint(.cold);
893
894 var bundle: ErrorBundle.Wip = undefined;
895 try bundle.init(gpa);
896 errdefer bundle.deinit();
897
898 try bundle.addRootErrorMessage(.{
899 .msg = try bundle.addString(fail_msg),
900 });
901
902 var cur_err: ?ErrorBundle.ErrorMessage = null;
903 var cur_notes: std.ArrayList(ErrorBundle.ErrorMessage) = .empty;
904 defer cur_notes.deinit(gpa);
905 for (comp.diagnostics.output.to_list.messages.items) |msg| {
906 switch (msg.kind) {
907 // Clear the current error so that notes don't bleed into unassociated errors
908 .off, .warning => {
909 cur_err = null;
910 continue;
911 },
912 .note => if (cur_err == null) continue,
913 .@"fatal error", .@"error" => {},
914 }
915
916 const src_loc = src_loc: {
917 if (msg.location) |location| {
918 break :src_loc try bundle.addSourceLocation(.{
919 .src_path = try bundle.addString(location.path),
920 .line = location.line_no - 1, // 1-based -> 0-based
921 .column = location.col - 1, // 1-based -> 0-based
922 .span_start = location.width,
923 .span_main = location.width,
924 .span_end = location.width,
925 .source_line = try bundle.addString(location.line),
926 });
927 }
928 break :src_loc ErrorBundle.SourceLocationIndex.none;
929 };
930
931 switch (msg.kind) {
932 .@"fatal error", .@"error" => {
933 if (cur_err) |err| {
934 try flushErrorMessageIntoBundle(&bundle, err, cur_notes.items);
935 }
936 cur_err = .{
937 .msg = try bundle.addString(msg.text),
938 .src_loc = src_loc,
939 };
940 cur_notes.clearRetainingCapacity();
941 },
942 .note => {
943 cur_err.?.notes_len += 1;
944 try cur_notes.append(gpa, .{
945 .msg = try bundle.addString(msg.text),
946 .src_loc = src_loc,
947 });
948 },
949 .off, .warning => unreachable,
950 }
951 }
952 if (cur_err) |err| {
953 try flushErrorMessageIntoBundle(&bundle, err, cur_notes.items);
954 }
955
956 return try bundle.toOwnedBundle("");
957}
lib/compiler/translate-c/main.zig+52-10
...@@ -13,24 +13,33 @@ pub fn main() u8 {...@@ -13,24 +13,33 @@ pub fn main() u8 {
13 const gpa = general_purpose_allocator.allocator();13 const gpa = general_purpose_allocator.allocator();
14 defer _ = general_purpose_allocator.deinit();14 defer _ = general_purpose_allocator.deinit();
1515
16 var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator);16 var arena_instance = std.heap.ArenaAllocator.init(gpa);
17 defer arena_instance.deinit();17 defer arena_instance.deinit();
18 const arena = arena_instance.allocator();18 const arena = arena_instance.allocator();
1919
20 const args = process.argsAlloc(arena) catch {20 var args = process.argsAlloc(arena) catch {
21 std.debug.print("ran out of memory allocating arguments\n", .{});21 std.debug.print("ran out of memory allocating arguments\n", .{});
22 if (fast_exit) process.exit(1);22 if (fast_exit) process.exit(1);
23 return 1;23 return 1;
24 };24 };
2525
26 var zig_integration = false;
27 if (args.len > 1 and std.mem.eql(u8, args[1], "--zig-integration")) {
28 zig_integration = true;
29 }
30
26 var stderr_buf: [1024]u8 = undefined;31 var stderr_buf: [1024]u8 = undefined;
27 var stderr = std.fs.File.stderr().writer(&stderr_buf);32 var stderr = std.fs.File.stderr().writer(&stderr_buf);
28 var diagnostics: aro.Diagnostics = .{33 var diagnostics: aro.Diagnostics = switch (zig_integration) {
29 .output = .{ .to_writer = .{34 false => .{ .output = .{ .to_writer = .{
30 .color = .detect(stderr.file),35 .color = .detect(stderr.file),
31 .writer = &stderr.interface,36 .writer = &stderr.interface,
32 } },37 } } },
38 true => .{ .output = .{ .to_list = .{
39 .arena = .init(gpa),
40 } } },
33 };41 };
42 defer diagnostics.deinit();
3443
35 var comp = aro.Compilation.initDefault(gpa, arena, &diagnostics, std.fs.cwd()) catch |err| switch (err) {44 var comp = aro.Compilation.initDefault(gpa, arena, &diagnostics, std.fs.cwd()) catch |err| switch (err) {
36 error.OutOfMemory => {45 error.OutOfMemory => {
...@@ -47,13 +56,22 @@ pub fn main() u8 {...@@ -47,13 +56,22 @@ pub fn main() u8 {
47 var toolchain: aro.Toolchain = .{ .driver = &driver, .filesystem = .{ .real = comp.cwd } };56 var toolchain: aro.Toolchain = .{ .driver = &driver, .filesystem = .{ .real = comp.cwd } };
48 defer toolchain.deinit();57 defer toolchain.deinit();
4958
50 translate(&driver, &toolchain, args) catch |err| switch (err) {59 translate(&driver, &toolchain, args, zig_integration) catch |err| switch (err) {
51 error.OutOfMemory => {60 error.OutOfMemory => {
52 std.debug.print("ran out of memory translating\n", .{});61 std.debug.print("ran out of memory translating\n", .{});
53 if (fast_exit) process.exit(1);62 if (fast_exit) process.exit(1);
54 return 1;63 return 1;
55 },64 },
56 error.FatalError => {65 error.FatalError => if (zig_integration) {
66 serveErrorBundle(arena, &diagnostics) catch |bundle_err| {
67 std.debug.print("unable to serve error bundle: {}\n", .{bundle_err});
68 if (fast_exit) process.exit(1);
69 return 1;
70 };
71
72 if (fast_exit) process.exit(0);
73 return 0;
74 } else {
57 if (fast_exit) process.exit(1);75 if (fast_exit) process.exit(1);
58 return 1;76 return 1;
59 },77 },
...@@ -63,10 +81,23 @@ pub fn main() u8 {...@@ -63,10 +81,23 @@ pub fn main() u8 {
63 return 1;81 return 1;
64 },82 },
65 };83 };
84
85 assert(comp.diagnostics.errors == 0 or !zig_integration);
66 if (fast_exit) process.exit(@intFromBool(comp.diagnostics.errors != 0));86 if (fast_exit) process.exit(@intFromBool(comp.diagnostics.errors != 0));
67 return @intFromBool(comp.diagnostics.errors != 0);87 return @intFromBool(comp.diagnostics.errors != 0);
68}88}
6989
90fn serveErrorBundle(arena: std.mem.Allocator, diagnostics: *const aro.Diagnostics) !void {
91 const error_bundle = try diagnostics.toErrorBundle(arena, "failed during translation");
92 var stdout_buffer: [1024]u8 = undefined;
93 var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer);
94 var server: std.zig.Server = .{
95 .out = &stdout_writer.interface,
96 .in = undefined,
97 };
98 try server.serveErrorBundle(error_bundle);
99}
100
70pub const usage =101pub const usage =
71 \\Usage {s}: [options] file [CC options]102 \\Usage {s}: [options] file [CC options]
72 \\103 \\
...@@ -79,7 +110,7 @@ pub const usage =...@@ -79,7 +110,7 @@ pub const usage =
79 \\110 \\
80;111;
81112
82fn translate(d: *aro.Driver, tc: *aro.Toolchain, args: [][:0]u8) !void {113fn translate(d: *aro.Driver, tc: *aro.Toolchain, args: [][:0]u8, zig_integration: bool) !void {
83 const gpa = d.comp.gpa;114 const gpa = d.comp.gpa;
84115
85 const aro_args = args: {116 const aro_args = args: {
...@@ -99,6 +130,9 @@ fn translate(d: *aro.Driver, tc: *aro.Toolchain, args: [][:0]u8) !void {...@@ -99,6 +130,9 @@ fn translate(d: *aro.Driver, tc: *aro.Toolchain, args: [][:0]u8) !void {
99 try stdout.interface.writeAll("0.0.0-dev\n");130 try stdout.interface.writeAll("0.0.0-dev\n");
100 try stdout.interface.flush();131 try stdout.interface.flush();
101 return;132 return;
133 } else if (mem.eql(u8, arg, "--zig-integration")) {
134 if (i != 1 or !zig_integration)
135 return d.fatal("--zig-integration must be the first argument", .{});
102 } else {136 } else {
103 i += 1;137 i += 1;
104 }138 }
...@@ -116,6 +150,14 @@ fn translate(d: *aro.Driver, tc: *aro.Toolchain, args: [][:0]u8) !void {...@@ -116,6 +150,14 @@ fn translate(d: *aro.Driver, tc: *aro.Toolchain, args: [][:0]u8) !void {
116 return d.fatal("user provided macro source exceeded max size", .{});150 return d.fatal("user provided macro source exceeded max size", .{});
117 }151 }
118152
153 const has_output_file = if (d.output_name) |path|
154 !std.mem.eql(u8, path, "-")
155 else
156 false;
157 if (zig_integration and !has_output_file) {
158 return d.fatal("--zig-integration requires specifying an output file", .{});
159 }
160
119 const content = try macro_buf.toOwnedSlice(gpa);161 const content = try macro_buf.toOwnedSlice(gpa);
120 errdefer gpa.free(content);162 errdefer gpa.free(content);
121163
...@@ -160,7 +202,7 @@ fn translate(d: *aro.Driver, tc: *aro.Toolchain, args: [][:0]u8) !void {...@@ -160,7 +202,7 @@ fn translate(d: *aro.Driver, tc: *aro.Toolchain, args: [][:0]u8) !void {
160 defer c_tree.deinit();202 defer c_tree.deinit();
161203
162 if (d.diagnostics.errors != 0) {204 if (d.diagnostics.errors != 0) {
163 if (fast_exit) process.exit(1);205 if (fast_exit and !zig_integration) process.exit(1);
164 return error.FatalError;206 return error.FatalError;
165 }207 }
166208
...@@ -212,7 +254,7 @@ fn translate(d: *aro.Driver, tc: *aro.Toolchain, args: [][:0]u8) !void {...@@ -212,7 +254,7 @@ fn translate(d: *aro.Driver, tc: *aro.Toolchain, args: [][:0]u8) !void {
212 if (out_writer.err) |write_err|254 if (out_writer.err) |write_err|
213 return d.fatal("failed to write result to '{s}': {s}", .{ out_file_path, aro.Driver.errorDescription(write_err) });255 return d.fatal("failed to write result to '{s}': {s}", .{ out_file_path, aro.Driver.errorDescription(write_err) });
214256
215 if (fast_exit) process.exit(0);257 if (fast_exit and !zig_integration) process.exit(0);
216}258}
217259
218test {260test {
lib/std/zig/ErrorBundle.zig+12
...@@ -416,6 +416,18 @@ pub const Wip = struct {...@@ -416,6 +416,18 @@ pub const Wip = struct {
416 wip.root_list.appendAssumeCapacity(try addErrorMessage(wip, em));416 wip.root_list.appendAssumeCapacity(try addErrorMessage(wip, em));
417 }417 }
418418
419 pub fn addRootErrorMessageWithNotes(
420 wip: *Wip,
421 msg: ErrorMessage,
422 notes: []const ErrorMessage,
423 ) !void {
424 try wip.addRootErrorMessage(msg);
425 const notes_start = try wip.reserveNotes(@intCast(notes.len));
426 for (notes_start.., notes) |i, note| {
427 wip.extra.items[i] = @intFromEnum(wip.addErrorMessageAssumeCapacity(note));
428 }
429 }
430
419 pub fn addErrorMessage(wip: *Wip, em: ErrorMessage) Allocator.Error!MessageIndex {431 pub fn addErrorMessage(wip: *Wip, em: ErrorMessage) Allocator.Error!MessageIndex {
420 return @enumFromInt(try addExtra(wip, em));432 return @enumFromInt(try addExtra(wip, em));
421 }433 }
src/Compilation.zig+2-2
...@@ -3398,7 +3398,7 @@ fn flush(...@@ -3398,7 +3398,7 @@ fn flush(
3398/// Linker backends which do not have this requirement can fall back to the simple3398/// Linker backends which do not have this requirement can fall back to the simple
3399/// implementation at the bottom of this function.3399/// implementation at the bottom of this function.
3400/// This function is only called when CacheMode is `whole`.3400/// This function is only called when CacheMode is `whole`.
3401fn renameTmpIntoCache(3401pub fn renameTmpIntoCache(
3402 cache_directory: Cache.Directory,3402 cache_directory: Cache.Directory,
3403 tmp_dir_sub_path: []const u8,3403 tmp_dir_sub_path: []const u8,
3404 o_sub_path: []const u8,3404 o_sub_path: []const u8,
...@@ -6684,7 +6684,7 @@ pub fn addTranslateCCArgs(...@@ -6684,7 +6684,7 @@ pub fn addTranslateCCArgs(
66846684
6685 try argv.appendSlice(&.{ "-x", "c" });6685 try argv.appendSlice(&.{ "-x", "c" });
66866686
6687 const resource_path = try comp.dirs.zig_lib.join(arena, &.{"compiler/aro/include"});6687 const resource_path = try comp.dirs.zig_lib.join(arena, &.{ "compiler", "aro", "include" });
6688 try argv.appendSlice(&.{ "-isystem", resource_path });6688 try argv.appendSlice(&.{ "-isystem", resource_path });
66896689
6690 try comp.addCommonCCArgs(arena, argv, ext, out_dep_path, owner_mod, .aro);6690 try comp.addCommonCCArgs(arena, argv, ext, out_dep_path, owner_mod, .aro);
src/main.zig+128-34
...@@ -4075,7 +4075,7 @@ fn serve(...@@ -4075,7 +4075,7 @@ fn serve(
4075 while (true) {4075 while (true) {
4076 const hdr = try server.receiveMessage();4076 const hdr = try server.receiveMessage();
40774077
4078 // Lock the debug server while hanling the message.4078 // Lock the debug server while handling the message.
4079 if (comp.debugIncremental()) ids.mutex.lock();4079 if (comp.debugIncremental()) ids.mutex.lock();
4080 defer if (comp.debugIncremental()) ids.mutex.unlock();4080 defer if (comp.debugIncremental()) ids.mutex.unlock();
40814081
...@@ -4515,48 +4515,142 @@ fn cmdTranslateC(...@@ -4515,48 +4515,142 @@ fn cmdTranslateC(
4515 prog_node: std.Progress.Node,4515 prog_node: std.Progress.Node,
4516) !void {4516) !void {
4517 dev.check(.translate_c_command);4517 dev.check(.translate_c_command);
4518 _ = file_system_inputs;4518 const color: Color = .auto;
4519 _ = fancy_output;
45204519
4521 assert(comp.c_source_files.len == 1);4520 assert(comp.c_source_files.len == 1);
4522 const c_source_file = comp.c_source_files[0];4521 const c_source_file = comp.c_source_files[0];
45234522
4524 var zig_cache_tmp_dir = try comp.dirs.local_cache.handle.makeOpenPath("tmp", .{});4523 const translated_zig_basename = try std.fmt.allocPrint(arena, "{s}.zig", .{comp.root_name});
4525 defer zig_cache_tmp_dir.close();4524
4525 var man: Cache.Manifest = comp.obtainCObjectCacheManifest(comp.root_mod);
4526 man.want_shared_lock = false;
4527 defer man.deinit();
45264528
4527 const ext = Compilation.classifyFileExt(c_source_file.src_path);4529 man.hash.add(@as(u16, 0xb945)); // Random number to distinguish translate-c from compiling C objects
4528 const out_dep_path: ?[]const u8 = blk: {4530 man.hash.add(comp.config.c_frontend);
4529 if (comp.disable_c_depfile) break :blk null;4531 Compilation.cache_helpers.hashCSource(&man, c_source_file) catch |err| {
4530 const c_src_basename = fs.path.basename(c_source_file.src_path);4532 fatal("unable to process '{s}': {s}", .{ c_source_file.src_path, @errorName(err) });
4531 const dep_basename = try std.fmt.allocPrint(arena, "{s}.d", .{c_src_basename});
4532 const out_dep_path = try comp.tmpFilePath(arena, dep_basename);
4533 break :blk out_dep_path;
4534 };4533 };
45354534
4536 var argv = std.array_list.Managed([]const u8).init(arena);4535 if (fancy_output) |p| p.cache_hit = true;
4537 try comp.addTranslateCCArgs(arena, &argv, ext, out_dep_path, comp.root_mod);4536 const bin_digest, const hex_digest = if (try man.hit()) digest: {
4538 try argv.append(c_source_file.src_path);4537 if (file_system_inputs) |buf| try man.populateFileSystemInputs(buf);
4539 if (comp.verbose_cc) Compilation.dump_argv(argv.items);4538 const bin_digest = man.finalBin();
45404539 const hex_digest = Cache.binToHex(bin_digest);
4541 try translateC(comp.gpa, arena, argv.items, prog_node, null);4540 break :digest .{ bin_digest, hex_digest };
45424541 } else digest: {
4543 if (out_dep_path) |dep_file_path| {4542 if (fancy_output) |p| p.cache_hit = false;
4544 const dep_basename = fs.path.basename(dep_file_path);4543
4545 // Add the files depended on to the cache system.4544 const tmp_basename = std.fmt.hex(std.crypto.random.int(u64));
4546 //man.addDepFilePost(zig_cache_tmp_dir, dep_basename) catch |err| switch (err) {4545 const tmp_sub_path = "tmp" ++ fs.path.sep_str ++ tmp_basename;
4547 // error.FileNotFound => {4546 const cache_dir = comp.dirs.local_cache.handle;
4548 // // Clang didn't emit the dep file; nothing to add to the manifest.4547 var cache_tmp_dir = try cache_dir.makeOpenPath(tmp_sub_path, .{});
4549 // break :add_deps;4548 defer cache_tmp_dir.close();
4550 // },4549
4551 // else => |e| return e,4550 const translated_path = try comp.dirs.local_cache.join(arena, &.{ tmp_sub_path, translated_zig_basename });
4552 //};4551
4553 // Just to save disk space, we delete the file because it is never needed again.4552 const ext = Compilation.classifyFileExt(c_source_file.src_path);
4554 zig_cache_tmp_dir.deleteFile(dep_basename) catch |err| {4553 const out_dep_path: ?[]const u8 = blk: {
4555 warn("failed to delete '{s}': {t}", .{ dep_file_path, err });4554 if (comp.disable_c_depfile) break :blk null;
4555 const c_src_basename = fs.path.basename(c_source_file.src_path);
4556 const dep_basename = try std.fmt.allocPrint(arena, "{s}.d", .{c_src_basename});
4557 const out_dep_path = try comp.dirs.local_cache.join(arena, &.{ tmp_sub_path, dep_basename });
4558 break :blk out_dep_path;
4556 };4559 };
4557 }
45584560
4559 return cleanExit();4561 var argv = std.array_list.Managed([]const u8).init(arena);
4562 try argv.append("--zig-integration");
4563 try comp.addTranslateCCArgs(arena, &argv, ext, out_dep_path, comp.root_mod);
4564 try argv.appendSlice(&.{ c_source_file.src_path, "-o", translated_path });
4565 if (comp.verbose_cc) Compilation.dump_argv(argv.items);
4566
4567 var stdout: []u8 = undefined;
4568 try translateC(comp.gpa, arena, argv.items, prog_node, &stdout);
4569
4570 if (stdout.len > 0) {
4571 var reader: std.Io.Reader = .fixed(stdout);
4572 const MessageHeader = std.zig.Server.Message.Header;
4573 const header = reader.takeStruct(MessageHeader, .little) catch unreachable;
4574 const body = reader.take(header.bytes_len) catch unreachable;
4575 switch (header.tag) {
4576 .error_bundle => {
4577 // TODO: De-dupe this logic
4578 const EbHdr = std.zig.Server.Message.ErrorBundle;
4579 const eb_hdr = @as(*align(1) const EbHdr, @ptrCast(body));
4580 const extra_bytes =
4581 body[@sizeOf(EbHdr)..][0 .. @sizeOf(u32) * eb_hdr.extra_len];
4582 const string_bytes =
4583 body[@sizeOf(EbHdr) + extra_bytes.len ..][0..eb_hdr.string_bytes_len];
4584 const unaligned_extra = std.mem.bytesAsSlice(u32, extra_bytes);
4585 const extra_array = try comp.gpa.alloc(u32, unaligned_extra.len);
4586 @memcpy(extra_array, unaligned_extra);
4587 const error_bundle: std.zig.ErrorBundle = .{
4588 .string_bytes = try comp.gpa.dupe(u8, string_bytes),
4589 .extra = extra_array,
4590 };
4591
4592 if (fancy_output) |p| {
4593 p.errors = error_bundle;
4594 return;
4595 } else {
4596 error_bundle.renderToStdErr(color.renderOptions());
4597 process.exit(1);
4598 }
4599
4600 return error.AnalysisFail;
4601 },
4602 else => unreachable, // No other messagse are sent
4603 }
4604 }
4605
4606 if (out_dep_path) |dep_file_path| {
4607 const dep_basename = fs.path.basename(dep_file_path);
4608 // Add the files depended on to the cache system.
4609 try man.addDepFilePost(cache_tmp_dir, dep_basename);
4610 // Just to save disk space, we delete the file because it is never needed again.
4611 cache_tmp_dir.deleteFile(dep_basename) catch |err| {
4612 warn("failed to delete '{s}': {t}", .{ dep_file_path, err });
4613 };
4614 }
4615
4616 const bin_digest = man.finalBin();
4617 const hex_digest = Cache.binToHex(bin_digest);
4618
4619 const o_sub_path = "o" ++ fs.path.sep_str ++ hex_digest;
4620 try Compilation.renameTmpIntoCache(
4621 comp.dirs.local_cache,
4622 tmp_sub_path,
4623 o_sub_path,
4624 );
4625
4626 man.writeManifest() catch |err| warn("failed to write cache manifest: {t}", .{err});
4627
4628 if (file_system_inputs) |buf| try man.populateFileSystemInputs(buf);
4629
4630 break :digest .{ bin_digest, hex_digest };
4631 };
4632
4633 if (fancy_output) |p| {
4634 p.digest = bin_digest;
4635 p.errors = std.zig.ErrorBundle.empty;
4636 } else {
4637 const out_zig_path = try fs.path.join(arena, &.{ "o", &hex_digest, translated_zig_basename });
4638 const zig_file = comp.dirs.local_cache.handle.openFile(out_zig_path, .{}) catch |err| {
4639 const path = comp.dirs.local_cache.path orelse ".";
4640 fatal("unable to open cached translated zig file '{s}{s}{s}': {s}", .{
4641 path,
4642 fs.path.sep_str,
4643 out_zig_path,
4644 @errorName(err),
4645 });
4646 };
4647 defer zig_file.close();
4648 var stdout_writer = fs.File.stdout().writer(&stdout_buffer);
4649 var file_reader = zig_file.reader(&.{});
4650 _ = try stdout_writer.interface.sendFileAll(&file_reader, .unlimited);
4651 try stdout_writer.interface.flush();
4652 return cleanExit();
4653 }
4560}4654}
45614655
4562pub fn translateC(4656pub fn translateC(