Commit e7a622fb33

Veikka Tuominen <git@vexu.eu>
2025-07-28 13:37:57
update aro and translate-c sources
1 parent e8e8d7e
lib/compiler/aro/aro/Parser/Diagnostic.zig
@@ -694,6 +694,12 @@ pub const invalid_cast_type: Diagnostic = .{
     .kind = .@"error",
 };
 
+pub const cast_to_same_type: Diagnostic = .{
+    .fmt = "C99 forbids casting nonscalar type {qt} to the same type",
+    .kind = .off,
+    .extension = true,
+};
+
 pub const invalid_cast_operand_type: Diagnostic = .{
     .fmt = "operand of type {qt} where arithmetic or pointer type is required",
     .kind = .@"error",
@@ -1484,9 +1490,10 @@ pub const duplicate_member: Diagnostic = .{
 };
 
 pub const binary_integer_literal: Diagnostic = .{
-    .fmt = "binary integer literals are a GNU extension",
+    .fmt = "binary integer literals are a C23 extension",
+    .opt = .@"c23-extensions",
     .kind = .off,
-    .opt = .@"gnu-binary-literal",
+    .suppress_version = .c23,
     .extension = true,
 };
 
lib/compiler/aro/aro/Compilation.zig
@@ -10,6 +10,7 @@ const CodeGenOptions = @import("../backend.zig").CodeGenOptions;
 const Builtins = @import("Builtins.zig");
 const Builtin = Builtins.Builtin;
 const Diagnostics = @import("Diagnostics.zig");
+const DepFile = @import("DepFile.zig");
 const LangOpts = @import("LangOpts.zig");
 const Pragma = @import("Pragma.zig");
 const record_layout = @import("record_layout.zig");
@@ -140,6 +141,7 @@ system_framework_dirs: std.ArrayListUnmanaged([]const u8) = .empty,
 /// Allocated into `gpa`, but keys are externally managed.
 embed_dirs: std.ArrayListUnmanaged([]const u8) = .empty,
 target: std.Target = @import("builtin").target,
+cmodel: std.builtin.CodeModel = .default,
 pragma_handlers: std.StringArrayHashMapUnmanaged(*Pragma) = .{},
 langopts: LangOpts = .{},
 generated_buf: std.ArrayListUnmanaged(u8) = .{},
@@ -349,30 +351,206 @@ fn generateSystemDefines(comp: *Compilation, w: *std.Io.Writer) !void {
 
     // architecture macros
     switch (comp.target.cpu.arch) {
-        .x86_64 => {
-            try define(w, "__amd64__");
-            try define(w, "__amd64");
-            try define(w, "__x86_64__");
-            try define(w, "__x86_64");
+        .x86, .x86_64 => {
+            try w.print("#define __code_model_{s}__ 1\n", .{switch (comp.cmodel) {
+                .default => "small",
+                else => @tagName(comp.cmodel),
+            }});
+
+            if (comp.target.cpu.arch == .x86_64) {
+                try define(w, "__amd64__");
+                try define(w, "__amd64");
+                try define(w, "__x86_64__");
+                try define(w, "__x86_64");
+
+                if (comp.target.os.tag == .windows and comp.target.abi == .msvc) {
+                    try w.writeAll(
+                        \\#define _M_X64 100
+                        \\#define _M_AMD64 100
+                        \\
+                    );
+                }
+            } else {
+                try defineStd(w, "i386", is_gnu);
+
+                if (comp.target.os.tag == .windows and comp.target.abi == .msvc) {
+                    try w.print("#define _M_IX86 {d}\n", .{blk: {
+                        if (comp.target.cpu.model == &std.Target.x86.cpu.i386) break :blk 300;
+                        if (comp.target.cpu.model == &std.Target.x86.cpu.i486) break :blk 400;
+                        if (comp.target.cpu.model == &std.Target.x86.cpu.i586) break :blk 500;
+                        break :blk @as(u32, 600);
+                    }});
+                }
+            }
+            try define(w, "__SEG_GS");
+            try define(w, "__SEG_FS");
+            try w.writeAll(
+                \\#define __seg_gs __attribute__((address_space(256)))
+                \\#define __seg_fs __attribute__((address_space(257)))
+                \\
+            );
 
-            if (comp.target.os.tag == .windows and comp.target.abi == .msvc) {
-                try w.writeAll(
-                    \\#define _M_X64 100
-                    \\#define _M_AMD64 100
-                    \\
-                );
+            if (comp.target.cpu.has(.x86, .sahf) or (comp.langopts.emulate == .clang and comp.target.cpu.arch == .x86)) {
+                try define(w, "__LAHF_SAHF__");
             }
-        },
-        .x86 => {
-            try defineStd(w, "i386", is_gnu);
 
-            if (comp.target.os.tag == .windows and comp.target.abi == .msvc) {
-                try w.print("#define _M_IX86 {d}\n", .{blk: {
-                    if (comp.target.cpu.model == &std.Target.x86.cpu.i386) break :blk 300;
-                    if (comp.target.cpu.model == &std.Target.x86.cpu.i486) break :blk 400;
-                    if (comp.target.cpu.model == &std.Target.x86.cpu.i586) break :blk 500;
-                    break :blk @as(u32, 600);
-                }});
+            const features = comp.target.cpu.features;
+            for ([_]struct { std.Target.x86.Feature, []const u8 }{
+                .{ .aes, "__AES__" },
+                .{ .vaes, "__VAES__" },
+                .{ .pclmul, "__PCLMUL__" },
+                .{ .vpclmulqdq, "__VPCLMULQDQ__" },
+                .{ .lzcnt, "__LZCNT__" },
+                .{ .rdrnd, "__RDRND__" },
+                .{ .fsgsbase, "__FSGSBASE__" },
+                .{ .bmi, "__BMI__" },
+                .{ .bmi2, "__BMI2__" },
+                .{ .popcnt, "__POPCNT__" },
+                .{ .rtm, "__RTM__" },
+                .{ .prfchw, "__PRFCHW__" },
+                .{ .rdseed, "__RDSEED__" },
+                .{ .adx, "__ADX__" },
+                .{ .tbm, "__TBM__" },
+                .{ .lwp, "__LWP__" },
+                .{ .mwaitx, "__MWAITX__" },
+                .{ .movbe, "__MOVBE__" },
+
+                .{ .xop, "__XOP__" },
+                .{ .fma4, "__FMA4__" },
+                .{ .sse4a, "__SSE4A__" },
+
+                .{ .fma, "__FMA__" },
+                .{ .f16c, "__F16C__" },
+                .{ .gfni, "__GFNI__" },
+                .{ .evex512, "__EVEX512__" },
+                .{ .avx10_1_256, "__AVX10_1__" },
+                .{ .avx10_1_512, "__AVX10_1_512__" },
+                .{ .avx10_2_256, "__AVX10_2__" },
+                .{ .avx10_2_512, "__AVX10_2_512__" },
+                .{ .avx512cd, "__AVX512CD__" },
+                .{ .avx512vpopcntdq, "__AVX512VPOPCNTDQ__" },
+                .{ .avx512vnni, "__AVX512VNNI__" },
+                .{ .avx512bf16, "__AVX512BF16__" },
+                .{ .avx512fp16, "__AVX512FP16__" },
+                .{ .avx512dq, "__AVX512DQ__" },
+                .{ .avx512bitalg, "__AVX512BITALG__" },
+                .{ .avx512bw, "__AVX512BW__" },
+
+                .{ .avx512vl, "__AVX512VL__" },
+                .{ .avx512vl, "__EVEX256__" },
+
+                .{ .avx512vbmi, "__AVX512VBMI__" },
+                .{ .avx512vbmi2, "__AVX512VBMI2__" },
+                .{ .avx512ifma, "__AVX512IFMA__" },
+                .{ .avx512vp2intersect, "__AVX512VP2INTERSECT__" },
+                .{ .sha, "__SHA__" },
+                .{ .sha512, "__SHA512__" },
+                .{ .fxsr, "__FXSR__" },
+                .{ .xsave, "__XSAVE__" },
+                .{ .xsaveopt, "__XSAVEOPT__" },
+                .{ .xsavec, "__XSAVEC__" },
+                .{ .xsaves, "__XSAVES__" },
+                .{ .pku, "__PKU__" },
+                .{ .clflushopt, "__CLFLUSHOPT__" },
+                .{ .clwb, "__CLWB__" },
+                .{ .wbnoinvd, "__WBNOINVD__" },
+                .{ .shstk, "__SHSTK__" },
+                .{ .sgx, "__SGX__" },
+                .{ .sm3, "__SM3__" },
+                .{ .sm4, "__SM4__" },
+                .{ .prefetchi, "__PREFETCHI__" },
+                .{ .clzero, "__CLZERO__" },
+                .{ .kl, "__KL__" },
+                .{ .widekl, "__WIDEKL__" },
+                .{ .rdpid, "__RDPID__" },
+                .{ .rdpru, "__RDPRU__" },
+                .{ .cldemote, "__CLDEMOTE__" },
+                .{ .waitpkg, "__WAITPKG__" },
+                .{ .movdiri, "__MOVDIRI__" },
+                .{ .movdir64b, "__MOVDIR64B__" },
+                .{ .movrs, "__MOVRS__" },
+                .{ .pconfig, "__PCONFIG__" },
+                .{ .ptwrite, "__PTWRITE__" },
+                .{ .invpcid, "__INVPCID__" },
+                .{ .enqcmd, "__ENQCMD__" },
+                .{ .hreset, "__HRESET__" },
+                .{ .amx_tile, "__AMX_TILE__" },
+                .{ .amx_int8, "__AMX_INT8__" },
+                .{ .amx_bf16, "__AMX_BF16__" },
+                .{ .amx_fp16, "__AMX_FP16__" },
+                .{ .amx_complex, "__AMX_COMPLEX__" },
+                .{ .amx_fp8, "__AMX_FP8__" },
+                .{ .amx_movrs, "__AMX_MOVRS__" },
+                .{ .amx_transpose, "__AMX_TRANSPOSE__" },
+                .{ .amx_avx512, "__AMX_AVX512__" },
+                .{ .amx_tf32, "__AMX_TF32__" },
+                .{ .cmpccxadd, "__CMPCCXADD__" },
+                .{ .raoint, "__RAOINT__" },
+                .{ .avxifma, "__AVXIFMA__" },
+                .{ .avxneconvert, "__AVXNECONVERT__" },
+                .{ .avxvnni, "__AVXVNNI__" },
+                .{ .avxvnniint16, "__AVXVNNIINT16__" },
+                .{ .avxvnniint8, "__AVXVNNIINT8__" },
+                .{ .serialize, "__SERIALIZE__" },
+                .{ .tsxldtrk, "__TSXLDTRK__" },
+                .{ .uintr, "__UINTR__" },
+                .{ .usermsr, "__USERMSR__" },
+                .{ .crc32, "__CRC32__" },
+                .{ .egpr, "__EGPR__" },
+                .{ .push2pop2, "__PUSH2POP2__" },
+                .{ .ppx, "__PPX__" },
+                .{ .ndd, "__NDD__" },
+                .{ .ccmp, "__CCMP__" },
+                .{ .nf, "__NF__" },
+                .{ .cf, "__CF__" },
+                .{ .zu, "__ZU__" },
+
+                .{ .avx512f, "__AVX512F__" },
+                .{ .avx2, "__AVX2__" },
+                .{ .avx, "__AVX__" },
+                .{ .sse4_2, "__SSE4_2__" },
+                .{ .sse4_1, "__SSE4_1__" },
+                .{ .ssse3, "__SSSE3__" },
+                .{ .sse3, "__SSE3__" },
+                .{ .sse2, "__SSE2__" },
+                .{ .sse, "__SSE__" },
+                .{ .sse, "__SSE_MATH__" },
+
+                .{ .mmx, "__MMX__" },
+            }) |fs| {
+                if (features.isEnabled(@intFromEnum(fs[0]))) {
+                    try define(w, fs[1]);
+                }
+            }
+
+            if (comp.langopts.ms_extensions and comp.target.cpu.arch == .x86) {
+                const level = if (comp.target.cpu.has(.x86, .sse2))
+                    "2"
+                else if (comp.target.cpu.has(.x86, .sse))
+                    "1"
+                else
+                    "0";
+
+                try w.print("#define _M_IX86_FP {s}\n", .{level});
+            }
+
+            if (comp.target.cpu.hasAll(.x86, &.{ .egpr, .push2pop2, .ppx, .ndd, .ccmp, .nf, .cf, .zu })) {
+                try define(w, "__APX_F__");
+            }
+
+            if (comp.target.cpu.hasAll(.x86, &.{ .egpr, .inline_asm_use_gpr32 })) {
+                try define(w, "__APX_INLINE_ASM_USE_GPR32__");
+            }
+
+            if (comp.target.cpu.has(.x86, .cx8)) {
+                try define(w, "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
+            }
+            if (comp.target.cpu.has(.x86, .cx16) and comp.target.cpu.arch == .x86_64) {
+                try define(w, "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
+            }
+
+            if (comp.hasFloat128()) {
+                try w.writeAll("#define __SIZEOF_FLOAT128__ 16\n");
             }
         },
         .mips,
@@ -443,13 +621,132 @@ fn generateSystemDefines(comp: *Compilation, w: *std.Io.Writer) !void {
                 try define(w, "__arm64__");
             }
             if (comp.target.os.tag == .windows and comp.target.abi == .msvc) {
-                try w.writeAll("#define _M_ARM64 100\n");
+                try w.writeAll("#define _M_ARM64 1\n");
+            }
+
+            {
+                const cmodel = switch (comp.cmodel) {
+                    .default => "small",
+                    else => @tagName(comp.cmodel),
+                };
+                try w.writeAll("#define __AARCH64_CMODEL_");
+                for (cmodel) |c| {
+                    try w.writeByte(std.ascii.toUpper(c));
+                }
+                try w.writeAll("__ 1\n");
+            }
+
+            if (comp.target.cpu.has(.aarch64, .fp_armv8)) {
+                try w.writeAll("#define __ARM_FP 0xE\n");
+            }
+            if (comp.target.cpu.has(.aarch64, .neon)) {
+                try define(w, "__ARM_NEON");
+                try w.writeAll("#define __ARM_NEON_FP 0xE\n");
+            }
+            if (comp.target.cpu.has(.aarch64, .bf16)) {
+                try define(w, "__ARM_FEATURE_BF16");
+                try define(w, "__ARM_FEATURE_BF16_VECTOR_ARITHMETIC");
+                try define(w, "__ARM_BF16_FORMAT_ALTERNATIVE");
+                try define(w, "__ARM_FEATURE_BF16_SCALAR_ARITHMETIC");
+                if (comp.target.cpu.has(.aarch64, .sve)) {
+                    try define(w, "__ARM_FEATURE_SVE_BF16");
+                }
+            }
+            if (comp.target.cpu.hasAll(.aarch64, &.{ .sve2, .sve_aes })) {
+                try define(w, "__ARM_FEATURE_SVE2_AES");
+            }
+            if (comp.target.cpu.hasAll(.aarch64, &.{ .sve2, .sve_bitperm })) {
+                try define(w, "__ARM_FEATURE_SVE2_BITPERM");
+            }
+            if (comp.target.cpu.has(.aarch64, .sme)) {
+                try define(w, "__ARM_FEATURE_SME");
+                try define(w, "__ARM_FEATURE_LOCALLY_STREAMING");
+            }
+            if (comp.target.cpu.has(.aarch64, .fmv)) {
+                try define(w, "__HAVE_FUNCTION_MULTI_VERSIONING");
+            }
+            if (comp.target.cpu.has(.aarch64, .sha3)) {
+                try define(w, "__ARM_FEATURE_SHA3");
+                try define(w, "__ARM_FEATURE_SHA512");
+            }
+            if (comp.target.cpu.has(.aarch64, .sm4)) {
+                try define(w, "__ARM_FEATURE_SM3");
+                try define(w, "__ARM_FEATURE_SM4");
+            }
+            if (!comp.target.cpu.has(.aarch64, .strict_align)) {
+                try define(w, "__ARM_FEATURE_UNALIGNED");
+            }
+            if (comp.target.cpu.hasAll(.aarch64, &.{ .neon, .fullfp16 })) {
+                try define(w, "__ARM_FEATURE_FP16_VECTOR_ARITHMETIC");
+            }
+            if (comp.target.cpu.has(.aarch64, .rcpc3)) {
+                try w.writeAll("#define __ARM_FEATURE_RCPC 3\n");
+            } else if (comp.target.cpu.has(.aarch64, .rcpc)) {
+                try define(w, "__ARM_FEATURE_RCPC");
+            }
+
+            const features = comp.target.cpu.features;
+            for ([_]struct { std.Target.aarch64.Feature, []const u8 }{
+                .{ .sve, "SVE" },
+                .{ .sve2, "SVE2" },
+                .{ .sve2p1, "SVE2p1" },
+                .{ .sve2_sha3, "SVE2_SHA3" },
+                .{ .sve2_sm4, "SVE2_SM4" },
+                .{ .sve_b16b16, "SVE_B16B16" },
+                .{ .sme2, "SME2" },
+                .{ .sme2p1, "SME2p1" },
+                .{ .sme_f16f16, "SME_F16F16" },
+                .{ .sme_b16b16, "SME_B16B16" },
+                .{ .crc, "CRC32" },
+                .{ .aes, "AES" },
+                .{ .sha2, "SHA2" },
+                .{ .pauth, "PAUTH" },
+                .{ .pauth_lr, "PAUTH_LR" },
+                .{ .bti, "BTI" },
+                .{ .fullfp16, "FP16_SCALAR_ARITHMETIC" },
+                .{ .dotprod, "DOTPROD" },
+                .{ .mte, "MEMORY_TAGGING" },
+                .{ .tme, "TME" },
+                .{ .i8mm, "MATMUL_INT8" },
+                .{ .lse, "ATOMICS" },
+                .{ .f64mm, "SVE_MATMUL_FP64" },
+                .{ .f32mm, "SVE_MATMUL_FP32" },
+                .{ .i8mm, "SVE_MATMUL_INT8" },
+                .{ .fp16fml, "FP16_FML" },
+                .{ .ls64, "LS64" },
+                .{ .rand, "RNG" },
+                .{ .mops, "MOPS" },
+                .{ .d128, "SYSREG128" },
+                .{ .gcs, "GCS" },
+            }) |fs| {
+                if (features.isEnabled(@intFromEnum(fs[0]))) {
+                    try w.print("#define __ARM_FEATURE_{s} 1\n", .{fs[1]});
+                }
             }
         },
         .msp430 => {
             try define(w, "MSP430");
             try define(w, "__MSP430__");
         },
+        .arc => {
+            try define(w, "__arc__");
+        },
+        .wasm32, .wasm64 => {
+            try define(w, "__wasm");
+            try define(w, "__wasm__");
+            if (comp.target.cpu.arch == .wasm32) {
+                try define(w, "__wasm32");
+                try define(w, "__wasm32__");
+            } else {
+                try define(w, "__wasm64");
+                try define(w, "__wasm64__");
+            }
+
+            for (comp.target.cpu.arch.allFeaturesList()) |feature| {
+                if (!comp.target.cpu.features.isEnabled(feature.index)) continue;
+                try w.print("#define __wasm_{s}__ 1\n", .{feature.name});
+            }
+        },
         else => {},
     }
 
@@ -1477,7 +1774,7 @@ fn getFileContents(comp: *Compilation, path: []const u8, limit: std.Io.Limit) ![
 
     var file_buf: [4096]u8 = undefined;
     var file_reader = file.reader(&file_buf);
-    if (limit.minInt(try file_reader.getSize()) > std.math.maxInt(u32)) return error.FileTooBig;
+    if (limit.minInt64(try file_reader.getSize()) > std.math.maxInt(u32)) return error.FileTooBig;
 
     _ = allocating.writer.sendFileAll(&file_reader, limit) catch |err| switch (err) {
         error.WriteFailed => return error.OutOfMemory,
@@ -1494,14 +1791,16 @@ pub fn findEmbed(
     /// angle bracket vs quotes
     include_type: IncludeType,
     limit: std.Io.Limit,
+    opt_dep_file: ?*DepFile,
 ) !?[]const u8 {
     if (std.fs.path.isAbsolute(filename)) {
-        return if (comp.getFileContents(filename, limit)) |some|
-            some
-        else |err| switch (err) {
+        if (comp.getFileContents(filename, limit)) |some| {
+            if (opt_dep_file) |dep_file| try dep_file.addDependencyDupe(comp.gpa, comp.arena, filename);
+            return some;
+        } else |err| switch (err) {
             error.OutOfMemory => |e| return e,
-            else => null,
-        };
+            else => return null,
+        }
     }
 
     var stack_fallback = std.heap.stackFallback(path_buf_stack_limit, comp.gpa);
@@ -1516,6 +1815,7 @@ pub fn findEmbed(
                 std.mem.replaceScalar(u8, path, '\\', '/');
             }
             if (comp.getFileContents(path, limit)) |some| {
+                if (opt_dep_file) |dep_file| try dep_file.addDependencyDupe(comp.gpa, comp.arena, filename);
                 return some;
             } else |err| switch (err) {
                 error.OutOfMemory => return error.OutOfMemory,
@@ -1531,6 +1831,7 @@ pub fn findEmbed(
             std.mem.replaceScalar(u8, path, '\\', '/');
         }
         if (comp.getFileContents(path, limit)) |some| {
+            if (opt_dep_file) |dep_file| try dep_file.addDependencyDupe(comp.gpa, comp.arena, filename);
             return some;
         } else |err| switch (err) {
             error.OutOfMemory => return error.OutOfMemory,
lib/compiler/aro/aro/DepFile.zig
@@ -0,0 +1,78 @@
+const std = @import("std");
+const Allocator = std.mem.Allocator;
+
+pub const Format = enum { make, nmake };
+
+const DepFile = @This();
+
+target: []const u8,
+deps: std.StringArrayHashMapUnmanaged(void) = .empty,
+format: Format,
+
+pub fn deinit(d: *DepFile, gpa: Allocator) void {
+    d.deps.deinit(gpa);
+    d.* = undefined;
+}
+
+pub fn addDependency(d: *DepFile, gpa: Allocator, path: []const u8) !void {
+    try d.deps.put(gpa, path, {});
+}
+
+pub fn addDependencyDupe(d: *DepFile, gpa: Allocator, arena: Allocator, path: []const u8) !void {
+    const gop = try d.deps.getOrPut(gpa, path);
+    if (gop.found_existing) return;
+    gop.key_ptr.* = try arena.dupe(u8, path);
+}
+
+pub fn write(d: *const DepFile, w: *std.Io.Writer) std.Io.Writer.Error!void {
+    const max_columns = 75;
+    var columns: usize = 0;
+
+    try w.writeAll(d.target);
+    columns += d.target.len;
+    try w.writeByte(':');
+    columns += 1;
+
+    for (d.deps.keys()) |path| {
+        if (std.mem.eql(u8, path, "<stdin>")) continue;
+
+        if (columns + path.len + " \\\n".len > max_columns) {
+            try w.writeAll(" \\\n ");
+            columns = 1;
+        }
+        try w.writeByte(' ');
+        try d.writePath(path, w);
+        columns += path.len + 1;
+    }
+    try w.writeByte('\n');
+    try w.flush();
+}
+
+fn writePath(d: *const DepFile, path: []const u8, w: *std.Io.Writer) !void {
+    switch (d.format) {
+        .nmake => {
+            if (std.mem.indexOfAny(u8, path, " #${}^!")) |_|
+                try w.print("\"{s}\"", .{path})
+            else
+                try w.writeAll(path);
+        },
+        .make => {
+            for (path, 0..) |c, i| {
+                if (c == '#') {
+                    try w.writeByte('\\');
+                } else if (c == '$') {
+                    try w.writeByte('$');
+                } else if (c == ' ') {
+                    try w.writeByte('\\');
+                    var j = i;
+                    while (j != 0) {
+                        j -= 1;
+                        if (path[j] != '\\') break;
+                        try w.writeByte('\\');
+                    }
+                }
+                try w.writeByte(c);
+            }
+        },
+    }
+}
lib/compiler/aro/aro/Diagnostics.zig
@@ -23,6 +23,52 @@ pub const Message = struct {
         @"error",
         @"fatal error",
     };
+
+    pub fn write(msg: Message, w: *std.Io.Writer, config: std.Io.tty.Config, details: bool) std.Io.tty.Config.SetColorError!void {
+        try config.setColor(w, .bold);
+        if (msg.location) |loc| {
+            try w.print("{s}:{d}:{d}: ", .{ loc.path, loc.line_no, loc.col });
+        }
+        switch (msg.effective_kind) {
+            .@"fatal error", .@"error" => try config.setColor(w, .bright_red),
+            .note => try config.setColor(w, .bright_cyan),
+            .warning => try config.setColor(w, .bright_magenta),
+            .off => unreachable,
+        }
+        try w.print("{s}: ", .{@tagName(msg.effective_kind)});
+
+        try config.setColor(w, .white);
+        try w.writeAll(msg.text);
+        if (msg.opt) |some| {
+            if (msg.effective_kind == .@"error" and msg.kind != .@"error") {
+                try w.print(" [-Werror,-W{s}]", .{@tagName(some)});
+            } else if (msg.effective_kind != .note) {
+                try w.print(" [-W{s}]", .{@tagName(some)});
+            }
+        } else if (msg.extension) {
+            if (msg.effective_kind == .@"error") {
+                try w.writeAll(" [-Werror,-Wpedantic]");
+            } else if (msg.effective_kind != msg.kind) {
+                try w.writeAll(" [-Wpedantic]");
+            }
+        }
+
+        if (!details or msg.location == null) {
+            try w.writeAll("\n");
+            try config.setColor(w, .reset);
+        } else {
+            const loc = msg.location.?;
+            const trailer = if (loc.end_with_splice) "\\ " else "";
+            try config.setColor(w, .reset);
+            try w.print("\n{s}{s}\n", .{ loc.line, trailer });
+            try w.splatByteAll(' ', loc.width);
+            try config.setColor(w, .bold);
+            try config.setColor(w, .bright_green);
+            try w.writeAll("^\n");
+            try config.setColor(w, .reset);
+        }
+        try w.flush();
+    }
 };
 
 pub const Option = enum {
@@ -247,6 +293,11 @@ output: union(enum) {
     },
     ignore,
 },
+/// Force usage of color in output.
+color: ?bool = null,
+/// Include line of code in output.
+details: bool = true,
+
 state: State = .{},
 /// Amount of error or fatal error messages that have been sent to `output`.
 errors: u32 = 0,
@@ -468,7 +519,10 @@ fn addMessage(d: *Diagnostics, msg: Message) Compilation.Error!void {
     switch (d.output) {
         .ignore => {},
         .to_writer => |writer| {
-            writeToWriter(msg, writer.writer, writer.color) catch {
+            var config = writer.color;
+            if (d.color == false) config = .no_color;
+            if (d.color == true and config == .no_color) config = .escape_codes;
+            msg.write(writer.writer, config, d.details) catch {
                 return error.FatalError;
             };
         },
@@ -485,48 +539,3 @@ fn addMessage(d: *Diagnostics, msg: Message) Compilation.Error!void {
         },
     }
 }
-
-pub fn writeToWriter(msg: Message, w: *std.Io.Writer, config: std.Io.tty.Config) !void {
-    try config.setColor(w, .bold);
-    if (msg.location) |loc| {
-        try w.print("{s}:{d}:{d}: ", .{ loc.path, loc.line_no, loc.col });
-    }
-    switch (msg.effective_kind) {
-        .@"fatal error", .@"error" => try config.setColor(w, .bright_red),
-        .note => try config.setColor(w, .bright_cyan),
-        .warning => try config.setColor(w, .bright_magenta),
-        .off => unreachable,
-    }
-    try w.print("{s}: ", .{@tagName(msg.effective_kind)});
-
-    try config.setColor(w, .white);
-    try w.writeAll(msg.text);
-    if (msg.opt) |some| {
-        if (msg.effective_kind == .@"error" and msg.kind != .@"error") {
-            try w.print(" [-Werror,-W{s}]", .{@tagName(some)});
-        } else if (msg.effective_kind != .note) {
-            try w.print(" [-W{s}]", .{@tagName(some)});
-        }
-    } else if (msg.extension) {
-        if (msg.effective_kind == .@"error") {
-            try w.writeAll(" [-Werror,-Wpedantic]");
-        } else if (msg.effective_kind != msg.kind) {
-            try w.writeAll(" [-Wpedantic]");
-        }
-    }
-
-    if (msg.location) |loc| {
-        const trailer = if (loc.end_with_splice) "\\ " else "";
-        try config.setColor(w, .reset);
-        try w.print("\n{s}{s}\n", .{ loc.line, trailer });
-        try w.splatByteAll(' ', loc.width);
-        try config.setColor(w, .bold);
-        try config.setColor(w, .bright_green);
-        try w.writeAll("^\n");
-        try config.setColor(w, .reset);
-    } else {
-        try w.writeAll("\n");
-        try config.setColor(w, .reset);
-    }
-    try w.flush();
-}
lib/compiler/aro/aro/Driver.zig
@@ -10,6 +10,7 @@ const Object = backend.Object;
 
 const Compilation = @import("Compilation.zig");
 const Diagnostics = @import("Diagnostics.zig");
+const DepFile = @import("DepFile.zig");
 const GCCVersion = @import("Driver/GCCVersion.zig");
 const LangOpts = @import("LangOpts.zig");
 const Preprocessor = @import("Preprocessor.zig");
@@ -63,7 +64,6 @@ verbose_ast: bool = false,
 verbose_pp: bool = false,
 verbose_ir: bool = false,
 verbose_linker_args: bool = false,
-color: ?bool = null,
 nobuiltininc: bool = false,
 nostdinc: bool = false,
 nostdlibinc: bool = false,
@@ -73,7 +73,6 @@ mabicalls: ?bool = null,
 dynamic_nopic: ?bool = null,
 ropi: bool = false,
 rwpi: bool = false,
-cmodel: std.builtin.CodeModel = .default,
 debug_dump_letters: packed struct(u3) {
     d: bool = false,
     m: bool = false,
@@ -88,17 +87,27 @@ debug_dump_letters: packed struct(u3) {
         return .result_only;
     }
 } = .{},
+dependencies: struct {
+    m: bool = false,
+    md: bool = false,
+    format: DepFile.Format = .make,
+    file: ?[]const u8 = null,
+} = .{},
 
 /// Full path to the aro executable
 aro_name: []const u8 = "",
 
-/// Value of --triple= passed via CLI
+/// Value of -target passed via CLI
 raw_target_triple: ?[]const u8 = null,
 
+/// Value of -mcpu passed via CLI
+raw_cpu: ?[]const u8 = null,
+
 /// Non-optimizing assembly backend is currently selected by passing `-O0`
 use_assembly_backend: bool = false,
 
 // linker options
+use_linker: ?[]const u8 = null,
 linker_path: ?[]const u8 = null,
 nodefaultlibs: bool = false,
 nolibc: bool = false,
@@ -133,13 +142,26 @@ pub const usage =
     \\  --help      Print this message
     \\  --version   Print aro version
     \\
-    \\Compile options:
-    \\  -c, --compile           Only run preprocess, compile, and assemble steps
+    \\Preprocessor options:
+    \\  -C                      Do not discard comments
+    \\  -CC                     Do not discard comments, including in macro expansions
     \\  -dM                     Output #define directives for all the macros defined during the execution of the preprocessor
     \\  -dD                     Like -dM except that it outputs both the #define directives and the result of preprocessing
     \\  -dN                     Like -dD, but emit only the macro names, not their expansions.
     \\  -D <macro>=<value>      Define <macro> to <value> (defaults to 1)
     \\  -E                      Only run the preprocessor
+    \\  -fdollars-in-identifiers
+    \\                          Allow '$' in identifiers
+    \\  -fno-dollars-in-identifiers
+    \\                          Disallow '$' in identifiers
+    \\  -M                      Output dependency file instead of preprocessing result
+    \\  -MD                     Like -M except -E is not implied
+    \\  -MF <file>              Write dependency file to <file>
+    \\  -MV                     Use NMake/Jom format for dependency file
+    \\  -P, --no-line-commands  Disable linemarker output in -E mode
+    \\
+    \\Compile options:
+    \\  -c, --compile           Only run preprocess, compile, and assemble steps
     \\  -fapple-kext            Use Apple's kernel extensions ABI
     \\  -fchar8_t               Enable char8_t (enabled by default in C23 and later)
     \\  -fno-char8_t            Disable char8_t (disabled by default for pre-C23)
@@ -158,10 +180,6 @@ pub const usage =
     \\  -fhosted                Compilation in a hosted environment
     \\  -fms-extensions         Enable support for Microsoft extensions
     \\  -fno-ms-extensions      Disable support for Microsoft extensions
-    \\  -fdollars-in-identifiers
-    \\                          Allow '$' in identifiers
-    \\  -fno-dollars-in-identifiers
-    \\                          Disallow '$' in identifiers
     \\  -g                      Generate debug information
     \\  -fmacro-backtrace-limit=<limit>
     \\                          Set limit on how many macro expansion traces are shown in errors (default 6)
@@ -197,6 +215,7 @@ pub const usage =
     \\  -mabicalls              Enable SVR4-style position-independent code (Mips only)
     \\  -mno-abicalls           Disable SVR4-style position-independent code (Mips only)
     \\  -mcmodel=<code-model>   Generate code for the given code model
+    \\  -mcpu [cpu]             Specify target CPU and feature set
     \\  -mkernel                Enable kernel development mode
     \\  -nobuiltininc           Do not search the compiler's builtin directory for include files
     \\  -resource-dir <dir>     Override the path to the compiler's builtin resource directory
@@ -204,7 +223,6 @@ pub const usage =
     \\                          Do not search the standard system directories or compiler builtin directories for include files.
     \\  -nostdlibinc            Do not search the standard system directories for include files, but do search compiler builtin include directories
     \\  -o <file>               Write output to <file>
-    \\  -P, --no-line-commands  Disable linemarker output in -E mode
     \\  -pedantic               Warn on language extensions
     \\  -pedantic-errors        Error on language extensions
     \\  --rtlib=<arg>           Compiler runtime library to use (libgcc or compiler-rt)
@@ -262,9 +280,12 @@ pub fn parseArgs(
     var pic_arg: []const u8 = "";
     var declspec_attrs: ?bool = null;
     var ms_extensions: ?bool = null;
+    var strip = true;
+    var debug: ?backend.CodeGenOptions.DebugFormat = null;
+    var emulate: ?LangOpts.Compiler = null;
     while (i < args.len) : (i += 1) {
         const arg = args[i];
-        if (mem.startsWith(u8, arg, "-") and arg.len > 1) {
+        if (arg.len > 1 and arg[0] == '-') {
             if (mem.eql(u8, arg, "--help")) {
                 try stdout.print(usage, .{args[0]});
                 try stdout.flush();
@@ -329,7 +350,7 @@ pub fn parseArgs(
             } else if (mem.eql(u8, arg, "-fapple-kext")) {
                 d.apple_kext = true;
             } else if (option(arg, "-mcmodel=")) |cmodel| {
-                d.cmodel = std.meta.stringToEnum(std.builtin.CodeModel, cmodel) orelse
+                d.comp.cmodel = std.meta.stringToEnum(std.builtin.CodeModel, cmodel) orelse
                     return d.fatal("unsupported machine code model: '{s}'", .{arg});
             } else if (mem.eql(u8, arg, "-mkernel")) {
                 d.mkernel = true;
@@ -339,14 +360,47 @@ pub fn parseArgs(
                 d.mabicalls = true;
             } else if (mem.eql(u8, arg, "-mno-abicalls")) {
                 d.mabicalls = false;
+            } else if (mem.eql(u8, arg, "-mcpu")) {
+                i += 1;
+                if (i >= args.len) {
+                    try d.err("expected argument after -mcpu", .{});
+                    continue;
+                }
+                d.raw_cpu = args[i];
+            } else if (option(arg, "-mcpu=")) |cpu| {
+                d.raw_cpu = cpu;
+            } else if (mem.eql(u8, arg, "-M") or mem.eql(u8, arg, "--dependencies")) {
+                d.dependencies.m = true;
+                // -M implies -w and -E
+                d.diagnostics.state.ignore_warnings = true;
+                d.only_preprocess = true;
+            } else if (mem.eql(u8, arg, "-MD") or mem.eql(u8, arg, "--write-dependencies")) {
+                d.dependencies.md = true;
+            } else if (mem.startsWith(u8, arg, "-MF")) {
+                var path = arg["-MF".len..];
+                if (path.len == 0) {
+                    i += 1;
+                    if (i >= args.len) {
+                        try d.err("expected argument after -MF", .{});
+                        continue;
+                    }
+                    path = args[i];
+                }
+                d.dependencies.file = path;
+            } else if (mem.eql(u8, arg, "-MV")) {
+                d.dependencies.format = .nmake;
             } else if (mem.eql(u8, arg, "-fchar8_t")) {
                 d.comp.langopts.has_char8_t_override = true;
             } else if (mem.eql(u8, arg, "-fno-char8_t")) {
                 d.comp.langopts.has_char8_t_override = false;
             } else if (mem.eql(u8, arg, "-fcolor-diagnostics")) {
-                d.color = true;
+                d.diagnostics.color = true;
             } else if (mem.eql(u8, arg, "-fno-color-diagnostics")) {
-                d.color = false;
+                d.diagnostics.color = false;
+            } else if (mem.eql(u8, arg, "-fcaret-diagnostics")) {
+                d.diagnostics.details = true;
+            } else if (mem.eql(u8, arg, "-fno-caret-diagnostics")) {
+                d.diagnostics.details = false;
             } else if (mem.eql(u8, arg, "-fcommon")) {
                 d.comp.code_gen_options.common = true;
             } else if (mem.eql(u8, arg, "-fno-common")) {
@@ -356,9 +410,31 @@ pub fn parseArgs(
             } else if (mem.eql(u8, arg, "-fno-dollars-in-identifiers")) {
                 d.comp.langopts.dollars_in_identifiers = false;
             } else if (mem.eql(u8, arg, "-g")) {
-                d.comp.code_gen_options.debug = true;
+                strip = false;
             } else if (mem.eql(u8, arg, "-g0")) {
-                d.comp.code_gen_options.debug = false;
+                strip = true;
+            } else if (mem.eql(u8, arg, "-gcodeview")) {
+                debug = .code_view;
+            } else if (mem.eql(u8, arg, "-gdwarf32")) {
+                debug = .{ .dwarf = .@"32" };
+            } else if (mem.eql(u8, arg, "-gdwarf64")) {
+                debug = .{ .dwarf = .@"64" };
+            } else if (mem.eql(u8, arg, "-gdwarf") or
+                mem.eql(u8, arg, "-gdwarf-2") or
+                mem.eql(u8, arg, "-gdwarf-3") or
+                mem.eql(u8, arg, "-gdwarf-4") or
+                mem.eql(u8, arg, "-gdwarf-5"))
+            {
+                d.comp.code_gen_options.dwarf_version = switch (arg[arg.len - 1]) {
+                    '2' => .@"2",
+                    '3' => .@"3",
+                    '4' => .@"4",
+                    '5' => .@"5",
+                    else => .@"0",
+                };
+                if (debug == null or debug.? != .dwarf) {
+                    debug = .{ .dwarf = .@"32" };
+                }
             } else if (mem.eql(u8, arg, "-fdigraphs")) {
                 d.comp.langopts.digraphs = true;
             } else if (mem.eql(u8, arg, "-fno-digraphs")) {
@@ -413,9 +489,9 @@ pub fn parseArgs(
                 ms_extensions = true;
             } else if (mem.eql(u8, arg, "-fno-ms-extensions")) {
                 ms_extensions = false;
-            } else if (mem.startsWith(u8, arg, "-fsyntax-only")) {
+            } else if (mem.eql(u8, arg, "-fsyntax-only")) {
                 d.only_syntax = true;
-            } else if (mem.startsWith(u8, arg, "-fno-syntax-only")) {
+            } else if (mem.eql(u8, arg, "-fno-syntax-only")) {
                 d.only_syntax = false;
             } else if (mem.eql(u8, arg, "-fgnuc-version=")) {
                 gnuc_version = "0";
@@ -483,12 +559,7 @@ pub fn parseArgs(
                     try d.err("invalid compiler '{s}'", .{arg});
                     continue;
                 };
-                d.comp.langopts.setEmulatedCompiler(compiler);
-                switch (d.comp.langopts.emulate) {
-                    .clang => try d.diagnostics.set("clang", .off),
-                    .gcc => try d.diagnostics.set("gnu", .off),
-                    .msvc => try d.diagnostics.set("microsoft", .off),
-                }
+                emulate = compiler;
             } else if (option(arg, "-ffp-eval-method=")) |fp_method_str| {
                 const fp_eval_method = std.meta.stringToEnum(LangOpts.FPEvalMethod, fp_method_str) orelse .indeterminate;
                 if (fp_eval_method == .indeterminate) {
@@ -554,8 +625,10 @@ pub fn parseArgs(
                     continue;
                 }
                 d.raw_target_triple = args[i];
+                emulate = null;
             } else if (option(arg, "--target=")) |triple| {
                 d.raw_target_triple = triple;
+                emulate = null;
             } else if (mem.eql(u8, arg, "--verbose-ast")) {
                 d.verbose_ast = true;
             } else if (mem.eql(u8, arg, "--verbose-pp")) {
@@ -571,6 +644,10 @@ pub fn parseArgs(
                 d.comp.langopts.preserve_comments = true;
                 d.comp.langopts.preserve_comments_in_macros = true;
                 comment_arg = arg;
+            } else if (option(arg, "-fuse-ld=")) |linker_name| {
+                d.use_linker = linker_name;
+            } else if (mem.eql(u8, arg, "-fuse-ld=")) {
+                d.use_linker = null;
             } else if (option(arg, "--ld-path=")) |linker_path| {
                 d.linker_path = linker_path;
             } else if (mem.eql(u8, arg, "-r")) {
@@ -624,6 +701,33 @@ pub fn parseArgs(
                 } else {
                     try d.err("invalid unwind library name  '{s}'", .{unwindlib});
                 }
+            } else if (mem.startsWith(u8, arg, "-x")) {
+                var lang = arg["-x".len..];
+                if (lang.len == 0) {
+                    i += 1;
+                    if (i >= args.len) {
+                        try d.err("expected argument after -x", .{});
+                        continue;
+                    }
+                    lang = args[i];
+                }
+                if (!mem.eql(u8, lang, "none") and !mem.eql(u8, lang, "c")) {
+                    try d.err("language not recognized: '{s}'", .{lang});
+                }
+            } else if (mem.startsWith(u8, arg, "-flto")) {
+                const rest = arg["-flto".len..];
+                if (rest.len == 0 or
+                    mem.eql(u8, rest, "=auto") or
+                    mem.eql(u8, rest, "=full") or
+                    mem.eql(u8, rest, "=jobserver") or
+                    mem.eql(u8, rest, "=thin"))
+                {
+                    try d.warn("lto not supported", .{});
+                } else {
+                    return d.fatal("invalid lto mode: '{s}'", .{arg});
+                }
+            } else if (mem.eql(u8, arg, "-fno-lto")) {
+                // nothing to do
             } else {
                 try d.warn("unknown argument '{s}'", .{arg});
             }
@@ -636,17 +740,33 @@ pub fn parseArgs(
             try d.inputs.append(d.comp.gpa, source);
         }
     }
-    if (d.raw_target_triple) |triple| triple: {
-        const query = std.Target.Query.parse(.{ .arch_os_abi = triple }) catch {
-            try d.err("invalid target '{s}'", .{triple});
-            d.raw_target_triple = null;
-            break :triple;
+    {
+        var diags: std.Target.Query.ParseOptions.Diagnostics = .{};
+        const opts: std.Target.Query.ParseOptions = .{
+            .arch_os_abi = d.raw_target_triple orelse "native",
+            .cpu_features = d.raw_cpu,
+            .diagnostics = &diags,
+        };
+        const query = std.Target.Query.parse(opts) catch |er| switch (er) {
+            error.UnknownCpuModel => {
+                return d.fatal("unknown CPU: '{s}'", .{diags.cpu_name.?});
+            },
+            error.UnknownCpuFeature => {
+                return d.fatal("unknown CPU feature: '{s}'", .{diags.unknown_feature_name.?});
+            },
+            error.UnknownArchitecture => {
+                return d.fatal("unknown architecture: '{s}'", .{diags.unknown_architecture_name.?});
+            },
+            else => |e| return d.fatal("unable to parse target query '{s}': {s}", .{
+                opts.arch_os_abi, @errorName(e),
+            }),
         };
-        const target = std.zig.system.resolveTargetQuery(query) catch |e| {
+        d.comp.target = std.zig.system.resolveTargetQuery(query) catch |e| {
             return d.fatal("unable to resolve target: {s}", .{errorDescription(e)});
         };
-        d.comp.target = target;
-        d.comp.langopts.setEmulatedCompiler(target_util.systemCompiler(target));
+    }
+    if (emulate != null or d.raw_target_triple != null) {
+        d.comp.langopts.setEmulatedCompiler(emulate orelse target_util.systemCompiler(d.comp.target));
         switch (d.comp.langopts.emulate) {
             .clang => try d.diagnostics.set("clang", .off),
             .gcc => try d.diagnostics.set("gnu", .off),
@@ -673,6 +793,19 @@ pub fn parseArgs(
     const pic_level, const is_pie = try d.getPICMode(pic_arg);
     d.comp.code_gen_options.pic_level = pic_level;
     d.comp.code_gen_options.is_pie = is_pie;
+    d.comp.code_gen_options.debug = debug: {
+        if (strip) break :debug .strip;
+        if (debug) |explicit| break :debug explicit;
+        break :debug switch (d.comp.target.ofmt) {
+            .elf, .goff, .macho, .wasm, .xcoff => .{ .dwarf = .@"32" },
+            .coff => .code_view,
+            .c => switch (d.comp.target.os.tag) {
+                .windows, .uefi => .code_view,
+                else => .{ .dwarf = .@"32" },
+            },
+            .spirv, .hex, .raw, .plan9 => .strip,
+        };
+    };
     if (declspec_attrs) |some| d.comp.langopts.declspec_attrs = some;
     if (ms_extensions) |some| d.comp.langopts.setMSExtensions(some);
     return false;
@@ -728,6 +861,7 @@ pub fn fatal(d: *Driver, comptime fmt: []const u8, args: anytype) error{ FatalEr
 }
 
 pub fn printDiagnosticsStats(d: *Driver) void {
+    if (!d.diagnostics.details) return;
     const warnings = d.diagnostics.warnings;
     const errors = d.diagnostics.errors;
 
@@ -743,14 +877,14 @@ pub fn printDiagnosticsStats(d: *Driver) void {
 }
 
 pub fn detectConfig(d: *Driver, file: std.fs.File) std.Io.tty.Config {
-    if (d.color == true) return .escape_codes;
-    if (d.color == false) return .no_color;
+    if (d.diagnostics.color == false) return .no_color;
+    const force_color = d.diagnostics.color == true;
 
     if (file.supportsAnsiEscapeCodes()) return .escape_codes;
     if (@import("builtin").os.tag == .windows and file.isTty()) {
         var info: std.os.windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
-        if (std.os.windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) != std.os.windows.TRUE) {
-            return .no_color;
+        if (std.os.windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) == std.os.windows.FALSE) {
+            return if (force_color) .escape_codes else .no_color;
         }
         return .{ .windows_api = .{
             .handle = file.handle,
@@ -758,7 +892,7 @@ pub fn detectConfig(d: *Driver, file: std.fs.File) std.Io.tty.Config {
         } };
     }
 
-    return .no_color;
+    return if (force_color) .escape_codes else .no_color;
 }
 
 pub fn errorDescription(e: anyerror) []const u8 {
@@ -851,6 +985,47 @@ pub fn main(d: *Driver, tc: *Toolchain, args: []const []const u8, comptime fast_
     if (fast_exit) std.process.exit(0);
 }
 
+/// Initializes a DepFile if requested by driver options.
+pub fn initDepFile(d: *Driver, source: Source, buf: *[std.fs.max_name_bytes]u8) Compilation.Error!?DepFile {
+    if (!d.dependencies.m and !d.dependencies.md) return null;
+    var dep_file: DepFile = .{
+        .target = undefined,
+        .format = d.dependencies.format,
+    };
+
+    if (d.dependencies.md and d.output_name != null) {
+        dep_file.target = d.output_name.?;
+    } else {
+        const args = .{
+            std.fs.path.stem(source.path),
+            d.comp.target.ofmt.fileExt(d.comp.target.cpu.arch),
+        };
+        dep_file.target = std.fmt.bufPrint(buf, "{s}{s}", args) catch
+            return d.fatal("dependency file name too long for filesystem '{s}{s}'", args);
+    }
+
+    try dep_file.addDependency(d.comp.gpa, source.path);
+    errdefer comptime unreachable;
+
+    return dep_file;
+}
+
+/// Returns name requested for the dependency file or null for stdout.
+pub fn getDepFileName(d: *Driver, source: Source, buf: *[std.fs.max_name_bytes]u8) Compilation.Error!?[]const u8 {
+    if (d.dependencies.file) |file| {
+        if (std.mem.eql(u8, file, "-")) return null;
+        return file;
+    }
+    if (!d.dependencies.md) {
+        if (d.output_name) |name| return name;
+        return null;
+    }
+
+    const base_name = std.fs.path.stem(d.output_name orelse source.path);
+    return std.fmt.bufPrint(buf, "{s}.d", .{base_name}) catch
+        return d.fatal("dependency file name too long for filesystem: {s}.d", .{base_name});
+}
+
 fn getRandomFilename(d: *Driver, buf: *[std.fs.max_name_bytes]u8, extension: []const u8) ![]const u8 {
     const random_bytes_count = 12;
     const sub_path_len = comptime std.fs.base64_encoder.calcSize(random_bytes_count);
@@ -925,6 +1100,12 @@ fn processSource(
     var pp = try Preprocessor.initDefault(d.comp);
     defer pp.deinit();
 
+    var name_buf: [std.fs.max_name_bytes]u8 = undefined;
+    var opt_dep_file = try d.initDepFile(source, &name_buf);
+    defer if (opt_dep_file) |*dep_file| dep_file.deinit(pp.gpa);
+
+    if (opt_dep_file) |*dep_file| pp.dep_file = dep_file;
+
     if (d.comp.langopts.ms_extensions) {
         d.comp.ms_cwd_source_id = source.id;
     }
@@ -943,6 +1124,22 @@ fn processSource(
 
     try pp.preprocessSources(&.{ source, builtin, user_macros });
 
+    var writer_buf: [4096]u8 = undefined;
+    if (opt_dep_file) |dep_file| {
+        const dep_file_name = try d.getDepFileName(source, writer_buf[0..std.fs.max_name_bytes]);
+
+        const file = if (dep_file_name) |path|
+            d.comp.cwd.createFile(path, .{}) catch |er|
+                return d.fatal("unable to create dependency file '{s}': {s}", .{ path, errorDescription(er) })
+        else
+            std.fs.File.stdout();
+        defer if (dep_file_name != null) file.close();
+
+        var file_writer = file.writer(&writer_buf);
+        dep_file.write(&file_writer.interface) catch
+            return d.fatal("unable to write dependency file: {s}", .{errorDescription(file_writer.err.?)});
+    }
+
     if (d.only_preprocess) {
         d.printDiagnosticsStats();
 
@@ -951,6 +1148,11 @@ fn processSource(
             return;
         }
 
+        if (d.dependencies.m and !d.dependencies.md) {
+            if (fast_exit) std.process.exit(1); // Not linking, no need for cleanup.
+            return;
+        }
+
         const file = if (d.output_name) |some|
             d.comp.cwd.createFile(some, .{}) catch |er|
                 return d.fatal("unable to create output file '{s}': {s}", .{ some, errorDescription(er) })
@@ -997,7 +1199,6 @@ fn processSource(
         );
     }
 
-    var name_buf: [std.fs.max_name_bytes]u8 = undefined;
     const out_file_name = try d.getOutFileName(source, &name_buf);
 
     if (d.use_assembly_backend) {
@@ -1039,8 +1240,7 @@ fn processSource(
         defer ir.deinit(d.comp.gpa);
 
         if (d.verbose_ir) {
-            var stdout_buf: [4096]u8 = undefined;
-            var stdout = std.fs.File.stdout().writer(&stdout_buf);
+            var stdout = std.fs.File.stdout().writer(&writer_buf);
             ir.dump(d.comp.gpa, d.detectConfig(stdout.file), &stdout.interface) catch {};
         }
 
@@ -1065,8 +1265,7 @@ fn processSource(
             return d.fatal("unable to create output file '{s}': {s}", .{ out_file_name, errorDescription(er) });
         defer out_file.close();
 
-        var file_buf: [4096]u8 = undefined;
-        var file_writer = out_file.writer(&file_buf);
+        var file_writer = out_file.writer(&writer_buf);
         obj.finish(&file_writer.interface) catch
             return d.fatal("could not output to object file '{s}': {s}", .{ out_file_name, errorDescription(file_writer.err.?) });
     }
@@ -1236,7 +1435,7 @@ pub fn getPICMode(d: *Driver, lastpic: []const u8) Compilation.Error!struct { ba
         } else {
             pic, pie = .{ false, false };
             if (target_util.isPS(target)) {
-                if (d.cmodel != .kernel) {
+                if (d.comp.cmodel != .kernel) {
                     pic = true;
                     try d.warn(
                         "option '{s}' was ignored by the {s} toolchain, using '-fPIC'",
lib/compiler/aro/aro/Parser.zig
@@ -6904,6 +6904,9 @@ pub const Result = struct {
                 try p.err(l_paren, .invalid_union_cast, .{res.qt});
                 return error.ParsingFailed;
             }
+        } else if (dest_qt.eql(res.qt, p.comp)) {
+            try p.err(l_paren, .cast_to_same_type, .{dest_qt});
+            cast_kind = .no_op;
         } else {
             try p.err(l_paren, .invalid_cast_type, .{dest_qt});
             return error.ParsingFailed;
@@ -8720,7 +8723,9 @@ fn fieldAccess(
     };
 
     if (record_ty.layout == null) {
-        std.debug.assert(is_ptr);
+        // Invalid use of incomplete type, error reported elsewhere.
+        if (!is_ptr) return error.ParsingFailed;
+
         try p.err(field_name_tok - 2, .deref_incomplete_ty_ptr, .{expr_base_qt});
         return error.ParsingFailed;
     }
lib/compiler/aro/aro/Preprocessor.zig
@@ -7,6 +7,7 @@ const Attribute = @import("Attribute.zig");
 const Compilation = @import("Compilation.zig");
 const Error = Compilation.Error;
 const Diagnostics = @import("Diagnostics.zig");
+const DepFile = @import("DepFile.zig");
 const features = @import("features.zig");
 const Hideset = @import("Hideset.zig");
 const Parser = @import("Parser.zig");
@@ -157,6 +158,9 @@ hideset: Hideset,
 source_epoch: SourceEpoch,
 m_times: std.AutoHashMapUnmanaged(Source.Id, u64) = .{},
 
+/// The dependency file tracking all includes and embeds.
+dep_file: ?*DepFile = null,
+
 pub const parse = Parser.parse;
 
 pub const Linemarkers = enum {
@@ -169,7 +173,7 @@ pub const Linemarkers = enum {
 };
 
 pub fn init(comp: *Compilation, source_epoch: SourceEpoch) Preprocessor {
-    const pp = Preprocessor{
+    const pp: Preprocessor = .{
         .comp = comp,
         .diagnostics = comp.diagnostics,
         .gpa = comp.gpa,
@@ -1614,13 +1618,18 @@ fn handleBuiltinMacro(pp: *Preprocessor, builtin: RawToken.Id, param_toks: []con
                 else => unreachable,
             };
             const filename = include_str[1 .. include_str.len - 1];
-            if (builtin == .macro_param_has_include or pp.include_depth == 0) {
-                if (builtin == .macro_param_has_include_next) {
-                    try pp.err(src_loc, .include_next_outside_header, .{});
+            const res = res: {
+                if (builtin == .macro_param_has_include or pp.include_depth == 0) {
+                    if (builtin == .macro_param_has_include_next) {
+                        try pp.err(src_loc, .include_next_outside_header, .{});
+                    }
+                    break :res try pp.comp.hasInclude(filename, src_loc.id, include_type, .first);
                 }
-                return pp.comp.hasInclude(filename, src_loc.id, include_type, .first);
-            }
-            return pp.comp.hasInclude(filename, src_loc.id, include_type, .next);
+                break :res try pp.comp.hasInclude(filename, src_loc.id, include_type, .next);
+            };
+
+            if (res) if (pp.dep_file) |dep_file| try dep_file.addDependencyDupe(pp.gpa, pp.comp.arena, filename);
+            return res;
         },
         else => unreachable,
     }
@@ -1929,7 +1938,7 @@ fn expandFuncMacro(
                         else => unreachable,
                     };
                     const filename = include_str[1 .. include_str.len - 1];
-                    const contents = (try pp.comp.findEmbed(filename, arg[0].loc.id, include_type, .limited(1))) orelse
+                    const contents = (try pp.comp.findEmbed(filename, arg[0].loc.id, include_type, .limited(1), pp.dep_file)) orelse
                         break :res not_found;
 
                     defer pp.comp.gpa.free(contents);
@@ -2537,7 +2546,7 @@ fn expandedSliceExtra(pp: *const Preprocessor, tok: anytype, macro_ws_handling:
     if (tok.id.lexeme()) |some| {
         if (!tok.id.allowsDigraphs(pp.comp.langopts) and !(tok.id == .macro_ws and macro_ws_handling == .preserve_macro_ws)) return some;
     }
-    var tmp_tokenizer = Tokenizer{
+    var tmp_tokenizer: Tokenizer = .{
         .buf = pp.comp.getSource(tok.loc.id).buf,
         .langopts = pp.comp.langopts,
         .index = tok.loc.byte_offset,
@@ -3087,7 +3096,7 @@ fn embed(pp: *Preprocessor, tokenizer: *Tokenizer) MacroError!void {
         }
     }
 
-    const embed_bytes = (try pp.comp.findEmbed(filename, first.source, include_type, limit orelse .unlimited)) orelse
+    const embed_bytes = (try pp.comp.findEmbed(filename, first.source, include_type, limit orelse .unlimited, pp.dep_file)) orelse
         return pp.fatalNotFound(filename_tok, filename);
     defer pp.comp.gpa.free(embed_bytes);
 
@@ -3143,6 +3152,7 @@ fn include(pp: *Preprocessor, tokenizer: *Tokenizer, which: Compilation.WhichInc
         if (pp.defines.contains(guard)) return;
     }
 
+    if (pp.dep_file) |dep| try dep.addDependency(pp.gpa, new_source.path);
     if (pp.verbose) {
         pp.verboseLog(first, "include file {s}", .{new_source.path});
     }
lib/compiler/aro/backend/CodeGenOptions.zig
@@ -11,7 +11,22 @@ pic_level: PicLevel,
 is_pie: bool,
 optimization_level: OptimizationLevel,
 /// Generate debug information
-debug: bool,
+debug: DebugFormat,
+dwarf_version: DwarfVersion,
+
+pub const DebugFormat = union(enum) {
+    strip,
+    dwarf: std.dwarf.Format,
+    code_view,
+};
+
+pub const DwarfVersion = enum(u3) {
+    @"0" = 0,
+    @"2" = 2,
+    @"3" = 3,
+    @"4" = 4,
+    @"5" = 5,
+};
 
 pub const PicLevel = enum(u8) {
     /// Do not generate position-independent code
@@ -60,5 +75,6 @@ pub const default: @This() = .{
     .pic_level = .none,
     .is_pie = false,
     .optimization_level = .@"0",
-    .debug = false,
+    .debug = .strip,
+    .dwarf_version = .@"0",
 };
lib/compiler/aro/include/float.h
@@ -0,0 +1,126 @@
+/* <float.h> for the Aro C compiler */
+
+#pragma once
+
+#undef FLT_RADIX
+#define FLT_RADIX __FLT_RADIX__
+
+#undef FLT_MANT_DIG
+#define FLT_MANT_DIG __FLT_MANT_DIG__
+
+#undef DBL_MANT_DIG
+#define DBL_MANT_DIG __DBL_MANT_DIG__
+
+#undef LDBL_MANT_DIG
+#define LDBL_MANT_DIG __LDBL_MANT_DIG__
+
+#if __STDC_VERSION__ >= 199901L
+#undef FLT_EVAL_METHOD
+#define FLT_EVAL_METHOD __FLT_EVAL_METHOD__
+
+#undef DECIMAL_DIG
+#define DECIMAL_DIG __DECIMAL_DIG__
+#endif  /* __STDC_VERSION__ >= 199901L */
+
+#undef FLT_DIG
+#define FLT_DIG __FLT_DIG__
+
+#undef DBL_DIG
+#define DBL_DIG __DBL_DIG__
+
+#undef LDBL_DIG
+#define LDBL_DIG __LDBL_DIG__
+
+#undef FLT_MIN_EXP
+#define FLT_MIN_EXP __FLT_MIN_EXP__
+
+#undef DBL_MIN_EXP
+#define DBL_MIN_EXP __DBL_MIN_EXP__
+
+#undef LDBL_MIN_EXP
+#define LDBL_MIN_EXP __LDBL_MIN_EXP__
+
+#undef FLT_MIN_10_EXP
+#define FLT_MIN_10_EXP __FLT_MIN_10_EXP__
+
+#undef DBL_MIN_10_EXP
+#define DBL_MIN_10_EXP __DBL_MIN_10_EXP__
+
+#undef LDBL_MIN_10_EXP
+#define LDBL_MIN_10_EXP __LDBL_MIN_10_EXP__
+
+#undef FLT_MAX_EXP
+#define FLT_MAX_EXP __FLT_MAX_EXP__
+
+#undef DBL_MAX_EXP
+#define DBL_MAX_EXP __DBL_MAX_EXP__
+
+#undef LDBL_MAX_EXP
+#define LDBL_MAX_EXP __LDBL_MAX_EXP__
+
+#undef FLT_MAX_10_EXP
+#define FLT_MAX_10_EXP __FLT_MAX_10_EXP__
+
+#undef DBL_MAX_10_EXP
+#define DBL_MAX_10_EXP __DBL_MAX_10_EXP__
+
+#undef LDBL_MAX_10_EXP
+#define LDBL_MAX_10_EXP __LDBL_MAX_10_EXP__
+
+#undef FLT_MAX
+#define FLT_MAX __FLT_MAX__
+
+#undef DBL_MAX
+#define DBL_MAX __DBL_MAX__
+
+#undef LDBL_MAX
+#define LDBL_MAX __LDBL_MAX__
+
+#undef FLT_EPSILON
+#define FLT_EPSILON __FLT_EPSILON__
+
+#undef DBL_EPSILON
+#define DBL_EPSILON __DBL_EPSILON__
+
+#undef LDBL_EPSILON
+#define LDBL_EPSILON __LDBL_EPSILON__
+
+#undef FLT_MIN
+#define FLT_MIN __FLT_MIN__
+
+#undef DBL_MIN
+#define DBL_MIN __DBL_MIN__
+
+#undef LDBL_MIN
+#define LDBL_MIN __LDBL_MIN__
+
+#if __STDC_VERSION__ >= 201112L
+
+#undef FLT_TRUE_MIN
+#define FLT_TRUE_MIN __FLT_DENORM_MIN__
+
+#undef DBL_TRUE_MIN
+#define DBL_TRUE_MIN __DBL_DENORM_MIN__
+
+#undef LDBL_TRUE_MIN
+#define LDBL_TRUE_MIN __LDBL_DENORM_MIN__
+
+#undef FLT_DECIMAL_DIG
+#define FLT_DECIMAL_DIG __FLT_DECIMAL_DIG__
+
+#undef DBL_DECIMAL_DIG
+#define DBL_DECIMAL_DIG __DBL_DECIMAL_DIG__
+
+#undef LDBL_DECIMAL_DIG
+#define LDBL_DECIMAL_DIG __LDBL_DECIMAL_DIG__
+
+#undef FLT_HAS_SUBNORM
+#define FLT_HAS_SUBNORM __FLT_HAS_DENORM__
+
+#undef DBL_HAS_SUBNORM
+#define DBL_HAS_SUBNORM __DBL_HAS_DENORM__
+
+#undef LDBL_HAS_SUBNORM
+#define LDBL_HAS_SUBNORM __LDBL_HAS_DENORM__
+
+#endif  /* __STDC_VERSION__ >= 201112L */
lib/compiler/aro/include/iso646.h
@@ -0,0 +1,15 @@
+/* <iso646.h> for the Aro C compiler */
+
+#pragma once
+
+#define and    &&
+#define and_eq &=
+#define bitand &
+#define bitor  |
+#define compl  ~
+#define not    !
+#define not_eq !=
+#define or     ||
+#define or_eq  |=
+#define xor    ^
+#define xor_eq ^=
lib/compiler/aro/include/limits.h
@@ -0,0 +1,124 @@
+/* <limits.h> for the Aro C compiler */
+
+#pragma once
+
+/* GlibC will try to include_next GCC's limits.h which will fail.
+   Define _GCC_LIMITS_H_ to prevent it.  */
+#if defined __GNUC__ && !defined _GCC_LIMITS_H_
+#define _GCC_LIMITS_H_
+#endif
+
+/* Include the system's limits.h */
+#if __STDC_HOSTED__ && __has_include_next(<limits.h>)
+#include_next <limits.h>
+#endif
+
+#undef SCHAR_MAX
+#define SCHAR_MAX __SCHAR_MAX__
+
+#undef SHRT_MAX
+#define SHRT_MAX  __SHRT_MAX__
+
+#undef INT_MAX
+#define INT_MAX   __INT_MAX__
+
+#undef LONG_MAX
+#define LONG_MAX  __LONG_MAX__
+
+#undef SCHAR_MIN
+#define SCHAR_MIN (-__SCHAR_MAX__-1)
+
+#undef SHRT_MIN
+#define SHRT_MIN  (-__SHRT_MAX__ -1)
+
+#undef INT_MIN
+#define INT_MIN   (-__INT_MAX__  -1)
+
+#undef LONG_MIN
+#define LONG_MIN  (-__LONG_MAX__ -1L)
+
+#undef UCHAR_MAX
+#define UCHAR_MAX (__SCHAR_MAX__*2  +1)
+
+#undef USHRT_MAX
+#define USHRT_MAX (__SHRT_MAX__ *2  +1)
+
+#undef UINT_MAX
+#define UINT_MAX  (__INT_MAX__  *2U +1U)
+
+#undef ULONG_MAX
+#define ULONG_MAX (__LONG_MAX__ *2UL+1UL)
+
+#ifndef MB_LEN_MAX
+#define MB_LEN_MAX 1
+#endif
+
+#undef CHAR_BIT
+#define CHAR_BIT  __CHAR_BIT__
+
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
+
+#undef BOOL_WIDTH
+#define BOOL_WIDTH   __BOOL_WIDTH__
+
+#undef CHAR_WIDTH
+#define CHAR_WIDTH   CHAR_BIT
+
+#undef SCHAR_WIDTH
+#define SCHAR_WIDTH  CHAR_BIT
+
+#undef UCHAR_WIDTH
+#define UCHAR_WIDTH  CHAR_BIT
+
+#undef USHRT_WIDTH
+#define USHRT_WIDTH  __SHRT_WIDTH__
+
+#undef SHRT_WIDTH
+#define SHRT_WIDTH   __SHRT_WIDTH__
+
+#undef UINT_WIDTH
+#define UINT_WIDTH   __INT_WIDTH__
+
+#undef INT_WIDTH
+#define INT_WIDTH    __INT_WIDTH__
+
+#undef ULONG_WIDTH
+#define ULONG_WIDTH  __LONG_WIDTH__
+
+#undef LONG_WIDTH
+#define LONG_WIDTH   __LONG_WIDTH__
+
+#undef ULLONG_WIDTH
+#define ULLONG_WIDTH __LLONG_WIDTH__
+
+#undef LLONG_WIDTH
+#define LLONG_WIDTH  __LLONG_WIDTH__
+
+#undef BITINT_MAXWIDTH
+#define BITINT_MAXWIDTH __BITINT_MAXWIDTH__
+
+#endif  /*  defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L */
+
+#undef CHAR_MIN
+#undef CHAR_MAX
+#ifdef __CHAR_UNSIGNED__
+#define CHAR_MIN 0
+#define CHAR_MAX UCHAR_MAX
+#else
+#define CHAR_MIN SCHAR_MIN
+#define CHAR_MAX __SCHAR_MAX__
+#endif
+
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+#undef  LLONG_MIN
+#define LLONG_MIN  (-__LONG_LONG_MAX__-1LL)
+
+#undef  LLONG_MAX
+#define LLONG_MAX  __LONG_LONG_MAX__
+
+#undef  ULLONG_MAX
+#define ULLONG_MAX (__LONG_LONG_MAX__*2ULL+1ULL)
+
+#endif
+
lib/compiler/aro/include/stdalign.h
@@ -0,0 +1,11 @@
+/* <stdalign.h> for the Aro C compiler */
+
+#pragma once
+#if __STDC_VERSION__ < 202311L
+
+#define alignas _Alignas
+#define alignof _Alignof
+
+#define __alignas_is_defined 1
+#define __alignof_is_defined 1
+#endif
lib/compiler/aro/include/stdarg.h
@@ -0,0 +1,28 @@
+/* <stdarg.h> for the Aro C compiler */
+
+#pragma once
+/* Todo: Set to 202311L once header is compliant with C23 */
+#define __STDC_VERSION_STDARG_H__ 0
+
+typedef __builtin_va_list va_list;
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000L
+/* C23 no longer requires the second parameter */
+#define va_start(ap, ...) __builtin_va_start(ap, __VA_ARGS__)
+#else
+#define va_start(ap, param) __builtin_va_start(ap, param)
+#endif
+#define va_end(ap) __builtin_va_end(ap)
+#define va_arg(ap, type) __builtin_va_arg(ap, type)
+
+/* GCC and Clang always define __va_copy */
+#define __va_copy(d, s) __builtin_va_copy(d, s)
+
+/* but va_copy only on c99+ or when strict ansi mode is turned off */
+#if __STDC_VERSION__ >= 199901L || !defined(__STRICT_ANSI__)
+#define va_copy(d, s) __builtin_va_copy(d, s)
+#endif
+
+#ifndef __GNUC_VA_LIST
+#define __GNUC_VA_LIST 1
+typedef __builtin_va_list __gnuc_va_list;
+#endif
lib/compiler/aro/include/stdatomic.h
@@ -0,0 +1,138 @@
+/* <stdatomic.h> for the Aro C compiler */
+
+#pragma once
+
+#define __STDC_VERSION_STDATOMIC_H__ 202311L
+
+#if __STDC_HOSTED__ && __has_include_next(<stdatomic.h>)
+#include_next <stdatomic.h>
+#else
+
+#include <stddef.h>
+#include <stdint.h>
+
+#define ATOMIC_BOOL_LOCK_FREE       __ATOMIC_BOOL_LOCK_FREE
+#define ATOMIC_CHAR_LOCK_FREE       __ATOMIC_CHAR_LOCK_FREE
+#define ATOMIC_CHAR16_T_LOCK_FREE   __ATOMIC_CHAR16_T_LOCK_FREE
+#define ATOMIC_CHAR32_T_LOCK_FREE   __ATOMIC_CHAR32_T_LOCK_FREE
+#define ATOMIC_WCHAR_T_LOCK_FREE    __ATOMIC_WCHAR_T_LOCK_FREE
+#define ATOMIC_SHORT_LOCK_FREE      __ATOMIC_SHORT_LOCK_FREE
+#define ATOMIC_INT_LOCK_FREE        __ATOMIC_INT_LOCK_FREE
+#define ATOMIC_LONG_LOCK_FREE       __ATOMIC_LONG_LOCK_FREE
+#define ATOMIC_LLONG_LOCK_FREE      __ATOMIC_LLONG_LOCK_FREE
+#define ATOMIC_POINTER_LOCK_FREE    __ATOMIC_POINTER_LOCK_FREE
+#if defined(__ATOMIC_CHAR8_T_LOCK_FREE)
+#define ATOMIC_CHAR8_T_LOCK_FREE    __ATOMIC_CHAR8_T_LOCK_FREE
+#endif
+
+#if __STDC_VERSION__ < 202311L
+/* ATOMIC_VAR_INIT was removed in C23 */
+#define ATOMIC_VAR_INIT(value) (value)
+#endif
+
+#define atomic_init __c11_atomic_init
+
+typedef enum memory_order {
+  memory_order_relaxed = __ATOMIC_RELAXED,
+  memory_order_consume = __ATOMIC_CONSUME,
+  memory_order_acquire = __ATOMIC_ACQUIRE,
+  memory_order_release = __ATOMIC_RELEASE,
+  memory_order_acq_rel = __ATOMIC_ACQ_REL,
+  memory_order_seq_cst = __ATOMIC_SEQ_CST
+} memory_order;
+
+#define kill_dependency(y) (y)
+
+void atomic_thread_fence(memory_order);
+void atomic_signal_fence(memory_order);
+
+#define atomic_thread_fence(order) __c11_atomic_thread_fence(order)
+#define atomic_signal_fence(order) __c11_atomic_signal_fence(order)
+
+#define atomic_is_lock_free(obj) __c11_atomic_is_lock_free(sizeof(*(obj)))
+
+typedef _Atomic(_Bool)              atomic_bool;
+typedef _Atomic(char)               atomic_char;
+typedef _Atomic(signed char)        atomic_schar;
+typedef _Atomic(unsigned char)      atomic_uchar;
+typedef _Atomic(short)              atomic_short;
+typedef _Atomic(unsigned short)     atomic_ushort;
+typedef _Atomic(int)                atomic_int;
+typedef _Atomic(unsigned int)       atomic_uint;
+typedef _Atomic(long)               atomic_long;
+typedef _Atomic(unsigned long)      atomic_ulong;
+typedef _Atomic(long long)          atomic_llong;
+typedef _Atomic(unsigned long long) atomic_ullong;
+typedef _Atomic(uint_least16_t)     atomic_char16_t;
+typedef _Atomic(uint_least32_t)     atomic_char32_t;
+typedef _Atomic(wchar_t)            atomic_wchar_t;
+typedef _Atomic(int_least8_t)       atomic_int_least8_t;
+typedef _Atomic(uint_least8_t)      atomic_uint_least8_t;
+typedef _Atomic(int_least16_t)      atomic_int_least16_t;
+typedef _Atomic(uint_least16_t)     atomic_uint_least16_t;
+typedef _Atomic(int_least32_t)      atomic_int_least32_t;
+typedef _Atomic(uint_least32_t)     atomic_uint_least32_t;
+typedef _Atomic(int_least64_t)      atomic_int_least64_t;
+typedef _Atomic(uint_least64_t)     atomic_uint_least64_t;
+typedef _Atomic(int_fast8_t)        atomic_int_fast8_t;
+typedef _Atomic(uint_fast8_t)       atomic_uint_fast8_t;
+typedef _Atomic(int_fast16_t)       atomic_int_fast16_t;
+typedef _Atomic(uint_fast16_t)      atomic_uint_fast16_t;
+typedef _Atomic(int_fast32_t)       atomic_int_fast32_t;
+typedef _Atomic(uint_fast32_t)      atomic_uint_fast32_t;
+typedef _Atomic(int_fast64_t)       atomic_int_fast64_t;
+typedef _Atomic(uint_fast64_t)      atomic_uint_fast64_t;
+typedef _Atomic(intptr_t)           atomic_intptr_t;
+typedef _Atomic(uintptr_t)          atomic_uintptr_t;
+typedef _Atomic(size_t)             atomic_size_t;
+typedef _Atomic(ptrdiff_t)          atomic_ptrdiff_t;
+typedef _Atomic(intmax_t)           atomic_intmax_t;
+typedef _Atomic(uintmax_t)          atomic_uintmax_t;
+
+#define atomic_store(object, desired) __c11_atomic_store(object, desired, __ATOMIC_SEQ_CST)
+#define atomic_store_explicit __c11_atomic_store
+
+#define atomic_load(object) __c11_atomic_load(object, __ATOMIC_SEQ_CST)
+#define atomic_load_explicit __c11_atomic_load
+
+#define atomic_exchange(object, desired) __c11_atomic_exchange(object, desired, __ATOMIC_SEQ_CST)
+#define atomic_exchange_explicit __c11_atomic_exchange
+
+#define atomic_compare_exchange_strong(object, expected, desired) __c11_atomic_compare_exchange_strong(object, expected, desired, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
+#define atomic_compare_exchange_strong_explicit __c11_atomic_compare_exchange_strong
+
+#define atomic_compare_exchange_weak(object, expected, desired) __c11_atomic_compare_exchange_weak(object, expected, desired, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
+#define atomic_compare_exchange_weak_explicit __c11_atomic_compare_exchange_weak
+
+#define atomic_fetch_add(object, operand) __c11_atomic_fetch_add(object, operand, __ATOMIC_SEQ_CST)
+#define atomic_fetch_add_explicit __c11_atomic_fetch_add
+
+#define atomic_fetch_sub(object, operand) __c11_atomic_fetch_sub(object, operand, __ATOMIC_SEQ_CST)
+#define atomic_fetch_sub_explicit __c11_atomic_fetch_sub
+
+#define atomic_fetch_or(object, operand) __c11_atomic_fetch_or(object, operand, __ATOMIC_SEQ_CST)
+#define atomic_fetch_or_explicit __c11_atomic_fetch_or
+
+#define atomic_fetch_xor(object, operand) __c11_atomic_fetch_xor(object, operand, __ATOMIC_SEQ_CST)
+#define atomic_fetch_xor_explicit __c11_atomic_fetch_xor
+
+#define atomic_fetch_and(object, operand) __c11_atomic_fetch_and(object, operand, __ATOMIC_SEQ_CST)
+#define atomic_fetch_and_explicit __c11_atomic_fetch_and
+
+typedef struct atomic_flag { atomic_bool _Value; } atomic_flag;
+
+#define ATOMIC_FLAG_INIT { 0 }
+
+_Bool atomic_flag_test_and_set(volatile atomic_flag *);
+_Bool atomic_flag_test_and_set_explicit(volatile atomic_flag *, memory_order);
+void atomic_flag_clear(volatile atomic_flag *);
+void atomic_flag_clear_explicit(volatile atomic_flag *, memory_order);
+
+#define atomic_flag_test_and_set(object) __c11_atomic_exchange(&(object)->_Value, 1, __ATOMIC_SEQ_CST)
+#define atomic_flag_test_and_set_explicit(object, order) __c11_atomic_exchange(&(object)->_Value, 1, order)
+
+#define atomic_flag_clear(object) __c11_atomic_store(&(object)->_Value, 0, __ATOMIC_SEQ_CST)
+#define atomic_flag_clear_explicit(object, order) __c11_atomic_store(&(object)->_Value, 0, order)
+
+
+#endif
lib/compiler/aro/include/stdbool.h
@@ -0,0 +1,13 @@
+/* <stdbool.h> for the Aro C compiler */
+
+#pragma once
+
+#if __STDC_VERSION__ < 202311L
+#define bool _Bool
+
+#define true 1
+#define false 0
+
+#define __bool_true_false_are_defined 1
+
+#endif
lib/compiler/aro/include/stdckdint.h
@@ -0,0 +1,9 @@
+/* <stdckdint.h> for the Aro C compiler */
+
+#pragma once
+
+#define __STDC_VERSION_STDCKDINT_H__ 202311L
+
+#define ckd_add(result, a, b) __builtin_add_overflow(a, b, result)
+#define ckd_sub(result, a, b) __builtin_sub_overflow(a, b, result)
+#define ckd_mul(result, a, b) __builtin_mul_overflow(a, b, result)
lib/compiler/aro/include/stddef.h
@@ -0,0 +1,31 @@
+/* <stddef.h> for the Aro C compiler */
+
+#pragma once
+
+#define __STDC_VERSION_STDDEF_H__ 202311L
+
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+typedef __SIZE_TYPE__ size_t;
+typedef __WCHAR_TYPE__ wchar_t;
+
+/* define max_align_t to match GCC and Clang */
+typedef struct {
+  long long __aro_max_align_ll;
+  long double __aro_max_align_ld;
+} max_align_t;
+
+#define NULL ((void*)0)
+#define offsetof(T, member) __builtin_offsetof(T, member)
+
+#if __STDC_VERSION__ >= 202311L
+#  pragma GCC diagnostic push
+#  pragma GCC diagnostic ignored "-Wpre-c23-compat"
+   typedef typeof(nullptr) nullptr_t;
+#  pragma GCC diagnostic pop
+
+#  if defined unreachable
+#    error unreachable() is a standard macro in C23
+#  else
+#    define unreachable() __builtin_unreachable()
+#  endif
+#endif
lib/compiler/aro/include/stdint.h
@@ -0,0 +1,289 @@
+/* <stdint.h> for the Aro C compiler */
+
+#pragma once
+
+
+#if __STDC_HOSTED__ && __has_include_next(<stdint.h>)
+
+# include_next <stdint.h>
+
+#else
+
+#define __stdint_int_c_cat(X, Y) X ## Y
+#define __stdint_int_c(V, SUFFIX) __stdint_int_c_cat(V, SUFFIX)
+#define __stdint_uint_c(V, SUFFIX) __stdint_int_c_cat(V##U, SUFFIX)
+
+#define INTPTR_MIN   (-__INTPTR_MAX__-1)
+#define INTPTR_MAX   __INTPTR_MAX__
+#define UINTPTR_MAX  __UINTPTR_MAX__
+#define PTRDIFF_MIN  (-__PTRDIFF_MAX__-1)
+#define PTRDIFF_MAX  __PTRDIFF_MAX__
+#define SIZE_MAX     __SIZE_MAX__
+#define INTMAX_MIN   (-__INTMAX_MAX__-1)
+#define INTMAX_MAX   __INTMAX_MAX__
+#define UINTMAX_MAX  __UINTMAX_MAX__
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
+# define INTPTR_WIDTH     __INTPTR_WIDTH__
+# define UINTPTR_WIDTH    __UINTPTR_WIDTH__
+# define INTMAX_WIDTH     __INTMAX_WIDTH__
+# define UINTMAX_WIDTH    __UINTMAX_WIDTH__
+# define PTRDIFF_WIDTH    __PTRDIFF_WIDTH__
+# define SIZE_WIDTH       __SIZE_WIDTH__
+# define WCHAR_WIDTH      __WCHAR_WIDTH__
+#endif
+
+typedef __INTMAX_TYPE__  intmax_t;
+typedef __UINTMAX_TYPE__ uintmax_t;
+
+#ifndef _INTPTR_T
+# ifndef __intptr_t_defined
+   typedef __INTPTR_TYPE__ intptr_t;
+#  define __intptr_t_defined
+#  define _INTPTR_T
+# endif
+#endif
+
+#ifndef _UINTPTR_T
+  typedef __UINTPTR_TYPE__ uintptr_t;
+# define _UINTPTR_T
+#endif
+
+
+#ifdef __INT64_TYPE__
+# ifndef __int8_t_defined /* glibc sys/types.h also defines int64_t*/
+   typedef __INT64_TYPE__ int64_t;
+# endif /* __int8_t_defined */
+  typedef __UINT64_TYPE__ uint64_t;
+
+# undef __int64_c_suffix
+# undef __int32_c_suffix
+# undef __int16_c_suffix
+# undef  __int8_c_suffix
+# ifdef __INT64_C_SUFFIX__
+#  define __int64_c_suffix __INT64_C_SUFFIX__
+#  define __int32_c_suffix __INT64_C_SUFFIX__
+#  define __int16_c_suffix __INT64_C_SUFFIX__
+#  define  __int8_c_suffix __INT64_C_SUFFIX__
+# endif /* __INT64_C_SUFFIX__ */
+
+# ifdef __int64_c_suffix
+#  define INT64_C(v) (__stdint_int_c(v, __int64_c_suffix))
+#  define UINT64_C(v) (__stdint_uint_c(v, __int64_c_suffix))
+# else
+#  define INT64_C(v) (v)
+#  define UINT64_C(v) (v ## U)
+# endif /* __int64_c_suffix */
+
+# define INT64_MAX           INT64_C( 9223372036854775807)
+# define INT64_MIN         (-INT64_C( 9223372036854775807)-1)
+# define UINT64_MAX         UINT64_C(18446744073709551615)
+# if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
+#  define UINT64_WIDTH         64
+#  define INT64_WIDTH          UINT64_WIDTH
+# endif /* __STDC_VERSION__ */
+
+#endif /* __INT64_TYPE__ */
+
+#ifdef __INT32_TYPE__
+# ifndef __int8_t_defined /* glibc sys/types.h also defines int32_t*/
+   typedef __INT32_TYPE__ int32_t;
+# endif /* __int8_t_defined */
+  typedef __UINT32_TYPE__ uint32_t;
+
+# undef __int32_c_suffix
+# undef __int16_c_suffix
+# undef  __int8_c_suffix
+# ifdef __INT32_C_SUFFIX__
+#  define __int32_c_suffix __INT32_C_SUFFIX__
+#  define __int16_c_suffix __INT32_C_SUFFIX__
+#  define  __int8_c_suffix __INT32_C_SUFFIX__
+# endif /* __INT32_C_SUFFIX__ */
+
+# ifdef __int32_c_suffix
+#  define INT32_C(v) (__stdint_int_c(v, __int32_c_suffix))
+#  define UINT32_C(v) (__stdint_uint_c(v, __int32_c_suffix))
+# else
+#  define INT32_C(v) (v)
+#  define UINT32_C(v) (v ## U)
+# endif /* __int32_c_suffix */
+
+# define INT32_MAX           INT32_C( 2147483647)
+# define INT32_MIN         (-INT32_C( 2147483647)-1)
+# define UINT32_MAX         UINT32_C(4294967295)
+# if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
+#  define UINT32_WIDTH         32
+#  define INT32_WIDTH          UINT32_WIDTH
+# endif /* __STDC_VERSION__ */
+
+#endif /* __INT32_TYPE__ */
+
+#ifdef __INT16_TYPE__
+# ifndef __int8_t_defined /* glibc sys/types.h also defines int16_t*/
+   typedef __INT16_TYPE__ int16_t;
+# endif /* __int8_t_defined */
+  typedef __UINT16_TYPE__ uint16_t;
+
+# undef __int16_c_suffix
+# undef  __int8_c_suffix
+# ifdef __INT16_C_SUFFIX__
+#  define __int16_c_suffix __INT16_C_SUFFIX__
+#  define  __int8_c_suffix __INT16_C_SUFFIX__
+# endif /* __INT16_C_SUFFIX__ */
+
+# ifdef __int16_c_suffix
+#  define INT16_C(v) (__stdint_int_c(v, __int16_c_suffix))
+#  define UINT16_C(v) (__stdint_uint_c(v, __int16_c_suffix))
+# else
+#  define INT16_C(v) (v)
+#  define UINT16_C(v) (v ## U)
+# endif /* __int16_c_suffix */
+
+# define INT16_MAX           INT16_C( 32767)
+# define INT16_MIN         (-INT16_C( 32767)-1)
+# define UINT16_MAX         UINT16_C(65535)
+# if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
+#  define UINT16_WIDTH         16
+#  define INT16_WIDTH          UINT16_WIDTH
+# endif /* __STDC_VERSION__ */
+
+#endif /* __INT16_TYPE__ */
+
+#ifdef __INT8_TYPE__
+# ifndef __int8_t_defined /* glibc sys/types.h also defines int8_t*/
+   typedef __INT8_TYPE__ int8_t;
+# endif /* __int8_t_defined */
+  typedef __UINT8_TYPE__ uint8_t;
+
+# undef  __int8_c_suffix
+# ifdef __INT8_C_SUFFIX__
+#  define  __int8_c_suffix __INT8_C_SUFFIX__
+# endif /* __INT8_C_SUFFIX__ */
+
+# ifdef __int8_c_suffix
+#  define INT8_C(v) (__stdint_int_c(v, __int8_c_suffix))
+#  define UINT8_C(v) (__stdint_uint_c(v, __int8_c_suffix))
+# else
+#  define INT8_C(v) (v)
+#  define UINT8_C(v) (v ## U)
+# endif /* __int8_c_suffix */
+
+# define INT8_MAX           INT8_C(127)
+# define INT8_MIN         (-INT8_C(127)-1)
+# define UINT8_MAX         UINT8_C(255)
+# if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
+#  define UINT8_WIDTH         8
+#  define INT8_WIDTH          UINT8_WIDTH
+# endif /* __STDC_VERSION__ */
+
+#endif /* __INT8_TYPE__ */
+
+typedef __INT_LEAST64_TYPE__ int_least64_t;
+typedef __INT_LEAST32_TYPE__ int_least32_t;
+typedef __INT_LEAST16_TYPE__ int_least16_t;
+typedef __INT_LEAST8_TYPE__ int_least8_t;
+
+typedef __UINT_LEAST64_TYPE__ uint_least64_t;
+typedef __UINT_LEAST32_TYPE__ uint_least32_t;
+typedef __UINT_LEAST16_TYPE__ uint_least16_t;
+typedef __UINT_LEAST8_TYPE__ uint_least8_t;
+
+#define INT_LEAST8_MAX __INT_LEAST8_MAX__
+#define INT_LEAST8_MIN (-__INT_LEAST8_MAX__-1)
+#define UINT_LEAST8_MAX __UINT_LEAST8_MAX__
+
+#define INT_LEAST16_MAX __INT_LEAST16_MAX__
+#define INT_LEAST16_MIN (-__INT_LEAST16_MAX__-1)
+#define UINT_LEAST16_MAX __UINT_LEAST16_MAX__
+
+#define INT_LEAST32_MAX __INT_LEAST32_MAX__
+#define INT_LEAST32_MIN (-__INT_LEAST32_MAX__-1)
+#define UINT_LEAST32_MAX __UINT_LEAST32_MAX__
+
+#define INT_LEAST64_MAX __INT_LEAST64_MAX__
+#define INT_LEAST64_MIN (-__INT_LEAST64_MAX__-1)
+#define UINT_LEAST64_MAX __UINT_LEAST64_MAX__
+
+
+typedef __INT_FAST64_TYPE__ int_fast64_t;
+typedef __INT_FAST32_TYPE__ int_fast32_t;
+typedef __INT_FAST16_TYPE__ int_fast16_t;
+typedef __INT_FAST8_TYPE__ int_fast8_t;
+
+typedef __UINT_FAST64_TYPE__ uint_fast64_t;
+typedef __UINT_FAST32_TYPE__ uint_fast32_t;
+typedef __UINT_FAST16_TYPE__ uint_fast16_t;
+typedef __UINT_FAST8_TYPE__ uint_fast8_t;
+
+#define INT_FAST8_MAX __INT_FAST8_MAX__
+#define INT_FAST8_MIN (-__INT_FAST8_MAX__-1)
+#define UINT_FAST8_MAX __UINT_FAST8_MAX__
+
+#define INT_FAST16_MAX __INT_FAST16_MAX__
+#define INT_FAST16_MIN (-__INT_FAST16_MAX__-1)
+#define UINT_FAST16_MAX __UINT_FAST16_MAX__
+
+#define INT_FAST32_MAX __INT_FAST32_MAX__
+#define INT_FAST32_MIN (-__INT_FAST32_MAX__-1)
+#define UINT_FAST32_MAX __UINT_FAST32_MAX__
+
+#define INT_FAST64_MAX __INT_FAST64_MAX__
+#define INT_FAST64_MIN (-__INT_FAST64_MAX__-1)
+#define UINT_FAST64_MAX __UINT_FAST64_MAX__
+
+
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
+
+#define INT_FAST8_WIDTH   __INT_FAST8_WIDTH__
+#define UINT_FAST8_WIDTH  __INT_FAST8_WIDTH__
+#define INT_LEAST8_WIDTH  __INT_LEAST8_WIDTH__
+#define UINT_LEAST8_WIDTH __INT_LEAST8_WIDTH__
+
+#define INT_FAST16_WIDTH   __INT_FAST16_WIDTH__
+#define UINT_FAST16_WIDTH  __INT_FAST16_WIDTH__
+#define INT_LEAST16_WIDTH  __INT_LEAST16_WIDTH__
+#define UINT_LEAST16_WIDTH __INT_LEAST16_WIDTH__
+
+#define INT_FAST32_WIDTH   __INT_FAST32_WIDTH__
+#define UINT_FAST32_WIDTH  __INT_FAST32_WIDTH__
+#define INT_LEAST32_WIDTH  __INT_LEAST32_WIDTH__
+#define UINT_LEAST32_WIDTH __INT_LEAST32_WIDTH__
+
+#define INT_FAST64_WIDTH   __INT_FAST64_WIDTH__
+#define UINT_FAST64_WIDTH  __INT_FAST64_WIDTH__
+#define INT_LEAST64_WIDTH  __INT_LEAST64_WIDTH__
+#define UINT_LEAST64_WIDTH __INT_LEAST64_WIDTH__
+
+#endif
+
+#ifdef __SIZEOF_INT128__
+typedef signed   __int128 int128_t;
+typedef unsigned __int128 uint128_t;
+typedef signed   __int128 int_fast128_t;
+typedef unsigned __int128 uint_fast128_t;
+typedef signed   __int128 int_least128_t;
+typedef unsigned __int128 uint_least128_t;
+# define UINT128_MAX         ((uint128_t)-1)
+# define INT128_MAX          ((int128_t)+(UINT128_MAX/2))
+# define INT128_MIN          (-INT128_MAX-1)
+# define UINT_LEAST128_MAX   UINT128_MAX
+# define INT_LEAST128_MAX    INT128_MAX
+# define INT_LEAST128_MIN    INT128_MIN
+# define UINT_FAST128_MAX    UINT128_MAX
+# define INT_FAST128_MAX     INT128_MAX
+# define INT_FAST128_MIN     INT128_MIN
+# define INT128_WIDTH        128
+# define UINT128_WIDTH       128
+# define INT_LEAST128_WIDTH  128
+# define UINT_LEAST128_WIDTH 128
+# define INT_FAST128_WIDTH   128
+# define UINT_FAST128_WIDTH  128
+# if UINT128_WIDTH > __LLONG_WIDTH__
+#  define INT128_C(N)         ((int_least128_t)+N ## WB)
+#  define UINT128_C(N)        ((uint_least128_t)+N ## WBU)
+# else
+#  define INT128_C(N)         ((int_least128_t)+N ## LL)
+#  define UINT128_C(N)        ((uint_least128_t)+N ## LLU)
+# endif
+#endif
+
+#endif /* __STDC_HOSTED__ && __has_include_next(<stdint.h>) */
lib/compiler/aro/include/stdnoreturn.h
@@ -0,0 +1,6 @@
+/* <stdnoreturn.h> for the Aro C compiler */
+
+#pragma once
+
+#define noreturn _Noreturn
+#define __noreturn_is_defined 1
lib/compiler/aro/include/varargs.h
@@ -0,0 +1,3 @@
+/* <varargs.h> for the Aro C compiler */
+#pragma once
+#error please use <stdarg.h> instead of <varargs.h>
lib/compiler/translate-c/main.zig
@@ -109,8 +109,6 @@ fn translate(d: *aro.Driver, tc: *aro.Toolchain, args: [][:0]u8) !void {
         var macro_buf: std.ArrayListUnmanaged(u8) = .empty;
         defer macro_buf.deinit(gpa);
 
-        try macro_buf.appendSlice(gpa, "#define __TRANSLATE_C__ 1\n");
-
         var discard_buf: [256]u8 = undefined;
         var discarding: std.io.Writer.Discarding = .init(&discard_buf);
         assert(!try d.parseArgs(&discarding.writer, &macro_buf, aro_args));
@@ -146,6 +144,12 @@ fn translate(d: *aro.Driver, tc: *aro.Toolchain, args: [][:0]u8) !void {
     var pp = try aro.Preprocessor.initDefault(d.comp);
     defer pp.deinit();
 
+    var name_buf: [std.fs.max_name_bytes]u8 = undefined;
+    var opt_dep_file = try d.initDepFile(source, &name_buf);
+    defer if (opt_dep_file) |*dep_file| dep_file.deinit(pp.gpa);
+
+    if (opt_dep_file) |*dep_file| pp.dep_file = dep_file;
+
     try pp.preprocessSources(&.{ source, builtin_macros, user_macros });
 
     var c_tree = try pp.parse();
@@ -156,6 +160,22 @@ fn translate(d: *aro.Driver, tc: *aro.Toolchain, args: [][:0]u8) !void {
         return error.FatalError;
     }
 
+    var out_buf: [4096]u8 = undefined;
+    if (opt_dep_file) |dep_file| {
+        const dep_file_name = try d.getDepFileName(source, out_buf[0..std.fs.max_name_bytes]);
+
+        const file = if (dep_file_name) |path|
+            d.comp.cwd.createFile(path, .{}) catch |er|
+                return d.fatal("unable to create dependency file '{s}': {s}", .{ path, aro.Driver.errorDescription(er) })
+        else
+            std.fs.File.stdout();
+        defer if (dep_file_name != null) file.close();
+
+        var file_writer = file.writer(&out_buf);
+        dep_file.write(&file_writer.interface) catch
+            return d.fatal("unable to write dependency file: {s}", .{aro.Driver.errorDescription(file_writer.err.?)});
+    }
+
     const rendered_zig = try Translator.translate(.{
         .gpa = gpa,
         .comp = d.comp,
@@ -182,7 +202,6 @@ fn translate(d: *aro.Driver, tc: *aro.Toolchain, args: [][:0]u8) !void {
         out_file_path = path;
     }
 
-    var out_buf: [4096]u8 = undefined;
     var out_writer = out_file.writer(&out_buf);
     out_writer.interface.writeAll(rendered_zig) catch
         return d.fatal("failed to write result to '{s}': {s}", .{ out_file_path, aro.Driver.errorDescription(out_writer.err.?) });
lib/compiler/translate-c/Translator.zig
@@ -171,7 +171,7 @@ pub const Options = struct {
     tree: *const aro.Tree,
 };
 
-pub fn translate(options: Options) ![]u8 {
+pub fn translate(options: Options) mem.Allocator.Error![]u8 {
     const gpa = options.gpa;
     var arena_allocator = std.heap.ArenaAllocator.init(gpa);
     defer arena_allocator.deinit();
@@ -219,19 +219,19 @@ pub fn translate(options: Options) ![]u8 {
     var aw: std.Io.Writer.Allocating = .init(gpa);
     defer aw.deinit();
 
-    try aw.writer.writeAll(
+    aw.writer.writeAll(
         \\pub const __builtin = @import("std").zig.c_translation.builtins;
         \\pub const __helpers = @import("std").zig.c_translation.helpers;
         \\
         \\
-    );
+    ) catch return error.OutOfMemory;
 
     var zig_ast = try ast.render(gpa, translator.global_scope.nodes.items);
     defer {
         gpa.free(zig_ast.source);
         zig_ast.deinit(gpa);
     }
-    try zig_ast.render(gpa, &aw.writer, .{});
+    zig_ast.render(gpa, &aw.writer, .{}) catch return error.OutOfMemory;
     return aw.toOwnedSlice();
 }
 
src/libs/mingw.zig
@@ -333,7 +333,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
         defer std.debug.unlockStderrWriter();
         for (aro_comp.diagnostics.output.to_list.messages.items) |msg| {
             if (msg.kind == .@"fatal error" or msg.kind == .@"error") {
-                aro.Diagnostics.writeToWriter(msg, w, std.io.tty.detectConfig(std.fs.File.stderr())) catch {};
+                msg.write(w, .detect(std.fs.File.stderr()), true) catch {};
                 return error.AroPreprocessorFailed;
             }
         }
build.zig
@@ -1144,7 +1144,6 @@ fn toNativePathSep(b: *std.Build, s: []const u8) []u8 {
 const zig_cpp_sources = [_][]const u8{
     // These are planned to stay even when we are self-hosted.
     "src/zig_llvm.cpp",
-    "src/zig_clang.cpp",
     "src/zig_llvm-ar.cpp",
     "src/zig_clang_driver.cpp",
     "src/zig_clang_cc1_main.cpp",