motiejus/zig

fork of https://codeberg.org/ziglang/zig
git clone https://git.jakstys.lt/motiejus/zig.git
Log | Tree | Refs | README | LICENSE

src/Compilation.zig (166458B) - Raw


      1 const Compilation = @This();
      2 
      3 const std = @import("std");
      4 const mem = std.mem;
      5 const Allocator = std.mem.Allocator;
      6 const assert = std.debug.assert;
      7 const log = std.log.scoped(.compilation);
      8 const Target = std.Target;
      9 
     10 const Value = @import("value.zig").Value;
     11 const Type = @import("type.zig").Type;
     12 const target_util = @import("target.zig");
     13 const Package = @import("Package.zig");
     14 const link = @import("link.zig");
     15 const trace = @import("tracy.zig").trace;
     16 const liveness = @import("liveness.zig");
     17 const build_options = @import("build_options");
     18 const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
     19 const glibc = @import("glibc.zig");
     20 const musl = @import("musl.zig");
     21 const mingw = @import("mingw.zig");
     22 const libunwind = @import("libunwind.zig");
     23 const libcxx = @import("libcxx.zig");
     24 const wasi_libc = @import("wasi_libc.zig");
     25 const fatal = @import("main.zig").fatal;
     26 const Module = @import("Module.zig");
     27 const Cache = @import("Cache.zig");
     28 const stage1 = @import("stage1.zig");
     29 const translate_c = @import("translate_c.zig");
     30 const c_codegen = @import("codegen/c.zig");
     31 const ThreadPool = @import("ThreadPool.zig");
     32 const WaitGroup = @import("WaitGroup.zig");
     33 const libtsan = @import("libtsan.zig");
     34 const Zir = @import("Zir.zig");
     35 
     36 /// General-purpose allocator. Used for both temporary and long-term storage.
     37 gpa: *Allocator,
     38 /// Arena-allocated memory used during initialization. Should be untouched until deinit.
     39 arena_state: std.heap.ArenaAllocator.State,
     40 bin_file: *link.File,
     41 c_object_table: std.AutoArrayHashMapUnmanaged(*CObject, void) = .{},
     42 c_object_cache_digest_set: std.AutoHashMapUnmanaged(Cache.BinDigest, void) = .{},
     43 stage1_lock: ?Cache.Lock = null,
     44 stage1_cache_manifest: *Cache.Manifest = undefined,
     45 
     46 link_error_flags: link.File.ErrorFlags = .{},
     47 
     48 work_queue: std.fifo.LinearFifo(Job, .Dynamic),
     49 
     50 /// These jobs are to invoke the Clang compiler to create an object file, which
     51 /// gets linked with the Compilation.
     52 c_object_work_queue: std.fifo.LinearFifo(*CObject, .Dynamic),
     53 
     54 /// These jobs are to tokenize, parse, and astgen files, which may be outdated
     55 /// since the last compilation, as well as scan for `@import` and queue up
     56 /// additional jobs corresponding to those new files.
     57 astgen_work_queue: std.fifo.LinearFifo(*Module.Scope.File, .Dynamic),
     58 
     59 /// The ErrorMsg memory is owned by the `CObject`, using Compilation's general purpose allocator.
     60 /// This data is accessed by multiple threads and is protected by `mutex`.
     61 failed_c_objects: std.AutoArrayHashMapUnmanaged(*CObject, *CObject.ErrorMsg) = .{},
     62 
     63 /// Miscellaneous things that can fail.
     64 misc_failures: std.AutoArrayHashMapUnmanaged(MiscTask, MiscError) = .{},
     65 
     66 keep_source_files_loaded: bool,
     67 use_clang: bool,
     68 sanitize_c: bool,
     69 /// When this is `true` it means invoking clang as a sub-process is expected to inherit
     70 /// stdin, stdout, stderr, and if it returns non success, to forward the exit code.
     71 /// Otherwise we attempt to parse the error messages and expose them via the Compilation API.
     72 /// This is `true` for `zig cc`, `zig c++`, and `zig translate-c`.
     73 clang_passthrough_mode: bool,
     74 clang_preprocessor_mode: ClangPreprocessorMode,
     75 /// Whether to print clang argvs to stdout.
     76 verbose_cc: bool,
     77 verbose_air: bool,
     78 verbose_llvm_ir: bool,
     79 verbose_cimport: bool,
     80 verbose_llvm_cpu_features: bool,
     81 disable_c_depfile: bool,
     82 time_report: bool,
     83 stack_report: bool,
     84 
     85 c_source_files: []const CSourceFile,
     86 clang_argv: []const []const u8,
     87 cache_parent: *Cache,
     88 /// Path to own executable for invoking `zig clang`.
     89 self_exe_path: ?[]const u8,
     90 zig_lib_directory: Directory,
     91 local_cache_directory: Directory,
     92 global_cache_directory: Directory,
     93 libc_include_dir_list: []const []const u8,
     94 thread_pool: *ThreadPool,
     95 
     96 /// Populated when we build the libc++ static library. A Job to build this is placed in the queue
     97 /// and resolved before calling linker.flush().
     98 libcxx_static_lib: ?CRTFile = null,
     99 /// Populated when we build the libc++abi static library. A Job to build this is placed in the queue
    100 /// and resolved before calling linker.flush().
    101 libcxxabi_static_lib: ?CRTFile = null,
    102 /// Populated when we build the libunwind static library. A Job to build this is placed in the queue
    103 /// and resolved before calling linker.flush().
    104 libunwind_static_lib: ?CRTFile = null,
    105 /// Populated when we build the TSAN static library. A Job to build this is placed in the queue
    106 /// and resolved before calling linker.flush().
    107 tsan_static_lib: ?CRTFile = null,
    108 /// Populated when we build the libssp static library. A Job to build this is placed in the queue
    109 /// and resolved before calling linker.flush().
    110 libssp_static_lib: ?CRTFile = null,
    111 /// Populated when we build the libc static library. A Job to build this is placed in the queue
    112 /// and resolved before calling linker.flush().
    113 libc_static_lib: ?CRTFile = null,
    114 /// Populated when we build the libcompiler_rt static library. A Job to build this is placed in the queue
    115 /// and resolved before calling linker.flush().
    116 compiler_rt_static_lib: ?CRTFile = null,
    117 /// Populated when we build the compiler_rt_obj object. A Job to build this is placed in the queue
    118 /// and resolved before calling linker.flush().
    119 compiler_rt_obj: ?CRTFile = null,
    120 
    121 glibc_so_files: ?glibc.BuiltSharedObjects = null,
    122 
    123 /// For example `Scrt1.o` and `libc_nonshared.a`. These are populated after building libc from source,
    124 /// The set of needed CRT (C runtime) files differs depending on the target and compilation settings.
    125 /// The key is the basename, and the value is the absolute path to the completed build artifact.
    126 crt_files: std.StringHashMapUnmanaged(CRTFile) = .{},
    127 
    128 /// Keeping track of this possibly open resource so we can close it later.
    129 owned_link_dir: ?std.fs.Dir,
    130 
    131 /// This is for stage1 and should be deleted upon completion of self-hosting.
    132 /// Don't use this for anything other than stage1 compatibility.
    133 color: @import("main.zig").Color = .auto,
    134 
    135 /// This mutex guards all `Compilation` mutable state.
    136 mutex: std.Thread.Mutex = .{},
    137 
    138 test_filter: ?[]const u8,
    139 test_name_prefix: ?[]const u8,
    140 test_evented_io: bool,
    141 debug_compiler_runtime_libs: bool,
    142 
    143 emit_asm: ?EmitLoc,
    144 emit_llvm_ir: ?EmitLoc,
    145 emit_analysis: ?EmitLoc,
    146 emit_docs: ?EmitLoc,
    147 
    148 work_queue_wait_group: WaitGroup,
    149 astgen_wait_group: WaitGroup,
    150 
    151 pub const InnerError = Module.InnerError;
    152 
    153 pub const CRTFile = struct {
    154     lock: Cache.Lock,
    155     full_object_path: []const u8,
    156 
    157     fn deinit(self: *CRTFile, gpa: *Allocator) void {
    158         self.lock.release();
    159         gpa.free(self.full_object_path);
    160         self.* = undefined;
    161     }
    162 };
    163 
    164 /// For passing to a C compiler.
    165 pub const CSourceFile = struct {
    166     src_path: []const u8,
    167     extra_flags: []const []const u8 = &[0][]const u8{},
    168 };
    169 
    170 const Job = union(enum) {
    171     /// Write the machine code for a Decl to the output file.
    172     codegen_decl: *Module.Decl,
    173     /// Render the .h file snippet for the Decl.
    174     emit_h_decl: *Module.Decl,
    175     /// The Decl needs to be analyzed and possibly export itself.
    176     /// It may have already be analyzed, or it may have been determined
    177     /// to be outdated; in this case perform semantic analysis again.
    178     analyze_decl: *Module.Decl,
    179     /// The source file containing the Decl has been updated, and so the
    180     /// Decl may need its line number information updated in the debug info.
    181     update_line_number: *Module.Decl,
    182     /// The main source file for the package needs to be analyzed.
    183     analyze_pkg: *Package,
    184 
    185     /// one of the glibc static objects
    186     glibc_crt_file: glibc.CRTFile,
    187     /// all of the glibc shared objects
    188     glibc_shared_objects,
    189     /// one of the musl static objects
    190     musl_crt_file: musl.CRTFile,
    191     /// one of the mingw-w64 static objects
    192     mingw_crt_file: mingw.CRTFile,
    193     /// libunwind.a, usually needed when linking libc
    194     libunwind: void,
    195     libcxx: void,
    196     libcxxabi: void,
    197     libtsan: void,
    198     libssp: void,
    199     compiler_rt_lib: void,
    200     compiler_rt_obj: void,
    201     /// needed when not linking libc and using LLVM for code generation because it generates
    202     /// calls to, for example, memcpy and memset.
    203     zig_libc: void,
    204     /// WASI libc sysroot
    205     wasi_libc_sysroot: void,
    206 
    207     /// Use stage1 C++ code to compile zig code into an object file.
    208     stage1_module: void,
    209 
    210     /// The value is the index into `link.File.Options.system_libs`.
    211     windows_import_lib: usize,
    212 };
    213 
    214 pub const CObject = struct {
    215     /// Relative to cwd. Owned by arena.
    216     src: CSourceFile,
    217     status: union(enum) {
    218         new,
    219         success: struct {
    220             /// The outputted result. Owned by gpa.
    221             object_path: []u8,
    222             /// This is a file system lock on the cache hash manifest representing this
    223             /// object. It prevents other invocations of the Zig compiler from interfering
    224             /// with this object until released.
    225             lock: Cache.Lock,
    226         },
    227         /// There will be a corresponding ErrorMsg in Compilation.failed_c_objects.
    228         failure,
    229         /// A transient failure happened when trying to compile the C Object; it may
    230         /// succeed if we try again. There may be a corresponding ErrorMsg in
    231         /// Compilation.failed_c_objects. If there is not, the failure is out of memory.
    232         failure_retryable,
    233     },
    234 
    235     pub const ErrorMsg = struct {
    236         msg: []const u8,
    237         line: u32,
    238         column: u32,
    239 
    240         pub fn destroy(em: *ErrorMsg, gpa: *Allocator) void {
    241             gpa.free(em.msg);
    242             gpa.destroy(em);
    243         }
    244     };
    245 
    246     /// Returns if there was failure.
    247     pub fn clearStatus(self: *CObject, gpa: *Allocator) bool {
    248         switch (self.status) {
    249             .new => return false,
    250             .failure, .failure_retryable => {
    251                 self.status = .new;
    252                 return true;
    253             },
    254             .success => |*success| {
    255                 gpa.free(success.object_path);
    256                 success.lock.release();
    257                 self.status = .new;
    258                 return false;
    259             },
    260         }
    261     }
    262 
    263     pub fn destroy(self: *CObject, gpa: *Allocator) void {
    264         _ = self.clearStatus(gpa);
    265         gpa.destroy(self);
    266     }
    267 };
    268 
    269 pub const MiscTask = enum {
    270     write_builtin_zig,
    271     glibc_crt_file,
    272     glibc_shared_objects,
    273     musl_crt_file,
    274     mingw_crt_file,
    275     windows_import_lib,
    276     libunwind,
    277     libcxx,
    278     libcxxabi,
    279     libtsan,
    280     wasi_libc_sysroot,
    281     compiler_rt,
    282     libssp,
    283     zig_libc,
    284     analyze_pkg,
    285 };
    286 
    287 pub const MiscError = struct {
    288     /// Allocated with gpa.
    289     msg: []u8,
    290     children: ?AllErrors = null,
    291 
    292     pub fn deinit(misc_err: *MiscError, gpa: *Allocator) void {
    293         gpa.free(misc_err.msg);
    294         if (misc_err.children) |*children| {
    295             children.deinit(gpa);
    296         }
    297         misc_err.* = undefined;
    298     }
    299 };
    300 
    301 /// To support incremental compilation, errors are stored in various places
    302 /// so that they can be created and destroyed appropriately. This structure
    303 /// is used to collect all the errors from the various places into one
    304 /// convenient place for API users to consume. It is allocated into 1 arena
    305 /// and freed all at once.
    306 pub const AllErrors = struct {
    307     arena: std.heap.ArenaAllocator.State,
    308     list: []const Message,
    309 
    310     pub const Message = union(enum) {
    311         src: struct {
    312             msg: []const u8,
    313             src_path: []const u8,
    314             line: u32,
    315             column: u32,
    316             byte_offset: u32,
    317             /// Does not include the trailing newline.
    318             source_line: ?[]const u8,
    319             notes: []Message = &.{},
    320         },
    321         plain: struct {
    322             msg: []const u8,
    323             notes: []Message = &.{},
    324         },
    325 
    326         pub fn renderToStdErr(msg: Message, ttyconf: std.debug.TTY.Config) void {
    327             const stderr_mutex = std.debug.getStderrMutex();
    328             const held = std.debug.getStderrMutex().acquire();
    329             defer held.release();
    330             const stderr = std.io.getStdErr();
    331             return msg.renderToStdErrInner(ttyconf, stderr, "error:", .Red, 0) catch return;
    332         }
    333 
    334         fn renderToStdErrInner(
    335             msg: Message,
    336             ttyconf: std.debug.TTY.Config,
    337             stderr_file: std.fs.File,
    338             kind: []const u8,
    339             color: std.debug.TTY.Color,
    340             indent: usize,
    341         ) anyerror!void {
    342             const stderr = stderr_file.writer();
    343             switch (msg) {
    344                 .src => |src| {
    345                     ttyconf.setColor(stderr, .Bold);
    346                     try stderr.print("{s}:{d}:{d}: ", .{
    347                         src.src_path,
    348                         src.line + 1,
    349                         src.column + 1,
    350                     });
    351                     ttyconf.setColor(stderr, color);
    352                     try stderr.writeByteNTimes(' ', indent);
    353                     try stderr.writeAll(kind);
    354                     ttyconf.setColor(stderr, .Reset);
    355                     ttyconf.setColor(stderr, .Bold);
    356                     try stderr.print(" {s}\n", .{src.msg});
    357                     ttyconf.setColor(stderr, .Reset);
    358                     if (ttyconf != .no_color) {
    359                         if (src.source_line) |line| {
    360                             for (line) |b| switch (b) {
    361                                 '\t' => try stderr.writeByte(' '),
    362                                 else => try stderr.writeByte(b),
    363                             };
    364                             try stderr.writeByte('\n');
    365                             try stderr.writeByteNTimes(' ', src.column);
    366                             ttyconf.setColor(stderr, .Green);
    367                             try stderr.writeAll("^\n");
    368                             ttyconf.setColor(stderr, .Reset);
    369                         }
    370                     }
    371                     for (src.notes) |note| {
    372                         try note.renderToStdErrInner(ttyconf, stderr_file, "note:", .Cyan, indent);
    373                     }
    374                 },
    375                 .plain => |plain| {
    376                     ttyconf.setColor(stderr, color);
    377                     try stderr.writeByteNTimes(' ', indent);
    378                     try stderr.writeAll(kind);
    379                     ttyconf.setColor(stderr, .Reset);
    380                     try stderr.print(" {s}\n", .{plain.msg});
    381                     ttyconf.setColor(stderr, .Reset);
    382                     for (plain.notes) |note| {
    383                         try note.renderToStdErrInner(ttyconf, stderr_file, "error:", .Red, indent + 4);
    384                     }
    385                 },
    386             }
    387         }
    388     };
    389 
    390     pub fn deinit(self: *AllErrors, gpa: *Allocator) void {
    391         self.arena.promote(gpa).deinit();
    392     }
    393 
    394     fn add(
    395         module: *Module,
    396         arena: *std.heap.ArenaAllocator,
    397         errors: *std.ArrayList(Message),
    398         module_err_msg: Module.ErrorMsg,
    399     ) !void {
    400         const notes = try arena.allocator.alloc(Message, module_err_msg.notes.len);
    401         for (notes) |*note, i| {
    402             const module_note = module_err_msg.notes[i];
    403             const source = try module_note.src_loc.file_scope.getSource(module.gpa);
    404             const byte_offset = try module_note.src_loc.byteOffset(module.gpa);
    405             const loc = std.zig.findLineColumn(source, byte_offset);
    406             const sub_file_path = module_note.src_loc.file_scope.sub_file_path;
    407             note.* = .{
    408                 .src = .{
    409                     .src_path = try arena.allocator.dupe(u8, sub_file_path),
    410                     .msg = try arena.allocator.dupe(u8, module_note.msg),
    411                     .byte_offset = byte_offset,
    412                     .line = @intCast(u32, loc.line),
    413                     .column = @intCast(u32, loc.column),
    414                     .source_line = try arena.allocator.dupe(u8, loc.source_line),
    415                 },
    416             };
    417         }
    418         if (module_err_msg.src_loc.lazy == .entire_file) {
    419             try errors.append(.{
    420                 .plain = .{
    421                     .msg = try arena.allocator.dupe(u8, module_err_msg.msg),
    422                 },
    423             });
    424             return;
    425         }
    426         const source = try module_err_msg.src_loc.file_scope.getSource(module.gpa);
    427         const byte_offset = try module_err_msg.src_loc.byteOffset(module.gpa);
    428         const loc = std.zig.findLineColumn(source, byte_offset);
    429         const sub_file_path = module_err_msg.src_loc.file_scope.sub_file_path;
    430         try errors.append(.{
    431             .src = .{
    432                 .src_path = try arena.allocator.dupe(u8, sub_file_path),
    433                 .msg = try arena.allocator.dupe(u8, module_err_msg.msg),
    434                 .byte_offset = byte_offset,
    435                 .line = @intCast(u32, loc.line),
    436                 .column = @intCast(u32, loc.column),
    437                 .notes = notes,
    438                 .source_line = try arena.allocator.dupe(u8, loc.source_line),
    439             },
    440         });
    441     }
    442 
    443     pub fn addZir(
    444         arena: *Allocator,
    445         errors: *std.ArrayList(Message),
    446         file: *Module.Scope.File,
    447     ) !void {
    448         assert(file.zir_loaded);
    449         assert(file.tree_loaded);
    450         assert(file.source_loaded);
    451         const payload_index = file.zir.extra[@enumToInt(Zir.ExtraIndex.compile_errors)];
    452         assert(payload_index != 0);
    453 
    454         const header = file.zir.extraData(Zir.Inst.CompileErrors, payload_index);
    455         const items_len = header.data.items_len;
    456         var extra_index = header.end;
    457         var item_i: usize = 0;
    458         while (item_i < items_len) : (item_i += 1) {
    459             const item = file.zir.extraData(Zir.Inst.CompileErrors.Item, extra_index);
    460             extra_index = item.end;
    461 
    462             var notes: []Message = &[0]Message{};
    463             if (item.data.notes != 0) {
    464                 const block = file.zir.extraData(Zir.Inst.Block, item.data.notes);
    465                 const body = file.zir.extra[block.end..][0..block.data.body_len];
    466                 notes = try arena.alloc(Message, body.len);
    467                 for (notes) |*note, i| {
    468                     const note_item = file.zir.extraData(Zir.Inst.CompileErrors.Item, body[i]);
    469                     const msg = file.zir.nullTerminatedString(note_item.data.msg);
    470                     const byte_offset = blk: {
    471                         const token_starts = file.tree.tokens.items(.start);
    472                         if (note_item.data.node != 0) {
    473                             const main_tokens = file.tree.nodes.items(.main_token);
    474                             const main_token = main_tokens[note_item.data.node];
    475                             break :blk token_starts[main_token];
    476                         }
    477                         break :blk token_starts[note_item.data.token] + note_item.data.byte_offset;
    478                     };
    479                     const loc = std.zig.findLineColumn(file.source, byte_offset);
    480 
    481                     note.* = .{
    482                         .src = .{
    483                             .src_path = try arena.dupe(u8, file.sub_file_path),
    484                             .msg = try arena.dupe(u8, msg),
    485                             .byte_offset = byte_offset,
    486                             .line = @intCast(u32, loc.line),
    487                             .column = @intCast(u32, loc.column),
    488                             .notes = &.{}, // TODO rework this function to be recursive
    489                             .source_line = try arena.dupe(u8, loc.source_line),
    490                         },
    491                     };
    492                 }
    493             }
    494 
    495             const msg = file.zir.nullTerminatedString(item.data.msg);
    496             const byte_offset = blk: {
    497                 const token_starts = file.tree.tokens.items(.start);
    498                 if (item.data.node != 0) {
    499                     const main_tokens = file.tree.nodes.items(.main_token);
    500                     const main_token = main_tokens[item.data.node];
    501                     break :blk token_starts[main_token];
    502                 }
    503                 break :blk token_starts[item.data.token] + item.data.byte_offset;
    504             };
    505             const loc = std.zig.findLineColumn(file.source, byte_offset);
    506 
    507             try errors.append(.{
    508                 .src = .{
    509                     .src_path = try arena.dupe(u8, file.sub_file_path),
    510                     .msg = try arena.dupe(u8, msg),
    511                     .byte_offset = byte_offset,
    512                     .line = @intCast(u32, loc.line),
    513                     .column = @intCast(u32, loc.column),
    514                     .notes = notes,
    515                     .source_line = try arena.dupe(u8, loc.source_line),
    516                 },
    517             });
    518         }
    519     }
    520 
    521     fn addPlain(
    522         arena: *std.heap.ArenaAllocator,
    523         errors: *std.ArrayList(Message),
    524         msg: []const u8,
    525     ) !void {
    526         try errors.append(.{ .plain = .{ .msg = msg } });
    527     }
    528 
    529     fn addPlainWithChildren(
    530         arena: *std.heap.ArenaAllocator,
    531         errors: *std.ArrayList(Message),
    532         msg: []const u8,
    533         optional_children: ?AllErrors,
    534     ) !void {
    535         const duped_msg = try arena.allocator.dupe(u8, msg);
    536         if (optional_children) |*children| {
    537             try errors.append(.{ .plain = .{
    538                 .msg = duped_msg,
    539                 .notes = try dupeList(children.list, &arena.allocator),
    540             } });
    541         } else {
    542             try errors.append(.{ .plain = .{ .msg = duped_msg } });
    543         }
    544     }
    545 
    546     fn dupeList(list: []const Message, arena: *Allocator) Allocator.Error![]Message {
    547         const duped_list = try arena.alloc(Message, list.len);
    548         for (list) |item, i| {
    549             duped_list[i] = switch (item) {
    550                 .src => |src| .{ .src = .{
    551                     .msg = try arena.dupe(u8, src.msg),
    552                     .src_path = try arena.dupe(u8, src.src_path),
    553                     .line = src.line,
    554                     .column = src.column,
    555                     .byte_offset = src.byte_offset,
    556                     .source_line = if (src.source_line) |s| try arena.dupe(u8, s) else null,
    557                     .notes = try dupeList(src.notes, arena),
    558                 } },
    559                 .plain => |plain| .{ .plain = .{
    560                     .msg = try arena.dupe(u8, plain.msg),
    561                     .notes = try dupeList(plain.notes, arena),
    562                 } },
    563             };
    564         }
    565         return duped_list;
    566     }
    567 };
    568 
    569 pub const Directory = struct {
    570     /// This field is redundant for operations that can act on the open directory handle
    571     /// directly, but it is needed when passing the directory to a child process.
    572     /// `null` means cwd.
    573     path: ?[]const u8,
    574     handle: std.fs.Dir,
    575 
    576     pub fn join(self: Directory, allocator: *Allocator, paths: []const []const u8) ![]u8 {
    577         if (self.path) |p| {
    578             // TODO clean way to do this with only 1 allocation
    579             const part2 = try std.fs.path.join(allocator, paths);
    580             defer allocator.free(part2);
    581             return std.fs.path.join(allocator, &[_][]const u8{ p, part2 });
    582         } else {
    583             return std.fs.path.join(allocator, paths);
    584         }
    585     }
    586 };
    587 
    588 pub const EmitLoc = struct {
    589     /// If this is `null` it means the file will be output to the cache directory.
    590     /// When provided, both the open file handle and the path name must outlive the `Compilation`.
    591     directory: ?Compilation.Directory,
    592     /// This may not have sub-directories in it.
    593     basename: []const u8,
    594 };
    595 
    596 pub const ClangPreprocessorMode = enum {
    597     no,
    598     /// This means we are doing `zig cc -E -o <path>`.
    599     yes,
    600     /// This means we are doing `zig cc -E`.
    601     stdout,
    602 };
    603 
    604 pub const InitOptions = struct {
    605     zig_lib_directory: Directory,
    606     local_cache_directory: Directory,
    607     global_cache_directory: Directory,
    608     target: Target,
    609     root_name: []const u8,
    610     root_pkg: ?*Package,
    611     output_mode: std.builtin.OutputMode,
    612     thread_pool: *ThreadPool,
    613     dynamic_linker: ?[]const u8 = null,
    614     /// `null` means to not emit a binary file.
    615     emit_bin: ?EmitLoc,
    616     /// `null` means to not emit a C header file.
    617     emit_h: ?EmitLoc = null,
    618     /// `null` means to not emit assembly.
    619     emit_asm: ?EmitLoc = null,
    620     /// `null` means to not emit LLVM IR.
    621     emit_llvm_ir: ?EmitLoc = null,
    622     /// `null` means to not emit semantic analysis JSON.
    623     emit_analysis: ?EmitLoc = null,
    624     /// `null` means to not emit docs.
    625     emit_docs: ?EmitLoc = null,
    626     link_mode: ?std.builtin.LinkMode = null,
    627     dll_export_fns: ?bool = false,
    628     /// Normally when using LLD to link, Zig uses a file named "lld.id" in the
    629     /// same directory as the output binary which contains the hash of the link
    630     /// operation, allowing Zig to skip linking when the hash would be unchanged.
    631     /// In the case that the output binary is being emitted into a directory which
    632     /// is externally modified - essentially anything other than zig-cache - then
    633     /// this flag would be set to disable this machinery to avoid false positives.
    634     disable_lld_caching: bool = false,
    635     object_format: ?std.Target.ObjectFormat = null,
    636     optimize_mode: std.builtin.Mode = .Debug,
    637     keep_source_files_loaded: bool = false,
    638     clang_argv: []const []const u8 = &[0][]const u8{},
    639     lld_argv: []const []const u8 = &[0][]const u8{},
    640     lib_dirs: []const []const u8 = &[0][]const u8{},
    641     rpath_list: []const []const u8 = &[0][]const u8{},
    642     c_source_files: []const CSourceFile = &[0]CSourceFile{},
    643     link_objects: []const []const u8 = &[0][]const u8{},
    644     framework_dirs: []const []const u8 = &[0][]const u8{},
    645     frameworks: []const []const u8 = &[0][]const u8{},
    646     system_libs: []const []const u8 = &[0][]const u8{},
    647     link_libc: bool = false,
    648     link_libcpp: bool = false,
    649     link_libunwind: bool = false,
    650     want_pic: ?bool = null,
    651     /// This means that if the output mode is an executable it will be a
    652     /// Position Independent Executable. If the output mode is not an
    653     /// executable this field is ignored.
    654     want_pie: ?bool = null,
    655     want_sanitize_c: ?bool = null,
    656     want_stack_check: ?bool = null,
    657     want_red_zone: ?bool = null,
    658     want_valgrind: ?bool = null,
    659     want_tsan: ?bool = null,
    660     want_compiler_rt: ?bool = null,
    661     want_lto: ?bool = null,
    662     use_llvm: ?bool = null,
    663     use_lld: ?bool = null,
    664     use_clang: ?bool = null,
    665     rdynamic: bool = false,
    666     strip: bool = false,
    667     single_threaded: bool = false,
    668     function_sections: bool = false,
    669     is_native_os: bool,
    670     is_native_abi: bool,
    671     time_report: bool = false,
    672     stack_report: bool = false,
    673     link_eh_frame_hdr: bool = false,
    674     link_emit_relocs: bool = false,
    675     linker_script: ?[]const u8 = null,
    676     version_script: ?[]const u8 = null,
    677     soname: ?[]const u8 = null,
    678     linker_gc_sections: ?bool = null,
    679     linker_allow_shlib_undefined: ?bool = null,
    680     linker_bind_global_refs_locally: ?bool = null,
    681     each_lib_rpath: ?bool = null,
    682     disable_c_depfile: bool = false,
    683     linker_z_nodelete: bool = false,
    684     linker_z_defs: bool = false,
    685     linker_tsaware: bool = false,
    686     linker_nxcompat: bool = false,
    687     linker_dynamicbase: bool = false,
    688     major_subsystem_version: ?u32 = null,
    689     minor_subsystem_version: ?u32 = null,
    690     clang_passthrough_mode: bool = false,
    691     verbose_cc: bool = false,
    692     verbose_link: bool = false,
    693     verbose_air: bool = false,
    694     verbose_llvm_ir: bool = false,
    695     verbose_cimport: bool = false,
    696     verbose_llvm_cpu_features: bool = false,
    697     is_test: bool = false,
    698     test_evented_io: bool = false,
    699     debug_compiler_runtime_libs: bool = false,
    700     /// Normally when you create a `Compilation`, Zig will automatically build
    701     /// and link in required dependencies, such as compiler-rt and libc. When
    702     /// building such dependencies themselves, this flag must be set to avoid
    703     /// infinite recursion.
    704     skip_linker_dependencies: bool = false,
    705     parent_compilation_link_libc: bool = false,
    706     stack_size_override: ?u64 = null,
    707     image_base_override: ?u64 = null,
    708     self_exe_path: ?[]const u8 = null,
    709     version: ?std.builtin.Version = null,
    710     libc_installation: ?*const LibCInstallation = null,
    711     machine_code_model: std.builtin.CodeModel = .default,
    712     clang_preprocessor_mode: ClangPreprocessorMode = .no,
    713     /// This is for stage1 and should be deleted upon completion of self-hosting.
    714     color: @import("main.zig").Color = .auto,
    715     test_filter: ?[]const u8 = null,
    716     test_name_prefix: ?[]const u8 = null,
    717     subsystem: ?std.Target.SubSystem = null,
    718 };
    719 
    720 fn addPackageTableToCacheHash(
    721     hash: *Cache.HashHelper,
    722     arena: *std.heap.ArenaAllocator,
    723     pkg_table: Package.Table,
    724     hash_type: union(enum) { path_bytes, files: *Cache.Manifest },
    725 ) (error{OutOfMemory} || std.os.GetCwdError)!void {
    726     const allocator = &arena.allocator;
    727 
    728     const packages = try allocator.alloc(Package.Table.KV, pkg_table.count());
    729     {
    730         // Copy over the hashmap entries to our slice
    731         var table_it = pkg_table.iterator();
    732         var idx: usize = 0;
    733         while (table_it.next()) |entry| : (idx += 1) {
    734             packages[idx] = .{
    735                 .key = entry.key_ptr.*,
    736                 .value = entry.value_ptr.*,
    737             };
    738         }
    739     }
    740     // Sort the slice by package name
    741     std.sort.sort(Package.Table.KV, packages, {}, struct {
    742         fn lessThan(_: void, lhs: Package.Table.KV, rhs: Package.Table.KV) bool {
    743             return std.mem.lessThan(u8, lhs.key, rhs.key);
    744         }
    745     }.lessThan);
    746 
    747     for (packages) |pkg| {
    748         // Finally insert the package name and path to the cache hash.
    749         hash.addBytes(pkg.key);
    750         switch (hash_type) {
    751             .path_bytes => {
    752                 hash.addBytes(pkg.value.root_src_path);
    753                 hash.addOptionalBytes(pkg.value.root_src_directory.path);
    754             },
    755             .files => |man| {
    756                 const pkg_zig_file = try pkg.value.root_src_directory.join(allocator, &[_][]const u8{
    757                     pkg.value.root_src_path,
    758                 });
    759                 _ = try man.addFile(pkg_zig_file, null);
    760             },
    761         }
    762         // Recurse to handle the package's dependencies
    763         try addPackageTableToCacheHash(hash, arena, pkg.value.table, hash_type);
    764     }
    765 }
    766 
    767 pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
    768     const is_dyn_lib = switch (options.output_mode) {
    769         .Obj, .Exe => false,
    770         .Lib => (options.link_mode orelse .Static) == .Dynamic,
    771     };
    772     const is_exe_or_dyn_lib = switch (options.output_mode) {
    773         .Obj => false,
    774         .Lib => is_dyn_lib,
    775         .Exe => true,
    776     };
    777 
    778     const needs_c_symbols = !options.skip_linker_dependencies and is_exe_or_dyn_lib;
    779 
    780     const comp: *Compilation = comp: {
    781         // For allocations that have the same lifetime as Compilation. This arena is used only during this
    782         // initialization and then is freed in deinit().
    783         var arena_allocator = std.heap.ArenaAllocator.init(gpa);
    784         errdefer arena_allocator.deinit();
    785         const arena = &arena_allocator.allocator;
    786 
    787         // We put the `Compilation` itself in the arena. Freeing the arena will free the module.
    788         // It's initialized later after we prepare the initialization options.
    789         const comp = try arena.create(Compilation);
    790         const root_name = try arena.dupe(u8, options.root_name);
    791 
    792         const ofmt = options.object_format orelse options.target.getObjectFormat();
    793 
    794         // Make a decision on whether to use LLVM or our own backend.
    795         const use_llvm = if (options.use_llvm) |explicit| explicit else blk: {
    796             // If we have no zig code to compile, no need for LLVM.
    797             if (options.root_pkg == null)
    798                 break :blk false;
    799 
    800             // If we are outputting .c code we must use Zig backend.
    801             if (ofmt == .c)
    802                 break :blk false;
    803 
    804             // If we are the stage1 compiler, we depend on the stage1 c++ llvm backend
    805             // to compile zig code.
    806             if (build_options.is_stage1)
    807                 break :blk true;
    808 
    809             // We would want to prefer LLVM for release builds when it is available, however
    810             // we don't have an LLVM backend yet :)
    811             // We would also want to prefer LLVM for architectures that we don't have self-hosted support for too.
    812             break :blk false;
    813         };
    814         if (!use_llvm and options.machine_code_model != .default) {
    815             return error.MachineCodeModelNotSupported;
    816         }
    817 
    818         // Make a decision on whether to use LLD or our own linker.
    819         const use_lld = if (options.use_lld) |explicit| explicit else blk: {
    820             if (!build_options.have_llvm)
    821                 break :blk false;
    822 
    823             if (ofmt == .c)
    824                 break :blk false;
    825 
    826             if (options.want_lto) |lto| {
    827                 if (lto) {
    828                     break :blk true;
    829                 }
    830             }
    831 
    832             // Our linker can't handle objects or most advanced options yet.
    833             if (options.link_objects.len != 0 or
    834                 options.c_source_files.len != 0 or
    835                 options.frameworks.len != 0 or
    836                 options.system_libs.len != 0 or
    837                 options.link_libc or options.link_libcpp or
    838                 options.link_eh_frame_hdr or
    839                 options.link_emit_relocs or
    840                 options.output_mode == .Lib or
    841                 options.lld_argv.len != 0 or
    842                 options.image_base_override != null or
    843                 options.linker_script != null or options.version_script != null)
    844             {
    845                 break :blk true;
    846             }
    847 
    848             if (use_llvm) {
    849                 // If stage1 generates an object file, self-hosted linker is not
    850                 // yet sophisticated enough to handle that.
    851                 break :blk options.root_pkg != null;
    852             }
    853 
    854             break :blk false;
    855         };
    856 
    857         const DarwinOptions = struct {
    858             syslibroot: ?[]const u8 = null,
    859             system_linker_hack: bool = false,
    860         };
    861 
    862         const darwin_options: DarwinOptions = if (build_options.have_llvm and comptime std.Target.current.isDarwin()) outer: {
    863             const opts: DarwinOptions = if (use_lld and std.builtin.os.tag == .macos and options.target.isDarwin()) inner: {
    864                 // TODO Revisit this targeting versions lower than macOS 11 when LLVM 12 is out.
    865                 // See https://github.com/ziglang/zig/issues/6996
    866                 const at_least_big_sur = options.target.os.getVersionRange().semver.min.major >= 11;
    867                 const syslibroot = if (at_least_big_sur) try std.zig.system.getSDKPath(arena) else null;
    868                 const system_linker_hack = std.os.getenv("ZIG_SYSTEM_LINKER_HACK") != null;
    869                 break :inner .{
    870                     .syslibroot = syslibroot,
    871                     .system_linker_hack = system_linker_hack,
    872                 };
    873             } else .{};
    874             break :outer opts;
    875         } else .{};
    876 
    877         const lto = blk: {
    878             if (options.want_lto) |explicit| {
    879                 if (!use_lld)
    880                     return error.LtoUnavailableWithoutLld;
    881                 break :blk explicit;
    882             } else if (!use_lld) {
    883                 break :blk false;
    884             } else if (options.c_source_files.len == 0) {
    885                 break :blk false;
    886             } else if (darwin_options.system_linker_hack) {
    887                 break :blk false;
    888             } else switch (options.output_mode) {
    889                 .Lib, .Obj => break :blk false,
    890                 .Exe => switch (options.optimize_mode) {
    891                     .Debug => break :blk false,
    892                     .ReleaseSafe, .ReleaseFast, .ReleaseSmall => break :blk true,
    893                 },
    894             }
    895         };
    896 
    897         const tsan = options.want_tsan orelse false;
    898         // TSAN is implemented in C++ so it requires linking libc++.
    899         const link_libcpp = options.link_libcpp or tsan;
    900         const link_libc = link_libcpp or options.link_libc or
    901             target_util.osRequiresLibC(options.target);
    902 
    903         const link_libunwind = options.link_libunwind or
    904             (link_libcpp and target_util.libcNeedsLibUnwind(options.target));
    905 
    906         const must_dynamic_link = dl: {
    907             if (target_util.cannotDynamicLink(options.target))
    908                 break :dl false;
    909             if (is_exe_or_dyn_lib and link_libc and
    910                 (options.target.isGnuLibC() or target_util.osRequiresLibC(options.target)))
    911             {
    912                 break :dl true;
    913             }
    914             const any_dyn_libs: bool = x: {
    915                 if (options.system_libs.len != 0)
    916                     break :x true;
    917                 for (options.link_objects) |obj| {
    918                     switch (classifyFileExt(obj)) {
    919                         .shared_library => break :x true,
    920                         else => continue,
    921                     }
    922                 }
    923                 break :x false;
    924             };
    925             if (any_dyn_libs) {
    926                 // When creating a executable that links to system libraries,
    927                 // we require dynamic linking, but we must not link static libraries
    928                 // or object files dynamically!
    929                 break :dl (options.output_mode == .Exe);
    930             }
    931 
    932             break :dl false;
    933         };
    934         const default_link_mode: std.builtin.LinkMode = blk: {
    935             if (must_dynamic_link) {
    936                 break :blk .Dynamic;
    937             } else if (is_exe_or_dyn_lib and link_libc and
    938                 options.is_native_abi and options.target.abi.isMusl())
    939             {
    940                 // If targeting the system's native ABI and the system's
    941                 // libc is musl, link dynamically by default.
    942                 break :blk .Dynamic;
    943             } else {
    944                 break :blk .Static;
    945             }
    946         };
    947         const link_mode: std.builtin.LinkMode = if (options.link_mode) |lm| blk: {
    948             if (lm == .Static and must_dynamic_link) {
    949                 return error.UnableToStaticLink;
    950             }
    951             break :blk lm;
    952         } else default_link_mode;
    953 
    954         const dll_export_fns = if (options.dll_export_fns) |explicit| explicit else is_dyn_lib;
    955 
    956         const libc_dirs = try detectLibCIncludeDirs(
    957             arena,
    958             options.zig_lib_directory.path.?,
    959             options.target,
    960             options.is_native_abi,
    961             link_libc,
    962             options.system_libs.len != 0,
    963             options.libc_installation,
    964         );
    965 
    966         const must_pie = target_util.requiresPIE(options.target);
    967         const pie: bool = if (options.want_pie) |explicit| pie: {
    968             if (!explicit and must_pie) {
    969                 return error.TargetRequiresPIE;
    970             }
    971             break :pie explicit;
    972         } else must_pie or tsan;
    973 
    974         const must_pic: bool = b: {
    975             if (target_util.requiresPIC(options.target, link_libc))
    976                 break :b true;
    977             break :b link_mode == .Dynamic;
    978         };
    979         const pic = if (options.want_pic) |explicit| pic: {
    980             if (!explicit) {
    981                 if (must_pic) {
    982                     return error.TargetRequiresPIC;
    983                 }
    984                 if (pie) {
    985                     return error.PIERequiresPIC;
    986                 }
    987             }
    988             break :pic explicit;
    989         } else pie or must_pic;
    990 
    991         // Make a decision on whether to use Clang for translate-c and compiling C files.
    992         const use_clang = if (options.use_clang) |explicit| explicit else blk: {
    993             if (build_options.have_llvm) {
    994                 // Can't use it if we don't have it!
    995                 break :blk false;
    996             }
    997             // It's not planned to do our own translate-c or C compilation.
    998             break :blk true;
    999         };
   1000 
   1001         const is_safe_mode = switch (options.optimize_mode) {
   1002             .Debug, .ReleaseSafe => true,
   1003             .ReleaseFast, .ReleaseSmall => false,
   1004         };
   1005 
   1006         const sanitize_c = options.want_sanitize_c orelse is_safe_mode;
   1007 
   1008         const stack_check: bool = b: {
   1009             if (!target_util.supportsStackProbing(options.target))
   1010                 break :b false;
   1011             break :b options.want_stack_check orelse is_safe_mode;
   1012         };
   1013 
   1014         const valgrind: bool = b: {
   1015             if (!target_util.hasValgrindSupport(options.target))
   1016                 break :b false;
   1017             break :b options.want_valgrind orelse (options.optimize_mode == .Debug);
   1018         };
   1019 
   1020         const include_compiler_rt = options.want_compiler_rt orelse needs_c_symbols;
   1021 
   1022         const single_threaded = options.single_threaded or target_util.isSingleThreaded(options.target);
   1023 
   1024         const llvm_cpu_features: ?[*:0]const u8 = if (build_options.have_llvm and use_llvm) blk: {
   1025             var buf = std.ArrayList(u8).init(arena);
   1026             for (options.target.cpu.arch.allFeaturesList()) |feature, index_usize| {
   1027                 const index = @intCast(Target.Cpu.Feature.Set.Index, index_usize);
   1028                 const is_enabled = options.target.cpu.features.isEnabled(index);
   1029 
   1030                 if (feature.llvm_name) |llvm_name| {
   1031                     const plus_or_minus = "-+"[@boolToInt(is_enabled)];
   1032                     try buf.ensureCapacity(buf.items.len + 2 + llvm_name.len);
   1033                     buf.appendAssumeCapacity(plus_or_minus);
   1034                     buf.appendSliceAssumeCapacity(llvm_name);
   1035                     buf.appendSliceAssumeCapacity(",");
   1036                 }
   1037             }
   1038             assert(mem.endsWith(u8, buf.items, ","));
   1039             buf.items[buf.items.len - 1] = 0;
   1040             buf.shrinkAndFree(buf.items.len);
   1041             break :blk buf.items[0 .. buf.items.len - 1 :0].ptr;
   1042         } else null;
   1043 
   1044         const strip = options.strip or !target_util.hasDebugInfo(options.target);
   1045         const red_zone = options.want_red_zone orelse target_util.hasRedZone(options.target);
   1046 
   1047         // We put everything into the cache hash that *cannot be modified during an incremental update*.
   1048         // For example, one cannot change the target between updates, but one can change source files,
   1049         // so the target goes into the cache hash, but source files do not. This is so that we can
   1050         // find the same binary and incrementally update it even if there are modified source files.
   1051         // We do this even if outputting to the current directory because we need somewhere to store
   1052         // incremental compilation metadata.
   1053         const cache = try arena.create(Cache);
   1054         cache.* = .{
   1055             .gpa = gpa,
   1056             .manifest_dir = try options.local_cache_directory.handle.makeOpenPath("h", .{}),
   1057         };
   1058         errdefer cache.manifest_dir.close();
   1059 
   1060         // This is shared hasher state common to zig source and all C source files.
   1061         cache.hash.addBytes(build_options.version);
   1062         cache.hash.addBytes(options.zig_lib_directory.path orelse ".");
   1063         cache.hash.add(options.optimize_mode);
   1064         cache.hash.add(options.target.cpu.arch);
   1065         cache.hash.addBytes(options.target.cpu.model.name);
   1066         cache.hash.add(options.target.cpu.features.ints);
   1067         cache.hash.add(options.target.os.tag);
   1068         cache.hash.add(options.target.os.getVersionRange());
   1069         cache.hash.add(options.is_native_os);
   1070         cache.hash.add(options.target.abi);
   1071         cache.hash.add(ofmt);
   1072         cache.hash.add(pic);
   1073         cache.hash.add(pie);
   1074         cache.hash.add(lto);
   1075         cache.hash.add(tsan);
   1076         cache.hash.add(stack_check);
   1077         cache.hash.add(red_zone);
   1078         cache.hash.add(link_mode);
   1079         cache.hash.add(options.function_sections);
   1080         cache.hash.add(strip);
   1081         cache.hash.add(link_libc);
   1082         cache.hash.add(link_libcpp);
   1083         cache.hash.add(link_libunwind);
   1084         cache.hash.add(options.output_mode);
   1085         cache.hash.add(options.machine_code_model);
   1086         cache.hash.addOptionalEmitLoc(options.emit_bin);
   1087         cache.hash.addBytes(options.root_name);
   1088         // TODO audit this and make sure everything is in it
   1089 
   1090         const module: ?*Module = if (options.root_pkg) |root_pkg| blk: {
   1091             // Options that are specific to zig source files, that cannot be
   1092             // modified between incremental updates.
   1093             var hash = cache.hash;
   1094 
   1095             // Here we put the root source file path name, but *not* with addFile. We want the
   1096             // hash to be the same regardless of the contents of the source file, because
   1097             // incremental compilation will handle it, but we do want to namespace different
   1098             // source file names because they are likely different compilations and therefore this
   1099             // would be likely to cause cache hits.
   1100             hash.addBytes(root_pkg.root_src_path);
   1101             hash.addOptionalBytes(root_pkg.root_src_directory.path);
   1102             {
   1103                 var local_arena = std.heap.ArenaAllocator.init(gpa);
   1104                 defer local_arena.deinit();
   1105                 try addPackageTableToCacheHash(&hash, &local_arena, root_pkg.table, .path_bytes);
   1106             }
   1107             hash.add(valgrind);
   1108             hash.add(single_threaded);
   1109             hash.add(dll_export_fns);
   1110             hash.add(options.is_test);
   1111             hash.add(options.skip_linker_dependencies);
   1112             hash.add(options.parent_compilation_link_libc);
   1113 
   1114             const digest = hash.final();
   1115             const artifact_sub_dir = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest });
   1116             var artifact_dir = try options.local_cache_directory.handle.makeOpenPath(artifact_sub_dir, .{});
   1117             errdefer artifact_dir.close();
   1118             const zig_cache_artifact_directory: Directory = .{
   1119                 .handle = artifact_dir,
   1120                 .path = if (options.local_cache_directory.path) |p|
   1121                     try std.fs.path.join(arena, &[_][]const u8{ p, artifact_sub_dir })
   1122                 else
   1123                     artifact_sub_dir,
   1124             };
   1125 
   1126             // If we rely on stage1, we must not redundantly add these packages.
   1127             const use_stage1 = build_options.is_stage1 and use_llvm;
   1128             if (!use_stage1) {
   1129                 const builtin_pkg = try Package.createWithDir(
   1130                     gpa,
   1131                     zig_cache_artifact_directory,
   1132                     null,
   1133                     "builtin.zig",
   1134                 );
   1135                 errdefer builtin_pkg.destroy(gpa);
   1136 
   1137                 const std_pkg = try Package.createWithDir(
   1138                     gpa,
   1139                     options.zig_lib_directory,
   1140                     "std",
   1141                     "std.zig",
   1142                 );
   1143                 errdefer std_pkg.destroy(gpa);
   1144 
   1145                 try root_pkg.addAndAdopt(gpa, "builtin", builtin_pkg);
   1146                 try root_pkg.add(gpa, "root", root_pkg);
   1147                 try root_pkg.addAndAdopt(gpa, "std", std_pkg);
   1148 
   1149                 try std_pkg.add(gpa, "builtin", builtin_pkg);
   1150                 try std_pkg.add(gpa, "root", root_pkg);
   1151                 try std_pkg.add(gpa, "std", std_pkg);
   1152 
   1153                 try builtin_pkg.add(gpa, "std", std_pkg);
   1154                 try builtin_pkg.add(gpa, "builtin", builtin_pkg);
   1155             }
   1156 
   1157             // Pre-open the directory handles for cached ZIR code so that it does not need
   1158             // to redundantly happen for each AstGen operation.
   1159             const zir_sub_dir = "z";
   1160 
   1161             var local_zir_dir = try options.local_cache_directory.handle.makeOpenPath(zir_sub_dir, .{});
   1162             errdefer local_zir_dir.close();
   1163             const local_zir_cache: Directory = .{
   1164                 .handle = local_zir_dir,
   1165                 .path = try options.local_cache_directory.join(arena, &[_][]const u8{zir_sub_dir}),
   1166             };
   1167             var global_zir_dir = try options.global_cache_directory.handle.makeOpenPath(zir_sub_dir, .{});
   1168             errdefer global_zir_dir.close();
   1169             const global_zir_cache: Directory = .{
   1170                 .handle = global_zir_dir,
   1171                 .path = try options.global_cache_directory.join(arena, &[_][]const u8{zir_sub_dir}),
   1172             };
   1173 
   1174             const emit_h: ?*Module.GlobalEmitH = if (options.emit_h) |loc| eh: {
   1175                 const eh = try gpa.create(Module.GlobalEmitH);
   1176                 eh.* = .{ .loc = loc };
   1177                 break :eh eh;
   1178             } else null;
   1179             errdefer if (emit_h) |eh| gpa.destroy(eh);
   1180 
   1181             // TODO when we implement serialization and deserialization of incremental
   1182             // compilation metadata, this is where we would load it. We have open a handle
   1183             // to the directory where the output either already is, or will be.
   1184             // However we currently do not have serialization of such metadata, so for now
   1185             // we set up an empty Module that does the entire compilation fresh.
   1186 
   1187             const module = try arena.create(Module);
   1188             errdefer module.deinit();
   1189             module.* = .{
   1190                 .gpa = gpa,
   1191                 .comp = comp,
   1192                 .root_pkg = root_pkg,
   1193                 .zig_cache_artifact_directory = zig_cache_artifact_directory,
   1194                 .global_zir_cache = global_zir_cache,
   1195                 .local_zir_cache = local_zir_cache,
   1196                 .emit_h = emit_h,
   1197                 .error_name_list = try std.ArrayListUnmanaged([]const u8).initCapacity(gpa, 1),
   1198             };
   1199             module.error_name_list.appendAssumeCapacity("(no error)");
   1200 
   1201             break :blk module;
   1202         } else blk: {
   1203             if (options.emit_h != null) return error.NoZigModuleForCHeader;
   1204             break :blk null;
   1205         };
   1206         errdefer if (module) |zm| zm.deinit();
   1207 
   1208         const error_return_tracing = !strip and switch (options.optimize_mode) {
   1209             .Debug, .ReleaseSafe => true,
   1210             .ReleaseFast, .ReleaseSmall => false,
   1211         };
   1212 
   1213         // For resource management purposes.
   1214         var owned_link_dir: ?std.fs.Dir = null;
   1215         errdefer if (owned_link_dir) |*dir| dir.close();
   1216 
   1217         const bin_file_emit: ?link.Emit = blk: {
   1218             const emit_bin = options.emit_bin orelse break :blk null;
   1219             if (emit_bin.directory) |directory| {
   1220                 break :blk link.Emit{
   1221                     .directory = directory,
   1222                     .sub_path = emit_bin.basename,
   1223                 };
   1224             }
   1225             if (module) |zm| {
   1226                 break :blk link.Emit{
   1227                     .directory = zm.zig_cache_artifact_directory,
   1228                     .sub_path = emit_bin.basename,
   1229                 };
   1230             }
   1231             // We could use the cache hash as is no problem, however, we increase
   1232             // the likelihood of cache hits by adding the first C source file
   1233             // path name (not contents) to the hash. This way if the user is compiling
   1234             // foo.c and bar.c as separate compilations, they get different cache
   1235             // directories.
   1236             var hash = cache.hash;
   1237             if (options.c_source_files.len >= 1) {
   1238                 hash.addBytes(options.c_source_files[0].src_path);
   1239             } else if (options.link_objects.len >= 1) {
   1240                 hash.addBytes(options.link_objects[0]);
   1241             }
   1242 
   1243             const digest = hash.final();
   1244             const artifact_sub_dir = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest });
   1245             var artifact_dir = try options.local_cache_directory.handle.makeOpenPath(artifact_sub_dir, .{});
   1246             owned_link_dir = artifact_dir;
   1247             const link_artifact_directory: Directory = .{
   1248                 .handle = artifact_dir,
   1249                 .path = try options.local_cache_directory.join(arena, &[_][]const u8{artifact_sub_dir}),
   1250             };
   1251             break :blk link.Emit{
   1252                 .directory = link_artifact_directory,
   1253                 .sub_path = emit_bin.basename,
   1254             };
   1255         };
   1256 
   1257         var system_libs: std.StringArrayHashMapUnmanaged(void) = .{};
   1258         errdefer system_libs.deinit(gpa);
   1259         try system_libs.ensureCapacity(gpa, options.system_libs.len);
   1260         for (options.system_libs) |lib_name| {
   1261             system_libs.putAssumeCapacity(lib_name, {});
   1262         }
   1263 
   1264         const bin_file = try link.File.openPath(gpa, .{
   1265             .emit = bin_file_emit,
   1266             .root_name = root_name,
   1267             .module = module,
   1268             .target = options.target,
   1269             .dynamic_linker = options.dynamic_linker,
   1270             .output_mode = options.output_mode,
   1271             .link_mode = link_mode,
   1272             .object_format = ofmt,
   1273             .optimize_mode = options.optimize_mode,
   1274             .use_lld = use_lld,
   1275             .use_llvm = use_llvm,
   1276             .system_linker_hack = darwin_options.system_linker_hack,
   1277             .link_libc = link_libc,
   1278             .link_libcpp = link_libcpp,
   1279             .link_libunwind = link_libunwind,
   1280             .objects = options.link_objects,
   1281             .frameworks = options.frameworks,
   1282             .framework_dirs = options.framework_dirs,
   1283             .system_libs = system_libs,
   1284             .syslibroot = darwin_options.syslibroot,
   1285             .lib_dirs = options.lib_dirs,
   1286             .rpath_list = options.rpath_list,
   1287             .strip = strip,
   1288             .is_native_os = options.is_native_os,
   1289             .is_native_abi = options.is_native_abi,
   1290             .function_sections = options.function_sections,
   1291             .allow_shlib_undefined = options.linker_allow_shlib_undefined,
   1292             .bind_global_refs_locally = options.linker_bind_global_refs_locally orelse false,
   1293             .z_nodelete = options.linker_z_nodelete,
   1294             .z_defs = options.linker_z_defs,
   1295             .tsaware = options.linker_tsaware,
   1296             .nxcompat = options.linker_nxcompat,
   1297             .dynamicbase = options.linker_dynamicbase,
   1298             .major_subsystem_version = options.major_subsystem_version,
   1299             .minor_subsystem_version = options.minor_subsystem_version,
   1300             .stack_size_override = options.stack_size_override,
   1301             .image_base_override = options.image_base_override,
   1302             .include_compiler_rt = include_compiler_rt,
   1303             .linker_script = options.linker_script,
   1304             .version_script = options.version_script,
   1305             .gc_sections = options.linker_gc_sections,
   1306             .eh_frame_hdr = options.link_eh_frame_hdr,
   1307             .emit_relocs = options.link_emit_relocs,
   1308             .rdynamic = options.rdynamic,
   1309             .extra_lld_args = options.lld_argv,
   1310             .soname = options.soname,
   1311             .version = options.version,
   1312             .libc_installation = libc_dirs.libc_installation,
   1313             .pic = pic,
   1314             .pie = pie,
   1315             .lto = lto,
   1316             .valgrind = valgrind,
   1317             .tsan = tsan,
   1318             .stack_check = stack_check,
   1319             .red_zone = red_zone,
   1320             .single_threaded = single_threaded,
   1321             .verbose_link = options.verbose_link,
   1322             .machine_code_model = options.machine_code_model,
   1323             .dll_export_fns = dll_export_fns,
   1324             .error_return_tracing = error_return_tracing,
   1325             .llvm_cpu_features = llvm_cpu_features,
   1326             .skip_linker_dependencies = options.skip_linker_dependencies,
   1327             .parent_compilation_link_libc = options.parent_compilation_link_libc,
   1328             .each_lib_rpath = options.each_lib_rpath orelse options.is_native_os,
   1329             .disable_lld_caching = options.disable_lld_caching,
   1330             .subsystem = options.subsystem,
   1331             .is_test = options.is_test,
   1332         });
   1333         errdefer bin_file.destroy();
   1334         comp.* = .{
   1335             .gpa = gpa,
   1336             .arena_state = arena_allocator.state,
   1337             .zig_lib_directory = options.zig_lib_directory,
   1338             .local_cache_directory = options.local_cache_directory,
   1339             .global_cache_directory = options.global_cache_directory,
   1340             .bin_file = bin_file,
   1341             .emit_asm = options.emit_asm,
   1342             .emit_llvm_ir = options.emit_llvm_ir,
   1343             .emit_analysis = options.emit_analysis,
   1344             .emit_docs = options.emit_docs,
   1345             .work_queue = std.fifo.LinearFifo(Job, .Dynamic).init(gpa),
   1346             .c_object_work_queue = std.fifo.LinearFifo(*CObject, .Dynamic).init(gpa),
   1347             .astgen_work_queue = std.fifo.LinearFifo(*Module.Scope.File, .Dynamic).init(gpa),
   1348             .keep_source_files_loaded = options.keep_source_files_loaded,
   1349             .use_clang = use_clang,
   1350             .clang_argv = options.clang_argv,
   1351             .c_source_files = options.c_source_files,
   1352             .cache_parent = cache,
   1353             .self_exe_path = options.self_exe_path,
   1354             .libc_include_dir_list = libc_dirs.libc_include_dir_list,
   1355             .sanitize_c = sanitize_c,
   1356             .thread_pool = options.thread_pool,
   1357             .clang_passthrough_mode = options.clang_passthrough_mode,
   1358             .clang_preprocessor_mode = options.clang_preprocessor_mode,
   1359             .verbose_cc = options.verbose_cc,
   1360             .verbose_air = options.verbose_air,
   1361             .verbose_llvm_ir = options.verbose_llvm_ir,
   1362             .verbose_cimport = options.verbose_cimport,
   1363             .verbose_llvm_cpu_features = options.verbose_llvm_cpu_features,
   1364             .disable_c_depfile = options.disable_c_depfile,
   1365             .owned_link_dir = owned_link_dir,
   1366             .color = options.color,
   1367             .time_report = options.time_report,
   1368             .stack_report = options.stack_report,
   1369             .test_filter = options.test_filter,
   1370             .test_name_prefix = options.test_name_prefix,
   1371             .test_evented_io = options.test_evented_io,
   1372             .debug_compiler_runtime_libs = options.debug_compiler_runtime_libs,
   1373             .work_queue_wait_group = undefined,
   1374             .astgen_wait_group = undefined,
   1375         };
   1376         break :comp comp;
   1377     };
   1378     errdefer comp.destroy();
   1379 
   1380     try comp.work_queue_wait_group.init();
   1381     errdefer comp.work_queue_wait_group.deinit();
   1382 
   1383     try comp.astgen_wait_group.init();
   1384     errdefer comp.astgen_wait_group.deinit();
   1385 
   1386     // Add a `CObject` for each `c_source_files`.
   1387     try comp.c_object_table.ensureCapacity(gpa, options.c_source_files.len);
   1388     for (options.c_source_files) |c_source_file| {
   1389         const c_object = try gpa.create(CObject);
   1390         errdefer gpa.destroy(c_object);
   1391 
   1392         c_object.* = .{
   1393             .status = .{ .new = {} },
   1394             .src = c_source_file,
   1395         };
   1396         comp.c_object_table.putAssumeCapacityNoClobber(c_object, {});
   1397     }
   1398 
   1399     if (comp.bin_file.options.emit != null and !comp.bin_file.options.skip_linker_dependencies) {
   1400         // If we need to build glibc for the target, add work items for it.
   1401         // We go through the work queue so that building can be done in parallel.
   1402         if (comp.wantBuildGLibCFromSource()) {
   1403             try comp.addBuildingGLibCJobs();
   1404         }
   1405         if (comp.wantBuildMuslFromSource()) {
   1406             try comp.work_queue.ensureUnusedCapacity(6);
   1407             if (musl.needsCrtiCrtn(comp.getTarget())) {
   1408                 comp.work_queue.writeAssumeCapacity(&[_]Job{
   1409                     .{ .musl_crt_file = .crti_o },
   1410                     .{ .musl_crt_file = .crtn_o },
   1411                 });
   1412             }
   1413             comp.work_queue.writeAssumeCapacity(&[_]Job{
   1414                 .{ .musl_crt_file = .crt1_o },
   1415                 .{ .musl_crt_file = .scrt1_o },
   1416                 .{ .musl_crt_file = .rcrt1_o },
   1417                 switch (comp.bin_file.options.link_mode) {
   1418                     .Static => .{ .musl_crt_file = .libc_a },
   1419                     .Dynamic => .{ .musl_crt_file = .libc_so },
   1420                 },
   1421             });
   1422         }
   1423         if (comp.wantBuildWasiLibcSysrootFromSource()) {
   1424             try comp.work_queue.write(&[_]Job{.{ .wasi_libc_sysroot = {} }});
   1425         }
   1426         if (comp.wantBuildMinGWFromSource()) {
   1427             const static_lib_jobs = [_]Job{
   1428                 .{ .mingw_crt_file = .mingw32_lib },
   1429                 .{ .mingw_crt_file = .msvcrt_os_lib },
   1430                 .{ .mingw_crt_file = .mingwex_lib },
   1431                 .{ .mingw_crt_file = .uuid_lib },
   1432             };
   1433             const crt_job: Job = .{ .mingw_crt_file = if (is_dyn_lib) .dllcrt2_o else .crt2_o };
   1434             try comp.work_queue.ensureUnusedCapacity(static_lib_jobs.len + 1);
   1435             comp.work_queue.writeAssumeCapacity(&static_lib_jobs);
   1436             comp.work_queue.writeItemAssumeCapacity(crt_job);
   1437 
   1438             // When linking mingw-w64 there are some import libs we always need.
   1439             for (mingw.always_link_libs) |name| {
   1440                 try comp.bin_file.options.system_libs.put(comp.gpa, name, .{});
   1441             }
   1442         }
   1443         // Generate Windows import libs.
   1444         if (comp.getTarget().os.tag == .windows) {
   1445             const count = comp.bin_file.options.system_libs.count();
   1446             try comp.work_queue.ensureUnusedCapacity(count);
   1447             var i: usize = 0;
   1448             while (i < count) : (i += 1) {
   1449                 comp.work_queue.writeItemAssumeCapacity(.{ .windows_import_lib = i });
   1450             }
   1451         }
   1452         if (comp.wantBuildLibUnwindFromSource()) {
   1453             try comp.work_queue.writeItem(.{ .libunwind = {} });
   1454         }
   1455         if (build_options.have_llvm and is_exe_or_dyn_lib and comp.bin_file.options.link_libcpp) {
   1456             try comp.work_queue.writeItem(.libcxx);
   1457             try comp.work_queue.writeItem(.libcxxabi);
   1458         }
   1459         if (build_options.have_llvm and comp.bin_file.options.tsan) {
   1460             try comp.work_queue.writeItem(.libtsan);
   1461         }
   1462 
   1463         // The `is_stage1` condition is here only because stage2 cannot yet build compiler-rt.
   1464         // Once it is capable this condition should be removed.
   1465         if (build_options.is_stage1) {
   1466             if (comp.bin_file.options.include_compiler_rt) {
   1467                 if (is_exe_or_dyn_lib) {
   1468                     try comp.work_queue.writeItem(.{ .compiler_rt_lib = {} });
   1469                 } else {
   1470                     try comp.work_queue.writeItem(.{ .compiler_rt_obj = {} });
   1471                     if (comp.bin_file.options.object_format != .elf and
   1472                         comp.bin_file.options.output_mode == .Obj)
   1473                     {
   1474                         // For ELF we can rely on using -r to link multiple objects together into one,
   1475                         // but to truly support `build-obj -fcompiler-rt` will require virtually
   1476                         // injecting `_ = @import("compiler_rt.zig")` into the root source file of
   1477                         // the compilation.
   1478                         fatal("Embedding compiler-rt into {s} objects is not yet implemented.", .{
   1479                             @tagName(comp.bin_file.options.object_format),
   1480                         });
   1481                     }
   1482                 }
   1483             }
   1484             if (needs_c_symbols) {
   1485                 // MinGW provides no libssp, use our own implementation.
   1486                 if (comp.getTarget().isMinGW()) {
   1487                     try comp.work_queue.writeItem(.{ .libssp = {} });
   1488                 }
   1489                 if (!comp.bin_file.options.link_libc) {
   1490                     try comp.work_queue.writeItem(.{ .zig_libc = {} });
   1491                 }
   1492             }
   1493         }
   1494     }
   1495 
   1496     if (build_options.is_stage1 and comp.bin_file.options.use_llvm) {
   1497         try comp.work_queue.writeItem(.{ .stage1_module = {} });
   1498     }
   1499 
   1500     return comp;
   1501 }
   1502 
   1503 fn releaseStage1Lock(comp: *Compilation) void {
   1504     if (comp.stage1_lock) |*lock| {
   1505         lock.release();
   1506         comp.stage1_lock = null;
   1507     }
   1508 }
   1509 
   1510 pub fn destroy(self: *Compilation) void {
   1511     const optional_module = self.bin_file.options.module;
   1512     self.bin_file.destroy();
   1513     if (optional_module) |module| module.deinit();
   1514 
   1515     self.releaseStage1Lock();
   1516 
   1517     const gpa = self.gpa;
   1518     self.work_queue.deinit();
   1519     self.c_object_work_queue.deinit();
   1520     self.astgen_work_queue.deinit();
   1521 
   1522     {
   1523         var it = self.crt_files.iterator();
   1524         while (it.next()) |entry| {
   1525             gpa.free(entry.key_ptr.*);
   1526             entry.value_ptr.deinit(gpa);
   1527         }
   1528         self.crt_files.deinit(gpa);
   1529     }
   1530 
   1531     if (self.libunwind_static_lib) |*crt_file| {
   1532         crt_file.deinit(gpa);
   1533     }
   1534     if (self.libcxx_static_lib) |*crt_file| {
   1535         crt_file.deinit(gpa);
   1536     }
   1537     if (self.libcxxabi_static_lib) |*crt_file| {
   1538         crt_file.deinit(gpa);
   1539     }
   1540     if (self.compiler_rt_static_lib) |*crt_file| {
   1541         crt_file.deinit(gpa);
   1542     }
   1543     if (self.libssp_static_lib) |*crt_file| {
   1544         crt_file.deinit(gpa);
   1545     }
   1546     if (self.libc_static_lib) |*crt_file| {
   1547         crt_file.deinit(gpa);
   1548     }
   1549 
   1550     if (self.glibc_so_files) |*glibc_file| {
   1551         glibc_file.deinit(gpa);
   1552     }
   1553 
   1554     for (self.c_object_table.keys()) |key| {
   1555         key.destroy(gpa);
   1556     }
   1557     self.c_object_table.deinit(gpa);
   1558     self.c_object_cache_digest_set.deinit(gpa);
   1559 
   1560     for (self.failed_c_objects.values()) |value| {
   1561         value.destroy(gpa);
   1562     }
   1563     self.failed_c_objects.deinit(gpa);
   1564 
   1565     self.clearMiscFailures();
   1566 
   1567     self.cache_parent.manifest_dir.close();
   1568     if (self.owned_link_dir) |*dir| dir.close();
   1569 
   1570     self.work_queue_wait_group.deinit();
   1571     self.astgen_wait_group.deinit();
   1572 
   1573     // This destroys `self`.
   1574     self.arena_state.promote(gpa).deinit();
   1575 }
   1576 
   1577 pub fn clearMiscFailures(comp: *Compilation) void {
   1578     for (comp.misc_failures.values()) |*value| {
   1579         value.deinit(comp.gpa);
   1580     }
   1581     comp.misc_failures.deinit(comp.gpa);
   1582     comp.misc_failures = .{};
   1583 }
   1584 
   1585 pub fn getTarget(self: Compilation) Target {
   1586     return self.bin_file.options.target;
   1587 }
   1588 
   1589 /// Detect changes to source files, perform semantic analysis, and update the output files.
   1590 pub fn update(self: *Compilation) !void {
   1591     const tracy = trace(@src());
   1592     defer tracy.end();
   1593 
   1594     self.clearMiscFailures();
   1595     self.c_object_cache_digest_set.clearRetainingCapacity();
   1596 
   1597     // For compiling C objects, we rely on the cache hash system to avoid duplicating work.
   1598     // Add a Job for each C object.
   1599     try self.c_object_work_queue.ensureUnusedCapacity(self.c_object_table.count());
   1600     for (self.c_object_table.keys()) |key| {
   1601         assert(@ptrToInt(key) != 0xaaaa_aaaa_aaaa_aaaa);
   1602         self.c_object_work_queue.writeItemAssumeCapacity(key);
   1603     }
   1604 
   1605     const use_stage1 = build_options.omit_stage2 or
   1606         (build_options.is_stage1 and self.bin_file.options.use_llvm);
   1607     if (!use_stage1) {
   1608         if (self.bin_file.options.module) |module| {
   1609             module.compile_log_text.shrinkAndFree(module.gpa, 0);
   1610             module.generation += 1;
   1611 
   1612             // Make sure std.zig is inside the import_table. We unconditionally need
   1613             // it for start.zig.
   1614             const std_pkg = module.root_pkg.table.get("std").?;
   1615             _ = try module.importPkg(module.root_pkg, std_pkg);
   1616 
   1617             // Put a work item in for every known source file to detect if
   1618             // it changed, and, if so, re-compute ZIR and then queue the job
   1619             // to update it.
   1620             try self.astgen_work_queue.ensureUnusedCapacity(module.import_table.count());
   1621             for (module.import_table.values()) |value| {
   1622                 self.astgen_work_queue.writeItemAssumeCapacity(value);
   1623             }
   1624 
   1625             try self.work_queue.writeItem(.{ .analyze_pkg = std_pkg });
   1626         }
   1627     }
   1628 
   1629     try self.performAllTheWork();
   1630 
   1631     if (!use_stage1) {
   1632         if (self.bin_file.options.module) |module| {
   1633             // Process the deletion set. We use a while loop here because the
   1634             // deletion set may grow as we call `clearDecl` within this loop,
   1635             // and more unreferenced Decls are revealed.
   1636             while (module.deletion_set.count() != 0) {
   1637                 const decl = module.deletion_set.keys()[0];
   1638                 assert(decl.deletion_flag);
   1639                 assert(decl.dependants.count() == 0);
   1640                 const is_anon = if (decl.zir_decl_index == 0) blk: {
   1641                     break :blk decl.namespace.anon_decls.swapRemove(decl);
   1642                 } else false;
   1643 
   1644                 try module.clearDecl(decl, null);
   1645 
   1646                 if (is_anon) {
   1647                     decl.destroy(module);
   1648                 }
   1649             }
   1650 
   1651             try module.processExports();
   1652         }
   1653     }
   1654 
   1655     if (self.totalErrorCount() != 0) {
   1656         // Skip flushing.
   1657         self.link_error_flags = .{};
   1658         return;
   1659     }
   1660 
   1661     // This is needed before reading the error flags.
   1662     try self.bin_file.flush(self);
   1663     self.link_error_flags = self.bin_file.errorFlags();
   1664 
   1665     if (!use_stage1) {
   1666         if (self.bin_file.options.module) |module| {
   1667             try link.File.C.flushEmitH(module);
   1668         }
   1669     }
   1670 
   1671     // If there are any errors, we anticipate the source files being loaded
   1672     // to report error messages. Otherwise we unload all source files to save memory.
   1673     // The ZIR needs to stay loaded in memory because (1) Decl objects contain references
   1674     // to it, and (2) generic instantiations, comptime calls, inline calls will need
   1675     // to reference the ZIR.
   1676     if (self.totalErrorCount() == 0 and !self.keep_source_files_loaded) {
   1677         if (self.bin_file.options.module) |module| {
   1678             for (module.import_table.values()) |file| {
   1679                 file.unloadTree(self.gpa);
   1680                 file.unloadSource(self.gpa);
   1681             }
   1682         }
   1683     }
   1684 }
   1685 
   1686 /// Having the file open for writing is problematic as far as executing the
   1687 /// binary is concerned. This will remove the write flag, or close the file,
   1688 /// or whatever is needed so that it can be executed.
   1689 /// After this, one must call` makeFileWritable` before calling `update`.
   1690 pub fn makeBinFileExecutable(self: *Compilation) !void {
   1691     return self.bin_file.makeExecutable();
   1692 }
   1693 
   1694 pub fn makeBinFileWritable(self: *Compilation) !void {
   1695     return self.bin_file.makeWritable();
   1696 }
   1697 
   1698 pub fn totalErrorCount(self: *Compilation) usize {
   1699     var total: usize = self.failed_c_objects.count() + self.misc_failures.count();
   1700 
   1701     if (self.bin_file.options.module) |module| {
   1702         total += module.failed_exports.count();
   1703 
   1704         {
   1705             var it = module.failed_files.iterator();
   1706             while (it.next()) |entry| {
   1707                 if (entry.value_ptr.*) |_| {
   1708                     total += 1;
   1709                 } else {
   1710                     const file = entry.key_ptr.*;
   1711                     assert(file.zir_loaded);
   1712                     const payload_index = file.zir.extra[@enumToInt(Zir.ExtraIndex.compile_errors)];
   1713                     assert(payload_index != 0);
   1714                     const header = file.zir.extraData(Zir.Inst.CompileErrors, payload_index);
   1715                     total += header.data.items_len;
   1716                 }
   1717             }
   1718         }
   1719 
   1720         // Skip errors for Decls within files that failed parsing.
   1721         // When a parse error is introduced, we keep all the semantic analysis for
   1722         // the previous parse success, including compile errors, but we cannot
   1723         // emit them until the file succeeds parsing.
   1724         for (module.failed_decls.keys()) |key| {
   1725             if (key.namespace.file_scope.okToReportErrors()) {
   1726                 total += 1;
   1727             }
   1728         }
   1729         if (module.emit_h) |emit_h| {
   1730             for (emit_h.failed_decls.keys()) |key| {
   1731                 if (key.namespace.file_scope.okToReportErrors()) {
   1732                     total += 1;
   1733                 }
   1734             }
   1735         }
   1736     }
   1737 
   1738     // The "no entry point found" error only counts if there are no other errors.
   1739     if (total == 0) {
   1740         total += @boolToInt(self.link_error_flags.no_entry_point_found);
   1741     }
   1742 
   1743     // Compile log errors only count if there are no other errors.
   1744     if (total == 0) {
   1745         if (self.bin_file.options.module) |module| {
   1746             total += @boolToInt(module.compile_log_decls.count() != 0);
   1747         }
   1748     }
   1749 
   1750     return total;
   1751 }
   1752 
   1753 pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
   1754     var arena = std.heap.ArenaAllocator.init(self.gpa);
   1755     errdefer arena.deinit();
   1756 
   1757     var errors = std.ArrayList(AllErrors.Message).init(self.gpa);
   1758     defer errors.deinit();
   1759 
   1760     {
   1761         var it = self.failed_c_objects.iterator();
   1762         while (it.next()) |entry| {
   1763             const c_object = entry.key_ptr.*;
   1764             const err_msg = entry.value_ptr.*;
   1765             // TODO these fields will need to be adjusted when we have proper
   1766             // C error reporting bubbling up.
   1767             try errors.append(.{
   1768                 .src = .{
   1769                     .src_path = try arena.allocator.dupe(u8, c_object.src.src_path),
   1770                     .msg = try std.fmt.allocPrint(&arena.allocator, "unable to build C object: {s}", .{
   1771                         err_msg.msg,
   1772                     }),
   1773                     .byte_offset = 0,
   1774                     .line = err_msg.line,
   1775                     .column = err_msg.column,
   1776                     .source_line = null, // TODO
   1777                 },
   1778             });
   1779         }
   1780     }
   1781     for (self.misc_failures.values()) |*value| {
   1782         try AllErrors.addPlainWithChildren(&arena, &errors, value.msg, value.children);
   1783     }
   1784     if (self.bin_file.options.module) |module| {
   1785         {
   1786             var it = module.failed_files.iterator();
   1787             while (it.next()) |entry| {
   1788                 if (entry.value_ptr.*) |msg| {
   1789                     try AllErrors.add(module, &arena, &errors, msg.*);
   1790                 } else {
   1791                     // Must be ZIR errors. In order for ZIR errors to exist, the parsing
   1792                     // must have completed successfully.
   1793                     const tree = try entry.key_ptr.*.getTree(module.gpa);
   1794                     assert(tree.errors.len == 0);
   1795                     try AllErrors.addZir(&arena.allocator, &errors, entry.key_ptr.*);
   1796                 }
   1797             }
   1798         }
   1799         {
   1800             var it = module.failed_decls.iterator();
   1801             while (it.next()) |entry| {
   1802                 // Skip errors for Decls within files that had a parse failure.
   1803                 // We'll try again once parsing succeeds.
   1804                 if (entry.key_ptr.*.namespace.file_scope.okToReportErrors()) {
   1805                     try AllErrors.add(module, &arena, &errors, entry.value_ptr.*.*);
   1806                 }
   1807             }
   1808         }
   1809         if (module.emit_h) |emit_h| {
   1810             var it = emit_h.failed_decls.iterator();
   1811             while (it.next()) |entry| {
   1812                 // Skip errors for Decls within files that had a parse failure.
   1813                 // We'll try again once parsing succeeds.
   1814                 if (entry.key_ptr.*.namespace.file_scope.okToReportErrors()) {
   1815                     try AllErrors.add(module, &arena, &errors, entry.value_ptr.*.*);
   1816                 }
   1817             }
   1818         }
   1819         for (module.failed_exports.values()) |value| {
   1820             try AllErrors.add(module, &arena, &errors, value.*);
   1821         }
   1822     }
   1823 
   1824     if (errors.items.len == 0 and self.link_error_flags.no_entry_point_found) {
   1825         try errors.append(.{
   1826             .plain = .{
   1827                 .msg = try std.fmt.allocPrint(&arena.allocator, "no entry point found", .{}),
   1828             },
   1829         });
   1830     }
   1831 
   1832     if (self.bin_file.options.module) |module| {
   1833         if (errors.items.len == 0 and module.compile_log_decls.count() != 0) {
   1834             const keys = module.compile_log_decls.keys();
   1835             const values = module.compile_log_decls.values();
   1836             // First one will be the error; subsequent ones will be notes.
   1837             const src_loc = keys[0].nodeOffsetSrcLoc(values[0]);
   1838             const err_msg = Module.ErrorMsg{
   1839                 .src_loc = src_loc,
   1840                 .msg = "found compile log statement",
   1841                 .notes = try self.gpa.alloc(Module.ErrorMsg, module.compile_log_decls.count() - 1),
   1842             };
   1843             defer self.gpa.free(err_msg.notes);
   1844 
   1845             for (keys[1..]) |key, i| {
   1846                 err_msg.notes[i] = .{
   1847                     .src_loc = key.nodeOffsetSrcLoc(values[i + 1]),
   1848                     .msg = "also here",
   1849                 };
   1850             }
   1851 
   1852             try AllErrors.add(module, &arena, &errors, err_msg);
   1853         }
   1854     }
   1855 
   1856     assert(errors.items.len == self.totalErrorCount());
   1857 
   1858     return AllErrors{
   1859         .list = try arena.allocator.dupe(AllErrors.Message, errors.items),
   1860         .arena = arena.state,
   1861     };
   1862 }
   1863 
   1864 pub fn getCompileLogOutput(self: *Compilation) []const u8 {
   1865     const module = self.bin_file.options.module orelse return &[0]u8{};
   1866     return module.compile_log_text.items;
   1867 }
   1868 
   1869 pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemory }!void {
   1870     // If the terminal is dumb, we dont want to show the user all the
   1871     // output.
   1872     var progress: std.Progress = .{ .dont_print_on_dumb = true };
   1873     var main_progress_node = try progress.start("", 0);
   1874     defer main_progress_node.end();
   1875     if (self.color == .off) progress.terminal = null;
   1876 
   1877     // If we need to write out builtin.zig, it needs to be done before starting
   1878     // the AstGen tasks.
   1879     if (self.bin_file.options.module) |mod| {
   1880         if (mod.job_queued_update_builtin_zig) {
   1881             mod.job_queued_update_builtin_zig = false;
   1882             try self.updateBuiltinZigFile(mod);
   1883         }
   1884     }
   1885 
   1886     // Here we queue up all the AstGen tasks first, followed by C object compilation.
   1887     // We wait until the AstGen tasks are all completed before proceeding to the
   1888     // (at least for now) single-threaded main work queue. However, C object compilation
   1889     // only needs to be finished by the end of this function.
   1890 
   1891     var zir_prog_node = main_progress_node.start("AstGen", self.astgen_work_queue.count);
   1892     defer zir_prog_node.end();
   1893 
   1894     var c_obj_prog_node = main_progress_node.start("Compile C Objects", self.c_source_files.len);
   1895     defer c_obj_prog_node.end();
   1896 
   1897     self.work_queue_wait_group.reset();
   1898     defer self.work_queue_wait_group.wait();
   1899 
   1900     {
   1901         self.astgen_wait_group.reset();
   1902         defer self.astgen_wait_group.wait();
   1903 
   1904         while (self.astgen_work_queue.readItem()) |file| {
   1905             self.astgen_wait_group.start();
   1906             try self.thread_pool.spawn(workerAstGenFile, .{
   1907                 self, file, &zir_prog_node, &self.astgen_wait_group,
   1908             });
   1909         }
   1910 
   1911         while (self.c_object_work_queue.readItem()) |c_object| {
   1912             assert(@ptrToInt(c_object) != 0xaaaa_aaaa_aaaa_aaaa);
   1913             self.work_queue_wait_group.start();
   1914             try self.thread_pool.spawn(workerUpdateCObject, .{
   1915                 self, c_object, &c_obj_prog_node, &self.work_queue_wait_group,
   1916             });
   1917         }
   1918     }
   1919 
   1920     // Iterate over all the files and look for outdated and deleted declarations.
   1921     if (self.bin_file.options.module) |mod| {
   1922         try mod.processOutdatedAndDeletedDecls();
   1923     }
   1924 
   1925     while (self.work_queue.readItem()) |work_item| switch (work_item) {
   1926         .codegen_decl => |decl| switch (decl.analysis) {
   1927             .unreferenced => unreachable,
   1928             .in_progress => unreachable,
   1929             .outdated => unreachable,
   1930 
   1931             .file_failure,
   1932             .sema_failure,
   1933             .codegen_failure,
   1934             .dependency_failure,
   1935             .sema_failure_retryable,
   1936             => continue,
   1937 
   1938             .complete, .codegen_failure_retryable => {
   1939                 if (build_options.omit_stage2)
   1940                     @panic("sadly stage2 is omitted from this build to save memory on the CI server");
   1941                 const module = self.bin_file.options.module.?;
   1942                 assert(decl.has_tv);
   1943                 if (decl.val.castTag(.function)) |payload| {
   1944                     const func = payload.data;
   1945                     switch (func.state) {
   1946                         .queued => module.analyzeFnBody(decl, func) catch |err| switch (err) {
   1947                             error.AnalysisFail => {
   1948                                 assert(func.state != .in_progress);
   1949                                 continue;
   1950                             },
   1951                             error.OutOfMemory => return error.OutOfMemory,
   1952                         },
   1953                         .in_progress => unreachable,
   1954                         .inline_only => unreachable, // don't queue work for this
   1955                         .sema_failure, .dependency_failure => continue,
   1956                         .success => {},
   1957                     }
   1958                     // Here we tack on additional allocations to the Decl's arena. The allocations
   1959                     // are lifetime annotations in the ZIR.
   1960                     var decl_arena = decl.value_arena.?.promote(module.gpa);
   1961                     defer decl.value_arena.?.* = decl_arena.state;
   1962                     log.debug("analyze liveness of {s}", .{decl.name});
   1963                     try liveness.analyze(module.gpa, &decl_arena.allocator, func.body);
   1964 
   1965                     if (std.builtin.mode == .Debug and self.verbose_air) {
   1966                         func.dump(module.*);
   1967                     }
   1968                 }
   1969 
   1970                 assert(decl.ty.hasCodeGenBits());
   1971 
   1972                 self.bin_file.updateDecl(module, decl) catch |err| switch (err) {
   1973                     error.OutOfMemory => return error.OutOfMemory,
   1974                     error.AnalysisFail => {
   1975                         decl.analysis = .codegen_failure;
   1976                         continue;
   1977                     },
   1978                     else => {
   1979                         try module.failed_decls.ensureCapacity(module.gpa, module.failed_decls.count() + 1);
   1980                         module.failed_decls.putAssumeCapacityNoClobber(decl, try Module.ErrorMsg.create(
   1981                             module.gpa,
   1982                             decl.srcLoc(),
   1983                             "unable to codegen: {s}",
   1984                             .{@errorName(err)},
   1985                         ));
   1986                         decl.analysis = .codegen_failure_retryable;
   1987                         continue;
   1988                     },
   1989                 };
   1990             },
   1991         },
   1992         .emit_h_decl => |decl| switch (decl.analysis) {
   1993             .unreferenced => unreachable,
   1994             .in_progress => unreachable,
   1995             .outdated => unreachable,
   1996 
   1997             .file_failure,
   1998             .sema_failure,
   1999             .dependency_failure,
   2000             .sema_failure_retryable,
   2001             => continue,
   2002 
   2003             // emit-h only requires semantic analysis of the Decl to be complete,
   2004             // it does not depend on machine code generation to succeed.
   2005             .codegen_failure, .codegen_failure_retryable, .complete => {
   2006                 if (build_options.omit_stage2)
   2007                     @panic("sadly stage2 is omitted from this build to save memory on the CI server");
   2008                 const module = self.bin_file.options.module.?;
   2009                 const emit_h = module.emit_h.?;
   2010                 _ = try emit_h.decl_table.getOrPut(module.gpa, decl);
   2011                 const decl_emit_h = decl.getEmitH(module);
   2012                 const fwd_decl = &decl_emit_h.fwd_decl;
   2013                 fwd_decl.shrinkRetainingCapacity(0);
   2014 
   2015                 var dg: c_codegen.DeclGen = .{
   2016                     .module = module,
   2017                     .error_msg = null,
   2018                     .decl = decl,
   2019                     .fwd_decl = fwd_decl.toManaged(module.gpa),
   2020                     // we don't want to emit optionals and error unions to headers since they have no ABI
   2021                     .typedefs = undefined,
   2022                 };
   2023                 defer dg.fwd_decl.deinit();
   2024 
   2025                 c_codegen.genHeader(&dg) catch |err| switch (err) {
   2026                     error.AnalysisFail => {
   2027                         try emit_h.failed_decls.put(module.gpa, decl, dg.error_msg.?);
   2028                         continue;
   2029                     },
   2030                     else => |e| return e,
   2031                 };
   2032 
   2033                 fwd_decl.* = dg.fwd_decl.moveToUnmanaged();
   2034                 fwd_decl.shrinkAndFree(module.gpa, fwd_decl.items.len);
   2035             },
   2036         },
   2037         .analyze_decl => |decl| {
   2038             if (build_options.omit_stage2)
   2039                 @panic("sadly stage2 is omitted from this build to save memory on the CI server");
   2040             const module = self.bin_file.options.module.?;
   2041             module.ensureDeclAnalyzed(decl) catch |err| switch (err) {
   2042                 error.OutOfMemory => return error.OutOfMemory,
   2043                 error.AnalysisFail => continue,
   2044             };
   2045         },
   2046         .update_line_number => |decl| {
   2047             if (build_options.omit_stage2)
   2048                 @panic("sadly stage2 is omitted from this build to save memory on the CI server");
   2049             const module = self.bin_file.options.module.?;
   2050             self.bin_file.updateDeclLineNumber(module, decl) catch |err| {
   2051                 try module.failed_decls.ensureCapacity(module.gpa, module.failed_decls.count() + 1);
   2052                 module.failed_decls.putAssumeCapacityNoClobber(decl, try Module.ErrorMsg.create(
   2053                     module.gpa,
   2054                     decl.srcLoc(),
   2055                     "unable to update line number: {s}",
   2056                     .{@errorName(err)},
   2057                 ));
   2058                 decl.analysis = .codegen_failure_retryable;
   2059             };
   2060         },
   2061         .analyze_pkg => |pkg| {
   2062             if (build_options.omit_stage2)
   2063                 @panic("sadly stage2 is omitted from this build to save memory on the CI server");
   2064             const module = self.bin_file.options.module.?;
   2065             module.semaPkg(pkg) catch |err| switch (err) {
   2066                 error.CurrentWorkingDirectoryUnlinked,
   2067                 error.Unexpected,
   2068                 => try self.setMiscFailure(
   2069                     .analyze_pkg,
   2070                     "unexpected problem analyzing package '{s}'",
   2071                     .{pkg.root_src_path},
   2072                 ),
   2073                 error.OutOfMemory => return error.OutOfMemory,
   2074                 error.AnalysisFail => continue,
   2075             };
   2076         },
   2077         .glibc_crt_file => |crt_file| {
   2078             glibc.buildCRTFile(self, crt_file) catch |err| {
   2079                 // TODO Surface more error details.
   2080                 try self.setMiscFailure(.glibc_crt_file, "unable to build glibc CRT file: {s}", .{
   2081                     @errorName(err),
   2082                 });
   2083             };
   2084         },
   2085         .glibc_shared_objects => {
   2086             glibc.buildSharedObjects(self) catch |err| {
   2087                 // TODO Surface more error details.
   2088                 try self.setMiscFailure(
   2089                     .glibc_shared_objects,
   2090                     "unable to build glibc shared objects: {s}",
   2091                     .{@errorName(err)},
   2092                 );
   2093             };
   2094         },
   2095         .musl_crt_file => |crt_file| {
   2096             musl.buildCRTFile(self, crt_file) catch |err| {
   2097                 // TODO Surface more error details.
   2098                 try self.setMiscFailure(
   2099                     .musl_crt_file,
   2100                     "unable to build musl CRT file: {s}",
   2101                     .{@errorName(err)},
   2102                 );
   2103             };
   2104         },
   2105         .mingw_crt_file => |crt_file| {
   2106             mingw.buildCRTFile(self, crt_file) catch |err| {
   2107                 // TODO Surface more error details.
   2108                 try self.setMiscFailure(
   2109                     .mingw_crt_file,
   2110                     "unable to build mingw-w64 CRT file: {s}",
   2111                     .{@errorName(err)},
   2112                 );
   2113             };
   2114         },
   2115         .windows_import_lib => |index| {
   2116             const link_lib = self.bin_file.options.system_libs.keys()[index];
   2117             mingw.buildImportLib(self, link_lib) catch |err| {
   2118                 // TODO Surface more error details.
   2119                 try self.setMiscFailure(
   2120                     .windows_import_lib,
   2121                     "unable to generate DLL import .lib file: {s}",
   2122                     .{@errorName(err)},
   2123                 );
   2124             };
   2125         },
   2126         .libunwind => {
   2127             libunwind.buildStaticLib(self) catch |err| {
   2128                 // TODO Surface more error details.
   2129                 try self.setMiscFailure(
   2130                     .libunwind,
   2131                     "unable to build libunwind: {s}",
   2132                     .{@errorName(err)},
   2133                 );
   2134             };
   2135         },
   2136         .libcxx => {
   2137             libcxx.buildLibCXX(self) catch |err| {
   2138                 // TODO Surface more error details.
   2139                 try self.setMiscFailure(
   2140                     .libcxx,
   2141                     "unable to build libcxx: {s}",
   2142                     .{@errorName(err)},
   2143                 );
   2144             };
   2145         },
   2146         .libcxxabi => {
   2147             libcxx.buildLibCXXABI(self) catch |err| {
   2148                 // TODO Surface more error details.
   2149                 try self.setMiscFailure(
   2150                     .libcxxabi,
   2151                     "unable to build libcxxabi: {s}",
   2152                     .{@errorName(err)},
   2153                 );
   2154             };
   2155         },
   2156         .libtsan => {
   2157             libtsan.buildTsan(self) catch |err| {
   2158                 // TODO Surface more error details.
   2159                 try self.setMiscFailure(
   2160                     .libtsan,
   2161                     "unable to build TSAN library: {s}",
   2162                     .{@errorName(err)},
   2163                 );
   2164             };
   2165         },
   2166         .wasi_libc_sysroot => {
   2167             wasi_libc.buildWasiLibcSysroot(self) catch |err| {
   2168                 // TODO Surface more error details.
   2169                 try self.setMiscFailure(
   2170                     .wasi_libc_sysroot,
   2171                     "unable to build WASI libc sysroot: {s}",
   2172                     .{@errorName(err)},
   2173                 );
   2174             };
   2175         },
   2176         .compiler_rt_lib => {
   2177             self.buildOutputFromZig(
   2178                 "compiler_rt.zig",
   2179                 .Lib,
   2180                 &self.compiler_rt_static_lib,
   2181                 .compiler_rt,
   2182             ) catch |err| switch (err) {
   2183                 error.OutOfMemory => return error.OutOfMemory,
   2184                 error.SubCompilationFailed => continue, // error reported already
   2185                 else => try self.setMiscFailure(
   2186                     .compiler_rt,
   2187                     "unable to build compiler_rt: {s}",
   2188                     .{@errorName(err)},
   2189                 ),
   2190             };
   2191         },
   2192         .compiler_rt_obj => {
   2193             self.buildOutputFromZig(
   2194                 "compiler_rt.zig",
   2195                 .Obj,
   2196                 &self.compiler_rt_obj,
   2197                 .compiler_rt,
   2198             ) catch |err| switch (err) {
   2199                 error.OutOfMemory => return error.OutOfMemory,
   2200                 error.SubCompilationFailed => continue, // error reported already
   2201                 else => try self.setMiscFailure(
   2202                     .compiler_rt,
   2203                     "unable to build compiler_rt: {s}",
   2204                     .{@errorName(err)},
   2205                 ),
   2206             };
   2207         },
   2208         .libssp => {
   2209             self.buildOutputFromZig(
   2210                 "ssp.zig",
   2211                 .Lib,
   2212                 &self.libssp_static_lib,
   2213                 .libssp,
   2214             ) catch |err| switch (err) {
   2215                 error.OutOfMemory => return error.OutOfMemory,
   2216                 error.SubCompilationFailed => continue, // error reported already
   2217                 else => try self.setMiscFailure(
   2218                     .libssp,
   2219                     "unable to build libssp: {s}",
   2220                     .{@errorName(err)},
   2221                 ),
   2222             };
   2223         },
   2224         .zig_libc => {
   2225             self.buildOutputFromZig(
   2226                 "c.zig",
   2227                 .Lib,
   2228                 &self.libc_static_lib,
   2229                 .zig_libc,
   2230             ) catch |err| switch (err) {
   2231                 error.OutOfMemory => return error.OutOfMemory,
   2232                 error.SubCompilationFailed => continue, // error reported already
   2233                 else => try self.setMiscFailure(
   2234                     .zig_libc,
   2235                     "unable to build zig's multitarget libc: {s}",
   2236                     .{@errorName(err)},
   2237                 ),
   2238             };
   2239         },
   2240         .stage1_module => {
   2241             if (!build_options.is_stage1)
   2242                 unreachable;
   2243 
   2244             self.updateStage1Module(main_progress_node) catch |err| {
   2245                 fatal("unable to build stage1 zig object: {s}", .{@errorName(err)});
   2246             };
   2247         },
   2248     };
   2249 }
   2250 
   2251 fn workerAstGenFile(
   2252     comp: *Compilation,
   2253     file: *Module.Scope.File,
   2254     prog_node: *std.Progress.Node,
   2255     wg: *WaitGroup,
   2256 ) void {
   2257     defer wg.finish();
   2258 
   2259     const mod = comp.bin_file.options.module.?;
   2260     mod.astGenFile(file, prog_node) catch |err| switch (err) {
   2261         error.AnalysisFail => return,
   2262         else => {
   2263             file.status = .retryable_failure;
   2264             comp.reportRetryableAstGenError(file, err) catch |oom| switch (oom) {
   2265                 // Swallowing this error is OK because it's implied to be OOM when
   2266                 // there is a missing `failed_files` error message.
   2267                 error.OutOfMemory => {},
   2268             };
   2269             return;
   2270         },
   2271     };
   2272 
   2273     // Pre-emptively look for `@import` paths and queue them up.
   2274     // If we experience an error preemptively fetching the
   2275     // file, just ignore it and let it happen again later during Sema.
   2276     assert(file.zir_loaded);
   2277     const imports_index = file.zir.extra[@enumToInt(Zir.ExtraIndex.imports)];
   2278     if (imports_index != 0) {
   2279         const imports_len = file.zir.extra[imports_index];
   2280 
   2281         for (file.zir.extra[imports_index + 1 ..][0..imports_len]) |str_index| {
   2282             const import_path = file.zir.nullTerminatedString(str_index);
   2283 
   2284             const import_result = blk: {
   2285                 const lock = comp.mutex.acquire();
   2286                 defer lock.release();
   2287 
   2288                 break :blk mod.importFile(file, import_path) catch continue;
   2289             };
   2290             if (import_result.is_new) {
   2291                 wg.start();
   2292                 comp.thread_pool.spawn(workerAstGenFile, .{
   2293                     comp, import_result.file, prog_node, wg,
   2294                 }) catch {
   2295                     wg.finish();
   2296                     continue;
   2297                 };
   2298             }
   2299         }
   2300     }
   2301 }
   2302 
   2303 pub fn obtainCObjectCacheManifest(comp: *const Compilation) Cache.Manifest {
   2304     var man = comp.cache_parent.obtain();
   2305 
   2306     // Only things that need to be added on top of the base hash, and only things
   2307     // that apply both to @cImport and compiling C objects. No linking stuff here!
   2308     // Also nothing that applies only to compiling .zig code.
   2309     man.hash.add(comp.sanitize_c);
   2310     man.hash.addListOfBytes(comp.clang_argv);
   2311     man.hash.add(comp.bin_file.options.link_libcpp);
   2312     man.hash.addListOfBytes(comp.libc_include_dir_list);
   2313 
   2314     return man;
   2315 }
   2316 
   2317 test "cImport" {
   2318     _ = cImport;
   2319 }
   2320 
   2321 const CImportResult = struct {
   2322     out_zig_path: []u8,
   2323     errors: []translate_c.ClangErrMsg,
   2324 };
   2325 
   2326 /// Caller owns returned memory.
   2327 /// This API is currently coupled pretty tightly to stage1's needs; it will need to be reworked
   2328 /// a bit when we want to start using it from self-hosted.
   2329 pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult {
   2330     if (!build_options.have_llvm)
   2331         return error.ZigCompilerNotBuiltWithLLVMExtensions;
   2332 
   2333     const tracy = trace(@src());
   2334     defer tracy.end();
   2335 
   2336     const cimport_zig_basename = "cimport.zig";
   2337 
   2338     var man = comp.obtainCObjectCacheManifest();
   2339     defer man.deinit();
   2340 
   2341     man.hash.add(@as(u16, 0xb945)); // Random number to distinguish translate-c from compiling C objects
   2342     man.hash.addBytes(c_src);
   2343 
   2344     // If the previous invocation resulted in clang errors, we will see a hit
   2345     // here with 0 files in the manifest, in which case it is actually a miss.
   2346     // We need to "unhit" in this case, to keep the digests matching.
   2347     const prev_hash_state = man.hash.peekBin();
   2348     const actual_hit = hit: {
   2349         const is_hit = try man.hit();
   2350         if (man.files.items.len == 0) {
   2351             man.unhit(prev_hash_state, 0);
   2352             break :hit false;
   2353         }
   2354         break :hit true;
   2355     };
   2356     const digest = if (!actual_hit) digest: {
   2357         var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa);
   2358         defer arena_allocator.deinit();
   2359         const arena = &arena_allocator.allocator;
   2360 
   2361         const tmp_digest = man.hash.peek();
   2362         const tmp_dir_sub_path = try std.fs.path.join(arena, &[_][]const u8{ "o", &tmp_digest });
   2363         var zig_cache_tmp_dir = try comp.local_cache_directory.handle.makeOpenPath(tmp_dir_sub_path, .{});
   2364         defer zig_cache_tmp_dir.close();
   2365         const cimport_basename = "cimport.h";
   2366         const out_h_path = try comp.local_cache_directory.join(arena, &[_][]const u8{
   2367             tmp_dir_sub_path, cimport_basename,
   2368         });
   2369         const out_dep_path = try std.fmt.allocPrint(arena, "{s}.d", .{out_h_path});
   2370 
   2371         try zig_cache_tmp_dir.writeFile(cimport_basename, c_src);
   2372         if (comp.verbose_cimport) {
   2373             log.info("C import source: {s}", .{out_h_path});
   2374         }
   2375 
   2376         var argv = std.ArrayList([]const u8).init(comp.gpa);
   2377         defer argv.deinit();
   2378 
   2379         try comp.addTranslateCCArgs(arena, &argv, .c, out_dep_path);
   2380 
   2381         try argv.append(out_h_path);
   2382 
   2383         if (comp.verbose_cc) {
   2384             dump_argv(argv.items);
   2385         }
   2386 
   2387         // Convert to null terminated args.
   2388         const new_argv_with_sentinel = try arena.alloc(?[*:0]const u8, argv.items.len + 1);
   2389         new_argv_with_sentinel[argv.items.len] = null;
   2390         const new_argv = new_argv_with_sentinel[0..argv.items.len :null];
   2391         for (argv.items) |arg, i| {
   2392             new_argv[i] = try arena.dupeZ(u8, arg);
   2393         }
   2394 
   2395         const c_headers_dir_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{"include"});
   2396         const c_headers_dir_path_z = try arena.dupeZ(u8, c_headers_dir_path);
   2397         var clang_errors: []translate_c.ClangErrMsg = &[0]translate_c.ClangErrMsg{};
   2398         var tree = translate_c.translate(
   2399             comp.gpa,
   2400             new_argv.ptr,
   2401             new_argv.ptr + new_argv.len,
   2402             &clang_errors,
   2403             c_headers_dir_path_z,
   2404         ) catch |err| switch (err) {
   2405             error.OutOfMemory => return error.OutOfMemory,
   2406             error.ASTUnitFailure => {
   2407                 log.warn("clang API returned errors but due to a clang bug, it is not exposing the errors for zig to see. For more details: https://github.com/ziglang/zig/issues/4455", .{});
   2408                 return error.ASTUnitFailure;
   2409             },
   2410             error.SemanticAnalyzeFail => {
   2411                 return CImportResult{
   2412                     .out_zig_path = "",
   2413                     .errors = clang_errors,
   2414                 };
   2415             },
   2416         };
   2417         defer tree.deinit(comp.gpa);
   2418 
   2419         if (comp.verbose_cimport) {
   2420             log.info("C import .d file: {s}", .{out_dep_path});
   2421         }
   2422 
   2423         const dep_basename = std.fs.path.basename(out_dep_path);
   2424         try man.addDepFilePost(zig_cache_tmp_dir, dep_basename);
   2425         try comp.stage1_cache_manifest.addDepFilePost(zig_cache_tmp_dir, dep_basename);
   2426 
   2427         const digest = man.final();
   2428         const o_sub_path = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest });
   2429         var o_dir = try comp.local_cache_directory.handle.makeOpenPath(o_sub_path, .{});
   2430         defer o_dir.close();
   2431 
   2432         var out_zig_file = try o_dir.createFile(cimport_zig_basename, .{});
   2433         defer out_zig_file.close();
   2434 
   2435         const formatted = try tree.render(comp.gpa);
   2436         defer comp.gpa.free(formatted);
   2437 
   2438         try out_zig_file.writeAll(formatted);
   2439 
   2440         man.writeManifest() catch |err| {
   2441             log.warn("failed to write cache manifest for C import: {s}", .{@errorName(err)});
   2442         };
   2443 
   2444         break :digest digest;
   2445     } else man.final();
   2446 
   2447     const out_zig_path = try comp.local_cache_directory.join(comp.gpa, &[_][]const u8{
   2448         "o", &digest, cimport_zig_basename,
   2449     });
   2450     if (comp.verbose_cimport) {
   2451         log.info("C import output: {s}", .{out_zig_path});
   2452     }
   2453     return CImportResult{
   2454         .out_zig_path = out_zig_path,
   2455         .errors = &[0]translate_c.ClangErrMsg{},
   2456     };
   2457 }
   2458 
   2459 fn workerUpdateCObject(
   2460     comp: *Compilation,
   2461     c_object: *CObject,
   2462     progress_node: *std.Progress.Node,
   2463     wg: *WaitGroup,
   2464 ) void {
   2465     defer wg.finish();
   2466 
   2467     comp.updateCObject(c_object, progress_node) catch |err| switch (err) {
   2468         error.AnalysisFail => return,
   2469         else => {
   2470             comp.reportRetryableCObjectError(c_object, err) catch |oom| switch (oom) {
   2471                 // Swallowing this error is OK because it's implied to be OOM when
   2472                 // there is a missing failed_c_objects error message.
   2473                 error.OutOfMemory => {},
   2474             };
   2475         },
   2476     };
   2477 }
   2478 
   2479 fn reportRetryableCObjectError(
   2480     comp: *Compilation,
   2481     c_object: *CObject,
   2482     err: anyerror,
   2483 ) error{OutOfMemory}!void {
   2484     c_object.status = .failure_retryable;
   2485 
   2486     const c_obj_err_msg = try comp.gpa.create(CObject.ErrorMsg);
   2487     errdefer comp.gpa.destroy(c_obj_err_msg);
   2488     const msg = try std.fmt.allocPrint(comp.gpa, "unable to build C object: {s}", .{@errorName(err)});
   2489     errdefer comp.gpa.free(msg);
   2490     c_obj_err_msg.* = .{
   2491         .msg = msg,
   2492         .line = 0,
   2493         .column = 0,
   2494     };
   2495     {
   2496         const lock = comp.mutex.acquire();
   2497         defer lock.release();
   2498         try comp.failed_c_objects.putNoClobber(comp.gpa, c_object, c_obj_err_msg);
   2499     }
   2500 }
   2501 
   2502 fn reportRetryableAstGenError(
   2503     comp: *Compilation,
   2504     file: *Module.Scope.File,
   2505     err: anyerror,
   2506 ) error{OutOfMemory}!void {
   2507     const mod = comp.bin_file.options.module.?;
   2508     const gpa = mod.gpa;
   2509 
   2510     file.status = .retryable_failure;
   2511 
   2512     const err_msg = try Module.ErrorMsg.create(gpa, .{
   2513         .file_scope = file,
   2514         .parent_decl_node = 0,
   2515         .lazy = .entire_file,
   2516     }, "unable to load {s}: {s}", .{
   2517         file.sub_file_path, @errorName(err),
   2518     });
   2519     errdefer err_msg.destroy(gpa);
   2520 
   2521     {
   2522         const lock = comp.mutex.acquire();
   2523         defer lock.release();
   2524         try mod.failed_files.putNoClobber(gpa, file, err_msg);
   2525     }
   2526 }
   2527 
   2528 fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.Progress.Node) !void {
   2529     if (!build_options.have_llvm) {
   2530         return comp.failCObj(c_object, "clang not available: compiler built without LLVM extensions", .{});
   2531     }
   2532     const self_exe_path = comp.self_exe_path orelse
   2533         return comp.failCObj(c_object, "clang compilation disabled", .{});
   2534 
   2535     const tracy = trace(@src());
   2536     defer tracy.end();
   2537 
   2538     if (c_object.clearStatus(comp.gpa)) {
   2539         // There was previous failure.
   2540         const lock = comp.mutex.acquire();
   2541         defer lock.release();
   2542         // If the failure was OOM, there will not be an entry here, so we do
   2543         // not assert discard.
   2544         _ = comp.failed_c_objects.swapRemove(c_object);
   2545     }
   2546 
   2547     var man = comp.obtainCObjectCacheManifest();
   2548     defer man.deinit();
   2549 
   2550     man.hash.add(comp.clang_preprocessor_mode);
   2551 
   2552     try man.hashCSource(c_object.src);
   2553 
   2554     {
   2555         const is_collision = blk: {
   2556             const bin_digest = man.hash.peekBin();
   2557 
   2558             const lock = comp.mutex.acquire();
   2559             defer lock.release();
   2560 
   2561             const gop = try comp.c_object_cache_digest_set.getOrPut(comp.gpa, bin_digest);
   2562             break :blk gop.found_existing;
   2563         };
   2564         if (is_collision) {
   2565             return comp.failCObj(
   2566                 c_object,
   2567                 "the same source file was already added to the same compilation with the same flags",
   2568                 .{},
   2569             );
   2570         }
   2571     }
   2572 
   2573     var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa);
   2574     defer arena_allocator.deinit();
   2575     const arena = &arena_allocator.allocator;
   2576 
   2577     const c_source_basename = std.fs.path.basename(c_object.src.src_path);
   2578 
   2579     c_obj_prog_node.activate();
   2580     var child_progress_node = c_obj_prog_node.start(c_source_basename, 0);
   2581     child_progress_node.activate();
   2582     defer child_progress_node.end();
   2583 
   2584     // Special case when doing build-obj for just one C file. When there are more than one object
   2585     // file and building an object we need to link them together, but with just one it should go
   2586     // directly to the output file.
   2587     const direct_o = comp.c_source_files.len == 1 and comp.bin_file.options.module == null and
   2588         comp.bin_file.options.output_mode == .Obj and comp.bin_file.options.objects.len == 0;
   2589     const o_basename_noext = if (direct_o)
   2590         comp.bin_file.options.root_name
   2591     else
   2592         c_source_basename[0 .. c_source_basename.len - std.fs.path.extension(c_source_basename).len];
   2593     const o_basename = try std.fmt.allocPrint(arena, "{s}{s}", .{ o_basename_noext, comp.getTarget().oFileExt() });
   2594 
   2595     const digest = if (!comp.disable_c_depfile and try man.hit()) man.final() else blk: {
   2596         var argv = std.ArrayList([]const u8).init(comp.gpa);
   2597         defer argv.deinit();
   2598 
   2599         // We can't know the digest until we do the C compiler invocation, so we need a temporary filename.
   2600         const out_obj_path = try comp.tmpFilePath(arena, o_basename);
   2601         var zig_cache_tmp_dir = try comp.local_cache_directory.handle.makeOpenPath("tmp", .{});
   2602         defer zig_cache_tmp_dir.close();
   2603 
   2604         try argv.appendSlice(&[_][]const u8{ self_exe_path, "clang" });
   2605 
   2606         const ext = classifyFileExt(c_object.src.src_path);
   2607         const out_dep_path: ?[]const u8 = if (comp.disable_c_depfile or !ext.clangSupportsDepFile())
   2608             null
   2609         else
   2610             try std.fmt.allocPrint(arena, "{s}.d", .{out_obj_path});
   2611         try comp.addCCArgs(arena, &argv, ext, out_dep_path);
   2612 
   2613         try argv.ensureCapacity(argv.items.len + 3);
   2614         switch (comp.clang_preprocessor_mode) {
   2615             .no => argv.appendSliceAssumeCapacity(&[_][]const u8{ "-c", "-o", out_obj_path }),
   2616             .yes => argv.appendSliceAssumeCapacity(&[_][]const u8{ "-E", "-o", out_obj_path }),
   2617             .stdout => argv.appendAssumeCapacity("-E"),
   2618         }
   2619 
   2620         try argv.append(c_object.src.src_path);
   2621         try argv.appendSlice(c_object.src.extra_flags);
   2622 
   2623         if (comp.verbose_cc) {
   2624             dump_argv(argv.items);
   2625         }
   2626 
   2627         const child = try std.ChildProcess.init(argv.items, arena);
   2628         defer child.deinit();
   2629 
   2630         if (comp.clang_passthrough_mode) {
   2631             child.stdin_behavior = .Inherit;
   2632             child.stdout_behavior = .Inherit;
   2633             child.stderr_behavior = .Inherit;
   2634 
   2635             const term = child.spawnAndWait() catch |err| {
   2636                 return comp.failCObj(c_object, "unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) });
   2637             };
   2638             switch (term) {
   2639                 .Exited => |code| {
   2640                     if (code != 0) {
   2641                         // TODO https://github.com/ziglang/zig/issues/6342
   2642                         std.process.exit(1);
   2643                     }
   2644                     if (comp.clang_preprocessor_mode == .stdout)
   2645                         std.process.exit(0);
   2646                 },
   2647                 else => std.process.abort(),
   2648             }
   2649         } else {
   2650             child.stdin_behavior = .Ignore;
   2651             child.stdout_behavior = .Ignore;
   2652             child.stderr_behavior = .Pipe;
   2653 
   2654             try child.spawn();
   2655 
   2656             const stderr_reader = child.stderr.?.reader();
   2657 
   2658             // TODO https://github.com/ziglang/zig/issues/6343
   2659             // Please uncomment and use stdout once this issue is fixed
   2660             // const stdout = try stdout_reader.readAllAlloc(arena, std.math.maxInt(u32));
   2661             const stderr = try stderr_reader.readAllAlloc(arena, 10 * 1024 * 1024);
   2662 
   2663             const term = child.wait() catch |err| {
   2664                 return comp.failCObj(c_object, "unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) });
   2665             };
   2666 
   2667             switch (term) {
   2668                 .Exited => |code| {
   2669                     if (code != 0) {
   2670                         // TODO parse clang stderr and turn it into an error message
   2671                         // and then call failCObjWithOwnedErrorMsg
   2672                         log.err("clang failed with stderr: {s}", .{stderr});
   2673                         return comp.failCObj(c_object, "clang exited with code {d}", .{code});
   2674                     }
   2675                 },
   2676                 else => {
   2677                     log.err("clang terminated with stderr: {s}", .{stderr});
   2678                     return comp.failCObj(c_object, "clang terminated unexpectedly", .{});
   2679                 },
   2680             }
   2681         }
   2682 
   2683         if (out_dep_path) |dep_file_path| {
   2684             const dep_basename = std.fs.path.basename(dep_file_path);
   2685             // Add the files depended on to the cache system.
   2686             try man.addDepFilePost(zig_cache_tmp_dir, dep_basename);
   2687             // Just to save disk space, we delete the file because it is never needed again.
   2688             zig_cache_tmp_dir.deleteFile(dep_basename) catch |err| {
   2689                 log.warn("failed to delete '{s}': {s}", .{ dep_file_path, @errorName(err) });
   2690             };
   2691         }
   2692 
   2693         // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.
   2694         if (comp.disable_c_depfile) _ = try man.hit();
   2695 
   2696         // Rename into place.
   2697         const digest = man.final();
   2698         const o_sub_path = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest });
   2699         var o_dir = try comp.local_cache_directory.handle.makeOpenPath(o_sub_path, .{});
   2700         defer o_dir.close();
   2701         const tmp_basename = std.fs.path.basename(out_obj_path);
   2702         try std.fs.rename(zig_cache_tmp_dir, tmp_basename, o_dir, o_basename);
   2703 
   2704         man.writeManifest() catch |err| {
   2705             log.warn("failed to write cache manifest when compiling '{s}': {s}", .{ c_object.src.src_path, @errorName(err) });
   2706         };
   2707         break :blk digest;
   2708     };
   2709 
   2710     c_object.status = .{
   2711         .success = .{
   2712             .object_path = try comp.local_cache_directory.join(comp.gpa, &[_][]const u8{
   2713                 "o", &digest, o_basename,
   2714             }),
   2715             .lock = man.toOwnedLock(),
   2716         },
   2717     };
   2718 }
   2719 
   2720 pub fn tmpFilePath(comp: *Compilation, arena: *Allocator, suffix: []const u8) error{OutOfMemory}![]const u8 {
   2721     const s = std.fs.path.sep_str;
   2722     const rand_int = std.crypto.random.int(u64);
   2723     if (comp.local_cache_directory.path) |p| {
   2724         return std.fmt.allocPrint(arena, "{s}" ++ s ++ "tmp" ++ s ++ "{x}-{s}", .{ p, rand_int, suffix });
   2725     } else {
   2726         return std.fmt.allocPrint(arena, "tmp" ++ s ++ "{x}-{s}", .{ rand_int, suffix });
   2727     }
   2728 }
   2729 
   2730 pub fn addTranslateCCArgs(
   2731     comp: *Compilation,
   2732     arena: *Allocator,
   2733     argv: *std.ArrayList([]const u8),
   2734     ext: FileExt,
   2735     out_dep_path: ?[]const u8,
   2736 ) !void {
   2737     try argv.appendSlice(&[_][]const u8{ "-x", "c" });
   2738     try comp.addCCArgs(arena, argv, ext, out_dep_path);
   2739     // This gives us access to preprocessing entities, presumably at the cost of performance.
   2740     try argv.appendSlice(&[_][]const u8{ "-Xclang", "-detailed-preprocessing-record" });
   2741 }
   2742 
   2743 /// Add common C compiler args between translate-c and C object compilation.
   2744 pub fn addCCArgs(
   2745     comp: *const Compilation,
   2746     arena: *Allocator,
   2747     argv: *std.ArrayList([]const u8),
   2748     ext: FileExt,
   2749     out_dep_path: ?[]const u8,
   2750 ) !void {
   2751     const target = comp.getTarget();
   2752 
   2753     if (ext == .cpp) {
   2754         try argv.append("-nostdinc++");
   2755     }
   2756 
   2757     // We don't ever put `-fcolor-diagnostics` or `-fno-color-diagnostics` because in passthrough mode
   2758     // we want Clang to infer it, and in normal mode we always want it off, which will be true since
   2759     // clang will detect stderr as a pipe rather than a terminal.
   2760     if (!comp.clang_passthrough_mode) {
   2761         // Make stderr more easily parseable.
   2762         try argv.append("-fno-caret-diagnostics");
   2763     }
   2764 
   2765     if (comp.bin_file.options.function_sections) {
   2766         try argv.append("-ffunction-sections");
   2767     }
   2768 
   2769     if (comp.bin_file.options.link_libcpp) {
   2770         const libcxx_include_path = try std.fs.path.join(arena, &[_][]const u8{
   2771             comp.zig_lib_directory.path.?, "libcxx", "include",
   2772         });
   2773         const libcxxabi_include_path = try std.fs.path.join(arena, &[_][]const u8{
   2774             comp.zig_lib_directory.path.?, "libcxxabi", "include",
   2775         });
   2776 
   2777         try argv.append("-isystem");
   2778         try argv.append(libcxx_include_path);
   2779 
   2780         try argv.append("-isystem");
   2781         try argv.append(libcxxabi_include_path);
   2782 
   2783         if (target.abi.isMusl()) {
   2784             try argv.append("-D_LIBCPP_HAS_MUSL_LIBC");
   2785         }
   2786         try argv.append("-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS");
   2787         try argv.append("-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS");
   2788         try argv.append("-D_LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS");
   2789     }
   2790 
   2791     if (comp.bin_file.options.link_libunwind) {
   2792         const libunwind_include_path = try std.fs.path.join(arena, &[_][]const u8{
   2793             comp.zig_lib_directory.path.?, "libunwind", "include",
   2794         });
   2795 
   2796         try argv.append("-isystem");
   2797         try argv.append(libunwind_include_path);
   2798     }
   2799 
   2800     const llvm_triple = try @import("codegen/llvm.zig").targetTriple(arena, target);
   2801     try argv.appendSlice(&[_][]const u8{ "-target", llvm_triple });
   2802 
   2803     switch (ext) {
   2804         .c, .cpp, .h => {
   2805             try argv.appendSlice(&[_][]const u8{
   2806                 "-nostdinc",
   2807                 "-fno-spell-checking",
   2808             });
   2809             if (comp.bin_file.options.lto) {
   2810                 try argv.append("-flto");
   2811             }
   2812 
   2813             // According to Rich Felker libc headers are supposed to go before C language headers.
   2814             // However as noted by @dimenus, appending libc headers before c_headers breaks intrinsics
   2815             // and other compiler specific items.
   2816             const c_headers_dir = try std.fs.path.join(arena, &[_][]const u8{ comp.zig_lib_directory.path.?, "include" });
   2817             try argv.append("-isystem");
   2818             try argv.append(c_headers_dir);
   2819 
   2820             for (comp.libc_include_dir_list) |include_dir| {
   2821                 try argv.append("-isystem");
   2822                 try argv.append(include_dir);
   2823             }
   2824 
   2825             if (target.cpu.model.llvm_name) |llvm_name| {
   2826                 try argv.appendSlice(&[_][]const u8{
   2827                     "-Xclang", "-target-cpu", "-Xclang", llvm_name,
   2828                 });
   2829             }
   2830 
   2831             // It would be really nice if there was a more compact way to communicate this info to Clang.
   2832             const all_features_list = target.cpu.arch.allFeaturesList();
   2833             try argv.ensureCapacity(argv.items.len + all_features_list.len * 4);
   2834             for (all_features_list) |feature, index_usize| {
   2835                 const index = @intCast(std.Target.Cpu.Feature.Set.Index, index_usize);
   2836                 const is_enabled = target.cpu.features.isEnabled(index);
   2837 
   2838                 if (feature.llvm_name) |llvm_name| {
   2839                     argv.appendSliceAssumeCapacity(&[_][]const u8{ "-Xclang", "-target-feature", "-Xclang" });
   2840                     const plus_or_minus = "-+"[@boolToInt(is_enabled)];
   2841                     const arg = try std.fmt.allocPrint(arena, "{c}{s}", .{ plus_or_minus, llvm_name });
   2842                     argv.appendAssumeCapacity(arg);
   2843                 }
   2844             }
   2845             const mcmodel = comp.bin_file.options.machine_code_model;
   2846             if (mcmodel != .default) {
   2847                 try argv.append(try std.fmt.allocPrint(arena, "-mcmodel={s}", .{@tagName(mcmodel)}));
   2848             }
   2849 
   2850             switch (target.os.tag) {
   2851                 .windows => {
   2852                     // windows.h has files such as pshpack1.h which do #pragma packing,
   2853                     // triggering a clang warning. So for this target, we disable this warning.
   2854                     if (target.abi.isGnu()) {
   2855                         try argv.append("-Wno-pragma-pack");
   2856                     }
   2857                 },
   2858                 .macos => {
   2859                     // Pass the proper -m<os>-version-min argument for darwin.
   2860                     const ver = target.os.version_range.semver.min;
   2861                     try argv.append(try std.fmt.allocPrint(arena, "-mmacos-version-min={d}.{d}.{d}", .{
   2862                         ver.major, ver.minor, ver.patch,
   2863                     }));
   2864                 },
   2865                 .ios, .tvos, .watchos => switch (target.cpu.arch) {
   2866                     // Pass the proper -m<os>-version-min argument for darwin.
   2867                     .i386, .x86_64 => {
   2868                         const ver = target.os.version_range.semver.min;
   2869                         try argv.append(try std.fmt.allocPrint(
   2870                             arena,
   2871                             "-m{s}-simulator-version-min={d}.{d}.{d}",
   2872                             .{ @tagName(target.os.tag), ver.major, ver.minor, ver.patch },
   2873                         ));
   2874                     },
   2875                     else => {
   2876                         const ver = target.os.version_range.semver.min;
   2877                         try argv.append(try std.fmt.allocPrint(arena, "-m{s}-version-min={d}.{d}.{d}", .{
   2878                             @tagName(target.os.tag), ver.major, ver.minor, ver.patch,
   2879                         }));
   2880                     },
   2881                 },
   2882                 else => {},
   2883             }
   2884 
   2885             if (!comp.bin_file.options.strip) {
   2886                 try argv.append("-g");
   2887                 switch (comp.bin_file.options.object_format) {
   2888                     .coff, .pe => try argv.append("-gcodeview"),
   2889                     else => {},
   2890                 }
   2891             }
   2892 
   2893             if (target.cpu.arch.isThumb()) {
   2894                 try argv.append("-mthumb");
   2895             }
   2896 
   2897             if (comp.haveFramePointer()) {
   2898                 try argv.append("-fno-omit-frame-pointer");
   2899             } else {
   2900                 try argv.append("-fomit-frame-pointer");
   2901             }
   2902 
   2903             if (comp.sanitize_c and !comp.bin_file.options.tsan) {
   2904                 try argv.append("-fsanitize=undefined");
   2905                 try argv.append("-fsanitize-trap=undefined");
   2906             } else if (comp.sanitize_c and comp.bin_file.options.tsan) {
   2907                 try argv.append("-fsanitize=undefined,thread");
   2908                 try argv.append("-fsanitize-trap=undefined");
   2909             } else if (!comp.sanitize_c and comp.bin_file.options.tsan) {
   2910                 try argv.append("-fsanitize=thread");
   2911             }
   2912 
   2913             if (comp.bin_file.options.red_zone) {
   2914                 try argv.append("-mred-zone");
   2915             } else if (target_util.hasRedZone(target)) {
   2916                 try argv.append("-mno-red-zone");
   2917             }
   2918 
   2919             switch (comp.bin_file.options.optimize_mode) {
   2920                 .Debug => {
   2921                     // windows c runtime requires -D_DEBUG if using debug libraries
   2922                     try argv.append("-D_DEBUG");
   2923                     try argv.append("-Og");
   2924 
   2925                     if (comp.bin_file.options.link_libc and target.os.tag != .wasi) {
   2926                         try argv.append("-fstack-protector-strong");
   2927                         try argv.append("--param");
   2928                         try argv.append("ssp-buffer-size=4");
   2929                     } else {
   2930                         try argv.append("-fno-stack-protector");
   2931                     }
   2932                 },
   2933                 .ReleaseSafe => {
   2934                     // See the comment in the BuildModeFastRelease case for why we pass -O2 rather
   2935                     // than -O3 here.
   2936                     try argv.append("-O2");
   2937                     if (comp.bin_file.options.link_libc and target.os.tag != .wasi) {
   2938                         try argv.append("-D_FORTIFY_SOURCE=2");
   2939                         try argv.append("-fstack-protector-strong");
   2940                         try argv.append("--param");
   2941                         try argv.append("ssp-buffer-size=4");
   2942                     } else {
   2943                         try argv.append("-fno-stack-protector");
   2944                     }
   2945                 },
   2946                 .ReleaseFast => {
   2947                     try argv.append("-DNDEBUG");
   2948                     // Here we pass -O2 rather than -O3 because, although we do the equivalent of
   2949                     // -O3 in Zig code, the justification for the difference here is that Zig
   2950                     // has better detection and prevention of undefined behavior, so -O3 is safer for
   2951                     // Zig code than it is for C code. Also, C programmers are used to their code
   2952                     // running in -O2 and thus the -O3 path has been tested less.
   2953                     try argv.append("-O2");
   2954                     try argv.append("-fno-stack-protector");
   2955                 },
   2956                 .ReleaseSmall => {
   2957                     try argv.append("-DNDEBUG");
   2958                     try argv.append("-Os");
   2959                     try argv.append("-fno-stack-protector");
   2960                 },
   2961             }
   2962 
   2963             if (target_util.supports_fpic(target) and comp.bin_file.options.pic) {
   2964                 try argv.append("-fPIC");
   2965             }
   2966         },
   2967         .shared_library, .ll, .bc, .unknown, .static_library, .object, .zig => {},
   2968         .assembly => {
   2969             // The Clang assembler does not accept the list of CPU features like the
   2970             // compiler frontend does. Therefore we must hard-code the -m flags for
   2971             // all CPU features here.
   2972             switch (target.cpu.arch) {
   2973                 .riscv32, .riscv64 => {
   2974                     if (std.Target.riscv.featureSetHas(target.cpu.features, .relax)) {
   2975                         try argv.append("-mrelax");
   2976                     } else {
   2977                         try argv.append("-mno-relax");
   2978                     }
   2979                 },
   2980                 else => {
   2981                     // TODO
   2982                 },
   2983             }
   2984             if (target_util.clangAssemblerSupportsMcpuArg(target)) {
   2985                 if (target.cpu.model.llvm_name) |llvm_name| {
   2986                     try argv.append(try std.fmt.allocPrint(arena, "-mcpu={s}", .{llvm_name}));
   2987                 }
   2988             }
   2989         },
   2990     }
   2991     if (out_dep_path) |p| {
   2992         try argv.appendSlice(&[_][]const u8{ "-MD", "-MV", "-MF", p });
   2993     }
   2994 
   2995     // We never want clang to invoke the system assembler for anything. So we would want
   2996     // this option always enabled. However, it only matters for some targets. To avoid
   2997     // "unused parameter" warnings, and to keep CLI spam to a minimum, we only put this
   2998     // flag on the command line if it is necessary.
   2999     if (target_util.clangMightShellOutForAssembly(target)) {
   3000         try argv.append("-integrated-as");
   3001     }
   3002 
   3003     if (target.os.tag == .freestanding) {
   3004         try argv.append("-ffreestanding");
   3005     }
   3006 
   3007     try argv.appendSlice(comp.clang_argv);
   3008 }
   3009 
   3010 fn failCObj(comp: *Compilation, c_object: *CObject, comptime format: []const u8, args: anytype) InnerError {
   3011     @setCold(true);
   3012     const err_msg = blk: {
   3013         const msg = try std.fmt.allocPrint(comp.gpa, format, args);
   3014         errdefer comp.gpa.free(msg);
   3015         const err_msg = try comp.gpa.create(CObject.ErrorMsg);
   3016         errdefer comp.gpa.destroy(err_msg);
   3017         err_msg.* = .{
   3018             .msg = msg,
   3019             .line = 0,
   3020             .column = 0,
   3021         };
   3022         break :blk err_msg;
   3023     };
   3024     return comp.failCObjWithOwnedErrorMsg(c_object, err_msg);
   3025 }
   3026 
   3027 fn failCObjWithOwnedErrorMsg(
   3028     comp: *Compilation,
   3029     c_object: *CObject,
   3030     err_msg: *CObject.ErrorMsg,
   3031 ) InnerError {
   3032     @setCold(true);
   3033     {
   3034         const lock = comp.mutex.acquire();
   3035         defer lock.release();
   3036         {
   3037             errdefer err_msg.destroy(comp.gpa);
   3038             try comp.failed_c_objects.ensureCapacity(comp.gpa, comp.failed_c_objects.count() + 1);
   3039         }
   3040         comp.failed_c_objects.putAssumeCapacityNoClobber(c_object, err_msg);
   3041     }
   3042     c_object.status = .failure;
   3043     return error.AnalysisFail;
   3044 }
   3045 
   3046 pub const FileExt = enum {
   3047     c,
   3048     cpp,
   3049     h,
   3050     ll,
   3051     bc,
   3052     assembly,
   3053     shared_library,
   3054     object,
   3055     static_library,
   3056     zig,
   3057     unknown,
   3058 
   3059     pub fn clangSupportsDepFile(ext: FileExt) bool {
   3060         return switch (ext) {
   3061             .c, .cpp, .h => true,
   3062 
   3063             .ll,
   3064             .bc,
   3065             .assembly,
   3066             .shared_library,
   3067             .object,
   3068             .static_library,
   3069             .zig,
   3070             .unknown,
   3071             => false,
   3072         };
   3073     }
   3074 };
   3075 
   3076 pub fn hasObjectExt(filename: []const u8) bool {
   3077     return mem.endsWith(u8, filename, ".o") or mem.endsWith(u8, filename, ".obj");
   3078 }
   3079 
   3080 pub fn hasStaticLibraryExt(filename: []const u8) bool {
   3081     return mem.endsWith(u8, filename, ".a") or mem.endsWith(u8, filename, ".lib");
   3082 }
   3083 
   3084 pub fn hasCExt(filename: []const u8) bool {
   3085     return mem.endsWith(u8, filename, ".c");
   3086 }
   3087 
   3088 pub fn hasCppExt(filename: []const u8) bool {
   3089     return mem.endsWith(u8, filename, ".C") or
   3090         mem.endsWith(u8, filename, ".cc") or
   3091         mem.endsWith(u8, filename, ".cpp") or
   3092         mem.endsWith(u8, filename, ".cxx");
   3093 }
   3094 
   3095 pub fn hasAsmExt(filename: []const u8) bool {
   3096     return mem.endsWith(u8, filename, ".s") or mem.endsWith(u8, filename, ".S");
   3097 }
   3098 
   3099 pub fn hasSharedLibraryExt(filename: []const u8) bool {
   3100     if (mem.endsWith(u8, filename, ".so") or
   3101         mem.endsWith(u8, filename, ".dll") or
   3102         mem.endsWith(u8, filename, ".dylib") or
   3103         mem.endsWith(u8, filename, ".tbd"))
   3104     {
   3105         return true;
   3106     }
   3107     // Look for .so.X, .so.X.Y, .so.X.Y.Z
   3108     var it = mem.split(filename, ".");
   3109     _ = it.next().?;
   3110     var so_txt = it.next() orelse return false;
   3111     while (!mem.eql(u8, so_txt, "so")) {
   3112         so_txt = it.next() orelse return false;
   3113     }
   3114     const n1 = it.next() orelse return false;
   3115     const n2 = it.next();
   3116     const n3 = it.next();
   3117 
   3118     _ = std.fmt.parseInt(u32, n1, 10) catch return false;
   3119     if (n2) |x| _ = std.fmt.parseInt(u32, x, 10) catch return false;
   3120     if (n3) |x| _ = std.fmt.parseInt(u32, x, 10) catch return false;
   3121     if (it.next() != null) return false;
   3122 
   3123     return true;
   3124 }
   3125 
   3126 pub fn classifyFileExt(filename: []const u8) FileExt {
   3127     if (hasCExt(filename)) {
   3128         return .c;
   3129     } else if (hasCppExt(filename)) {
   3130         return .cpp;
   3131     } else if (mem.endsWith(u8, filename, ".ll")) {
   3132         return .ll;
   3133     } else if (mem.endsWith(u8, filename, ".bc")) {
   3134         return .bc;
   3135     } else if (hasAsmExt(filename)) {
   3136         return .assembly;
   3137     } else if (mem.endsWith(u8, filename, ".h")) {
   3138         return .h;
   3139     } else if (mem.endsWith(u8, filename, ".zig")) {
   3140         return .zig;
   3141     } else if (hasSharedLibraryExt(filename)) {
   3142         return .shared_library;
   3143     } else if (hasStaticLibraryExt(filename)) {
   3144         return .static_library;
   3145     } else if (hasObjectExt(filename)) {
   3146         return .object;
   3147     } else {
   3148         return .unknown;
   3149     }
   3150 }
   3151 
   3152 test "classifyFileExt" {
   3153     try std.testing.expectEqual(FileExt.cpp, classifyFileExt("foo.cc"));
   3154     try std.testing.expectEqual(FileExt.unknown, classifyFileExt("foo.nim"));
   3155     try std.testing.expectEqual(FileExt.shared_library, classifyFileExt("foo.so"));
   3156     try std.testing.expectEqual(FileExt.shared_library, classifyFileExt("foo.so.1"));
   3157     try std.testing.expectEqual(FileExt.shared_library, classifyFileExt("foo.so.1.2"));
   3158     try std.testing.expectEqual(FileExt.shared_library, classifyFileExt("foo.so.1.2.3"));
   3159     try std.testing.expectEqual(FileExt.unknown, classifyFileExt("foo.so.1.2.3~"));
   3160     try std.testing.expectEqual(FileExt.zig, classifyFileExt("foo.zig"));
   3161 }
   3162 
   3163 fn haveFramePointer(comp: *const Compilation) bool {
   3164     // If you complicate this logic make sure you update the parent cache hash.
   3165     // Right now it's not in the cache hash because the value depends on optimize_mode
   3166     // and strip which are both already part of the hash.
   3167     return switch (comp.bin_file.options.optimize_mode) {
   3168         .Debug, .ReleaseSafe => !comp.bin_file.options.strip,
   3169         .ReleaseSmall, .ReleaseFast => false,
   3170     };
   3171 }
   3172 
   3173 const LibCDirs = struct {
   3174     libc_include_dir_list: []const []const u8,
   3175     libc_installation: ?*const LibCInstallation,
   3176 };
   3177 
   3178 fn detectLibCIncludeDirs(
   3179     arena: *Allocator,
   3180     zig_lib_dir: []const u8,
   3181     target: Target,
   3182     is_native_abi: bool,
   3183     link_libc: bool,
   3184     link_system_libs: bool,
   3185     libc_installation: ?*const LibCInstallation,
   3186 ) !LibCDirs {
   3187     if (!link_libc) {
   3188         return LibCDirs{
   3189             .libc_include_dir_list = &[0][]u8{},
   3190             .libc_installation = null,
   3191         };
   3192     }
   3193 
   3194     if (libc_installation) |lci| {
   3195         return detectLibCFromLibCInstallation(arena, target, lci);
   3196     }
   3197 
   3198     // If linking system libraries and targeting the native abi, default to
   3199     // using the system libc installation.
   3200     if (link_system_libs and is_native_abi and !target.isMinGW()) {
   3201         const libc = try arena.create(LibCInstallation);
   3202         libc.* = try LibCInstallation.findNative(.{ .allocator = arena, .verbose = true });
   3203         return detectLibCFromLibCInstallation(arena, target, libc);
   3204     }
   3205 
   3206     // If not linking system libraries, build and provide our own libc by
   3207     // default if possible.
   3208     if (target_util.canBuildLibC(target)) {
   3209         const generic_name = target_util.libCGenericName(target);
   3210         // Some architectures are handled by the same set of headers.
   3211         const arch_name = if (target.abi.isMusl())
   3212             musl.archName(target.cpu.arch)
   3213         else if (target.cpu.arch.isThumb())
   3214             // ARM headers are valid for Thumb too.
   3215             switch (target.cpu.arch) {
   3216                 .thumb => "arm",
   3217                 .thumbeb => "armeb",
   3218                 else => unreachable,
   3219             }
   3220         else
   3221             @tagName(target.cpu.arch);
   3222         const os_name = @tagName(target.os.tag);
   3223         // Musl's headers are ABI-agnostic and so they all have the "musl" ABI name.
   3224         const abi_name = if (target.abi.isMusl()) "musl" else @tagName(target.abi);
   3225         const s = std.fs.path.sep_str;
   3226         const arch_include_dir = try std.fmt.allocPrint(
   3227             arena,
   3228             "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "{s}-{s}-{s}",
   3229             .{ zig_lib_dir, arch_name, os_name, abi_name },
   3230         );
   3231         const generic_include_dir = try std.fmt.allocPrint(
   3232             arena,
   3233             "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "generic-{s}",
   3234             .{ zig_lib_dir, generic_name },
   3235         );
   3236         const arch_os_include_dir = try std.fmt.allocPrint(
   3237             arena,
   3238             "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "{s}-{s}-any",
   3239             .{ zig_lib_dir, @tagName(target.cpu.arch), os_name },
   3240         );
   3241         const generic_os_include_dir = try std.fmt.allocPrint(
   3242             arena,
   3243             "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "any-{s}-any",
   3244             .{ zig_lib_dir, os_name },
   3245         );
   3246 
   3247         const list = try arena.alloc([]const u8, 4);
   3248         list[0] = arch_include_dir;
   3249         list[1] = generic_include_dir;
   3250         list[2] = arch_os_include_dir;
   3251         list[3] = generic_os_include_dir;
   3252         return LibCDirs{
   3253             .libc_include_dir_list = list,
   3254             .libc_installation = null,
   3255         };
   3256     }
   3257 
   3258     // If zig can't build the libc for the target and we are targeting the
   3259     // native abi, fall back to using the system libc installation.
   3260     if (is_native_abi) {
   3261         const libc = try arena.create(LibCInstallation);
   3262         libc.* = try LibCInstallation.findNative(.{ .allocator = arena, .verbose = true });
   3263         return detectLibCFromLibCInstallation(arena, target, libc);
   3264     }
   3265 
   3266     return LibCDirs{
   3267         .libc_include_dir_list = &[0][]u8{},
   3268         .libc_installation = null,
   3269     };
   3270 }
   3271 
   3272 fn detectLibCFromLibCInstallation(arena: *Allocator, target: Target, lci: *const LibCInstallation) !LibCDirs {
   3273     var list = std.ArrayList([]const u8).init(arena);
   3274     try list.ensureCapacity(4);
   3275 
   3276     list.appendAssumeCapacity(lci.include_dir.?);
   3277 
   3278     const is_redundant = mem.eql(u8, lci.sys_include_dir.?, lci.include_dir.?);
   3279     if (!is_redundant) list.appendAssumeCapacity(lci.sys_include_dir.?);
   3280 
   3281     if (target.os.tag == .windows) {
   3282         if (std.fs.path.dirname(lci.include_dir.?)) |include_dir_parent| {
   3283             const um_dir = try std.fs.path.join(arena, &[_][]const u8{ include_dir_parent, "um" });
   3284             list.appendAssumeCapacity(um_dir);
   3285 
   3286             const shared_dir = try std.fs.path.join(arena, &[_][]const u8{ include_dir_parent, "shared" });
   3287             list.appendAssumeCapacity(shared_dir);
   3288         }
   3289     }
   3290     return LibCDirs{
   3291         .libc_include_dir_list = list.items,
   3292         .libc_installation = lci,
   3293     };
   3294 }
   3295 
   3296 pub fn get_libc_crt_file(comp: *Compilation, arena: *Allocator, basename: []const u8) ![]const u8 {
   3297     if (comp.wantBuildGLibCFromSource() or
   3298         comp.wantBuildMuslFromSource() or
   3299         comp.wantBuildMinGWFromSource() or
   3300         comp.wantBuildWasiLibcSysrootFromSource())
   3301     {
   3302         return comp.crt_files.get(basename).?.full_object_path;
   3303     }
   3304     const lci = comp.bin_file.options.libc_installation orelse return error.LibCInstallationNotAvailable;
   3305     const crt_dir_path = lci.crt_dir orelse return error.LibCInstallationMissingCRTDir;
   3306     const full_path = try std.fs.path.join(arena, &[_][]const u8{ crt_dir_path, basename });
   3307     return full_path;
   3308 }
   3309 
   3310 fn addBuildingGLibCJobs(comp: *Compilation) !void {
   3311     try comp.work_queue.write(&[_]Job{
   3312         .{ .glibc_crt_file = .crti_o },
   3313         .{ .glibc_crt_file = .crtn_o },
   3314         .{ .glibc_crt_file = .scrt1_o },
   3315         .{ .glibc_crt_file = .libc_nonshared_a },
   3316         .{ .glibc_shared_objects = {} },
   3317     });
   3318 }
   3319 
   3320 fn wantBuildLibCFromSource(comp: Compilation) bool {
   3321     const is_exe_or_dyn_lib = switch (comp.bin_file.options.output_mode) {
   3322         .Obj => false,
   3323         .Lib => comp.bin_file.options.link_mode == .Dynamic,
   3324         .Exe => true,
   3325     };
   3326     return comp.bin_file.options.link_libc and is_exe_or_dyn_lib and
   3327         comp.bin_file.options.libc_installation == null and
   3328         comp.bin_file.options.object_format != .c;
   3329 }
   3330 
   3331 fn wantBuildGLibCFromSource(comp: Compilation) bool {
   3332     return comp.wantBuildLibCFromSource() and comp.getTarget().isGnuLibC();
   3333 }
   3334 
   3335 fn wantBuildMuslFromSource(comp: Compilation) bool {
   3336     return comp.wantBuildLibCFromSource() and comp.getTarget().isMusl() and
   3337         !comp.getTarget().isWasm();
   3338 }
   3339 
   3340 fn wantBuildWasiLibcSysrootFromSource(comp: Compilation) bool {
   3341     return comp.wantBuildLibCFromSource() and comp.getTarget().isWasm();
   3342 }
   3343 
   3344 fn wantBuildMinGWFromSource(comp: Compilation) bool {
   3345     return comp.wantBuildLibCFromSource() and comp.getTarget().isMinGW();
   3346 }
   3347 
   3348 fn wantBuildLibUnwindFromSource(comp: *Compilation) bool {
   3349     const is_exe_or_dyn_lib = switch (comp.bin_file.options.output_mode) {
   3350         .Obj => false,
   3351         .Lib => comp.bin_file.options.link_mode == .Dynamic,
   3352         .Exe => true,
   3353     };
   3354     return is_exe_or_dyn_lib and comp.bin_file.options.link_libunwind and
   3355         comp.bin_file.options.object_format != .c;
   3356 }
   3357 
   3358 fn updateBuiltinZigFile(comp: *Compilation, mod: *Module) Allocator.Error!void {
   3359     const tracy = trace(@src());
   3360     defer tracy.end();
   3361 
   3362     const source = try comp.generateBuiltinZigSource(comp.gpa);
   3363     defer comp.gpa.free(source);
   3364 
   3365     mod.zig_cache_artifact_directory.handle.writeFile("builtin.zig", source) catch |err| {
   3366         const dir_path: []const u8 = mod.zig_cache_artifact_directory.path orelse ".";
   3367         try comp.setMiscFailure(.write_builtin_zig, "unable to write builtin.zig to {s}: {s}", .{
   3368             dir_path,
   3369             @errorName(err),
   3370         });
   3371     };
   3372 }
   3373 
   3374 fn setMiscFailure(
   3375     comp: *Compilation,
   3376     tag: MiscTask,
   3377     comptime format: []const u8,
   3378     args: anytype,
   3379 ) Allocator.Error!void {
   3380     try comp.misc_failures.ensureCapacity(comp.gpa, comp.misc_failures.count() + 1);
   3381     const msg = try std.fmt.allocPrint(comp.gpa, format, args);
   3382     comp.misc_failures.putAssumeCapacityNoClobber(tag, .{ .msg = msg });
   3383 }
   3384 
   3385 pub fn dump_argv(argv: []const []const u8) void {
   3386     for (argv[0 .. argv.len - 1]) |arg| {
   3387         std.debug.print("{s} ", .{arg});
   3388     }
   3389     std.debug.print("{s}\n", .{argv[argv.len - 1]});
   3390 }
   3391 
   3392 pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) Allocator.Error![]u8 {
   3393     const tracy = trace(@src());
   3394     defer tracy.end();
   3395 
   3396     var buffer = std.ArrayList(u8).init(allocator);
   3397     defer buffer.deinit();
   3398 
   3399     const target = comp.getTarget();
   3400     const generic_arch_name = target.cpu.arch.genericName();
   3401     const use_stage1 = build_options.omit_stage2 or
   3402         (build_options.is_stage1 and comp.bin_file.options.use_llvm);
   3403 
   3404     @setEvalBranchQuota(4000);
   3405     try buffer.writer().print(
   3406         \\const std = @import("std");
   3407         \\/// Zig version. When writing code that supports multiple versions of Zig, prefer
   3408         \\/// feature detection (i.e. with `@hasDecl` or `@hasField`) over version checks.
   3409         \\pub const zig_version = std.SemanticVersion.parse("{s}") catch unreachable;
   3410         \\/// Temporary until self-hosted is feature complete.
   3411         \\pub const zig_is_stage2 = {};
   3412         \\/// Temporary until self-hosted supports the `cpu.arch` value.
   3413         \\pub const stage2_arch: std.Target.Cpu.Arch = .{};
   3414         \\
   3415         \\pub const output_mode = std.builtin.OutputMode.{};
   3416         \\pub const link_mode = std.builtin.LinkMode.{};
   3417         \\pub const is_test = {};
   3418         \\pub const single_threaded = {};
   3419         \\pub const abi = std.Target.Abi.{};
   3420         \\pub const cpu: std.Target.Cpu = .{{
   3421         \\    .arch = .{},
   3422         \\    .model = &std.Target.{}.cpu.{},
   3423         \\    .features = std.Target.{}.featureSet(&[_]std.Target.{}.Feature{{
   3424         \\
   3425     , .{
   3426         build_options.version,
   3427         !use_stage1,
   3428         std.zig.fmtId(@tagName(target.cpu.arch)),
   3429         std.zig.fmtId(@tagName(comp.bin_file.options.output_mode)),
   3430         std.zig.fmtId(@tagName(comp.bin_file.options.link_mode)),
   3431         comp.bin_file.options.is_test,
   3432         comp.bin_file.options.single_threaded,
   3433         std.zig.fmtId(@tagName(target.abi)),
   3434         std.zig.fmtId(@tagName(target.cpu.arch)),
   3435         std.zig.fmtId(generic_arch_name),
   3436         std.zig.fmtId(target.cpu.model.name),
   3437         std.zig.fmtId(generic_arch_name),
   3438         std.zig.fmtId(generic_arch_name),
   3439     });
   3440 
   3441     for (target.cpu.arch.allFeaturesList()) |feature, index_usize| {
   3442         const index = @intCast(std.Target.Cpu.Feature.Set.Index, index_usize);
   3443         const is_enabled = target.cpu.features.isEnabled(index);
   3444         if (is_enabled) {
   3445             try buffer.writer().print("        .{},\n", .{std.zig.fmtId(feature.name)});
   3446         }
   3447     }
   3448 
   3449     try buffer.writer().print(
   3450         \\    }}),
   3451         \\}};
   3452         \\pub const os = std.Target.Os{{
   3453         \\    .tag = .{},
   3454         \\    .version_range = .{{
   3455     ,
   3456         .{std.zig.fmtId(@tagName(target.os.tag))},
   3457     );
   3458 
   3459     switch (target.os.getVersionRange()) {
   3460         .none => try buffer.appendSlice(" .none = {} }\n"),
   3461         .semver => |semver| try buffer.writer().print(
   3462             \\ .semver = .{{
   3463             \\        .min = .{{
   3464             \\            .major = {},
   3465             \\            .minor = {},
   3466             \\            .patch = {},
   3467             \\        }},
   3468             \\        .max = .{{
   3469             \\            .major = {},
   3470             \\            .minor = {},
   3471             \\            .patch = {},
   3472             \\        }},
   3473             \\    }}}},
   3474             \\
   3475         , .{
   3476             semver.min.major,
   3477             semver.min.minor,
   3478             semver.min.patch,
   3479 
   3480             semver.max.major,
   3481             semver.max.minor,
   3482             semver.max.patch,
   3483         }),
   3484         .linux => |linux| try buffer.writer().print(
   3485             \\ .linux = .{{
   3486             \\        .range = .{{
   3487             \\            .min = .{{
   3488             \\                .major = {},
   3489             \\                .minor = {},
   3490             \\                .patch = {},
   3491             \\            }},
   3492             \\            .max = .{{
   3493             \\                .major = {},
   3494             \\                .minor = {},
   3495             \\                .patch = {},
   3496             \\            }},
   3497             \\        }},
   3498             \\        .glibc = .{{
   3499             \\            .major = {},
   3500             \\            .minor = {},
   3501             \\            .patch = {},
   3502             \\        }},
   3503             \\    }}}},
   3504             \\
   3505         , .{
   3506             linux.range.min.major,
   3507             linux.range.min.minor,
   3508             linux.range.min.patch,
   3509 
   3510             linux.range.max.major,
   3511             linux.range.max.minor,
   3512             linux.range.max.patch,
   3513 
   3514             linux.glibc.major,
   3515             linux.glibc.minor,
   3516             linux.glibc.patch,
   3517         }),
   3518         .windows => |windows| try buffer.writer().print(
   3519             \\ .windows = .{{
   3520             \\        .min = {s},
   3521             \\        .max = {s},
   3522             \\    }}}},
   3523             \\
   3524         ,
   3525             .{ windows.min, windows.max },
   3526         ),
   3527     }
   3528     try buffer.appendSlice("};\n");
   3529 
   3530     // This is so that compiler_rt and libc.zig libraries know whether they
   3531     // will eventually be linked with libc. They make different decisions
   3532     // about what to export depending on whether another libc will be linked
   3533     // in. For example, compiler_rt will not export the __chkstk symbol if it
   3534     // knows libc will provide it, and likewise c.zig will not export memcpy.
   3535     const link_libc = comp.bin_file.options.link_libc or
   3536         (comp.bin_file.options.skip_linker_dependencies and comp.bin_file.options.parent_compilation_link_libc);
   3537 
   3538     try buffer.writer().print(
   3539         \\pub const target = std.Target{{
   3540         \\    .cpu = cpu,
   3541         \\    .os = os,
   3542         \\    .abi = abi,
   3543         \\}};
   3544         \\pub const object_format = std.Target.ObjectFormat.{};
   3545         \\pub const mode = std.builtin.Mode.{};
   3546         \\pub const link_libc = {};
   3547         \\pub const link_libcpp = {};
   3548         \\pub const have_error_return_tracing = {};
   3549         \\pub const valgrind_support = {};
   3550         \\pub const position_independent_code = {};
   3551         \\pub const position_independent_executable = {};
   3552         \\pub const strip_debug_info = {};
   3553         \\pub const code_model = std.builtin.CodeModel.{};
   3554         \\
   3555     , .{
   3556         std.zig.fmtId(@tagName(comp.bin_file.options.object_format)),
   3557         std.zig.fmtId(@tagName(comp.bin_file.options.optimize_mode)),
   3558         link_libc,
   3559         comp.bin_file.options.link_libcpp,
   3560         comp.bin_file.options.error_return_tracing,
   3561         comp.bin_file.options.valgrind,
   3562         comp.bin_file.options.pic,
   3563         comp.bin_file.options.pie,
   3564         comp.bin_file.options.strip,
   3565         std.zig.fmtId(@tagName(comp.bin_file.options.machine_code_model)),
   3566     });
   3567 
   3568     if (comp.bin_file.options.is_test) {
   3569         try buffer.appendSlice(
   3570             \\pub var test_functions: []std.builtin.TestFn = undefined; // overwritten later
   3571             \\
   3572         );
   3573         if (comp.test_evented_io) {
   3574             try buffer.appendSlice(
   3575                 \\pub const test_io_mode = .evented;
   3576                 \\
   3577             );
   3578         } else {
   3579             try buffer.appendSlice(
   3580                 \\pub const test_io_mode = .blocking;
   3581                 \\
   3582             );
   3583         }
   3584     }
   3585 
   3586     return buffer.toOwnedSlice();
   3587 }
   3588 
   3589 pub fn updateSubCompilation(sub_compilation: *Compilation) !void {
   3590     try sub_compilation.update();
   3591 
   3592     // Look for compilation errors in this sub_compilation
   3593     // TODO instead of logging these errors, handle them in the callsites
   3594     // of updateSubCompilation and attach them as sub-errors, properly
   3595     // surfacing the errors. You can see an example of this already
   3596     // done inside buildOutputFromZig.
   3597     var errors = try sub_compilation.getAllErrorsAlloc();
   3598     defer errors.deinit(sub_compilation.gpa);
   3599 
   3600     if (errors.list.len != 0) {
   3601         for (errors.list) |full_err_msg| {
   3602             switch (full_err_msg) {
   3603                 .src => |src| {
   3604                     log.err("{s}:{d}:{d}: {s}", .{
   3605                         src.src_path,
   3606                         src.line + 1,
   3607                         src.column + 1,
   3608                         src.msg,
   3609                     });
   3610                 },
   3611                 .plain => |plain| {
   3612                     log.err("{s}", .{plain.msg});
   3613                 },
   3614             }
   3615         }
   3616         return error.BuildingLibCObjectFailed;
   3617     }
   3618 }
   3619 
   3620 fn buildOutputFromZig(
   3621     comp: *Compilation,
   3622     src_basename: []const u8,
   3623     output_mode: std.builtin.OutputMode,
   3624     out: *?CRTFile,
   3625     misc_task_tag: MiscTask,
   3626 ) !void {
   3627     const tracy = trace(@src());
   3628     defer tracy.end();
   3629 
   3630     std.debug.assert(output_mode != .Exe);
   3631     const special_sub = "std" ++ std.fs.path.sep_str ++ "special";
   3632     const special_path = try comp.zig_lib_directory.join(comp.gpa, &[_][]const u8{special_sub});
   3633     defer comp.gpa.free(special_path);
   3634 
   3635     var special_dir = try comp.zig_lib_directory.handle.openDir(special_sub, .{});
   3636     defer special_dir.close();
   3637 
   3638     var root_pkg: Package = .{
   3639         .root_src_directory = .{
   3640             .path = special_path,
   3641             .handle = special_dir,
   3642         },
   3643         .root_src_path = src_basename,
   3644     };
   3645     const root_name = src_basename[0 .. src_basename.len - std.fs.path.extension(src_basename).len];
   3646     const target = comp.getTarget();
   3647     const bin_basename = try std.zig.binNameAlloc(comp.gpa, .{
   3648         .root_name = root_name,
   3649         .target = target,
   3650         .output_mode = output_mode,
   3651     });
   3652     defer comp.gpa.free(bin_basename);
   3653 
   3654     const emit_bin = Compilation.EmitLoc{
   3655         .directory = null, // Put it in the cache directory.
   3656         .basename = bin_basename,
   3657     };
   3658     const sub_compilation = try Compilation.create(comp.gpa, .{
   3659         .global_cache_directory = comp.global_cache_directory,
   3660         .local_cache_directory = comp.global_cache_directory,
   3661         .zig_lib_directory = comp.zig_lib_directory,
   3662         .target = target,
   3663         .root_name = root_name,
   3664         .root_pkg = &root_pkg,
   3665         .output_mode = output_mode,
   3666         .thread_pool = comp.thread_pool,
   3667         .libc_installation = comp.bin_file.options.libc_installation,
   3668         .emit_bin = emit_bin,
   3669         .optimize_mode = comp.compilerRtOptMode(),
   3670         .link_mode = .Static,
   3671         .function_sections = true,
   3672         .want_sanitize_c = false,
   3673         .want_stack_check = false,
   3674         .want_red_zone = comp.bin_file.options.red_zone,
   3675         .want_valgrind = false,
   3676         .want_tsan = false,
   3677         .want_pic = comp.bin_file.options.pic,
   3678         .want_pie = comp.bin_file.options.pie,
   3679         .emit_h = null,
   3680         .strip = comp.compilerRtStrip(),
   3681         .is_native_os = comp.bin_file.options.is_native_os,
   3682         .is_native_abi = comp.bin_file.options.is_native_abi,
   3683         .self_exe_path = comp.self_exe_path,
   3684         .verbose_cc = comp.verbose_cc,
   3685         .verbose_link = comp.bin_file.options.verbose_link,
   3686         .verbose_air = comp.verbose_air,
   3687         .verbose_llvm_ir = comp.verbose_llvm_ir,
   3688         .verbose_cimport = comp.verbose_cimport,
   3689         .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
   3690         .clang_passthrough_mode = comp.clang_passthrough_mode,
   3691         .skip_linker_dependencies = true,
   3692         .parent_compilation_link_libc = comp.bin_file.options.link_libc,
   3693     });
   3694     defer sub_compilation.destroy();
   3695 
   3696     try sub_compilation.update();
   3697     // Look for compilation errors in this sub_compilation.
   3698     var keep_errors = false;
   3699     var errors = try sub_compilation.getAllErrorsAlloc();
   3700     defer if (!keep_errors) errors.deinit(sub_compilation.gpa);
   3701 
   3702     if (errors.list.len != 0) {
   3703         try comp.misc_failures.ensureCapacity(comp.gpa, comp.misc_failures.count() + 1);
   3704         comp.misc_failures.putAssumeCapacityNoClobber(misc_task_tag, .{
   3705             .msg = try std.fmt.allocPrint(comp.gpa, "sub-compilation of {s} failed", .{
   3706                 @tagName(misc_task_tag),
   3707             }),
   3708             .children = errors,
   3709         });
   3710         keep_errors = true;
   3711         return error.SubCompilationFailed;
   3712     }
   3713 
   3714     assert(out.* == null);
   3715     out.* = Compilation.CRTFile{
   3716         .full_object_path = try sub_compilation.bin_file.options.emit.?.directory.join(comp.gpa, &[_][]const u8{
   3717             sub_compilation.bin_file.options.emit.?.sub_path,
   3718         }),
   3719         .lock = sub_compilation.bin_file.toOwnedLock(),
   3720     };
   3721 }
   3722 
   3723 fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node) !void {
   3724     const tracy = trace(@src());
   3725     defer tracy.end();
   3726 
   3727     var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa);
   3728     defer arena_allocator.deinit();
   3729     const arena = &arena_allocator.allocator;
   3730 
   3731     // Here we use the legacy stage1 C++ compiler to compile Zig code.
   3732     const mod = comp.bin_file.options.module.?;
   3733     const directory = mod.zig_cache_artifact_directory; // Just an alias to make it shorter to type.
   3734     const main_zig_file = try mod.root_pkg.root_src_directory.join(arena, &[_][]const u8{
   3735         mod.root_pkg.root_src_path,
   3736     });
   3737     const zig_lib_dir = comp.zig_lib_directory.path.?;
   3738     const builtin_zig_path = try directory.join(arena, &[_][]const u8{"builtin.zig"});
   3739     const target = comp.getTarget();
   3740     const id_symlink_basename = "stage1.id";
   3741     const libs_txt_basename = "libs.txt";
   3742 
   3743     // We are about to obtain this lock, so here we give other processes a chance first.
   3744     comp.releaseStage1Lock();
   3745 
   3746     // Unlike with the self-hosted Zig module, stage1 does not support incremental compilation,
   3747     // so we input all the zig source files into the cache hash system. We're going to keep
   3748     // the artifact directory the same, however, so we take the same strategy as linking
   3749     // does where we have a file which specifies the hash of the output directory so that we can
   3750     // skip the expensive compilation step if the hash matches.
   3751     var man = comp.cache_parent.obtain();
   3752     defer man.deinit();
   3753 
   3754     _ = try man.addFile(main_zig_file, null);
   3755     {
   3756         var local_arena = std.heap.ArenaAllocator.init(comp.gpa);
   3757         defer local_arena.deinit();
   3758         try addPackageTableToCacheHash(&man.hash, &local_arena, mod.root_pkg.table, .{ .files = &man });
   3759     }
   3760     man.hash.add(comp.bin_file.options.valgrind);
   3761     man.hash.add(comp.bin_file.options.single_threaded);
   3762     man.hash.add(target.os.getVersionRange());
   3763     man.hash.add(comp.bin_file.options.dll_export_fns);
   3764     man.hash.add(comp.bin_file.options.function_sections);
   3765     man.hash.add(comp.bin_file.options.is_test);
   3766     man.hash.add(comp.bin_file.options.emit != null);
   3767     man.hash.add(mod.emit_h != null);
   3768     if (mod.emit_h) |emit_h| {
   3769         man.hash.addEmitLoc(emit_h.loc);
   3770     }
   3771     man.hash.addOptionalEmitLoc(comp.emit_asm);
   3772     man.hash.addOptionalEmitLoc(comp.emit_llvm_ir);
   3773     man.hash.addOptionalEmitLoc(comp.emit_analysis);
   3774     man.hash.addOptionalEmitLoc(comp.emit_docs);
   3775     man.hash.add(comp.test_evented_io);
   3776     man.hash.addOptionalBytes(comp.test_filter);
   3777     man.hash.addOptionalBytes(comp.test_name_prefix);
   3778 
   3779     // Capture the state in case we come back from this branch where the hash doesn't match.
   3780     const prev_hash_state = man.hash.peekBin();
   3781     const input_file_count = man.files.items.len;
   3782 
   3783     const hit = man.hit() catch |err| {
   3784         const i = man.failed_file_index orelse return err;
   3785         const file_path = man.files.items[i].path orelse return err;
   3786         fatal("unable to build stage1 zig object: {s}: {s}", .{ @errorName(err), file_path });
   3787     };
   3788     if (hit) {
   3789         const digest = man.final();
   3790 
   3791         // We use an extra hex-encoded byte here to store some flags.
   3792         var prev_digest_buf: [digest.len + 2]u8 = undefined;
   3793         const prev_digest: []u8 = Cache.readSmallFile(
   3794             directory.handle,
   3795             id_symlink_basename,
   3796             &prev_digest_buf,
   3797         ) catch |err| blk: {
   3798             log.debug("stage1 {s} new_digest={s} error: {s}", .{
   3799                 mod.root_pkg.root_src_path,
   3800                 std.fmt.fmtSliceHexLower(&digest),
   3801                 @errorName(err),
   3802             });
   3803             // Handle this as a cache miss.
   3804             break :blk prev_digest_buf[0..0];
   3805         };
   3806         if (prev_digest.len >= digest.len + 2) hit: {
   3807             if (!mem.eql(u8, prev_digest[0..digest.len], &digest))
   3808                 break :hit;
   3809 
   3810             log.debug("stage1 {s} digest={s} match - skipping invocation", .{
   3811                 mod.root_pkg.root_src_path,
   3812                 std.fmt.fmtSliceHexLower(&digest),
   3813             });
   3814             var flags_bytes: [1]u8 = undefined;
   3815             _ = std.fmt.hexToBytes(&flags_bytes, prev_digest[digest.len..]) catch {
   3816                 log.warn("bad cache stage1 digest: '{s}'", .{std.fmt.fmtSliceHexLower(prev_digest)});
   3817                 break :hit;
   3818             };
   3819 
   3820             if (directory.handle.readFileAlloc(comp.gpa, libs_txt_basename, 10 * 1024 * 1024)) |libs_txt| {
   3821                 var it = mem.tokenize(libs_txt, "\n");
   3822                 while (it.next()) |lib_name| {
   3823                     try comp.stage1AddLinkLib(lib_name);
   3824                 }
   3825             } else |err| switch (err) {
   3826                 error.FileNotFound => {}, // That's OK, it just means 0 libs.
   3827                 else => {
   3828                     log.warn("unable to read cached list of link libs: {s}", .{@errorName(err)});
   3829                     break :hit;
   3830                 },
   3831             }
   3832             comp.stage1_lock = man.toOwnedLock();
   3833             mod.stage1_flags = @bitCast(@TypeOf(mod.stage1_flags), flags_bytes[0]);
   3834             return;
   3835         }
   3836         log.debug("stage1 {s} prev_digest={s} new_digest={s}", .{
   3837             mod.root_pkg.root_src_path,
   3838             std.fmt.fmtSliceHexLower(prev_digest),
   3839             std.fmt.fmtSliceHexLower(&digest),
   3840         });
   3841         man.unhit(prev_hash_state, input_file_count);
   3842     }
   3843 
   3844     // We are about to change the output file to be different, so we invalidate the build hash now.
   3845     directory.handle.deleteFile(id_symlink_basename) catch |err| switch (err) {
   3846         error.FileNotFound => {},
   3847         else => |e| return e,
   3848     };
   3849 
   3850     const stage2_target = try arena.create(stage1.Stage2Target);
   3851     stage2_target.* = .{
   3852         .arch = @enumToInt(target.cpu.arch) + 1, // skip over ZigLLVM_UnknownArch
   3853         .os = @enumToInt(target.os.tag),
   3854         .abi = @enumToInt(target.abi),
   3855         .is_native_os = comp.bin_file.options.is_native_os,
   3856         .is_native_cpu = false, // Only true when bootstrapping the compiler.
   3857         .llvm_cpu_name = if (target.cpu.model.llvm_name) |s| s.ptr else null,
   3858         .llvm_cpu_features = comp.bin_file.options.llvm_cpu_features.?,
   3859     };
   3860 
   3861     comp.stage1_cache_manifest = &man;
   3862 
   3863     const main_pkg_path = mod.root_pkg.root_src_directory.path orelse "";
   3864 
   3865     const stage1_module = stage1.create(
   3866         @enumToInt(comp.bin_file.options.optimize_mode),
   3867         main_pkg_path.ptr,
   3868         main_pkg_path.len,
   3869         main_zig_file.ptr,
   3870         main_zig_file.len,
   3871         zig_lib_dir.ptr,
   3872         zig_lib_dir.len,
   3873         stage2_target,
   3874         comp.bin_file.options.is_test,
   3875     ) orelse return error.OutOfMemory;
   3876 
   3877     const emit_bin_path = if (comp.bin_file.options.emit != null) blk: {
   3878         const bin_basename = try std.zig.binNameAlloc(arena, .{
   3879             .root_name = comp.bin_file.options.root_name,
   3880             .target = target,
   3881             .output_mode = .Obj,
   3882         });
   3883         break :blk try directory.join(arena, &[_][]const u8{bin_basename});
   3884     } else "";
   3885     if (mod.emit_h != null) {
   3886         log.warn("-femit-h is not available in the stage1 backend; no .h file will be produced", .{});
   3887     }
   3888     const emit_h_loc: ?EmitLoc = if (mod.emit_h) |emit_h| emit_h.loc else null;
   3889     const emit_h_path = try stage1LocPath(arena, emit_h_loc, directory);
   3890     const emit_asm_path = try stage1LocPath(arena, comp.emit_asm, directory);
   3891     const emit_llvm_ir_path = try stage1LocPath(arena, comp.emit_llvm_ir, directory);
   3892     const emit_analysis_path = try stage1LocPath(arena, comp.emit_analysis, directory);
   3893     const emit_docs_path = try stage1LocPath(arena, comp.emit_docs, directory);
   3894     const stage1_pkg = try createStage1Pkg(arena, "root", mod.root_pkg, null);
   3895     const test_filter = comp.test_filter orelse ""[0..0];
   3896     const test_name_prefix = comp.test_name_prefix orelse ""[0..0];
   3897     const subsystem = if (comp.bin_file.options.subsystem) |s|
   3898         @intToEnum(stage1.TargetSubsystem, @enumToInt(s))
   3899     else
   3900         stage1.TargetSubsystem.Auto;
   3901     stage1_module.* = .{
   3902         .root_name_ptr = comp.bin_file.options.root_name.ptr,
   3903         .root_name_len = comp.bin_file.options.root_name.len,
   3904         .emit_o_ptr = emit_bin_path.ptr,
   3905         .emit_o_len = emit_bin_path.len,
   3906         .emit_h_ptr = emit_h_path.ptr,
   3907         .emit_h_len = emit_h_path.len,
   3908         .emit_asm_ptr = emit_asm_path.ptr,
   3909         .emit_asm_len = emit_asm_path.len,
   3910         .emit_llvm_ir_ptr = emit_llvm_ir_path.ptr,
   3911         .emit_llvm_ir_len = emit_llvm_ir_path.len,
   3912         .emit_analysis_json_ptr = emit_analysis_path.ptr,
   3913         .emit_analysis_json_len = emit_analysis_path.len,
   3914         .emit_docs_ptr = emit_docs_path.ptr,
   3915         .emit_docs_len = emit_docs_path.len,
   3916         .builtin_zig_path_ptr = builtin_zig_path.ptr,
   3917         .builtin_zig_path_len = builtin_zig_path.len,
   3918         .test_filter_ptr = test_filter.ptr,
   3919         .test_filter_len = test_filter.len,
   3920         .test_name_prefix_ptr = test_name_prefix.ptr,
   3921         .test_name_prefix_len = test_name_prefix.len,
   3922         .userdata = @ptrToInt(comp),
   3923         .root_pkg = stage1_pkg,
   3924         .code_model = @enumToInt(comp.bin_file.options.machine_code_model),
   3925         .subsystem = subsystem,
   3926         .err_color = @enumToInt(comp.color),
   3927         .pic = comp.bin_file.options.pic,
   3928         .pie = comp.bin_file.options.pie,
   3929         .lto = comp.bin_file.options.lto,
   3930         .link_libc = comp.bin_file.options.link_libc,
   3931         .link_libcpp = comp.bin_file.options.link_libcpp,
   3932         .strip = comp.bin_file.options.strip,
   3933         .is_single_threaded = comp.bin_file.options.single_threaded,
   3934         .dll_export_fns = comp.bin_file.options.dll_export_fns,
   3935         .link_mode_dynamic = comp.bin_file.options.link_mode == .Dynamic,
   3936         .valgrind_enabled = comp.bin_file.options.valgrind,
   3937         .tsan_enabled = comp.bin_file.options.tsan,
   3938         .function_sections = comp.bin_file.options.function_sections,
   3939         .enable_stack_probing = comp.bin_file.options.stack_check,
   3940         .red_zone = comp.bin_file.options.red_zone,
   3941         .enable_time_report = comp.time_report,
   3942         .enable_stack_report = comp.stack_report,
   3943         .test_is_evented = comp.test_evented_io,
   3944         .verbose_ir = comp.verbose_air,
   3945         .verbose_llvm_ir = comp.verbose_llvm_ir,
   3946         .verbose_cimport = comp.verbose_cimport,
   3947         .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
   3948         .main_progress_node = main_progress_node,
   3949         .have_c_main = false,
   3950         .have_winmain = false,
   3951         .have_wwinmain = false,
   3952         .have_winmain_crt_startup = false,
   3953         .have_wwinmain_crt_startup = false,
   3954         .have_dllmain_crt_startup = false,
   3955     };
   3956 
   3957     const inferred_lib_start_index = comp.bin_file.options.system_libs.count();
   3958     stage1_module.build_object();
   3959 
   3960     if (comp.bin_file.options.system_libs.count() > inferred_lib_start_index) {
   3961         // We need to save the inferred link libs to the cache, otherwise if we get a cache hit
   3962         // next time we will be missing these libs.
   3963         var libs_txt = std.ArrayList(u8).init(arena);
   3964         for (comp.bin_file.options.system_libs.keys()[inferred_lib_start_index..]) |key| {
   3965             try libs_txt.writer().print("{s}\n", .{key});
   3966         }
   3967         try directory.handle.writeFile(libs_txt_basename, libs_txt.items);
   3968     }
   3969 
   3970     mod.stage1_flags = .{
   3971         .have_c_main = stage1_module.have_c_main,
   3972         .have_winmain = stage1_module.have_winmain,
   3973         .have_wwinmain = stage1_module.have_wwinmain,
   3974         .have_winmain_crt_startup = stage1_module.have_winmain_crt_startup,
   3975         .have_wwinmain_crt_startup = stage1_module.have_wwinmain_crt_startup,
   3976         .have_dllmain_crt_startup = stage1_module.have_dllmain_crt_startup,
   3977     };
   3978 
   3979     stage1_module.destroy();
   3980 
   3981     const digest = man.final();
   3982 
   3983     // Update the small file with the digest. If it fails we can continue; it only
   3984     // means that the next invocation will have an unnecessary cache miss.
   3985     const stage1_flags_byte = @bitCast(u8, mod.stage1_flags);
   3986     log.debug("stage1 {s} final digest={s} flags={x}", .{
   3987         mod.root_pkg.root_src_path, std.fmt.fmtSliceHexLower(&digest), stage1_flags_byte,
   3988     });
   3989     var digest_plus_flags: [digest.len + 2]u8 = undefined;
   3990     digest_plus_flags[0..digest.len].* = digest;
   3991     assert(std.fmt.formatIntBuf(digest_plus_flags[digest.len..], stage1_flags_byte, 16, false, .{
   3992         .width = 2,
   3993         .fill = '0',
   3994     }) == 2);
   3995     log.debug("saved digest + flags: '{s}' (byte = {}) have_winmain_crt_startup={}", .{
   3996         digest_plus_flags, stage1_flags_byte, mod.stage1_flags.have_winmain_crt_startup,
   3997     });
   3998     Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest_plus_flags) catch |err| {
   3999         log.warn("failed to save stage1 hash digest file: {s}", .{@errorName(err)});
   4000     };
   4001     // Failure here only means an unnecessary cache miss.
   4002     man.writeManifest() catch |err| {
   4003         log.warn("failed to write cache manifest when linking: {s}", .{@errorName(err)});
   4004     };
   4005     // We hang on to this lock so that the output file path can be used without
   4006     // other processes clobbering it.
   4007     comp.stage1_lock = man.toOwnedLock();
   4008 }
   4009 
   4010 fn stage1LocPath(arena: *Allocator, opt_loc: ?EmitLoc, cache_directory: Directory) ![]const u8 {
   4011     const loc = opt_loc orelse return "";
   4012     const directory = loc.directory orelse cache_directory;
   4013     return directory.join(arena, &[_][]const u8{loc.basename});
   4014 }
   4015 
   4016 fn createStage1Pkg(
   4017     arena: *Allocator,
   4018     name: []const u8,
   4019     pkg: *Package,
   4020     parent_pkg: ?*stage1.Pkg,
   4021 ) error{OutOfMemory}!*stage1.Pkg {
   4022     const child_pkg = try arena.create(stage1.Pkg);
   4023 
   4024     const pkg_children = blk: {
   4025         var children = std.ArrayList(*stage1.Pkg).init(arena);
   4026         var it = pkg.table.iterator();
   4027         while (it.next()) |entry| {
   4028             try children.append(try createStage1Pkg(arena, entry.key_ptr.*, entry.value_ptr.*, child_pkg));
   4029         }
   4030         break :blk children.items;
   4031     };
   4032 
   4033     const src_path = try pkg.root_src_directory.join(arena, &[_][]const u8{pkg.root_src_path});
   4034 
   4035     child_pkg.* = .{
   4036         .name_ptr = name.ptr,
   4037         .name_len = name.len,
   4038         .path_ptr = src_path.ptr,
   4039         .path_len = src_path.len,
   4040         .children_ptr = pkg_children.ptr,
   4041         .children_len = pkg_children.len,
   4042         .parent = parent_pkg,
   4043     };
   4044     return child_pkg;
   4045 }
   4046 
   4047 pub fn build_crt_file(
   4048     comp: *Compilation,
   4049     root_name: []const u8,
   4050     output_mode: std.builtin.OutputMode,
   4051     c_source_files: []const Compilation.CSourceFile,
   4052 ) !void {
   4053     const tracy = trace(@src());
   4054     defer tracy.end();
   4055 
   4056     const target = comp.getTarget();
   4057     const basename = try std.zig.binNameAlloc(comp.gpa, .{
   4058         .root_name = root_name,
   4059         .target = target,
   4060         .output_mode = output_mode,
   4061     });
   4062     errdefer comp.gpa.free(basename);
   4063 
   4064     // TODO: This is extracted into a local variable to work around a stage1 miscompilation.
   4065     const emit_bin = Compilation.EmitLoc{
   4066         .directory = null, // Put it in the cache directory.
   4067         .basename = basename,
   4068     };
   4069     const sub_compilation = try Compilation.create(comp.gpa, .{
   4070         .local_cache_directory = comp.global_cache_directory,
   4071         .global_cache_directory = comp.global_cache_directory,
   4072         .zig_lib_directory = comp.zig_lib_directory,
   4073         .target = target,
   4074         .root_name = root_name,
   4075         .root_pkg = null,
   4076         .output_mode = output_mode,
   4077         .thread_pool = comp.thread_pool,
   4078         .libc_installation = comp.bin_file.options.libc_installation,
   4079         .emit_bin = emit_bin,
   4080         .optimize_mode = comp.compilerRtOptMode(),
   4081         .want_sanitize_c = false,
   4082         .want_stack_check = false,
   4083         .want_red_zone = comp.bin_file.options.red_zone,
   4084         .want_valgrind = false,
   4085         .want_tsan = false,
   4086         .want_pic = comp.bin_file.options.pic,
   4087         .want_pie = comp.bin_file.options.pie,
   4088         .want_lto = switch (output_mode) {
   4089             .Lib => comp.bin_file.options.lto,
   4090             .Obj, .Exe => false,
   4091         },
   4092         .emit_h = null,
   4093         .strip = comp.compilerRtStrip(),
   4094         .is_native_os = comp.bin_file.options.is_native_os,
   4095         .is_native_abi = comp.bin_file.options.is_native_abi,
   4096         .self_exe_path = comp.self_exe_path,
   4097         .c_source_files = c_source_files,
   4098         .verbose_cc = comp.verbose_cc,
   4099         .verbose_link = comp.bin_file.options.verbose_link,
   4100         .verbose_air = comp.verbose_air,
   4101         .verbose_llvm_ir = comp.verbose_llvm_ir,
   4102         .verbose_cimport = comp.verbose_cimport,
   4103         .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
   4104         .clang_passthrough_mode = comp.clang_passthrough_mode,
   4105         .skip_linker_dependencies = true,
   4106         .parent_compilation_link_libc = comp.bin_file.options.link_libc,
   4107     });
   4108     defer sub_compilation.destroy();
   4109 
   4110     try sub_compilation.updateSubCompilation();
   4111 
   4112     try comp.crt_files.ensureCapacity(comp.gpa, comp.crt_files.count() + 1);
   4113 
   4114     comp.crt_files.putAssumeCapacityNoClobber(basename, .{
   4115         .full_object_path = try sub_compilation.bin_file.options.emit.?.directory.join(comp.gpa, &[_][]const u8{
   4116             sub_compilation.bin_file.options.emit.?.sub_path,
   4117         }),
   4118         .lock = sub_compilation.bin_file.toOwnedLock(),
   4119     });
   4120 }
   4121 
   4122 pub fn stage1AddLinkLib(comp: *Compilation, lib_name: []const u8) !void {
   4123     // Avoid deadlocking on building import libs such as kernel32.lib
   4124     // This can happen when the user uses `build-exe foo.obj -lkernel32` and then
   4125     // when we create a sub-Compilation for zig libc, it also tries to build kernel32.lib.
   4126     if (comp.bin_file.options.skip_linker_dependencies) return;
   4127 
   4128     // This happens when an `extern "foo"` function is referenced by the stage1 backend.
   4129     // If we haven't seen this library yet and we're targeting Windows, we need to queue up
   4130     // a work item to produce the DLL import library for this.
   4131     const gop = try comp.bin_file.options.system_libs.getOrPut(comp.gpa, lib_name);
   4132     if (!gop.found_existing and comp.getTarget().os.tag == .windows) {
   4133         try comp.work_queue.writeItem(.{
   4134             .windows_import_lib = comp.bin_file.options.system_libs.count() - 1,
   4135         });
   4136     }
   4137 }
   4138 
   4139 /// This decides the optimization mode for all zig-provided libraries, including
   4140 /// compiler-rt, libcxx, libc, libunwind, etc.
   4141 pub fn compilerRtOptMode(comp: Compilation) std.builtin.Mode {
   4142     if (comp.debug_compiler_runtime_libs) {
   4143         return comp.bin_file.options.optimize_mode;
   4144     }
   4145     switch (comp.bin_file.options.optimize_mode) {
   4146         .Debug, .ReleaseSafe => return target_util.defaultCompilerRtOptimizeMode(comp.getTarget()),
   4147         .ReleaseFast => return .ReleaseFast,
   4148         .ReleaseSmall => return .ReleaseSmall,
   4149     }
   4150 }
   4151 
   4152 /// This decides whether to strip debug info for all zig-provided libraries, including
   4153 /// compiler-rt, libcxx, libc, libunwind, etc.
   4154 pub fn compilerRtStrip(comp: Compilation) bool {
   4155     if (comp.debug_compiler_runtime_libs) {
   4156         return comp.bin_file.options.strip;
   4157     } else {
   4158         return true;
   4159     }
   4160 }