zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

blob 57504d97 (261344B) - Raw


      1 const Compilation = @This();
      2 
      3 const std = @import("std");
      4 const builtin = @import("builtin");
      5 const mem = std.mem;
      6 const Allocator = std.mem.Allocator;
      7 const assert = std.debug.assert;
      8 const log = std.log.scoped(.compilation);
      9 const Target = std.Target;
     10 const ThreadPool = std.Thread.Pool;
     11 const WaitGroup = std.Thread.WaitGroup;
     12 const ErrorBundle = std.zig.ErrorBundle;
     13 
     14 const Value = @import("value.zig").Value;
     15 const Type = @import("type.zig").Type;
     16 const target_util = @import("target.zig");
     17 const Package = @import("Package.zig");
     18 const link = @import("link.zig");
     19 const tracy = @import("tracy.zig");
     20 const trace = tracy.trace;
     21 const build_options = @import("build_options");
     22 const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
     23 const glibc = @import("glibc.zig");
     24 const musl = @import("musl.zig");
     25 const mingw = @import("mingw.zig");
     26 const libunwind = @import("libunwind.zig");
     27 const libcxx = @import("libcxx.zig");
     28 const wasi_libc = @import("wasi_libc.zig");
     29 const fatal = @import("main.zig").fatal;
     30 const clangMain = @import("main.zig").clangMain;
     31 const Module = @import("Module.zig");
     32 const InternPool = @import("InternPool.zig");
     33 const BuildId = std.Build.CompileStep.BuildId;
     34 const Cache = std.Build.Cache;
     35 const translate_c = @import("translate_c.zig");
     36 const clang = @import("clang.zig");
     37 const c_codegen = @import("codegen/c.zig");
     38 const libtsan = @import("libtsan.zig");
     39 const Zir = @import("Zir.zig");
     40 const Autodoc = @import("Autodoc.zig");
     41 const Color = @import("main.zig").Color;
     42 const resinator = @import("resinator.zig");
     43 
     44 /// General-purpose allocator. Used for both temporary and long-term storage.
     45 gpa: Allocator,
     46 /// Arena-allocated memory used during initialization. Should be untouched until deinit.
     47 arena_state: std.heap.ArenaAllocator.State,
     48 bin_file: *link.File,
     49 c_object_table: std.AutoArrayHashMapUnmanaged(*CObject, void) = .{},
     50 win32_resource_table: std.AutoArrayHashMapUnmanaged(*Win32Resource, void) = .{},
     51 /// This is a pointer to a local variable inside `update()`.
     52 whole_cache_manifest: ?*Cache.Manifest = null,
     53 whole_cache_manifest_mutex: std.Thread.Mutex = .{},
     54 
     55 link_error_flags: link.File.ErrorFlags = .{},
     56 lld_errors: std.ArrayListUnmanaged(LldError) = .{},
     57 
     58 work_queue: std.fifo.LinearFifo(Job, .Dynamic),
     59 anon_work_queue: std.fifo.LinearFifo(Job, .Dynamic),
     60 
     61 /// These jobs are to invoke the Clang compiler to create an object file, which
     62 /// gets linked with the Compilation.
     63 c_object_work_queue: std.fifo.LinearFifo(*CObject, .Dynamic),
     64 
     65 /// These jobs are to invoke the RC compiler to create a compiled resource file (.res), which
     66 /// gets linked with the Compilation.
     67 win32_resource_work_queue: std.fifo.LinearFifo(*Win32Resource, .Dynamic),
     68 
     69 /// These jobs are to tokenize, parse, and astgen files, which may be outdated
     70 /// since the last compilation, as well as scan for `@import` and queue up
     71 /// additional jobs corresponding to those new files.
     72 astgen_work_queue: std.fifo.LinearFifo(*Module.File, .Dynamic),
     73 /// These jobs are to inspect the file system stat() and if the embedded file has changed
     74 /// on disk, mark the corresponding Decl outdated and queue up an `analyze_decl`
     75 /// task for it.
     76 embed_file_work_queue: std.fifo.LinearFifo(*Module.EmbedFile, .Dynamic),
     77 
     78 /// The ErrorMsg memory is owned by the `CObject`, using Compilation's general purpose allocator.
     79 /// This data is accessed by multiple threads and is protected by `mutex`.
     80 failed_c_objects: std.AutoArrayHashMapUnmanaged(*CObject, *CObject.ErrorMsg) = .{},
     81 
     82 /// The ErrorBundle memory is owned by the `Win32Resource`, using Compilation's general purpose allocator.
     83 /// This data is accessed by multiple threads and is protected by `mutex`.
     84 failed_win32_resources: std.AutoArrayHashMapUnmanaged(*Win32Resource, ErrorBundle) = .{},
     85 
     86 /// Miscellaneous things that can fail.
     87 misc_failures: std.AutoArrayHashMapUnmanaged(MiscTask, MiscError) = .{},
     88 
     89 keep_source_files_loaded: bool,
     90 use_clang: bool,
     91 sanitize_c: bool,
     92 /// When this is `true` it means invoking clang as a sub-process is expected to inherit
     93 /// stdin, stdout, stderr, and if it returns non success, to forward the exit code.
     94 /// Otherwise we attempt to parse the error messages and expose them via the Compilation API.
     95 /// This is `true` for `zig cc`, `zig c++`, and `zig translate-c`.
     96 clang_passthrough_mode: bool,
     97 clang_preprocessor_mode: ClangPreprocessorMode,
     98 /// Whether to print clang argvs to stdout.
     99 verbose_cc: bool,
    100 verbose_air: bool,
    101 verbose_intern_pool: bool,
    102 verbose_generic_instances: bool,
    103 verbose_llvm_ir: ?[]const u8,
    104 verbose_llvm_bc: ?[]const u8,
    105 verbose_cimport: bool,
    106 verbose_llvm_cpu_features: bool,
    107 disable_c_depfile: bool,
    108 time_report: bool,
    109 stack_report: bool,
    110 unwind_tables: bool,
    111 test_evented_io: bool,
    112 debug_compiler_runtime_libs: bool,
    113 debug_compile_errors: bool,
    114 job_queued_compiler_rt_lib: bool = false,
    115 job_queued_compiler_rt_obj: bool = false,
    116 alloc_failure_occurred: bool = false,
    117 formatted_panics: bool = false,
    118 last_update_was_cache_hit: bool = false,
    119 
    120 c_source_files: []const CSourceFile,
    121 clang_argv: []const []const u8,
    122 rc_source_files: []const RcSourceFile,
    123 cache_parent: *Cache,
    124 /// Path to own executable for invoking `zig clang`.
    125 self_exe_path: ?[]const u8,
    126 /// null means -fno-emit-bin.
    127 /// This is mutable memory allocated into the Compilation-lifetime arena (`arena_state`)
    128 /// of exactly the correct size for "o/[digest]/[basename]".
    129 /// The basename is of the outputted binary file in case we don't know the directory yet.
    130 whole_bin_sub_path: ?[]u8,
    131 /// Same as `whole_bin_sub_path` but for implibs.
    132 whole_implib_sub_path: ?[]u8,
    133 whole_docs_sub_path: ?[]u8,
    134 zig_lib_directory: Directory,
    135 local_cache_directory: Directory,
    136 global_cache_directory: Directory,
    137 libc_include_dir_list: []const []const u8,
    138 libc_framework_dir_list: []const []const u8,
    139 rc_include_dir_list: []const []const u8,
    140 thread_pool: *ThreadPool,
    141 
    142 /// Populated when we build the libc++ static library. A Job to build this is placed in the queue
    143 /// and resolved before calling linker.flush().
    144 libcxx_static_lib: ?CRTFile = null,
    145 /// Populated when we build the libc++abi static library. A Job to build this is placed in the queue
    146 /// and resolved before calling linker.flush().
    147 libcxxabi_static_lib: ?CRTFile = null,
    148 /// Populated when we build the libunwind static library. A Job to build this is placed in the queue
    149 /// and resolved before calling linker.flush().
    150 libunwind_static_lib: ?CRTFile = null,
    151 /// Populated when we build the TSAN static library. A Job to build this is placed in the queue
    152 /// and resolved before calling linker.flush().
    153 tsan_static_lib: ?CRTFile = null,
    154 /// Populated when we build the libssp static library. A Job to build this is placed in the queue
    155 /// and resolved before calling linker.flush().
    156 libssp_static_lib: ?CRTFile = null,
    157 /// Populated when we build the libc static library. A Job to build this is placed in the queue
    158 /// and resolved before calling linker.flush().
    159 libc_static_lib: ?CRTFile = null,
    160 /// Populated when we build the libcompiler_rt static library. A Job to build this is indicated
    161 /// by setting `job_queued_compiler_rt_lib` and resolved before calling linker.flush().
    162 compiler_rt_lib: ?CRTFile = null,
    163 /// Populated when we build the compiler_rt_obj object. A Job to build this is indicated
    164 /// by setting `job_queued_compiler_rt_obj` and resolved before calling linker.flush().
    165 compiler_rt_obj: ?CRTFile = null,
    166 
    167 glibc_so_files: ?glibc.BuiltSharedObjects = null,
    168 
    169 /// For example `Scrt1.o` and `libc_nonshared.a`. These are populated after building libc from source,
    170 /// The set of needed CRT (C runtime) files differs depending on the target and compilation settings.
    171 /// The key is the basename, and the value is the absolute path to the completed build artifact.
    172 crt_files: std.StringHashMapUnmanaged(CRTFile) = .{},
    173 
    174 /// Keeping track of this possibly open resource so we can close it later.
    175 owned_link_dir: ?std.fs.Dir,
    176 
    177 /// This is for stage1 and should be deleted upon completion of self-hosting.
    178 /// Don't use this for anything other than stage1 compatibility.
    179 color: Color = .auto,
    180 
    181 /// How many lines of reference trace should be included per compile error.
    182 /// Null means only show snippet on first error.
    183 reference_trace: ?u32 = null,
    184 
    185 libcxx_abi_version: libcxx.AbiVersion = libcxx.AbiVersion.default,
    186 
    187 /// This mutex guards all `Compilation` mutable state.
    188 mutex: std.Thread.Mutex = .{},
    189 
    190 test_filter: ?[]const u8,
    191 test_name_prefix: ?[]const u8,
    192 
    193 emit_asm: ?EmitLoc,
    194 emit_llvm_ir: ?EmitLoc,
    195 emit_llvm_bc: ?EmitLoc,
    196 
    197 work_queue_wait_group: WaitGroup = .{},
    198 astgen_wait_group: WaitGroup = .{},
    199 
    200 pub const default_stack_protector_buffer_size = 4;
    201 pub const SemaError = Module.SemaError;
    202 
    203 pub const CRTFile = struct {
    204     lock: Cache.Lock,
    205     full_object_path: []const u8,
    206 
    207     pub fn deinit(self: *CRTFile, gpa: Allocator) void {
    208         self.lock.release();
    209         gpa.free(self.full_object_path);
    210         self.* = undefined;
    211     }
    212 };
    213 
    214 // supported languages for "zig clang -x <lang>".
    215 // Loosely based on llvm-project/clang/include/clang/Driver/Types.def
    216 pub const LangToExt = std.ComptimeStringMap(FileExt, .{
    217     .{ "c", .c },
    218     .{ "c-header", .h },
    219     .{ "c++", .cpp },
    220     .{ "c++-header", .h },
    221     .{ "objective-c", .m },
    222     .{ "objective-c-header", .h },
    223     .{ "objective-c++", .mm },
    224     .{ "objective-c++-header", .h },
    225     .{ "assembler", .assembly },
    226     .{ "assembler-with-cpp", .assembly_with_cpp },
    227     .{ "cuda", .cu },
    228 });
    229 
    230 /// For passing to a C compiler.
    231 pub const CSourceFile = struct {
    232     src_path: []const u8,
    233     extra_flags: []const []const u8 = &.{},
    234     /// Same as extra_flags except they are not added to the Cache hash.
    235     cache_exempt_flags: []const []const u8 = &.{},
    236     // this field is non-null iff language was explicitly set with "-x lang".
    237     ext: ?FileExt = null,
    238 };
    239 
    240 /// For passing to resinator.
    241 pub const RcSourceFile = struct {
    242     src_path: []const u8,
    243     extra_flags: []const []const u8 = &.{},
    244 };
    245 
    246 pub const RcIncludes = enum {
    247     /// Use MSVC if available, fall back to MinGW.
    248     any,
    249     /// Use MSVC include paths (MSVC install + Windows SDK, must be present on the system).
    250     msvc,
    251     /// Use MinGW include paths (distributed with Zig).
    252     gnu,
    253     /// Do not use any autodetected include paths.
    254     none,
    255 };
    256 
    257 const Job = union(enum) {
    258     /// Write the constant value for a Decl to the output file.
    259     codegen_decl: Module.Decl.Index,
    260     /// Write the machine code for a function to the output file.
    261     /// This will either be a non-generic `func_decl` or a `func_instance`.
    262     codegen_func: InternPool.Index,
    263     /// Render the .h file snippet for the Decl.
    264     emit_h_decl: Module.Decl.Index,
    265     /// The Decl needs to be analyzed and possibly export itself.
    266     /// It may have already be analyzed, or it may have been determined
    267     /// to be outdated; in this case perform semantic analysis again.
    268     analyze_decl: Module.Decl.Index,
    269     /// The file that was loaded with `@embedFile` has changed on disk
    270     /// and has been re-loaded into memory. All Decls that depend on it
    271     /// need to be re-analyzed.
    272     update_embed_file: *Module.EmbedFile,
    273     /// The source file containing the Decl has been updated, and so the
    274     /// Decl may need its line number information updated in the debug info.
    275     update_line_number: Module.Decl.Index,
    276     /// The main source file for the package needs to be analyzed.
    277     analyze_pkg: *Package,
    278 
    279     /// one of the glibc static objects
    280     glibc_crt_file: glibc.CRTFile,
    281     /// all of the glibc shared objects
    282     glibc_shared_objects,
    283     /// one of the musl static objects
    284     musl_crt_file: musl.CRTFile,
    285     /// one of the mingw-w64 static objects
    286     mingw_crt_file: mingw.CRTFile,
    287     /// libunwind.a, usually needed when linking libc
    288     libunwind: void,
    289     libcxx: void,
    290     libcxxabi: void,
    291     libtsan: void,
    292     libssp: void,
    293     /// needed when not linking libc and using LLVM for code generation because it generates
    294     /// calls to, for example, memcpy and memset.
    295     zig_libc: void,
    296     /// one of WASI libc static objects
    297     wasi_libc_crt_file: wasi_libc.CRTFile,
    298 
    299     /// The value is the index into `link.File.Options.system_libs`.
    300     windows_import_lib: usize,
    301 };
    302 
    303 pub const CObject = struct {
    304     /// Relative to cwd. Owned by arena.
    305     src: CSourceFile,
    306     status: union(enum) {
    307         new,
    308         success: struct {
    309             /// The outputted result. Owned by gpa.
    310             object_path: []u8,
    311             /// This is a file system lock on the cache hash manifest representing this
    312             /// object. It prevents other invocations of the Zig compiler from interfering
    313             /// with this object until released.
    314             lock: Cache.Lock,
    315         },
    316         /// There will be a corresponding ErrorMsg in Compilation.failed_c_objects.
    317         failure,
    318         /// A transient failure happened when trying to compile the C Object; it may
    319         /// succeed if we try again. There may be a corresponding ErrorMsg in
    320         /// Compilation.failed_c_objects. If there is not, the failure is out of memory.
    321         failure_retryable,
    322     },
    323 
    324     pub const ErrorMsg = struct {
    325         msg: []const u8,
    326         line: u32,
    327         column: u32,
    328 
    329         pub fn destroy(em: *ErrorMsg, gpa: Allocator) void {
    330             gpa.free(em.msg);
    331             gpa.destroy(em);
    332         }
    333     };
    334 
    335     /// Returns if there was failure.
    336     pub fn clearStatus(self: *CObject, gpa: Allocator) bool {
    337         switch (self.status) {
    338             .new => return false,
    339             .failure, .failure_retryable => {
    340                 self.status = .new;
    341                 return true;
    342             },
    343             .success => |*success| {
    344                 gpa.free(success.object_path);
    345                 success.lock.release();
    346                 self.status = .new;
    347                 return false;
    348             },
    349         }
    350     }
    351 
    352     pub fn destroy(self: *CObject, gpa: Allocator) void {
    353         _ = self.clearStatus(gpa);
    354         gpa.destroy(self);
    355     }
    356 };
    357 
    358 pub const Win32Resource = struct {
    359     /// Relative to cwd. Owned by arena.
    360     src: RcSourceFile,
    361     status: union(enum) {
    362         new,
    363         success: struct {
    364             /// The outputted result. Owned by gpa.
    365             res_path: []u8,
    366             /// This is a file system lock on the cache hash manifest representing this
    367             /// object. It prevents other invocations of the Zig compiler from interfering
    368             /// with this object until released.
    369             lock: Cache.Lock,
    370         },
    371         /// There will be a corresponding ErrorMsg in Compilation.failed_win32_resources.
    372         failure,
    373         /// A transient failure happened when trying to compile the resource file; it may
    374         /// succeed if we try again. There may be a corresponding ErrorMsg in
    375         /// Compilation.failed_win32_resources. If there is not, the failure is out of memory.
    376         failure_retryable,
    377     },
    378 
    379     /// Returns true if there was failure.
    380     pub fn clearStatus(self: *Win32Resource, gpa: Allocator) bool {
    381         switch (self.status) {
    382             .new => return false,
    383             .failure, .failure_retryable => {
    384                 self.status = .new;
    385                 return true;
    386             },
    387             .success => |*success| {
    388                 gpa.free(success.res_path);
    389                 success.lock.release();
    390                 self.status = .new;
    391                 return false;
    392             },
    393         }
    394     }
    395 
    396     pub fn destroy(self: *Win32Resource, gpa: Allocator) void {
    397         _ = self.clearStatus(gpa);
    398         gpa.destroy(self);
    399     }
    400 };
    401 
    402 pub const MiscTask = enum {
    403     write_builtin_zig,
    404     glibc_crt_file,
    405     glibc_shared_objects,
    406     musl_crt_file,
    407     mingw_crt_file,
    408     windows_import_lib,
    409     libunwind,
    410     libcxx,
    411     libcxxabi,
    412     libtsan,
    413     wasi_libc_crt_file,
    414     compiler_rt,
    415     libssp,
    416     zig_libc,
    417     analyze_pkg,
    418 
    419     @"musl crti.o",
    420     @"musl crtn.o",
    421     @"musl crt1.o",
    422     @"musl rcrt1.o",
    423     @"musl Scrt1.o",
    424     @"musl libc.a",
    425     @"musl libc.so",
    426 
    427     @"wasi crt1-reactor.o",
    428     @"wasi crt1-command.o",
    429     @"wasi libc.a",
    430     @"libwasi-emulated-process-clocks.a",
    431     @"libwasi-emulated-getpid.a",
    432     @"libwasi-emulated-mman.a",
    433     @"libwasi-emulated-signal.a",
    434 
    435     @"glibc crti.o",
    436     @"glibc crtn.o",
    437     @"glibc Scrt1.o",
    438     @"glibc libc_nonshared.a",
    439     @"glibc shared object",
    440 
    441     @"mingw-w64 crt2.o",
    442     @"mingw-w64 dllcrt2.o",
    443     @"mingw-w64 mingw32.lib",
    444     @"mingw-w64 msvcrt-os.lib",
    445     @"mingw-w64 mingwex.lib",
    446     @"mingw-w64 uuid.lib",
    447 };
    448 
    449 pub const MiscError = struct {
    450     /// Allocated with gpa.
    451     msg: []u8,
    452     children: ?ErrorBundle = null,
    453 
    454     pub fn deinit(misc_err: *MiscError, gpa: Allocator) void {
    455         gpa.free(misc_err.msg);
    456         if (misc_err.children) |*children| {
    457             children.deinit(gpa);
    458         }
    459         misc_err.* = undefined;
    460     }
    461 };
    462 
    463 pub const LldError = struct {
    464     /// Allocated with gpa.
    465     msg: []const u8,
    466     context_lines: []const []const u8 = &.{},
    467 
    468     pub fn deinit(self: *LldError, gpa: Allocator) void {
    469         for (self.context_lines) |line| {
    470             gpa.free(line);
    471         }
    472 
    473         gpa.free(self.context_lines);
    474         gpa.free(self.msg);
    475     }
    476 };
    477 
    478 pub const Directory = Cache.Directory;
    479 
    480 pub const EmitLoc = struct {
    481     /// If this is `null` it means the file will be output to the cache directory.
    482     /// When provided, both the open file handle and the path name must outlive the `Compilation`.
    483     directory: ?Compilation.Directory,
    484     /// This may not have sub-directories in it.
    485     basename: []const u8,
    486 };
    487 
    488 pub const cache_helpers = struct {
    489     pub fn addEmitLoc(hh: *Cache.HashHelper, emit_loc: EmitLoc) void {
    490         hh.addBytes(emit_loc.basename);
    491     }
    492 
    493     pub fn addOptionalEmitLoc(hh: *Cache.HashHelper, optional_emit_loc: ?EmitLoc) void {
    494         hh.add(optional_emit_loc != null);
    495         addEmitLoc(hh, optional_emit_loc orelse return);
    496     }
    497 
    498     pub fn hashCSource(self: *Cache.Manifest, c_source: Compilation.CSourceFile) !void {
    499         _ = try self.addFile(c_source.src_path, null);
    500         // Hash the extra flags, with special care to call addFile for file parameters.
    501         // TODO this logic can likely be improved by utilizing clang_options_data.zig.
    502         const file_args = [_][]const u8{"-include"};
    503         var arg_i: usize = 0;
    504         while (arg_i < c_source.extra_flags.len) : (arg_i += 1) {
    505             const arg = c_source.extra_flags[arg_i];
    506             self.hash.addBytes(arg);
    507             for (file_args) |file_arg| {
    508                 if (mem.eql(u8, file_arg, arg) and arg_i + 1 < c_source.extra_flags.len) {
    509                     arg_i += 1;
    510                     _ = try self.addFile(c_source.extra_flags[arg_i], null);
    511                 }
    512             }
    513         }
    514     }
    515 };
    516 
    517 pub const ClangPreprocessorMode = enum {
    518     no,
    519     /// This means we are doing `zig cc -E -o <path>`.
    520     yes,
    521     /// This means we are doing `zig cc -E`.
    522     stdout,
    523 };
    524 
    525 pub const Framework = link.Framework;
    526 pub const SystemLib = link.SystemLib;
    527 pub const CacheMode = link.CacheMode;
    528 
    529 pub const LinkObject = struct {
    530     path: []const u8,
    531     must_link: bool = false,
    532     // When the library is passed via a positional argument, it will be
    533     // added as a full path. If it's `-l<lib>`, then just the basename.
    534     //
    535     // Consistent with `withLOption` variable name in lld ELF driver.
    536     loption: bool = false,
    537 };
    538 
    539 pub const InitOptions = struct {
    540     zig_lib_directory: Directory,
    541     local_cache_directory: Directory,
    542     global_cache_directory: Directory,
    543     target: Target,
    544     root_name: []const u8,
    545     main_pkg: ?*Package,
    546     output_mode: std.builtin.OutputMode,
    547     thread_pool: *ThreadPool,
    548     dynamic_linker: ?[]const u8 = null,
    549     sysroot: ?[]const u8 = null,
    550     /// `null` means to not emit a binary file.
    551     emit_bin: ?EmitLoc,
    552     /// `null` means to not emit a C header file.
    553     emit_h: ?EmitLoc = null,
    554     /// `null` means to not emit assembly.
    555     emit_asm: ?EmitLoc = null,
    556     /// `null` means to not emit LLVM IR.
    557     emit_llvm_ir: ?EmitLoc = null,
    558     /// `null` means to not emit LLVM module bitcode.
    559     emit_llvm_bc: ?EmitLoc = null,
    560     /// `null` means to not emit docs.
    561     emit_docs: ?EmitLoc = null,
    562     /// `null` means to not emit an import lib.
    563     emit_implib: ?EmitLoc = null,
    564     link_mode: ?std.builtin.LinkMode = null,
    565     dll_export_fns: ?bool = false,
    566     /// Normally when using LLD to link, Zig uses a file named "lld.id" in the
    567     /// same directory as the output binary which contains the hash of the link
    568     /// operation, allowing Zig to skip linking when the hash would be unchanged.
    569     /// In the case that the output binary is being emitted into a directory which
    570     /// is externally modified - essentially anything other than zig-cache - then
    571     /// this flag would be set to disable this machinery to avoid false positives.
    572     disable_lld_caching: bool = false,
    573     cache_mode: CacheMode = .incremental,
    574     optimize_mode: std.builtin.OptimizeMode = .Debug,
    575     keep_source_files_loaded: bool = false,
    576     clang_argv: []const []const u8 = &[0][]const u8{},
    577     lib_dirs: []const []const u8 = &[0][]const u8{},
    578     rpath_list: []const []const u8 = &[0][]const u8{},
    579     symbol_wrap_set: std.StringArrayHashMapUnmanaged(void) = .{},
    580     c_source_files: []const CSourceFile = &[0]CSourceFile{},
    581     rc_source_files: []const RcSourceFile = &[0]RcSourceFile{},
    582     rc_includes: RcIncludes = .any,
    583     link_objects: []LinkObject = &[0]LinkObject{},
    584     framework_dirs: []const []const u8 = &[0][]const u8{},
    585     frameworks: []const Framework = &.{},
    586     system_lib_names: []const []const u8 = &.{},
    587     system_lib_infos: []const SystemLib = &.{},
    588     /// These correspond to the WASI libc emulated subcomponents including:
    589     /// * process clocks
    590     /// * getpid
    591     /// * mman
    592     /// * signal
    593     wasi_emulated_libs: []const wasi_libc.CRTFile = &[0]wasi_libc.CRTFile{},
    594     link_libc: bool = false,
    595     link_libcpp: bool = false,
    596     link_libunwind: bool = false,
    597     want_pic: ?bool = null,
    598     /// This means that if the output mode is an executable it will be a
    599     /// Position Independent Executable. If the output mode is not an
    600     /// executable this field is ignored.
    601     want_pie: ?bool = null,
    602     want_sanitize_c: ?bool = null,
    603     want_stack_check: ?bool = null,
    604     /// null means default.
    605     /// 0 means no stack protector.
    606     /// other number means stack protection with that buffer size.
    607     want_stack_protector: ?u32 = null,
    608     want_red_zone: ?bool = null,
    609     omit_frame_pointer: ?bool = null,
    610     want_valgrind: ?bool = null,
    611     want_tsan: ?bool = null,
    612     want_compiler_rt: ?bool = null,
    613     want_lto: ?bool = null,
    614     want_unwind_tables: ?bool = null,
    615     use_llvm: ?bool = null,
    616     use_lib_llvm: ?bool = null,
    617     use_lld: ?bool = null,
    618     use_clang: ?bool = null,
    619     single_threaded: ?bool = null,
    620     strip: ?bool = null,
    621     formatted_panics: ?bool = null,
    622     rdynamic: bool = false,
    623     function_sections: bool = false,
    624     no_builtin: bool = false,
    625     is_native_os: bool,
    626     is_native_abi: bool,
    627     time_report: bool = false,
    628     stack_report: bool = false,
    629     link_eh_frame_hdr: bool = false,
    630     link_emit_relocs: bool = false,
    631     linker_script: ?[]const u8 = null,
    632     version_script: ?[]const u8 = null,
    633     soname: ?[]const u8 = null,
    634     linker_gc_sections: ?bool = null,
    635     linker_allow_shlib_undefined: ?bool = null,
    636     linker_bind_global_refs_locally: ?bool = null,
    637     linker_import_memory: ?bool = null,
    638     linker_export_memory: ?bool = null,
    639     linker_import_symbols: bool = false,
    640     linker_import_table: bool = false,
    641     linker_export_table: bool = false,
    642     linker_initial_memory: ?u64 = null,
    643     linker_max_memory: ?u64 = null,
    644     linker_shared_memory: bool = false,
    645     linker_global_base: ?u64 = null,
    646     linker_export_symbol_names: []const []const u8 = &.{},
    647     linker_print_gc_sections: bool = false,
    648     linker_print_icf_sections: bool = false,
    649     linker_print_map: bool = false,
    650     linker_opt_bisect_limit: i32 = -1,
    651     each_lib_rpath: ?bool = null,
    652     build_id: ?BuildId = null,
    653     disable_c_depfile: bool = false,
    654     linker_z_nodelete: bool = false,
    655     linker_z_notext: bool = false,
    656     linker_z_defs: bool = false,
    657     linker_z_origin: bool = false,
    658     linker_z_now: bool = true,
    659     linker_z_relro: bool = true,
    660     linker_z_nocopyreloc: bool = false,
    661     linker_z_common_page_size: ?u64 = null,
    662     linker_z_max_page_size: ?u64 = null,
    663     linker_tsaware: bool = false,
    664     linker_nxcompat: bool = false,
    665     linker_dynamicbase: bool = true,
    666     linker_optimization: ?u8 = null,
    667     linker_compress_debug_sections: ?link.CompressDebugSections = null,
    668     linker_module_definition_file: ?[]const u8 = null,
    669     linker_sort_section: ?link.SortSection = null,
    670     major_subsystem_version: ?u32 = null,
    671     minor_subsystem_version: ?u32 = null,
    672     clang_passthrough_mode: bool = false,
    673     verbose_cc: bool = false,
    674     verbose_link: bool = false,
    675     verbose_air: bool = false,
    676     verbose_intern_pool: bool = false,
    677     verbose_generic_instances: bool = false,
    678     verbose_llvm_ir: ?[]const u8 = null,
    679     verbose_llvm_bc: ?[]const u8 = null,
    680     verbose_cimport: bool = false,
    681     verbose_llvm_cpu_features: bool = false,
    682     is_test: bool = false,
    683     test_evented_io: bool = false,
    684     debug_compiler_runtime_libs: bool = false,
    685     debug_compile_errors: bool = false,
    686     /// Normally when you create a `Compilation`, Zig will automatically build
    687     /// and link in required dependencies, such as compiler-rt and libc. When
    688     /// building such dependencies themselves, this flag must be set to avoid
    689     /// infinite recursion.
    690     skip_linker_dependencies: bool = false,
    691     parent_compilation_link_libc: bool = false,
    692     hash_style: link.HashStyle = .both,
    693     entry: ?[]const u8 = null,
    694     force_undefined_symbols: std.StringArrayHashMapUnmanaged(void) = .{},
    695     stack_size_override: ?u64 = null,
    696     image_base_override: ?u64 = null,
    697     self_exe_path: ?[]const u8 = null,
    698     version: ?std.SemanticVersion = null,
    699     compatibility_version: ?std.SemanticVersion = null,
    700     libc_installation: ?*const LibCInstallation = null,
    701     machine_code_model: std.builtin.CodeModel = .default,
    702     clang_preprocessor_mode: ClangPreprocessorMode = .no,
    703     /// This is for stage1 and should be deleted upon completion of self-hosting.
    704     color: Color = .auto,
    705     reference_trace: ?u32 = null,
    706     error_tracing: ?bool = null,
    707     test_filter: ?[]const u8 = null,
    708     test_name_prefix: ?[]const u8 = null,
    709     test_runner_path: ?[]const u8 = null,
    710     subsystem: ?std.Target.SubSystem = null,
    711     dwarf_format: ?std.dwarf.Format = null,
    712     /// WASI-only. Type of WASI execution model ("command" or "reactor").
    713     wasi_exec_model: ?std.builtin.WasiExecModel = null,
    714     /// (Zig compiler development) Enable dumping linker's state as JSON.
    715     enable_link_snapshots: bool = false,
    716     /// (Darwin) Install name of the dylib
    717     install_name: ?[]const u8 = null,
    718     /// (Darwin) Path to entitlements file
    719     entitlements: ?[]const u8 = null,
    720     /// (Darwin) size of the __PAGEZERO segment
    721     pagezero_size: ?u64 = null,
    722     /// (Darwin) set minimum space for future expansion of the load commands
    723     headerpad_size: ?u32 = null,
    724     /// (Darwin) set enough space as if all paths were MATPATHLEN
    725     headerpad_max_install_names: bool = false,
    726     /// (Darwin) remove dylibs that are unreachable by the entry point or exported symbols
    727     dead_strip_dylibs: bool = false,
    728     libcxx_abi_version: libcxx.AbiVersion = libcxx.AbiVersion.default,
    729     /// (Windows) PDB source path prefix to instruct the linker how to resolve relative
    730     /// paths when consolidating CodeView streams into a single PDB file.
    731     pdb_source_path: ?[]const u8 = null,
    732     /// (Windows) PDB output path
    733     pdb_out_path: ?[]const u8 = null,
    734 };
    735 
    736 fn addPackageTableToCacheHash(
    737     hash: *Cache.HashHelper,
    738     arena: *std.heap.ArenaAllocator,
    739     pkg_table: Package.Table,
    740     seen_table: *std.AutoHashMap(*Package, void),
    741     hash_type: union(enum) { path_bytes, files: *Cache.Manifest },
    742 ) (error{OutOfMemory} || std.os.GetCwdError)!void {
    743     const allocator = arena.allocator();
    744 
    745     const packages = try allocator.alloc(Package.Table.KV, pkg_table.count());
    746     {
    747         // Copy over the hashmap entries to our slice
    748         var table_it = pkg_table.iterator();
    749         var idx: usize = 0;
    750         while (table_it.next()) |entry| : (idx += 1) {
    751             packages[idx] = .{
    752                 .key = entry.key_ptr.*,
    753                 .value = entry.value_ptr.*,
    754             };
    755         }
    756     }
    757     // Sort the slice by package name
    758     mem.sort(Package.Table.KV, packages, {}, struct {
    759         fn lessThan(_: void, lhs: Package.Table.KV, rhs: Package.Table.KV) bool {
    760             return std.mem.lessThan(u8, lhs.key, rhs.key);
    761         }
    762     }.lessThan);
    763 
    764     for (packages) |pkg| {
    765         if ((try seen_table.getOrPut(pkg.value)).found_existing) continue;
    766 
    767         // Finally insert the package name and path to the cache hash.
    768         hash.addBytes(pkg.key);
    769         switch (hash_type) {
    770             .path_bytes => {
    771                 hash.addBytes(pkg.value.root_src_path);
    772                 hash.addOptionalBytes(pkg.value.root_src_directory.path);
    773             },
    774             .files => |man| {
    775                 const pkg_zig_file = try pkg.value.root_src_directory.join(allocator, &[_][]const u8{
    776                     pkg.value.root_src_path,
    777                 });
    778                 _ = try man.addFile(pkg_zig_file, null);
    779             },
    780         }
    781         // Recurse to handle the package's dependencies
    782         try addPackageTableToCacheHash(hash, arena, pkg.value.table, seen_table, hash_type);
    783     }
    784 }
    785 
    786 pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
    787     const is_dyn_lib = switch (options.output_mode) {
    788         .Obj, .Exe => false,
    789         .Lib => (options.link_mode orelse .Static) == .Dynamic,
    790     };
    791     const is_exe_or_dyn_lib = switch (options.output_mode) {
    792         .Obj => false,
    793         .Lib => is_dyn_lib,
    794         .Exe => true,
    795     };
    796 
    797     const needs_c_symbols = !options.skip_linker_dependencies and is_exe_or_dyn_lib;
    798 
    799     // WASI-only. Resolve the optional exec-model option, defaults to command.
    800     const wasi_exec_model = if (options.target.os.tag != .wasi) undefined else options.wasi_exec_model orelse .command;
    801 
    802     if (options.linker_export_table and options.linker_import_table) {
    803         return error.ExportTableAndImportTableConflict;
    804     }
    805 
    806     // The `have_llvm` condition is here only because native backends cannot yet build compiler-rt.
    807     // Once they are capable this condition could be removed. When removing this condition,
    808     // also test the use case of `build-obj -fcompiler-rt` with the native backends
    809     // and make sure the compiler-rt symbols are emitted.
    810     const is_p9 = options.target.os.tag == .plan9;
    811     const is_spv = options.target.cpu.arch.isSpirV();
    812     const capable_of_building_compiler_rt = build_options.have_llvm and !is_p9 and !is_spv;
    813     const capable_of_building_zig_libc = build_options.have_llvm and !is_p9 and !is_spv;
    814     const capable_of_building_ssp = build_options.have_llvm and !is_p9 and !is_spv;
    815 
    816     const comp: *Compilation = comp: {
    817         // For allocations that have the same lifetime as Compilation. This arena is used only during this
    818         // initialization and then is freed in deinit().
    819         var arena_allocator = std.heap.ArenaAllocator.init(gpa);
    820         errdefer arena_allocator.deinit();
    821         const arena = arena_allocator.allocator();
    822 
    823         // We put the `Compilation` itself in the arena. Freeing the arena will free the module.
    824         // It's initialized later after we prepare the initialization options.
    825         const comp = try arena.create(Compilation);
    826         const root_name = try arena.dupeZ(u8, options.root_name);
    827 
    828         // Make a decision on whether to use LLVM or our own backend.
    829         const use_lib_llvm = options.use_lib_llvm orelse build_options.have_llvm;
    830         const use_llvm = blk: {
    831             if (options.use_llvm) |explicit|
    832                 break :blk explicit;
    833 
    834             // If emitting to LLVM bitcode object format, must use LLVM backend.
    835             if (options.emit_llvm_ir != null or options.emit_llvm_bc != null)
    836                 break :blk true;
    837 
    838             // If we have no zig code to compile, no need for LLVM.
    839             if (options.main_pkg == null)
    840                 break :blk false;
    841 
    842             // If LLVM does not support the target, then we can't use it.
    843             if (!target_util.hasLlvmSupport(options.target, options.target.ofmt))
    844                 break :blk false;
    845 
    846             // Prefer LLVM for release builds.
    847             if (options.optimize_mode != .Debug)
    848                 break :blk true;
    849 
    850             // At this point we would prefer to use our own self-hosted backend,
    851             // because the compilation speed is better than LLVM. But only do it if
    852             // we are confident in the robustness of the backend.
    853             break :blk !target_util.selfHostedBackendIsAsRobustAsLlvm(options.target);
    854         };
    855         if (!use_llvm) {
    856             if (options.use_llvm == true) {
    857                 return error.ZigCompilerNotBuiltWithLLVMExtensions;
    858             }
    859             if (options.emit_llvm_ir != null or options.emit_llvm_bc != null) {
    860                 return error.EmittingLlvmModuleRequiresUsingLlvmBackend;
    861             }
    862         }
    863 
    864         // TODO: once we support incremental compilation for the LLVM backend via
    865         // saving the LLVM module into a bitcode file and restoring it, along with
    866         // compiler state, the second clause here can be removed so that incremental
    867         // cache mode is used for LLVM backend too. We need some fuzz testing before
    868         // that can be enabled.
    869         const cache_mode = if ((use_llvm or options.main_pkg == null) and !options.disable_lld_caching)
    870             CacheMode.whole
    871         else
    872             options.cache_mode;
    873 
    874         const tsan = options.want_tsan orelse false;
    875         // TSAN is implemented in C++ so it requires linking libc++.
    876         const link_libcpp = options.link_libcpp or tsan;
    877         const link_libc = link_libcpp or options.link_libc or options.link_libunwind or
    878             target_util.osRequiresLibC(options.target);
    879 
    880         const link_libunwind = options.link_libunwind or
    881             (link_libcpp and target_util.libcNeedsLibUnwind(options.target));
    882         const unwind_tables = options.want_unwind_tables orelse
    883             (link_libunwind or target_util.needUnwindTables(options.target));
    884         const link_eh_frame_hdr = options.link_eh_frame_hdr or unwind_tables;
    885         const build_id = options.build_id orelse .none;
    886 
    887         // Make a decision on whether to use LLD or our own linker.
    888         const use_lld = options.use_lld orelse blk: {
    889             if (options.target.isDarwin()) {
    890                 break :blk false;
    891             }
    892 
    893             if (!build_options.have_llvm)
    894                 break :blk false;
    895 
    896             if (options.target.ofmt == .c)
    897                 break :blk false;
    898 
    899             if (options.want_lto) |lto| {
    900                 if (lto) {
    901                     break :blk true;
    902                 }
    903             }
    904 
    905             // Our linker can't handle objects or most advanced options yet.
    906             if (options.link_objects.len != 0 or
    907                 options.c_source_files.len != 0 or
    908                 options.frameworks.len != 0 or
    909                 options.system_lib_names.len != 0 or
    910                 options.link_libc or options.link_libcpp or
    911                 link_eh_frame_hdr or
    912                 options.link_emit_relocs or
    913                 options.output_mode == .Lib or
    914                 options.linker_script != null or options.version_script != null or
    915                 options.emit_implib != null or
    916                 build_id != .none or
    917                 options.symbol_wrap_set.count() > 0)
    918             {
    919                 break :blk true;
    920             }
    921 
    922             if (use_llvm) {
    923                 // If stage1 generates an object file, self-hosted linker is not
    924                 // yet sophisticated enough to handle that.
    925                 break :blk options.main_pkg != null;
    926             }
    927 
    928             break :blk false;
    929         };
    930 
    931         const lto = blk: {
    932             if (options.want_lto) |explicit| {
    933                 if (!use_lld and !options.target.isDarwin())
    934                     return error.LtoUnavailableWithoutLld;
    935                 break :blk explicit;
    936             } else if (!use_lld) {
    937                 // TODO zig ld LTO support
    938                 // See https://github.com/ziglang/zig/issues/8680
    939                 break :blk false;
    940             } else if (options.c_source_files.len == 0) {
    941                 break :blk false;
    942             } else if (options.target.cpu.arch.isRISCV()) {
    943                 // Clang and LLVM currently don't support RISC-V target-abi for LTO.
    944                 // Compiling with LTO may fail or produce undesired results.
    945                 // See https://reviews.llvm.org/D71387
    946                 // See https://reviews.llvm.org/D102582
    947                 break :blk false;
    948             } else switch (options.output_mode) {
    949                 .Lib, .Obj => break :blk false,
    950                 .Exe => switch (options.optimize_mode) {
    951                     .Debug => break :blk false,
    952                     .ReleaseSafe, .ReleaseFast, .ReleaseSmall => break :blk true,
    953                 },
    954             }
    955         };
    956 
    957         const must_dynamic_link = dl: {
    958             if (target_util.cannotDynamicLink(options.target))
    959                 break :dl false;
    960             if (is_exe_or_dyn_lib and link_libc and
    961                 (options.target.isGnuLibC() or target_util.osRequiresLibC(options.target)))
    962             {
    963                 break :dl true;
    964             }
    965             const any_dyn_libs: bool = x: {
    966                 if (options.system_lib_names.len != 0)
    967                     break :x true;
    968                 for (options.link_objects) |obj| {
    969                     switch (classifyFileExt(obj.path)) {
    970                         .shared_library => break :x true,
    971                         else => continue,
    972                     }
    973                 }
    974                 break :x false;
    975             };
    976             if (any_dyn_libs) {
    977                 // When creating a executable that links to system libraries,
    978                 // we require dynamic linking, but we must not link static libraries
    979                 // or object files dynamically!
    980                 break :dl (options.output_mode == .Exe);
    981             }
    982 
    983             break :dl false;
    984         };
    985         const default_link_mode: std.builtin.LinkMode = blk: {
    986             if (must_dynamic_link) {
    987                 break :blk .Dynamic;
    988             } else if (is_exe_or_dyn_lib and link_libc and
    989                 options.is_native_abi and options.target.abi.isMusl())
    990             {
    991                 // If targeting the system's native ABI and the system's
    992                 // libc is musl, link dynamically by default.
    993                 break :blk .Dynamic;
    994             } else {
    995                 break :blk .Static;
    996             }
    997         };
    998         const link_mode: std.builtin.LinkMode = if (options.link_mode) |lm| blk: {
    999             if (lm == .Static and must_dynamic_link) {
   1000                 return error.UnableToStaticLink;
   1001             }
   1002             break :blk lm;
   1003         } else default_link_mode;
   1004 
   1005         const dll_export_fns = options.dll_export_fns orelse (is_dyn_lib or options.rdynamic);
   1006 
   1007         const libc_dirs = try detectLibCIncludeDirs(
   1008             arena,
   1009             options.zig_lib_directory.path.?,
   1010             options.target,
   1011             options.is_native_abi,
   1012             link_libc,
   1013             options.libc_installation,
   1014         );
   1015 
   1016         const rc_dirs = try detectWin32ResourceIncludeDirs(
   1017             arena,
   1018             options,
   1019         );
   1020 
   1021         const sysroot = options.sysroot orelse libc_dirs.sysroot;
   1022 
   1023         const must_pie = target_util.requiresPIE(options.target);
   1024         const pie: bool = if (options.want_pie) |explicit| pie: {
   1025             if (!explicit and must_pie) {
   1026                 return error.TargetRequiresPIE;
   1027             }
   1028             break :pie explicit;
   1029         } else must_pie or tsan;
   1030 
   1031         const must_pic: bool = b: {
   1032             if (target_util.requiresPIC(options.target, link_libc))
   1033                 break :b true;
   1034             break :b link_mode == .Dynamic;
   1035         };
   1036         const pic = if (options.want_pic) |explicit| pic: {
   1037             if (!explicit) {
   1038                 if (must_pic) {
   1039                     return error.TargetRequiresPIC;
   1040                 }
   1041                 if (pie) {
   1042                     return error.PIERequiresPIC;
   1043                 }
   1044             }
   1045             break :pic explicit;
   1046         } else pie or must_pic;
   1047 
   1048         // Make a decision on whether to use Clang for translate-c and compiling C files.
   1049         const use_clang = if (options.use_clang) |explicit| explicit else blk: {
   1050             if (build_options.have_llvm) {
   1051                 // Can't use it if we don't have it!
   1052                 break :blk false;
   1053             }
   1054             // It's not planned to do our own translate-c or C compilation.
   1055             break :blk true;
   1056         };
   1057 
   1058         const is_safe_mode = switch (options.optimize_mode) {
   1059             .Debug, .ReleaseSafe => true,
   1060             .ReleaseFast, .ReleaseSmall => false,
   1061         };
   1062 
   1063         const sanitize_c = options.want_sanitize_c orelse is_safe_mode;
   1064 
   1065         const stack_check: bool = options.want_stack_check orelse b: {
   1066             if (!target_util.supportsStackProbing(options.target)) break :b false;
   1067             break :b is_safe_mode;
   1068         };
   1069         if (stack_check and !target_util.supportsStackProbing(options.target))
   1070             return error.StackCheckUnsupportedByTarget;
   1071 
   1072         const stack_protector: u32 = options.want_stack_protector orelse b: {
   1073             if (!target_util.supportsStackProtector(options.target)) break :b @as(u32, 0);
   1074 
   1075             // This logic is checking for linking libc because otherwise our start code
   1076             // which is trying to set up TLS (i.e. the fs/gs registers) but the stack
   1077             // protection code depends on fs/gs registers being already set up.
   1078             // If we were able to annotate start code, or perhaps the entire std lib,
   1079             // as being exempt from stack protection checks, we could change this logic
   1080             // to supporting stack protection even when not linking libc.
   1081             // TODO file issue about this
   1082             if (!link_libc) break :b 0;
   1083             if (!capable_of_building_ssp) break :b 0;
   1084             if (is_safe_mode) break :b default_stack_protector_buffer_size;
   1085             break :b 0;
   1086         };
   1087         if (stack_protector != 0) {
   1088             if (!target_util.supportsStackProtector(options.target))
   1089                 return error.StackProtectorUnsupportedByTarget;
   1090             if (!capable_of_building_ssp)
   1091                 return error.StackProtectorUnsupportedByBackend;
   1092             if (!link_libc)
   1093                 return error.StackProtectorUnavailableWithoutLibC;
   1094         }
   1095 
   1096         const valgrind: bool = b: {
   1097             if (!target_util.hasValgrindSupport(options.target))
   1098                 break :b false;
   1099             break :b options.want_valgrind orelse (options.optimize_mode == .Debug);
   1100         };
   1101 
   1102         const include_compiler_rt = options.want_compiler_rt orelse needs_c_symbols;
   1103 
   1104         const must_single_thread = target_util.isSingleThreaded(options.target);
   1105         const single_threaded = options.single_threaded orelse must_single_thread;
   1106         if (must_single_thread and !single_threaded) {
   1107             return error.TargetRequiresSingleThreaded;
   1108         }
   1109 
   1110         const llvm_cpu_features: ?[*:0]const u8 = if (use_llvm) blk: {
   1111             var buf = std.ArrayList(u8).init(arena);
   1112             for (options.target.cpu.arch.allFeaturesList(), 0..) |feature, index_usize| {
   1113                 const index = @as(Target.Cpu.Feature.Set.Index, @intCast(index_usize));
   1114                 const is_enabled = options.target.cpu.features.isEnabled(index);
   1115 
   1116                 if (feature.llvm_name) |llvm_name| {
   1117                     const plus_or_minus = "-+"[@intFromBool(is_enabled)];
   1118                     try buf.ensureUnusedCapacity(2 + llvm_name.len);
   1119                     buf.appendAssumeCapacity(plus_or_minus);
   1120                     buf.appendSliceAssumeCapacity(llvm_name);
   1121                     buf.appendSliceAssumeCapacity(",");
   1122                 }
   1123             }
   1124             if (buf.items.len == 0) break :blk "";
   1125             assert(mem.endsWith(u8, buf.items, ","));
   1126             buf.items[buf.items.len - 1] = 0;
   1127             buf.shrinkAndFree(buf.items.len);
   1128             break :blk buf.items[0 .. buf.items.len - 1 :0].ptr;
   1129         } else null;
   1130 
   1131         if (options.verbose_llvm_cpu_features) {
   1132             if (llvm_cpu_features) |cf| print: {
   1133                 std.debug.getStderrMutex().lock();
   1134                 defer std.debug.getStderrMutex().unlock();
   1135                 const stderr = std.io.getStdErr().writer();
   1136                 nosuspend stderr.print("compilation: {s}\n", .{options.root_name}) catch break :print;
   1137                 nosuspend stderr.print("  target: {s}\n", .{try options.target.zigTriple(arena)}) catch break :print;
   1138                 nosuspend stderr.print("  cpu: {s}\n", .{options.target.cpu.model.name}) catch break :print;
   1139                 nosuspend stderr.print("  features: {s}\n", .{cf}) catch {};
   1140             }
   1141         }
   1142 
   1143         const strip = options.strip orelse !target_util.hasDebugInfo(options.target);
   1144         const red_zone = options.want_red_zone orelse target_util.hasRedZone(options.target);
   1145         const omit_frame_pointer = options.omit_frame_pointer orelse (options.optimize_mode != .Debug);
   1146         const linker_optimization: u8 = options.linker_optimization orelse switch (options.optimize_mode) {
   1147             .Debug => @as(u8, 0),
   1148             else => @as(u8, 3),
   1149         };
   1150         const formatted_panics = options.formatted_panics orelse (options.optimize_mode == .Debug);
   1151 
   1152         // We put everything into the cache hash that *cannot be modified
   1153         // during an incremental update*. For example, one cannot change the
   1154         // target between updates, but one can change source files, so the
   1155         // target goes into the cache hash, but source files do not. This is so
   1156         // that we can find the same binary and incrementally update it even if
   1157         // there are modified source files. We do this even if outputting to
   1158         // the current directory because we need somewhere to store incremental
   1159         // compilation metadata.
   1160         const cache = try arena.create(Cache);
   1161         cache.* = .{
   1162             .gpa = gpa,
   1163             .manifest_dir = try options.local_cache_directory.handle.makeOpenPath("h", .{}),
   1164         };
   1165         cache.addPrefix(.{ .path = null, .handle = std.fs.cwd() });
   1166         cache.addPrefix(options.zig_lib_directory);
   1167         cache.addPrefix(options.local_cache_directory);
   1168         errdefer cache.manifest_dir.close();
   1169 
   1170         // This is shared hasher state common to zig source and all C source files.
   1171         cache.hash.addBytes(build_options.version);
   1172         cache.hash.add(builtin.zig_backend);
   1173         cache.hash.add(options.optimize_mode);
   1174         cache.hash.add(options.target.cpu.arch);
   1175         cache.hash.addBytes(options.target.cpu.model.name);
   1176         cache.hash.add(options.target.cpu.features.ints);
   1177         cache.hash.add(options.target.os.tag);
   1178         cache.hash.add(options.target.os.getVersionRange());
   1179         cache.hash.add(options.is_native_os);
   1180         cache.hash.add(options.target.abi);
   1181         cache.hash.add(options.target.ofmt);
   1182         cache.hash.add(pic);
   1183         cache.hash.add(pie);
   1184         cache.hash.add(lto);
   1185         cache.hash.add(unwind_tables);
   1186         cache.hash.add(tsan);
   1187         cache.hash.add(stack_check);
   1188         cache.hash.add(stack_protector);
   1189         cache.hash.add(red_zone);
   1190         cache.hash.add(omit_frame_pointer);
   1191         cache.hash.add(link_mode);
   1192         cache.hash.add(options.function_sections);
   1193         cache.hash.add(options.no_builtin);
   1194         cache.hash.add(strip);
   1195         cache.hash.add(link_libc);
   1196         cache.hash.add(link_libcpp);
   1197         cache.hash.add(link_libunwind);
   1198         cache.hash.add(options.output_mode);
   1199         cache.hash.add(options.machine_code_model);
   1200         cache.hash.addOptional(options.dwarf_format);
   1201         cache_helpers.addOptionalEmitLoc(&cache.hash, options.emit_bin);
   1202         cache_helpers.addOptionalEmitLoc(&cache.hash, options.emit_implib);
   1203         cache_helpers.addOptionalEmitLoc(&cache.hash, options.emit_docs);
   1204         cache.hash.addBytes(options.root_name);
   1205         if (options.target.os.tag == .wasi) cache.hash.add(wasi_exec_model);
   1206         // TODO audit this and make sure everything is in it
   1207 
   1208         const module: ?*Module = if (options.main_pkg) |main_pkg| blk: {
   1209             // Options that are specific to zig source files, that cannot be
   1210             // modified between incremental updates.
   1211             var hash = cache.hash;
   1212 
   1213             switch (cache_mode) {
   1214                 .incremental => {
   1215                     // Here we put the root source file path name, but *not* with addFile.
   1216                     // We want the hash to be the same regardless of the contents of the
   1217                     // source file, because incremental compilation will handle it, but we
   1218                     // do want to namespace different source file names because they are
   1219                     // likely different compilations and therefore this would be likely to
   1220                     // cause cache hits.
   1221                     hash.addBytes(main_pkg.root_src_path);
   1222                     hash.addOptionalBytes(main_pkg.root_src_directory.path);
   1223                     {
   1224                         var seen_table = std.AutoHashMap(*Package, void).init(arena);
   1225                         try addPackageTableToCacheHash(&hash, &arena_allocator, main_pkg.table, &seen_table, .path_bytes);
   1226                     }
   1227                 },
   1228                 .whole => {
   1229                     // In this case, we postpone adding the input source file until
   1230                     // we create the cache manifest, in update(), because we want to
   1231                     // track it and packages as files.
   1232                 },
   1233             }
   1234 
   1235             // Synchronize with other matching comments: ZigOnlyHashStuff
   1236             hash.add(valgrind);
   1237             hash.add(single_threaded);
   1238             hash.add(use_llvm);
   1239             hash.add(use_lib_llvm);
   1240             hash.add(dll_export_fns);
   1241             hash.add(options.is_test);
   1242             hash.add(options.test_evented_io);
   1243             hash.addOptionalBytes(options.test_filter);
   1244             hash.addOptionalBytes(options.test_name_prefix);
   1245             hash.add(options.skip_linker_dependencies);
   1246             hash.add(options.parent_compilation_link_libc);
   1247             hash.add(formatted_panics);
   1248 
   1249             // In the case of incremental cache mode, this `zig_cache_artifact_directory`
   1250             // is computed based on a hash of non-linker inputs, and it is where all
   1251             // build artifacts are stored (even while in-progress).
   1252             //
   1253             // For whole cache mode, it is still used for builtin.zig so that the file
   1254             // path to builtin.zig can remain consistent during a debugging session at
   1255             // runtime. However, we don't know where to put outputs from the linker
   1256             // until the final cache hash, which is available after the
   1257             // compilation is complete.
   1258             //
   1259             // Therefore, in whole cache mode, we additionally create a temporary cache
   1260             // directory for these two kinds of build artifacts, and then rename it
   1261             // into place after the final hash is known. However, we don't want
   1262             // to create the temporary directory here, because in the case of a cache hit,
   1263             // this would have been wasted syscalls to make the directory and then not
   1264             // use it (or delete it).
   1265             //
   1266             // In summary, for whole cache mode, we simulate `-fno-emit-bin` in this
   1267             // function, and `zig_cache_artifact_directory` is *wrong* except for builtin.zig,
   1268             // and then at the beginning of `update()` when we find out whether we need
   1269             // a temporary directory, we patch up all the places that the incorrect
   1270             // `zig_cache_artifact_directory` was passed to various components of the compiler.
   1271 
   1272             const digest = hash.final();
   1273             const artifact_sub_dir = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest });
   1274             var artifact_dir = try options.local_cache_directory.handle.makeOpenPath(artifact_sub_dir, .{});
   1275             errdefer artifact_dir.close();
   1276             const zig_cache_artifact_directory: Directory = .{
   1277                 .handle = artifact_dir,
   1278                 .path = try options.local_cache_directory.join(arena, &[_][]const u8{artifact_sub_dir}),
   1279             };
   1280 
   1281             const builtin_pkg = try Package.createWithDir(
   1282                 gpa,
   1283                 zig_cache_artifact_directory,
   1284                 null,
   1285                 "builtin.zig",
   1286             );
   1287             errdefer builtin_pkg.destroy(gpa);
   1288 
   1289             // When you're testing std, the main module is std. In that case, we'll just set the std
   1290             // module to the main one, since avoiding the errors caused by duplicating it is more
   1291             // effort than it's worth.
   1292             const main_pkg_is_std = m: {
   1293                 const std_path = try std.fs.path.resolve(arena, &[_][]const u8{
   1294                     options.zig_lib_directory.path orelse ".",
   1295                     "std",
   1296                     "std.zig",
   1297                 });
   1298                 defer arena.free(std_path);
   1299                 const main_path = try std.fs.path.resolve(arena, &[_][]const u8{
   1300                     main_pkg.root_src_directory.path orelse ".",
   1301                     main_pkg.root_src_path,
   1302                 });
   1303                 defer arena.free(main_path);
   1304                 break :m mem.eql(u8, main_path, std_path);
   1305             };
   1306 
   1307             const std_pkg = if (main_pkg_is_std)
   1308                 main_pkg
   1309             else
   1310                 try Package.createWithDir(
   1311                     gpa,
   1312                     options.zig_lib_directory,
   1313                     "std",
   1314                     "std.zig",
   1315                 );
   1316 
   1317             errdefer if (!main_pkg_is_std) std_pkg.destroy(gpa);
   1318 
   1319             const root_pkg = if (options.is_test) root_pkg: {
   1320                 const test_pkg = if (options.test_runner_path) |test_runner| test_pkg: {
   1321                     const test_dir = std.fs.path.dirname(test_runner);
   1322                     const basename = std.fs.path.basename(test_runner);
   1323                     const pkg = try Package.create(gpa, test_dir, basename);
   1324 
   1325                     // copy package table from main_pkg to root_pkg
   1326                     pkg.table = try main_pkg.table.clone(gpa);
   1327                     break :test_pkg pkg;
   1328                 } else try Package.createWithDir(
   1329                     gpa,
   1330                     options.zig_lib_directory,
   1331                     null,
   1332                     "test_runner.zig",
   1333                 );
   1334                 errdefer test_pkg.destroy(gpa);
   1335 
   1336                 break :root_pkg test_pkg;
   1337             } else main_pkg;
   1338             errdefer if (options.is_test) root_pkg.destroy(gpa);
   1339 
   1340             const compiler_rt_pkg = if (include_compiler_rt and options.output_mode == .Obj) compiler_rt_pkg: {
   1341                 break :compiler_rt_pkg try Package.createWithDir(
   1342                     gpa,
   1343                     options.zig_lib_directory,
   1344                     null,
   1345                     "compiler_rt.zig",
   1346                 );
   1347             } else null;
   1348             errdefer if (compiler_rt_pkg) |p| p.destroy(gpa);
   1349 
   1350             try main_pkg.add(gpa, "builtin", builtin_pkg);
   1351             try main_pkg.add(gpa, "root", root_pkg);
   1352             try main_pkg.add(gpa, "std", std_pkg);
   1353 
   1354             if (compiler_rt_pkg) |p| {
   1355                 try main_pkg.add(gpa, "compiler_rt", p);
   1356             }
   1357 
   1358             // Pre-open the directory handles for cached ZIR code so that it does not need
   1359             // to redundantly happen for each AstGen operation.
   1360             const zir_sub_dir = "z";
   1361 
   1362             var local_zir_dir = try options.local_cache_directory.handle.makeOpenPath(zir_sub_dir, .{});
   1363             errdefer local_zir_dir.close();
   1364             const local_zir_cache: Directory = .{
   1365                 .handle = local_zir_dir,
   1366                 .path = try options.local_cache_directory.join(arena, &[_][]const u8{zir_sub_dir}),
   1367             };
   1368             var global_zir_dir = try options.global_cache_directory.handle.makeOpenPath(zir_sub_dir, .{});
   1369             errdefer global_zir_dir.close();
   1370             const global_zir_cache: Directory = .{
   1371                 .handle = global_zir_dir,
   1372                 .path = try options.global_cache_directory.join(arena, &[_][]const u8{zir_sub_dir}),
   1373             };
   1374 
   1375             const emit_h: ?*Module.GlobalEmitH = if (options.emit_h) |loc| eh: {
   1376                 const eh = try gpa.create(Module.GlobalEmitH);
   1377                 eh.* = .{ .loc = loc };
   1378                 break :eh eh;
   1379             } else null;
   1380             errdefer if (emit_h) |eh| gpa.destroy(eh);
   1381 
   1382             // TODO when we implement serialization and deserialization of incremental
   1383             // compilation metadata, this is where we would load it. We have open a handle
   1384             // to the directory where the output either already is, or will be.
   1385             // However we currently do not have serialization of such metadata, so for now
   1386             // we set up an empty Module that does the entire compilation fresh.
   1387 
   1388             const module = try arena.create(Module);
   1389             errdefer module.deinit();
   1390             module.* = .{
   1391                 .gpa = gpa,
   1392                 .comp = comp,
   1393                 .main_pkg = main_pkg,
   1394                 .root_pkg = root_pkg,
   1395                 .zig_cache_artifact_directory = zig_cache_artifact_directory,
   1396                 .global_zir_cache = global_zir_cache,
   1397                 .local_zir_cache = local_zir_cache,
   1398                 .emit_h = emit_h,
   1399                 .tmp_hack_arena = std.heap.ArenaAllocator.init(gpa),
   1400             };
   1401             try module.init();
   1402 
   1403             break :blk module;
   1404         } else blk: {
   1405             if (options.emit_h != null) return error.NoZigModuleForCHeader;
   1406             break :blk null;
   1407         };
   1408         errdefer if (module) |zm| zm.deinit();
   1409 
   1410         const error_return_tracing = !strip and switch (options.optimize_mode) {
   1411             .Debug, .ReleaseSafe => (!options.target.isWasm() or options.target.os.tag == .emscripten) and
   1412                 !options.target.cpu.arch.isBpf() and (options.error_tracing orelse true),
   1413             .ReleaseFast => options.error_tracing orelse false,
   1414             .ReleaseSmall => false,
   1415         };
   1416 
   1417         // For resource management purposes.
   1418         var owned_link_dir: ?std.fs.Dir = null;
   1419         errdefer if (owned_link_dir) |*dir| dir.close();
   1420 
   1421         const bin_file_emit: ?link.Emit = blk: {
   1422             const emit_bin = options.emit_bin orelse break :blk null;
   1423 
   1424             if (emit_bin.directory) |directory| {
   1425                 break :blk link.Emit{
   1426                     .directory = directory,
   1427                     .sub_path = emit_bin.basename,
   1428                 };
   1429             }
   1430 
   1431             // In case of whole cache mode, `whole_bin_sub_path` is used to distinguish
   1432             // between -femit-bin and -fno-emit-bin.
   1433             switch (cache_mode) {
   1434                 .whole => break :blk null,
   1435                 .incremental => {},
   1436             }
   1437 
   1438             if (module) |zm| {
   1439                 break :blk link.Emit{
   1440                     .directory = zm.zig_cache_artifact_directory,
   1441                     .sub_path = emit_bin.basename,
   1442                 };
   1443             }
   1444 
   1445             // We could use the cache hash as is no problem, however, we increase
   1446             // the likelihood of cache hits by adding the first C source file
   1447             // path name (not contents) to the hash. This way if the user is compiling
   1448             // foo.c and bar.c as separate compilations, they get different cache
   1449             // directories.
   1450             var hash = cache.hash;
   1451             if (options.c_source_files.len >= 1) {
   1452                 hash.addBytes(options.c_source_files[0].src_path);
   1453             } else if (options.link_objects.len >= 1) {
   1454                 hash.addBytes(options.link_objects[0].path);
   1455             }
   1456 
   1457             const digest = hash.final();
   1458             const artifact_sub_dir = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest });
   1459             var artifact_dir = try options.local_cache_directory.handle.makeOpenPath(artifact_sub_dir, .{});
   1460             owned_link_dir = artifact_dir;
   1461             const link_artifact_directory: Directory = .{
   1462                 .handle = artifact_dir,
   1463                 .path = try options.local_cache_directory.join(arena, &[_][]const u8{artifact_sub_dir}),
   1464             };
   1465             break :blk link.Emit{
   1466                 .directory = link_artifact_directory,
   1467                 .sub_path = emit_bin.basename,
   1468             };
   1469         };
   1470 
   1471         const implib_emit: ?link.Emit = blk: {
   1472             const emit_implib = options.emit_implib orelse break :blk null;
   1473 
   1474             if (emit_implib.directory) |directory| {
   1475                 break :blk link.Emit{
   1476                     .directory = directory,
   1477                     .sub_path = emit_implib.basename,
   1478                 };
   1479             }
   1480 
   1481             // This is here for the same reason as in `bin_file_emit` above.
   1482             switch (cache_mode) {
   1483                 .whole => break :blk null,
   1484                 .incremental => {},
   1485             }
   1486 
   1487             // Use the same directory as the bin. The CLI already emits an
   1488             // error if -fno-emit-bin is combined with -femit-implib.
   1489             break :blk link.Emit{
   1490                 .directory = bin_file_emit.?.directory,
   1491                 .sub_path = emit_implib.basename,
   1492             };
   1493         };
   1494 
   1495         const docs_emit: ?link.Emit = blk: {
   1496             const emit_docs = options.emit_docs orelse break :blk null;
   1497 
   1498             if (emit_docs.directory) |directory| {
   1499                 break :blk .{
   1500                     .directory = directory,
   1501                     .sub_path = emit_docs.basename,
   1502                 };
   1503             }
   1504 
   1505             // This is here for the same reason as in `bin_file_emit` above.
   1506             switch (cache_mode) {
   1507                 .whole => break :blk null,
   1508                 .incremental => {},
   1509             }
   1510 
   1511             // Use the same directory as the bin, if possible.
   1512             if (bin_file_emit) |x| break :blk .{
   1513                 .directory = x.directory,
   1514                 .sub_path = emit_docs.basename,
   1515             };
   1516 
   1517             break :blk .{
   1518                 .directory = module.?.zig_cache_artifact_directory,
   1519                 .sub_path = emit_docs.basename,
   1520             };
   1521         };
   1522 
   1523         // This is so that when doing `CacheMode.whole`, the mechanism in update()
   1524         // can use it for communicating the result directory via `bin_file.emit`.
   1525         // This is used to distinguish between -fno-emit-bin and -femit-bin
   1526         // for `CacheMode.whole`.
   1527         // This memory will be overwritten with the real digest in update() but
   1528         // the basename will be preserved.
   1529         const whole_bin_sub_path: ?[]u8 = try prepareWholeEmitSubPath(arena, options.emit_bin);
   1530         // Same thing but for implibs.
   1531         const whole_implib_sub_path: ?[]u8 = try prepareWholeEmitSubPath(arena, options.emit_implib);
   1532         const whole_docs_sub_path: ?[]u8 = try prepareWholeEmitSubPath(arena, options.emit_docs);
   1533 
   1534         var system_libs: std.StringArrayHashMapUnmanaged(SystemLib) = .{};
   1535         errdefer system_libs.deinit(gpa);
   1536         try system_libs.ensureTotalCapacity(gpa, options.system_lib_names.len);
   1537         for (options.system_lib_names, 0..) |lib_name, i| {
   1538             system_libs.putAssumeCapacity(lib_name, options.system_lib_infos[i]);
   1539         }
   1540 
   1541         const bin_file = try link.File.openPath(gpa, .{
   1542             .emit = bin_file_emit,
   1543             .implib_emit = implib_emit,
   1544             .docs_emit = docs_emit,
   1545             .root_name = root_name,
   1546             .module = module,
   1547             .target = options.target,
   1548             .dynamic_linker = options.dynamic_linker,
   1549             .sysroot = sysroot,
   1550             .output_mode = options.output_mode,
   1551             .link_mode = link_mode,
   1552             .optimize_mode = options.optimize_mode,
   1553             .use_lld = use_lld,
   1554             .use_llvm = use_llvm,
   1555             .use_lib_llvm = use_lib_llvm,
   1556             .link_libc = link_libc,
   1557             .link_libcpp = link_libcpp,
   1558             .link_libunwind = link_libunwind,
   1559             .objects = options.link_objects,
   1560             .frameworks = options.frameworks,
   1561             .framework_dirs = options.framework_dirs,
   1562             .system_libs = system_libs,
   1563             .wasi_emulated_libs = options.wasi_emulated_libs,
   1564             .lib_dirs = options.lib_dirs,
   1565             .rpath_list = options.rpath_list,
   1566             .symbol_wrap_set = options.symbol_wrap_set,
   1567             .strip = strip,
   1568             .is_native_os = options.is_native_os,
   1569             .is_native_abi = options.is_native_abi,
   1570             .function_sections = options.function_sections,
   1571             .no_builtin = options.no_builtin,
   1572             .allow_shlib_undefined = options.linker_allow_shlib_undefined,
   1573             .bind_global_refs_locally = options.linker_bind_global_refs_locally orelse false,
   1574             .compress_debug_sections = options.linker_compress_debug_sections orelse .none,
   1575             .module_definition_file = options.linker_module_definition_file,
   1576             .sort_section = options.linker_sort_section,
   1577             .import_memory = options.linker_import_memory orelse false,
   1578             .export_memory = options.linker_export_memory orelse !(options.linker_import_memory orelse false),
   1579             .import_symbols = options.linker_import_symbols,
   1580             .import_table = options.linker_import_table,
   1581             .export_table = options.linker_export_table,
   1582             .initial_memory = options.linker_initial_memory,
   1583             .max_memory = options.linker_max_memory,
   1584             .shared_memory = options.linker_shared_memory,
   1585             .global_base = options.linker_global_base,
   1586             .export_symbol_names = options.linker_export_symbol_names,
   1587             .print_gc_sections = options.linker_print_gc_sections,
   1588             .print_icf_sections = options.linker_print_icf_sections,
   1589             .print_map = options.linker_print_map,
   1590             .opt_bisect_limit = options.linker_opt_bisect_limit,
   1591             .z_nodelete = options.linker_z_nodelete,
   1592             .z_notext = options.linker_z_notext,
   1593             .z_defs = options.linker_z_defs,
   1594             .z_origin = options.linker_z_origin,
   1595             .z_nocopyreloc = options.linker_z_nocopyreloc,
   1596             .z_now = options.linker_z_now,
   1597             .z_relro = options.linker_z_relro,
   1598             .z_common_page_size = options.linker_z_common_page_size,
   1599             .z_max_page_size = options.linker_z_max_page_size,
   1600             .tsaware = options.linker_tsaware,
   1601             .nxcompat = options.linker_nxcompat,
   1602             .dynamicbase = options.linker_dynamicbase,
   1603             .linker_optimization = linker_optimization,
   1604             .major_subsystem_version = options.major_subsystem_version,
   1605             .minor_subsystem_version = options.minor_subsystem_version,
   1606             .entry = options.entry,
   1607             .stack_size_override = options.stack_size_override,
   1608             .image_base_override = options.image_base_override,
   1609             .include_compiler_rt = include_compiler_rt,
   1610             .linker_script = options.linker_script,
   1611             .version_script = options.version_script,
   1612             .gc_sections = options.linker_gc_sections,
   1613             .eh_frame_hdr = link_eh_frame_hdr,
   1614             .emit_relocs = options.link_emit_relocs,
   1615             .rdynamic = options.rdynamic,
   1616             .soname = options.soname,
   1617             .version = options.version,
   1618             .compatibility_version = options.compatibility_version,
   1619             .libc_installation = libc_dirs.libc_installation,
   1620             .pic = pic,
   1621             .pie = pie,
   1622             .lto = lto,
   1623             .valgrind = valgrind,
   1624             .tsan = tsan,
   1625             .stack_check = stack_check,
   1626             .stack_protector = stack_protector,
   1627             .red_zone = red_zone,
   1628             .omit_frame_pointer = omit_frame_pointer,
   1629             .single_threaded = single_threaded,
   1630             .verbose_link = options.verbose_link,
   1631             .machine_code_model = options.machine_code_model,
   1632             .dll_export_fns = dll_export_fns,
   1633             .error_return_tracing = error_return_tracing,
   1634             .llvm_cpu_features = llvm_cpu_features,
   1635             .skip_linker_dependencies = options.skip_linker_dependencies,
   1636             .parent_compilation_link_libc = options.parent_compilation_link_libc,
   1637             .each_lib_rpath = options.each_lib_rpath orelse false,
   1638             .build_id = build_id,
   1639             .cache_mode = cache_mode,
   1640             .disable_lld_caching = options.disable_lld_caching or cache_mode == .whole,
   1641             .subsystem = options.subsystem,
   1642             .is_test = options.is_test,
   1643             .dwarf_format = options.dwarf_format,
   1644             .wasi_exec_model = wasi_exec_model,
   1645             .hash_style = options.hash_style,
   1646             .enable_link_snapshots = options.enable_link_snapshots,
   1647             .install_name = options.install_name,
   1648             .entitlements = options.entitlements,
   1649             .pagezero_size = options.pagezero_size,
   1650             .headerpad_size = options.headerpad_size,
   1651             .headerpad_max_install_names = options.headerpad_max_install_names,
   1652             .dead_strip_dylibs = options.dead_strip_dylibs,
   1653             .force_undefined_symbols = options.force_undefined_symbols,
   1654             .pdb_source_path = options.pdb_source_path,
   1655             .pdb_out_path = options.pdb_out_path,
   1656         });
   1657         errdefer bin_file.destroy();
   1658         comp.* = .{
   1659             .gpa = gpa,
   1660             .arena_state = arena_allocator.state,
   1661             .zig_lib_directory = options.zig_lib_directory,
   1662             .local_cache_directory = options.local_cache_directory,
   1663             .global_cache_directory = options.global_cache_directory,
   1664             .bin_file = bin_file,
   1665             .whole_bin_sub_path = whole_bin_sub_path,
   1666             .whole_implib_sub_path = whole_implib_sub_path,
   1667             .whole_docs_sub_path = whole_docs_sub_path,
   1668             .emit_asm = options.emit_asm,
   1669             .emit_llvm_ir = options.emit_llvm_ir,
   1670             .emit_llvm_bc = options.emit_llvm_bc,
   1671             .work_queue = std.fifo.LinearFifo(Job, .Dynamic).init(gpa),
   1672             .anon_work_queue = std.fifo.LinearFifo(Job, .Dynamic).init(gpa),
   1673             .c_object_work_queue = std.fifo.LinearFifo(*CObject, .Dynamic).init(gpa),
   1674             .win32_resource_work_queue = std.fifo.LinearFifo(*Win32Resource, .Dynamic).init(gpa),
   1675             .astgen_work_queue = std.fifo.LinearFifo(*Module.File, .Dynamic).init(gpa),
   1676             .embed_file_work_queue = std.fifo.LinearFifo(*Module.EmbedFile, .Dynamic).init(gpa),
   1677             .keep_source_files_loaded = options.keep_source_files_loaded,
   1678             .use_clang = use_clang,
   1679             .clang_argv = options.clang_argv,
   1680             .c_source_files = options.c_source_files,
   1681             .rc_source_files = options.rc_source_files,
   1682             .cache_parent = cache,
   1683             .self_exe_path = options.self_exe_path,
   1684             .libc_include_dir_list = libc_dirs.libc_include_dir_list,
   1685             .libc_framework_dir_list = libc_dirs.libc_framework_dir_list,
   1686             .rc_include_dir_list = rc_dirs.libc_include_dir_list,
   1687             .sanitize_c = sanitize_c,
   1688             .thread_pool = options.thread_pool,
   1689             .clang_passthrough_mode = options.clang_passthrough_mode,
   1690             .clang_preprocessor_mode = options.clang_preprocessor_mode,
   1691             .verbose_cc = options.verbose_cc,
   1692             .verbose_air = options.verbose_air,
   1693             .verbose_intern_pool = options.verbose_intern_pool,
   1694             .verbose_generic_instances = options.verbose_generic_instances,
   1695             .verbose_llvm_ir = options.verbose_llvm_ir,
   1696             .verbose_llvm_bc = options.verbose_llvm_bc,
   1697             .verbose_cimport = options.verbose_cimport,
   1698             .verbose_llvm_cpu_features = options.verbose_llvm_cpu_features,
   1699             .disable_c_depfile = options.disable_c_depfile,
   1700             .owned_link_dir = owned_link_dir,
   1701             .color = options.color,
   1702             .reference_trace = options.reference_trace,
   1703             .formatted_panics = formatted_panics,
   1704             .time_report = options.time_report,
   1705             .stack_report = options.stack_report,
   1706             .unwind_tables = unwind_tables,
   1707             .test_filter = options.test_filter,
   1708             .test_name_prefix = options.test_name_prefix,
   1709             .test_evented_io = options.test_evented_io,
   1710             .debug_compiler_runtime_libs = options.debug_compiler_runtime_libs,
   1711             .debug_compile_errors = options.debug_compile_errors,
   1712             .libcxx_abi_version = options.libcxx_abi_version,
   1713         };
   1714         break :comp comp;
   1715     };
   1716     errdefer comp.destroy();
   1717 
   1718     const target = comp.getTarget();
   1719 
   1720     // Add a `CObject` for each `c_source_files`.
   1721     try comp.c_object_table.ensureTotalCapacity(gpa, options.c_source_files.len);
   1722     for (options.c_source_files) |c_source_file| {
   1723         const c_object = try gpa.create(CObject);
   1724         errdefer gpa.destroy(c_object);
   1725 
   1726         c_object.* = .{
   1727             .status = .{ .new = {} },
   1728             .src = c_source_file,
   1729         };
   1730         comp.c_object_table.putAssumeCapacityNoClobber(c_object, {});
   1731     }
   1732 
   1733     // Add a `Win32Resource` for each `rc_source_files`.
   1734     try comp.win32_resource_table.ensureTotalCapacity(gpa, options.rc_source_files.len);
   1735     for (options.rc_source_files) |rc_source_file| {
   1736         const win32_resource = try gpa.create(Win32Resource);
   1737         errdefer gpa.destroy(win32_resource);
   1738 
   1739         win32_resource.* = .{
   1740             .status = .{ .new = {} },
   1741             .src = rc_source_file,
   1742         };
   1743         comp.win32_resource_table.putAssumeCapacityNoClobber(win32_resource, {});
   1744     }
   1745 
   1746     const have_bin_emit = comp.bin_file.options.emit != null or comp.whole_bin_sub_path != null;
   1747 
   1748     if (have_bin_emit and !comp.bin_file.options.skip_linker_dependencies and target.ofmt != .c) {
   1749         if (target.isDarwin()) {
   1750             switch (target.abi) {
   1751                 .none,
   1752                 .simulator,
   1753                 .macabi,
   1754                 => {},
   1755                 else => return error.LibCUnavailable,
   1756             }
   1757         }
   1758         // If we need to build glibc for the target, add work items for it.
   1759         // We go through the work queue so that building can be done in parallel.
   1760         if (comp.wantBuildGLibCFromSource()) {
   1761             if (!target_util.canBuildLibC(target)) return error.LibCUnavailable;
   1762 
   1763             if (glibc.needsCrtiCrtn(target)) {
   1764                 try comp.work_queue.write(&[_]Job{
   1765                     .{ .glibc_crt_file = .crti_o },
   1766                     .{ .glibc_crt_file = .crtn_o },
   1767                 });
   1768             }
   1769             try comp.work_queue.write(&[_]Job{
   1770                 .{ .glibc_crt_file = .scrt1_o },
   1771                 .{ .glibc_crt_file = .libc_nonshared_a },
   1772                 .{ .glibc_shared_objects = {} },
   1773             });
   1774         }
   1775         if (comp.wantBuildMuslFromSource()) {
   1776             if (!target_util.canBuildLibC(target)) return error.LibCUnavailable;
   1777 
   1778             try comp.work_queue.ensureUnusedCapacity(6);
   1779             if (musl.needsCrtiCrtn(target)) {
   1780                 comp.work_queue.writeAssumeCapacity(&[_]Job{
   1781                     .{ .musl_crt_file = .crti_o },
   1782                     .{ .musl_crt_file = .crtn_o },
   1783                 });
   1784             }
   1785             comp.work_queue.writeAssumeCapacity(&[_]Job{
   1786                 .{ .musl_crt_file = .crt1_o },
   1787                 .{ .musl_crt_file = .scrt1_o },
   1788                 .{ .musl_crt_file = .rcrt1_o },
   1789                 switch (comp.bin_file.options.link_mode) {
   1790                     .Static => .{ .musl_crt_file = .libc_a },
   1791                     .Dynamic => .{ .musl_crt_file = .libc_so },
   1792                 },
   1793             });
   1794         }
   1795         if (comp.wantBuildWasiLibcFromSource()) {
   1796             if (!target_util.canBuildLibC(target)) return error.LibCUnavailable;
   1797 
   1798             const wasi_emulated_libs = comp.bin_file.options.wasi_emulated_libs;
   1799             try comp.work_queue.ensureUnusedCapacity(wasi_emulated_libs.len + 2); // worst-case we need all components
   1800             for (wasi_emulated_libs) |crt_file| {
   1801                 comp.work_queue.writeItemAssumeCapacity(.{
   1802                     .wasi_libc_crt_file = crt_file,
   1803                 });
   1804             }
   1805             comp.work_queue.writeAssumeCapacity(&[_]Job{
   1806                 .{ .wasi_libc_crt_file = wasi_libc.execModelCrtFile(wasi_exec_model) },
   1807                 .{ .wasi_libc_crt_file = .libc_a },
   1808             });
   1809         }
   1810         if (comp.wantBuildMinGWFromSource()) {
   1811             if (!target_util.canBuildLibC(target)) return error.LibCUnavailable;
   1812 
   1813             const static_lib_jobs = [_]Job{
   1814                 .{ .mingw_crt_file = .mingw32_lib },
   1815                 .{ .mingw_crt_file = .msvcrt_os_lib },
   1816                 .{ .mingw_crt_file = .mingwex_lib },
   1817                 .{ .mingw_crt_file = .uuid_lib },
   1818             };
   1819             const crt_job: Job = .{ .mingw_crt_file = if (is_dyn_lib) .dllcrt2_o else .crt2_o };
   1820             try comp.work_queue.ensureUnusedCapacity(static_lib_jobs.len + 1);
   1821             comp.work_queue.writeAssumeCapacity(&static_lib_jobs);
   1822             comp.work_queue.writeItemAssumeCapacity(crt_job);
   1823 
   1824             // When linking mingw-w64 there are some import libs we always need.
   1825             for (mingw.always_link_libs) |name| {
   1826                 try comp.bin_file.options.system_libs.put(comp.gpa, name, .{
   1827                     .needed = false,
   1828                     .weak = false,
   1829                     .path = null,
   1830                 });
   1831             }
   1832         }
   1833         // Generate Windows import libs.
   1834         if (target.os.tag == .windows) {
   1835             const count = comp.bin_file.options.system_libs.count();
   1836             try comp.work_queue.ensureUnusedCapacity(count);
   1837             for (0..count) |i| {
   1838                 comp.work_queue.writeItemAssumeCapacity(.{ .windows_import_lib = i });
   1839             }
   1840         }
   1841         if (comp.wantBuildLibUnwindFromSource()) {
   1842             try comp.work_queue.writeItem(.{ .libunwind = {} });
   1843         }
   1844         if (build_options.have_llvm and is_exe_or_dyn_lib and comp.bin_file.options.link_libcpp) {
   1845             try comp.work_queue.writeItem(.libcxx);
   1846             try comp.work_queue.writeItem(.libcxxabi);
   1847         }
   1848         if (build_options.have_llvm and comp.bin_file.options.tsan) {
   1849             try comp.work_queue.writeItem(.libtsan);
   1850         }
   1851 
   1852         if (comp.getTarget().isMinGW() and !comp.bin_file.options.single_threaded) {
   1853             // LLD might drop some symbols as unused during LTO and GCing, therefore,
   1854             // we force mark them for resolution here.
   1855 
   1856             var tls_index_sym = switch (comp.getTarget().cpu.arch) {
   1857                 .x86 => "__tls_index",
   1858                 else => "_tls_index",
   1859             };
   1860 
   1861             try comp.bin_file.options.force_undefined_symbols.put(comp.gpa, tls_index_sym, {});
   1862         }
   1863 
   1864         if (comp.bin_file.options.include_compiler_rt and capable_of_building_compiler_rt) {
   1865             if (is_exe_or_dyn_lib) {
   1866                 log.debug("queuing a job to build compiler_rt_lib", .{});
   1867                 comp.job_queued_compiler_rt_lib = true;
   1868             } else if (options.output_mode != .Obj) {
   1869                 log.debug("queuing a job to build compiler_rt_obj", .{});
   1870                 // If build-obj with -fcompiler-rt is requested, that is handled specially
   1871                 // elsewhere. In this case we are making a static library, so we ask
   1872                 // for a compiler-rt object to put in it.
   1873                 comp.job_queued_compiler_rt_obj = true;
   1874             }
   1875         }
   1876         if (needs_c_symbols) {
   1877             // Related: https://github.com/ziglang/zig/issues/7265.
   1878             if (comp.bin_file.options.stack_protector != 0 and
   1879                 (!comp.bin_file.options.link_libc or
   1880                 !target_util.libcProvidesStackProtector(target)))
   1881             {
   1882                 try comp.work_queue.writeItem(.{ .libssp = {} });
   1883             }
   1884 
   1885             if (!comp.bin_file.options.link_libc and capable_of_building_zig_libc) {
   1886                 try comp.work_queue.writeItem(.{ .zig_libc = {} });
   1887             }
   1888         }
   1889     }
   1890 
   1891     return comp;
   1892 }
   1893 
   1894 pub fn destroy(self: *Compilation) void {
   1895     const optional_module = self.bin_file.options.module;
   1896     self.bin_file.destroy();
   1897     if (optional_module) |module| module.deinit();
   1898 
   1899     const gpa = self.gpa;
   1900     self.work_queue.deinit();
   1901     self.anon_work_queue.deinit();
   1902     self.c_object_work_queue.deinit();
   1903     self.win32_resource_work_queue.deinit();
   1904     self.astgen_work_queue.deinit();
   1905     self.embed_file_work_queue.deinit();
   1906 
   1907     {
   1908         var it = self.crt_files.iterator();
   1909         while (it.next()) |entry| {
   1910             gpa.free(entry.key_ptr.*);
   1911             entry.value_ptr.deinit(gpa);
   1912         }
   1913         self.crt_files.deinit(gpa);
   1914     }
   1915 
   1916     if (self.libunwind_static_lib) |*crt_file| {
   1917         crt_file.deinit(gpa);
   1918     }
   1919     if (self.libcxx_static_lib) |*crt_file| {
   1920         crt_file.deinit(gpa);
   1921     }
   1922     if (self.libcxxabi_static_lib) |*crt_file| {
   1923         crt_file.deinit(gpa);
   1924     }
   1925     if (self.compiler_rt_lib) |*crt_file| {
   1926         crt_file.deinit(gpa);
   1927     }
   1928     if (self.compiler_rt_obj) |*crt_file| {
   1929         crt_file.deinit(gpa);
   1930     }
   1931     if (self.libssp_static_lib) |*crt_file| {
   1932         crt_file.deinit(gpa);
   1933     }
   1934     if (self.libc_static_lib) |*crt_file| {
   1935         crt_file.deinit(gpa);
   1936     }
   1937 
   1938     if (self.glibc_so_files) |*glibc_file| {
   1939         glibc_file.deinit(gpa);
   1940     }
   1941 
   1942     for (self.c_object_table.keys()) |key| {
   1943         key.destroy(gpa);
   1944     }
   1945     self.c_object_table.deinit(gpa);
   1946 
   1947     for (self.failed_c_objects.values()) |value| {
   1948         value.destroy(gpa);
   1949     }
   1950     self.failed_c_objects.deinit(gpa);
   1951 
   1952     for (self.win32_resource_table.keys()) |key| {
   1953         key.destroy(gpa);
   1954     }
   1955     self.win32_resource_table.deinit(gpa);
   1956 
   1957     for (self.failed_win32_resources.values()) |*value| {
   1958         value.deinit(gpa);
   1959     }
   1960     self.failed_win32_resources.deinit(gpa);
   1961 
   1962     for (self.lld_errors.items) |*lld_error| {
   1963         lld_error.deinit(gpa);
   1964     }
   1965     self.lld_errors.deinit(gpa);
   1966 
   1967     self.clearMiscFailures();
   1968 
   1969     self.cache_parent.manifest_dir.close();
   1970     if (self.owned_link_dir) |*dir| dir.close();
   1971 
   1972     // This destroys `self`.
   1973     self.arena_state.promote(gpa).deinit();
   1974 }
   1975 
   1976 pub fn clearMiscFailures(comp: *Compilation) void {
   1977     comp.alloc_failure_occurred = false;
   1978     for (comp.misc_failures.values()) |*value| {
   1979         value.deinit(comp.gpa);
   1980     }
   1981     comp.misc_failures.deinit(comp.gpa);
   1982     comp.misc_failures = .{};
   1983 }
   1984 
   1985 pub fn getTarget(self: Compilation) Target {
   1986     return self.bin_file.options.target;
   1987 }
   1988 
   1989 fn restorePrevZigCacheArtifactDirectory(comp: *Compilation, directory: *Directory) void {
   1990     if (directory.path) |p| comp.gpa.free(p);
   1991 
   1992     // Restore the Module's previous zig_cache_artifact_directory
   1993     // This is only for cleanup purposes; Module.deinit calls close
   1994     // on the handle of zig_cache_artifact_directory.
   1995     if (comp.bin_file.options.module) |module| {
   1996         const builtin_pkg = module.main_pkg.table.get("builtin").?;
   1997         module.zig_cache_artifact_directory = builtin_pkg.root_src_directory;
   1998     }
   1999 }
   2000 
   2001 fn cleanupTmpArtifactDirectory(
   2002     comp: *Compilation,
   2003     tmp_artifact_directory: *?Directory,
   2004     tmp_dir_sub_path: []const u8,
   2005 ) void {
   2006     comp.gpa.free(tmp_dir_sub_path);
   2007     if (tmp_artifact_directory.*) |*directory| {
   2008         directory.handle.close();
   2009         restorePrevZigCacheArtifactDirectory(comp, directory);
   2010     }
   2011 }
   2012 
   2013 pub fn hotCodeSwap(comp: *Compilation, prog_node: *std.Progress.Node, pid: std.ChildProcess.Id) !void {
   2014     comp.bin_file.child_pid = pid;
   2015     try comp.makeBinFileWritable();
   2016     try comp.update(prog_node);
   2017     try comp.makeBinFileExecutable();
   2018 }
   2019 
   2020 /// Detect changes to source files, perform semantic analysis, and update the output files.
   2021 pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void {
   2022     const tracy_trace = trace(@src());
   2023     defer tracy_trace.end();
   2024 
   2025     comp.clearMiscFailures();
   2026     comp.last_update_was_cache_hit = false;
   2027 
   2028     var man: Cache.Manifest = undefined;
   2029     defer if (comp.whole_cache_manifest != null) man.deinit();
   2030 
   2031     var tmp_dir_sub_path: []const u8 = &.{};
   2032     var tmp_artifact_directory: ?Directory = null;
   2033     defer cleanupTmpArtifactDirectory(comp, &tmp_artifact_directory, tmp_dir_sub_path);
   2034 
   2035     // If using the whole caching strategy, we check for *everything* up front, including
   2036     // C source files.
   2037     if (comp.bin_file.options.cache_mode == .whole) {
   2038         // We are about to obtain this lock, so here we give other processes a chance first.
   2039         comp.bin_file.releaseLock();
   2040 
   2041         man = comp.cache_parent.obtain();
   2042         comp.whole_cache_manifest = &man;
   2043         try comp.addNonIncrementalStuffToCacheManifest(&man);
   2044 
   2045         const is_hit = man.hit() catch |err| {
   2046             // TODO properly bubble these up instead of emitting a warning
   2047             const i = man.failed_file_index orelse return err;
   2048             const pp = man.files.items[i].prefixed_path orelse return err;
   2049             const prefix = man.cache.prefixes()[pp.prefix].path orelse "";
   2050             std.log.warn("{s}: {s}{s}", .{ @errorName(err), prefix, pp.sub_path });
   2051             return err;
   2052         };
   2053         if (is_hit) {
   2054             comp.last_update_was_cache_hit = true;
   2055             log.debug("CacheMode.whole cache hit for {s}", .{comp.bin_file.options.root_name});
   2056             const digest = man.final();
   2057 
   2058             comp.wholeCacheModeSetBinFilePath(&digest);
   2059 
   2060             assert(comp.bin_file.lock == null);
   2061             comp.bin_file.lock = man.toOwnedLock();
   2062             return;
   2063         }
   2064         log.debug("CacheMode.whole cache miss for {s}", .{comp.bin_file.options.root_name});
   2065 
   2066         // Initialize `bin_file.emit` with a temporary Directory so that compilation can
   2067         // continue on the same path as incremental, using the temporary Directory.
   2068         tmp_artifact_directory = d: {
   2069             const s = std.fs.path.sep_str;
   2070             const rand_int = std.crypto.random.int(u64);
   2071 
   2072             tmp_dir_sub_path = try std.fmt.allocPrint(comp.gpa, "tmp" ++ s ++ "{x}", .{rand_int});
   2073 
   2074             const path = try comp.local_cache_directory.join(comp.gpa, &.{tmp_dir_sub_path});
   2075             errdefer comp.gpa.free(path);
   2076 
   2077             const handle = try comp.local_cache_directory.handle.makeOpenPath(tmp_dir_sub_path, .{});
   2078             errdefer handle.close();
   2079 
   2080             break :d .{
   2081                 .path = path,
   2082                 .handle = handle,
   2083             };
   2084         };
   2085 
   2086         // This updates the output directory for linker outputs.
   2087         if (comp.bin_file.options.module) |module| {
   2088             module.zig_cache_artifact_directory = tmp_artifact_directory.?;
   2089         }
   2090 
   2091         // This resets the link.File to operate as if we called openPath() in create()
   2092         // instead of simulating -fno-emit-bin.
   2093         var options = comp.bin_file.options.move();
   2094         if (comp.whole_bin_sub_path) |sub_path| {
   2095             options.emit = .{
   2096                 .directory = tmp_artifact_directory.?,
   2097                 .sub_path = std.fs.path.basename(sub_path),
   2098             };
   2099         }
   2100         if (comp.whole_implib_sub_path) |sub_path| {
   2101             options.implib_emit = .{
   2102                 .directory = tmp_artifact_directory.?,
   2103                 .sub_path = std.fs.path.basename(sub_path),
   2104             };
   2105         }
   2106         if (comp.whole_docs_sub_path) |sub_path| {
   2107             options.docs_emit = .{
   2108                 .directory = tmp_artifact_directory.?,
   2109                 .sub_path = std.fs.path.basename(sub_path),
   2110             };
   2111         }
   2112         var old_bin_file = comp.bin_file;
   2113         comp.bin_file = try link.File.openPath(comp.gpa, options);
   2114         old_bin_file.destroy();
   2115     }
   2116 
   2117     // For compiling C objects, we rely on the cache hash system to avoid duplicating work.
   2118     // Add a Job for each C object.
   2119     try comp.c_object_work_queue.ensureUnusedCapacity(comp.c_object_table.count());
   2120     for (comp.c_object_table.keys()) |key| {
   2121         comp.c_object_work_queue.writeItemAssumeCapacity(key);
   2122     }
   2123 
   2124     // For compiling Win32 resources, we rely on the cache hash system to avoid duplicating work.
   2125     // Add a Job for each Win32 resource file.
   2126     try comp.win32_resource_work_queue.ensureUnusedCapacity(comp.win32_resource_table.count());
   2127     for (comp.win32_resource_table.keys()) |key| {
   2128         comp.win32_resource_work_queue.writeItemAssumeCapacity(key);
   2129     }
   2130 
   2131     if (comp.bin_file.options.module) |module| {
   2132         module.compile_log_text.shrinkAndFree(module.gpa, 0);
   2133         module.generation += 1;
   2134 
   2135         // Make sure std.zig is inside the import_table. We unconditionally need
   2136         // it for start.zig.
   2137         const std_pkg = module.main_pkg.table.get("std").?;
   2138         _ = try module.importPkg(std_pkg);
   2139 
   2140         // Normally we rely on importing std to in turn import the root source file
   2141         // in the start code, but when using the stage1 backend that won't happen,
   2142         // so in order to run AstGen on the root source file we put it into the
   2143         // import_table here.
   2144         // Likewise, in the case of `zig test`, the test runner is the root source file,
   2145         // and so there is nothing to import the main file.
   2146         if (comp.bin_file.options.is_test) {
   2147             _ = try module.importPkg(module.main_pkg);
   2148         }
   2149 
   2150         if (module.main_pkg.table.get("compiler_rt")) |compiler_rt_pkg| {
   2151             _ = try module.importPkg(compiler_rt_pkg);
   2152         }
   2153 
   2154         // Put a work item in for every known source file to detect if
   2155         // it changed, and, if so, re-compute ZIR and then queue the job
   2156         // to update it.
   2157         // We still want AstGen work items for stage1 so that we expose compile errors
   2158         // that are implemented in stage2 but not stage1.
   2159         try comp.astgen_work_queue.ensureUnusedCapacity(module.import_table.count());
   2160         for (module.import_table.values()) |value| {
   2161             comp.astgen_work_queue.writeItemAssumeCapacity(value);
   2162         }
   2163 
   2164         // Put a work item in for checking if any files used with `@embedFile` changed.
   2165         {
   2166             try comp.embed_file_work_queue.ensureUnusedCapacity(module.embed_table.count());
   2167             var it = module.embed_table.iterator();
   2168             while (it.next()) |entry| {
   2169                 const embed_file = entry.value_ptr.*;
   2170                 comp.embed_file_work_queue.writeItemAssumeCapacity(embed_file);
   2171             }
   2172         }
   2173 
   2174         try comp.work_queue.writeItem(.{ .analyze_pkg = std_pkg });
   2175         if (comp.bin_file.options.is_test) {
   2176             try comp.work_queue.writeItem(.{ .analyze_pkg = module.main_pkg });
   2177         }
   2178 
   2179         if (module.main_pkg.table.get("compiler_rt")) |compiler_rt_pkg| {
   2180             try comp.work_queue.writeItem(.{ .analyze_pkg = compiler_rt_pkg });
   2181         }
   2182     }
   2183 
   2184     try comp.performAllTheWork(main_progress_node);
   2185 
   2186     if (comp.bin_file.options.module) |module| {
   2187         if (builtin.mode == .Debug and comp.verbose_intern_pool) {
   2188             std.debug.print("intern pool stats for '{s}':\n", .{
   2189                 comp.bin_file.options.root_name,
   2190             });
   2191             module.intern_pool.dump();
   2192         }
   2193 
   2194         if (builtin.mode == .Debug and comp.verbose_generic_instances) {
   2195             std.debug.print("generic instances for '{s}:0x{x}':\n", .{
   2196                 comp.bin_file.options.root_name,
   2197                 @as(usize, @intFromPtr(module)),
   2198             });
   2199             module.intern_pool.dumpGenericInstances(comp.gpa);
   2200         }
   2201 
   2202         if (comp.bin_file.options.is_test and comp.totalErrorCount() == 0) {
   2203             // The `test_functions` decl has been intentionally postponed until now,
   2204             // at which point we must populate it with the list of test functions that
   2205             // have been discovered and not filtered out.
   2206             try module.populateTestFunctions(main_progress_node);
   2207         }
   2208 
   2209         // Process the deletion set. We use a while loop here because the
   2210         // deletion set may grow as we call `clearDecl` within this loop,
   2211         // and more unreferenced Decls are revealed.
   2212         while (module.deletion_set.count() != 0) {
   2213             const decl_index = module.deletion_set.keys()[0];
   2214             const decl = module.declPtr(decl_index);
   2215             assert(decl.deletion_flag);
   2216             assert(decl.dependants.count() == 0);
   2217             assert(decl.zir_decl_index != 0);
   2218 
   2219             try module.clearDecl(decl_index, null);
   2220         }
   2221 
   2222         try module.processExports();
   2223     }
   2224 
   2225     if (comp.totalErrorCount() != 0) {
   2226         // Skip flushing and keep source files loaded for error reporting.
   2227         comp.link_error_flags = .{};
   2228         return;
   2229     }
   2230 
   2231     // Flush takes care of -femit-bin, but we still have -femit-llvm-ir, -femit-llvm-bc, and
   2232     // -femit-asm to handle, in the case of C objects.
   2233     comp.emitOthers();
   2234 
   2235     if (comp.whole_cache_manifest != null) {
   2236         const digest = man.final();
   2237 
   2238         // Rename the temporary directory into place.
   2239         var directory = tmp_artifact_directory.?;
   2240         tmp_artifact_directory = null;
   2241 
   2242         directory.handle.close();
   2243         defer restorePrevZigCacheArtifactDirectory(comp, &directory);
   2244 
   2245         const o_sub_path = try std.fs.path.join(comp.gpa, &[_][]const u8{ "o", &digest });
   2246         defer comp.gpa.free(o_sub_path);
   2247 
   2248         // Work around windows `AccessDenied` if any files within this directory are open
   2249         // by doing the makeExecutable/makeWritable dance.
   2250         const need_writable_dance = builtin.os.tag == .windows and comp.bin_file.file != null;
   2251         if (need_writable_dance) {
   2252             try comp.bin_file.makeExecutable();
   2253         }
   2254 
   2255         try comp.bin_file.renameTmpIntoCache(comp.local_cache_directory, tmp_dir_sub_path, o_sub_path);
   2256         comp.wholeCacheModeSetBinFilePath(&digest);
   2257 
   2258         // Has to be after the `wholeCacheModeSetBinFilePath` above.
   2259         if (need_writable_dance) {
   2260             try comp.bin_file.makeWritable();
   2261         }
   2262 
   2263         // This is intentionally sandwiched between renameTmpIntoCache() and writeManifest().
   2264         if (comp.bin_file.options.module) |module| {
   2265             // We need to set the zig_cache_artifact_directory for -femit-asm, -femit-llvm-ir,
   2266             // etc to know where to output to.
   2267             var artifact_dir = try comp.local_cache_directory.handle.openDir(o_sub_path, .{});
   2268             defer artifact_dir.close();
   2269 
   2270             var dir_path = try comp.local_cache_directory.join(comp.gpa, &.{o_sub_path});
   2271             defer comp.gpa.free(dir_path);
   2272 
   2273             module.zig_cache_artifact_directory = .{
   2274                 .handle = artifact_dir,
   2275                 .path = dir_path,
   2276             };
   2277 
   2278             try comp.flush(main_progress_node);
   2279             if (comp.totalErrorCount() != 0) return;
   2280 
   2281             // Note the placement of this logic is relying on the call to
   2282             // `wholeCacheModeSetBinFilePath` above.
   2283             try maybeGenerateAutodocs(comp, main_progress_node);
   2284         } else {
   2285             try comp.flush(main_progress_node);
   2286             if (comp.totalErrorCount() != 0) return;
   2287         }
   2288 
   2289         // Failure here only means an unnecessary cache miss.
   2290         man.writeManifest() catch |err| {
   2291             log.warn("failed to write cache manifest: {s}", .{@errorName(err)});
   2292         };
   2293 
   2294         assert(comp.bin_file.lock == null);
   2295         comp.bin_file.lock = man.toOwnedLock();
   2296     } else {
   2297         try comp.flush(main_progress_node);
   2298 
   2299         if (comp.totalErrorCount() == 0) {
   2300             try maybeGenerateAutodocs(comp, main_progress_node);
   2301         }
   2302     }
   2303 
   2304     // Unload all source files to save memory.
   2305     // The ZIR needs to stay loaded in memory because (1) Decl objects contain references
   2306     // to it, and (2) generic instantiations, comptime calls, inline calls will need
   2307     // to reference the ZIR.
   2308     if (!comp.keep_source_files_loaded) {
   2309         if (comp.bin_file.options.module) |module| {
   2310             for (module.import_table.values()) |file| {
   2311                 file.unloadTree(comp.gpa);
   2312                 file.unloadSource(comp.gpa);
   2313             }
   2314         }
   2315     }
   2316 }
   2317 
   2318 fn maybeGenerateAutodocs(comp: *Compilation, prog_node: *std.Progress.Node) !void {
   2319     const mod = comp.bin_file.options.module orelse return;
   2320     // TODO: do this in a separate job during performAllTheWork(). The
   2321     // file copies at the end of generate() can also be extracted to
   2322     // separate jobs
   2323     if (!build_options.only_c and !build_options.only_core_functionality) {
   2324         if (comp.bin_file.options.docs_emit) |emit| {
   2325             var dir = try emit.directory.handle.makeOpenPath(emit.sub_path, .{});
   2326             defer dir.close();
   2327 
   2328             var sub_prog_node = prog_node.start("Generating documentation", 0);
   2329             sub_prog_node.activate();
   2330             sub_prog_node.context.refresh();
   2331             defer sub_prog_node.end();
   2332 
   2333             try Autodoc.generate(mod, dir);
   2334         }
   2335     }
   2336 }
   2337 
   2338 fn flush(comp: *Compilation, prog_node: *std.Progress.Node) !void {
   2339     // This is needed before reading the error flags.
   2340     comp.bin_file.flush(comp, prog_node) catch |err| switch (err) {
   2341         error.FlushFailure => {}, // error reported through link_error_flags
   2342         error.LLDReportedFailure => {}, // error reported via lockAndParseLldStderr
   2343         else => |e| return e,
   2344     };
   2345     comp.link_error_flags = comp.bin_file.errorFlags();
   2346 
   2347     if (comp.bin_file.options.module) |module| {
   2348         try link.File.C.flushEmitH(module);
   2349     }
   2350 }
   2351 
   2352 /// Communicate the output binary location to parent Compilations.
   2353 fn wholeCacheModeSetBinFilePath(comp: *Compilation, digest: *const [Cache.hex_digest_len]u8) void {
   2354     const digest_start = 2; // "o/[digest]/[basename]"
   2355 
   2356     if (comp.whole_bin_sub_path) |sub_path| {
   2357         @memcpy(sub_path[digest_start..][0..digest.len], digest);
   2358 
   2359         comp.bin_file.options.emit = .{
   2360             .directory = comp.local_cache_directory,
   2361             .sub_path = sub_path,
   2362         };
   2363     }
   2364 
   2365     if (comp.whole_implib_sub_path) |sub_path| {
   2366         @memcpy(sub_path[digest_start..][0..digest.len], digest);
   2367 
   2368         comp.bin_file.options.implib_emit = .{
   2369             .directory = comp.local_cache_directory,
   2370             .sub_path = sub_path,
   2371         };
   2372     }
   2373 
   2374     if (comp.whole_docs_sub_path) |sub_path| {
   2375         @memcpy(sub_path[digest_start..][0..digest.len], digest);
   2376 
   2377         comp.bin_file.options.docs_emit = .{
   2378             .directory = comp.local_cache_directory,
   2379             .sub_path = sub_path,
   2380         };
   2381     }
   2382 }
   2383 
   2384 fn prepareWholeEmitSubPath(arena: Allocator, opt_emit: ?EmitLoc) error{OutOfMemory}!?[]u8 {
   2385     const emit = opt_emit orelse return null;
   2386     if (emit.directory != null) return null;
   2387     const s = std.fs.path.sep_str;
   2388     const format = "o" ++ s ++ ("x" ** Cache.hex_digest_len) ++ s ++ "{s}";
   2389     return try std.fmt.allocPrint(arena, format, .{emit.basename});
   2390 }
   2391 
   2392 /// This is only observed at compile-time and used to emit a compile error
   2393 /// to remind the programmer to update multiple related pieces of code that
   2394 /// are in different locations. Bump this number when adding or deleting
   2395 /// anything from the link cache manifest.
   2396 pub const link_hash_implementation_version = 10;
   2397 
   2398 fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifest) !void {
   2399     const gpa = comp.gpa;
   2400     const target = comp.getTarget();
   2401 
   2402     var arena_allocator = std.heap.ArenaAllocator.init(gpa);
   2403     defer arena_allocator.deinit();
   2404     const arena = arena_allocator.allocator();
   2405 
   2406     comptime assert(link_hash_implementation_version == 10);
   2407 
   2408     if (comp.bin_file.options.module) |mod| {
   2409         const main_zig_file = try mod.main_pkg.root_src_directory.join(arena, &[_][]const u8{
   2410             mod.main_pkg.root_src_path,
   2411         });
   2412         _ = try man.addFile(main_zig_file, null);
   2413         {
   2414             var seen_table = std.AutoHashMap(*Package, void).init(arena);
   2415 
   2416             // Skip builtin.zig; it is useless as an input, and we don't want to have to
   2417             // write it before checking for a cache hit.
   2418             const builtin_pkg = mod.main_pkg.table.get("builtin").?;
   2419             try seen_table.put(builtin_pkg, {});
   2420 
   2421             try addPackageTableToCacheHash(&man.hash, &arena_allocator, mod.main_pkg.table, &seen_table, .{ .files = man });
   2422         }
   2423 
   2424         // Synchronize with other matching comments: ZigOnlyHashStuff
   2425         man.hash.add(comp.bin_file.options.valgrind);
   2426         man.hash.add(comp.bin_file.options.single_threaded);
   2427         man.hash.add(comp.bin_file.options.use_llvm);
   2428         man.hash.add(comp.bin_file.options.dll_export_fns);
   2429         man.hash.add(comp.bin_file.options.is_test);
   2430         man.hash.add(comp.test_evented_io);
   2431         man.hash.addOptionalBytes(comp.test_filter);
   2432         man.hash.addOptionalBytes(comp.test_name_prefix);
   2433         man.hash.add(comp.bin_file.options.skip_linker_dependencies);
   2434         man.hash.add(comp.bin_file.options.parent_compilation_link_libc);
   2435         man.hash.add(mod.emit_h != null);
   2436     }
   2437 
   2438     try man.addOptionalFile(comp.bin_file.options.linker_script);
   2439     try man.addOptionalFile(comp.bin_file.options.version_script);
   2440 
   2441     for (comp.bin_file.options.objects) |obj| {
   2442         _ = try man.addFile(obj.path, null);
   2443         man.hash.add(obj.must_link);
   2444         man.hash.add(obj.loption);
   2445     }
   2446 
   2447     for (comp.c_object_table.keys()) |key| {
   2448         _ = try man.addFile(key.src.src_path, null);
   2449         man.hash.addOptional(key.src.ext);
   2450         man.hash.addListOfBytes(key.src.extra_flags);
   2451     }
   2452 
   2453     for (comp.win32_resource_table.keys()) |key| {
   2454         _ = try man.addFile(key.src.src_path, null);
   2455         man.hash.addListOfBytes(key.src.extra_flags);
   2456     }
   2457 
   2458     man.hash.addListOfBytes(comp.rc_include_dir_list);
   2459 
   2460     cache_helpers.addOptionalEmitLoc(&man.hash, comp.emit_asm);
   2461     cache_helpers.addOptionalEmitLoc(&man.hash, comp.emit_llvm_ir);
   2462     cache_helpers.addOptionalEmitLoc(&man.hash, comp.emit_llvm_bc);
   2463 
   2464     man.hash.addListOfBytes(comp.clang_argv);
   2465 
   2466     man.hash.addOptional(comp.bin_file.options.stack_size_override);
   2467     man.hash.addOptional(comp.bin_file.options.image_base_override);
   2468     man.hash.addOptional(comp.bin_file.options.gc_sections);
   2469     man.hash.add(comp.bin_file.options.eh_frame_hdr);
   2470     man.hash.add(comp.bin_file.options.emit_relocs);
   2471     man.hash.add(comp.bin_file.options.rdynamic);
   2472     man.hash.addListOfBytes(comp.bin_file.options.lib_dirs);
   2473     man.hash.addListOfBytes(comp.bin_file.options.rpath_list);
   2474     man.hash.addListOfBytes(comp.bin_file.options.symbol_wrap_set.keys());
   2475     man.hash.add(comp.bin_file.options.each_lib_rpath);
   2476     man.hash.add(comp.bin_file.options.build_id);
   2477     man.hash.add(comp.bin_file.options.skip_linker_dependencies);
   2478     man.hash.add(comp.bin_file.options.z_nodelete);
   2479     man.hash.add(comp.bin_file.options.z_notext);
   2480     man.hash.add(comp.bin_file.options.z_defs);
   2481     man.hash.add(comp.bin_file.options.z_origin);
   2482     man.hash.add(comp.bin_file.options.z_nocopyreloc);
   2483     man.hash.add(comp.bin_file.options.z_now);
   2484     man.hash.add(comp.bin_file.options.z_relro);
   2485     man.hash.add(comp.bin_file.options.z_common_page_size orelse 0);
   2486     man.hash.add(comp.bin_file.options.z_max_page_size orelse 0);
   2487     man.hash.add(comp.bin_file.options.hash_style);
   2488     man.hash.add(comp.bin_file.options.compress_debug_sections);
   2489     man.hash.add(comp.bin_file.options.include_compiler_rt);
   2490     man.hash.addOptional(comp.bin_file.options.sort_section);
   2491     if (comp.bin_file.options.link_libc) {
   2492         man.hash.add(comp.bin_file.options.libc_installation != null);
   2493         if (comp.bin_file.options.libc_installation) |libc_installation| {
   2494             man.hash.addOptionalBytes(libc_installation.crt_dir);
   2495             if (target.abi == .msvc) {
   2496                 man.hash.addOptionalBytes(libc_installation.msvc_lib_dir);
   2497                 man.hash.addOptionalBytes(libc_installation.kernel32_lib_dir);
   2498             }
   2499         }
   2500         man.hash.addOptionalBytes(comp.bin_file.options.dynamic_linker);
   2501     }
   2502     man.hash.addOptionalBytes(comp.bin_file.options.soname);
   2503     man.hash.addOptional(comp.bin_file.options.version);
   2504     try link.hashAddSystemLibs(man, comp.bin_file.options.system_libs);
   2505     man.hash.addListOfBytes(comp.bin_file.options.force_undefined_symbols.keys());
   2506     man.hash.addOptional(comp.bin_file.options.allow_shlib_undefined);
   2507     man.hash.add(comp.bin_file.options.bind_global_refs_locally);
   2508     man.hash.add(comp.bin_file.options.tsan);
   2509     man.hash.addOptionalBytes(comp.bin_file.options.sysroot);
   2510     man.hash.add(comp.bin_file.options.linker_optimization);
   2511 
   2512     // WASM specific stuff
   2513     man.hash.add(comp.bin_file.options.import_memory);
   2514     man.hash.add(comp.bin_file.options.export_memory);
   2515     man.hash.addOptional(comp.bin_file.options.initial_memory);
   2516     man.hash.addOptional(comp.bin_file.options.max_memory);
   2517     man.hash.add(comp.bin_file.options.shared_memory);
   2518     man.hash.addOptional(comp.bin_file.options.global_base);
   2519 
   2520     // Mach-O specific stuff
   2521     man.hash.addListOfBytes(comp.bin_file.options.framework_dirs);
   2522     try link.hashAddFrameworks(man, comp.bin_file.options.frameworks);
   2523     try man.addOptionalFile(comp.bin_file.options.entitlements);
   2524     man.hash.addOptional(comp.bin_file.options.pagezero_size);
   2525     man.hash.addOptional(comp.bin_file.options.headerpad_size);
   2526     man.hash.add(comp.bin_file.options.headerpad_max_install_names);
   2527     man.hash.add(comp.bin_file.options.dead_strip_dylibs);
   2528 
   2529     // COFF specific stuff
   2530     man.hash.addOptional(comp.bin_file.options.subsystem);
   2531     man.hash.add(comp.bin_file.options.tsaware);
   2532     man.hash.add(comp.bin_file.options.nxcompat);
   2533     man.hash.add(comp.bin_file.options.dynamicbase);
   2534     man.hash.addOptional(comp.bin_file.options.major_subsystem_version);
   2535     man.hash.addOptional(comp.bin_file.options.minor_subsystem_version);
   2536 }
   2537 
   2538 fn emitOthers(comp: *Compilation) void {
   2539     if (comp.bin_file.options.output_mode != .Obj or comp.bin_file.options.module != null or
   2540         comp.c_object_table.count() == 0)
   2541     {
   2542         return;
   2543     }
   2544     const obj_path = comp.c_object_table.keys()[0].status.success.object_path;
   2545     const cwd = std.fs.cwd();
   2546     const ext = std.fs.path.extension(obj_path);
   2547     const basename = obj_path[0 .. obj_path.len - ext.len];
   2548     // This obj path always ends with the object file extension, but if we change the
   2549     // extension to .ll, .bc, or .s, then it will be the path to those things.
   2550     const outs = [_]struct {
   2551         emit: ?EmitLoc,
   2552         ext: []const u8,
   2553     }{
   2554         .{ .emit = comp.emit_asm, .ext = ".s" },
   2555         .{ .emit = comp.emit_llvm_ir, .ext = ".ll" },
   2556         .{ .emit = comp.emit_llvm_bc, .ext = ".bc" },
   2557     };
   2558     for (outs) |out| {
   2559         if (out.emit) |loc| {
   2560             if (loc.directory) |directory| {
   2561                 const src_path = std.fmt.allocPrint(comp.gpa, "{s}{s}", .{
   2562                     basename, out.ext,
   2563                 }) catch |err| {
   2564                     log.err("unable to copy {s}{s}: {s}", .{ basename, out.ext, @errorName(err) });
   2565                     continue;
   2566                 };
   2567                 defer comp.gpa.free(src_path);
   2568                 cwd.copyFile(src_path, directory.handle, loc.basename, .{}) catch |err| {
   2569                     log.err("unable to copy {s}: {s}", .{ src_path, @errorName(err) });
   2570                 };
   2571             }
   2572         }
   2573     }
   2574 }
   2575 
   2576 fn reportMultiModuleErrors(mod: *Module) !void {
   2577     // Some cases can give you a whole bunch of multi-module errors, which it's not helpful to
   2578     // print all of, so we'll cap the number of these to emit.
   2579     var num_errors: u32 = 0;
   2580     const max_errors = 5;
   2581     // Attach the "some omitted" note to the final error message
   2582     var last_err: ?*Module.ErrorMsg = null;
   2583 
   2584     for (mod.import_table.values()) |file| {
   2585         if (!file.multi_pkg) continue;
   2586 
   2587         num_errors += 1;
   2588         if (num_errors > max_errors) continue;
   2589 
   2590         const err = err_blk: {
   2591             // Like with errors, let's cap the number of notes to prevent a huge error spew.
   2592             const max_notes = 5;
   2593             const omitted = file.references.items.len -| max_notes;
   2594             const num_notes = file.references.items.len - omitted;
   2595 
   2596             const notes = try mod.gpa.alloc(Module.ErrorMsg, if (omitted > 0) num_notes + 1 else num_notes);
   2597             errdefer mod.gpa.free(notes);
   2598 
   2599             for (notes[0..num_notes], file.references.items[0..num_notes], 0..) |*note, ref, i| {
   2600                 errdefer for (notes[0..i]) |*n| n.deinit(mod.gpa);
   2601                 note.* = switch (ref) {
   2602                     .import => |loc| blk: {
   2603                         const name = try loc.file_scope.pkg.getName(mod.gpa, mod.*);
   2604                         defer mod.gpa.free(name);
   2605                         break :blk try Module.ErrorMsg.init(
   2606                             mod.gpa,
   2607                             loc,
   2608                             "imported from module {s}",
   2609                             .{name},
   2610                         );
   2611                     },
   2612                     .root => |pkg| blk: {
   2613                         const name = try pkg.getName(mod.gpa, mod.*);
   2614                         defer mod.gpa.free(name);
   2615                         break :blk try Module.ErrorMsg.init(
   2616                             mod.gpa,
   2617                             .{ .file_scope = file, .parent_decl_node = 0, .lazy = .entire_file },
   2618                             "root of module {s}",
   2619                             .{name},
   2620                         );
   2621                     },
   2622                 };
   2623             }
   2624             errdefer for (notes[0..num_notes]) |*n| n.deinit(mod.gpa);
   2625 
   2626             if (omitted > 0) {
   2627                 notes[num_notes] = try Module.ErrorMsg.init(
   2628                     mod.gpa,
   2629                     .{ .file_scope = file, .parent_decl_node = 0, .lazy = .entire_file },
   2630                     "{} more references omitted",
   2631                     .{omitted},
   2632                 );
   2633             }
   2634             errdefer if (omitted > 0) notes[num_notes].deinit(mod.gpa);
   2635 
   2636             const err = try Module.ErrorMsg.create(
   2637                 mod.gpa,
   2638                 .{ .file_scope = file, .parent_decl_node = 0, .lazy = .entire_file },
   2639                 "file exists in multiple modules",
   2640                 .{},
   2641             );
   2642             err.notes = notes;
   2643             break :err_blk err;
   2644         };
   2645         errdefer err.destroy(mod.gpa);
   2646         try mod.failed_files.putNoClobber(mod.gpa, file, err);
   2647         last_err = err;
   2648     }
   2649 
   2650     // If we omitted any errors, add a note saying that
   2651     if (num_errors > max_errors) {
   2652         const err = last_err.?;
   2653 
   2654         // There isn't really any meaningful place to put this note, so just attach it to the
   2655         // last failed file
   2656         var note = try Module.ErrorMsg.init(
   2657             mod.gpa,
   2658             err.src_loc,
   2659             "{} more errors omitted",
   2660             .{num_errors - max_errors},
   2661         );
   2662         errdefer note.deinit(mod.gpa);
   2663 
   2664         const i = err.notes.len;
   2665         err.notes = try mod.gpa.realloc(err.notes, i + 1);
   2666         err.notes[i] = note;
   2667     }
   2668 
   2669     // Now that we've reported the errors, we need to deal with
   2670     // dependencies. Any file referenced by a multi_pkg file should also be
   2671     // marked multi_pkg and have its status set to astgen_failure, as it's
   2672     // ambiguous which package they should be analyzed as a part of. We need
   2673     // to add this flag after reporting the errors however, as otherwise
   2674     // we'd get an error for every single downstream file, which wouldn't be
   2675     // very useful.
   2676     for (mod.import_table.values()) |file| {
   2677         if (file.multi_pkg) file.recursiveMarkMultiPkg(mod);
   2678     }
   2679 }
   2680 
   2681 /// Having the file open for writing is problematic as far as executing the
   2682 /// binary is concerned. This will remove the write flag, or close the file,
   2683 /// or whatever is needed so that it can be executed.
   2684 /// After this, one must call` makeFileWritable` before calling `update`.
   2685 pub fn makeBinFileExecutable(self: *Compilation) !void {
   2686     return self.bin_file.makeExecutable();
   2687 }
   2688 
   2689 pub fn makeBinFileWritable(self: *Compilation) !void {
   2690     return self.bin_file.makeWritable();
   2691 }
   2692 
   2693 /// This function is temporally single-threaded.
   2694 pub fn totalErrorCount(self: *Compilation) u32 {
   2695     var total: usize = self.failed_c_objects.count() +
   2696         self.misc_failures.count() +
   2697         @intFromBool(self.alloc_failure_occurred) +
   2698         self.lld_errors.items.len;
   2699 
   2700     for (self.failed_win32_resources.values()) |errs| {
   2701         total += errs.errorMessageCount();
   2702     }
   2703 
   2704     if (self.bin_file.options.module) |module| {
   2705         total += module.failed_exports.count();
   2706         total += module.failed_embed_files.count();
   2707 
   2708         {
   2709             var it = module.failed_files.iterator();
   2710             while (it.next()) |entry| {
   2711                 if (entry.value_ptr.*) |_| {
   2712                     total += 1;
   2713                 } else {
   2714                     const file = entry.key_ptr.*;
   2715                     assert(file.zir_loaded);
   2716                     const payload_index = file.zir.extra[@intFromEnum(Zir.ExtraIndex.compile_errors)];
   2717                     assert(payload_index != 0);
   2718                     const header = file.zir.extraData(Zir.Inst.CompileErrors, payload_index);
   2719                     total += header.data.items_len;
   2720                 }
   2721             }
   2722         }
   2723 
   2724         // Skip errors for Decls within files that failed parsing.
   2725         // When a parse error is introduced, we keep all the semantic analysis for
   2726         // the previous parse success, including compile errors, but we cannot
   2727         // emit them until the file succeeds parsing.
   2728         for (module.failed_decls.keys()) |key| {
   2729             if (module.declFileScope(key).okToReportErrors()) {
   2730                 total += 1;
   2731                 if (module.cimport_errors.get(key)) |errors| {
   2732                     total += errors.len;
   2733                 }
   2734             }
   2735         }
   2736         if (module.emit_h) |emit_h| {
   2737             for (emit_h.failed_decls.keys()) |key| {
   2738                 if (module.declFileScope(key).okToReportErrors()) {
   2739                     total += 1;
   2740                 }
   2741             }
   2742         }
   2743     }
   2744 
   2745     // The "no entry point found" error only counts if there are no semantic analysis errors.
   2746     if (total == 0) {
   2747         total += @intFromBool(self.link_error_flags.no_entry_point_found);
   2748     }
   2749     total += @intFromBool(self.link_error_flags.missing_libc);
   2750 
   2751     // Misc linker errors
   2752     total += self.bin_file.miscErrors().len;
   2753 
   2754     // Compile log errors only count if there are no other errors.
   2755     if (total == 0) {
   2756         if (self.bin_file.options.module) |module| {
   2757             total += @intFromBool(module.compile_log_decls.count() != 0);
   2758         }
   2759     }
   2760 
   2761     return @as(u32, @intCast(total));
   2762 }
   2763 
   2764 /// This function is temporally single-threaded.
   2765 pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle {
   2766     const gpa = self.gpa;
   2767 
   2768     var bundle: ErrorBundle.Wip = undefined;
   2769     try bundle.init(gpa);
   2770     defer bundle.deinit();
   2771 
   2772     {
   2773         var it = self.failed_c_objects.iterator();
   2774         while (it.next()) |entry| {
   2775             const c_object = entry.key_ptr.*;
   2776             const err_msg = entry.value_ptr.*;
   2777             // TODO these fields will need to be adjusted when we have proper
   2778             // C error reporting bubbling up.
   2779             try bundle.addRootErrorMessage(.{
   2780                 .msg = try bundle.printString("unable to build C object: {s}", .{err_msg.msg}),
   2781                 .src_loc = try bundle.addSourceLocation(.{
   2782                     .src_path = try bundle.addString(c_object.src.src_path),
   2783                     .span_start = 0,
   2784                     .span_main = 0,
   2785                     .span_end = 1,
   2786                     .line = err_msg.line,
   2787                     .column = err_msg.column,
   2788                     .source_line = 0, // TODO
   2789                 }),
   2790             });
   2791         }
   2792     }
   2793 
   2794     {
   2795         var it = self.failed_win32_resources.iterator();
   2796         while (it.next()) |entry| {
   2797             try bundle.addBundleAsRoots(entry.value_ptr.*);
   2798         }
   2799     }
   2800 
   2801     for (self.lld_errors.items) |lld_error| {
   2802         const notes_len = @as(u32, @intCast(lld_error.context_lines.len));
   2803 
   2804         try bundle.addRootErrorMessage(.{
   2805             .msg = try bundle.addString(lld_error.msg),
   2806             .notes_len = notes_len,
   2807         });
   2808         const notes_start = try bundle.reserveNotes(notes_len);
   2809         for (notes_start.., lld_error.context_lines) |note, context_line| {
   2810             bundle.extra.items[note] = @intFromEnum(bundle.addErrorMessageAssumeCapacity(.{
   2811                 .msg = try bundle.addString(context_line),
   2812             }));
   2813         }
   2814     }
   2815     for (self.misc_failures.values()) |*value| {
   2816         try bundle.addRootErrorMessage(.{
   2817             .msg = try bundle.addString(value.msg),
   2818             .notes_len = if (value.children) |b| b.errorMessageCount() else 0,
   2819         });
   2820         if (value.children) |b| try bundle.addBundleAsNotes(b);
   2821     }
   2822     if (self.alloc_failure_occurred) {
   2823         try bundle.addRootErrorMessage(.{
   2824             .msg = try bundle.addString("memory allocation failure"),
   2825         });
   2826     }
   2827     if (self.bin_file.options.module) |module| {
   2828         {
   2829             var it = module.failed_files.iterator();
   2830             while (it.next()) |entry| {
   2831                 if (entry.value_ptr.*) |msg| {
   2832                     try addModuleErrorMsg(module, &bundle, msg.*);
   2833                 } else {
   2834                     // Must be ZIR errors. Note that this may include AST errors.
   2835                     // addZirErrorMessages asserts that the tree is loaded.
   2836                     _ = try entry.key_ptr.*.getTree(gpa);
   2837                     try addZirErrorMessages(&bundle, entry.key_ptr.*);
   2838                 }
   2839             }
   2840         }
   2841         {
   2842             var it = module.failed_embed_files.iterator();
   2843             while (it.next()) |entry| {
   2844                 const msg = entry.value_ptr.*;
   2845                 try addModuleErrorMsg(module, &bundle, msg.*);
   2846             }
   2847         }
   2848         {
   2849             var it = module.failed_decls.iterator();
   2850             while (it.next()) |entry| {
   2851                 const decl_index = entry.key_ptr.*;
   2852                 // Skip errors for Decls within files that had a parse failure.
   2853                 // We'll try again once parsing succeeds.
   2854                 if (module.declFileScope(decl_index).okToReportErrors()) {
   2855                     try addModuleErrorMsg(module, &bundle, entry.value_ptr.*.*);
   2856                     if (module.cimport_errors.get(entry.key_ptr.*)) |cimport_errors| for (cimport_errors) |c_error| {
   2857                         try bundle.addRootErrorMessage(.{
   2858                             .msg = try bundle.addString(std.mem.span(c_error.msg)),
   2859                             .src_loc = if (c_error.path) |some| try bundle.addSourceLocation(.{
   2860                                 .src_path = try bundle.addString(std.mem.span(some)),
   2861                                 .span_start = c_error.offset,
   2862                                 .span_main = c_error.offset,
   2863                                 .span_end = c_error.offset + 1,
   2864                                 .line = c_error.line,
   2865                                 .column = c_error.column,
   2866                                 .source_line = if (c_error.source_line) |line| try bundle.addString(std.mem.span(line)) else 0,
   2867                             }) else .none,
   2868                         });
   2869                     };
   2870                 }
   2871             }
   2872         }
   2873         if (module.emit_h) |emit_h| {
   2874             var it = emit_h.failed_decls.iterator();
   2875             while (it.next()) |entry| {
   2876                 const decl_index = entry.key_ptr.*;
   2877                 // Skip errors for Decls within files that had a parse failure.
   2878                 // We'll try again once parsing succeeds.
   2879                 if (module.declFileScope(decl_index).okToReportErrors()) {
   2880                     try addModuleErrorMsg(module, &bundle, entry.value_ptr.*.*);
   2881                 }
   2882             }
   2883         }
   2884         for (module.failed_exports.values()) |value| {
   2885             try addModuleErrorMsg(module, &bundle, value.*);
   2886         }
   2887     }
   2888 
   2889     if (bundle.root_list.items.len == 0) {
   2890         if (self.link_error_flags.no_entry_point_found) {
   2891             try bundle.addRootErrorMessage(.{
   2892                 .msg = try bundle.addString("no entry point found"),
   2893             });
   2894         }
   2895     }
   2896 
   2897     if (self.link_error_flags.missing_libc) {
   2898         try bundle.addRootErrorMessage(.{
   2899             .msg = try bundle.addString("libc not available"),
   2900             .notes_len = 2,
   2901         });
   2902         const notes_start = try bundle.reserveNotes(2);
   2903         bundle.extra.items[notes_start + 0] = @intFromEnum(try bundle.addErrorMessage(.{
   2904             .msg = try bundle.addString("run 'zig libc -h' to learn about libc installations"),
   2905         }));
   2906         bundle.extra.items[notes_start + 1] = @intFromEnum(try bundle.addErrorMessage(.{
   2907             .msg = try bundle.addString("run 'zig targets' to see the targets for which zig can always provide libc"),
   2908         }));
   2909     }
   2910 
   2911     for (self.bin_file.miscErrors()) |link_err| {
   2912         try bundle.addRootErrorMessage(.{
   2913             .msg = try bundle.addString(link_err.msg),
   2914             .notes_len = @intCast(link_err.notes.len),
   2915         });
   2916         const notes_start = try bundle.reserveNotes(@intCast(link_err.notes.len));
   2917         for (link_err.notes, 0..) |note, i| {
   2918             bundle.extra.items[notes_start + i] = @intFromEnum(try bundle.addErrorMessage(.{
   2919                 .msg = try bundle.addString(note.msg),
   2920             }));
   2921         }
   2922     }
   2923 
   2924     if (self.bin_file.options.module) |module| {
   2925         if (bundle.root_list.items.len == 0 and module.compile_log_decls.count() != 0) {
   2926             const keys = module.compile_log_decls.keys();
   2927             const values = module.compile_log_decls.values();
   2928             // First one will be the error; subsequent ones will be notes.
   2929             const err_decl = module.declPtr(keys[0]);
   2930             const src_loc = err_decl.nodeOffsetSrcLoc(values[0], module);
   2931             const err_msg = Module.ErrorMsg{
   2932                 .src_loc = src_loc,
   2933                 .msg = "found compile log statement",
   2934                 .notes = try gpa.alloc(Module.ErrorMsg, module.compile_log_decls.count() - 1),
   2935             };
   2936             defer gpa.free(err_msg.notes);
   2937 
   2938             for (keys[1..], 0..) |key, i| {
   2939                 const note_decl = module.declPtr(key);
   2940                 err_msg.notes[i] = .{
   2941                     .src_loc = note_decl.nodeOffsetSrcLoc(values[i + 1], module),
   2942                     .msg = "also here",
   2943                 };
   2944             }
   2945 
   2946             try addModuleErrorMsg(module, &bundle, err_msg);
   2947         }
   2948     }
   2949 
   2950     assert(self.totalErrorCount() == bundle.root_list.items.len);
   2951 
   2952     const compile_log_text = if (self.bin_file.options.module) |m| m.compile_log_text.items else "";
   2953     return bundle.toOwnedBundle(compile_log_text);
   2954 }
   2955 
   2956 pub const ErrorNoteHashContext = struct {
   2957     eb: *const ErrorBundle.Wip,
   2958 
   2959     pub fn hash(ctx: ErrorNoteHashContext, key: ErrorBundle.ErrorMessage) u32 {
   2960         var hasher = std.hash.Wyhash.init(0);
   2961         const eb = ctx.eb.tmpBundle();
   2962 
   2963         hasher.update(eb.nullTerminatedString(key.msg));
   2964         if (key.src_loc != .none) {
   2965             const src = eb.getSourceLocation(key.src_loc);
   2966             hasher.update(eb.nullTerminatedString(src.src_path));
   2967             std.hash.autoHash(&hasher, src.line);
   2968             std.hash.autoHash(&hasher, src.column);
   2969             std.hash.autoHash(&hasher, src.span_main);
   2970         }
   2971 
   2972         return @as(u32, @truncate(hasher.final()));
   2973     }
   2974 
   2975     pub fn eql(
   2976         ctx: ErrorNoteHashContext,
   2977         a: ErrorBundle.ErrorMessage,
   2978         b: ErrorBundle.ErrorMessage,
   2979         b_index: usize,
   2980     ) bool {
   2981         _ = b_index;
   2982         const eb = ctx.eb.tmpBundle();
   2983         const msg_a = eb.nullTerminatedString(a.msg);
   2984         const msg_b = eb.nullTerminatedString(b.msg);
   2985         if (!std.mem.eql(u8, msg_a, msg_b)) return false;
   2986 
   2987         if (a.src_loc == .none and b.src_loc == .none) return true;
   2988         if (a.src_loc == .none or b.src_loc == .none) return false;
   2989         const src_a = eb.getSourceLocation(a.src_loc);
   2990         const src_b = eb.getSourceLocation(b.src_loc);
   2991 
   2992         const src_path_a = eb.nullTerminatedString(src_a.src_path);
   2993         const src_path_b = eb.nullTerminatedString(src_b.src_path);
   2994 
   2995         return std.mem.eql(u8, src_path_a, src_path_b) and
   2996             src_a.line == src_b.line and
   2997             src_a.column == src_b.column and
   2998             src_a.span_main == src_b.span_main;
   2999     }
   3000 };
   3001 
   3002 pub fn addModuleErrorMsg(mod: *Module, eb: *ErrorBundle.Wip, module_err_msg: Module.ErrorMsg) !void {
   3003     const gpa = eb.gpa;
   3004     const ip = &mod.intern_pool;
   3005     const err_source = module_err_msg.src_loc.file_scope.getSource(gpa) catch |err| {
   3006         const file_path = try module_err_msg.src_loc.file_scope.fullPath(gpa);
   3007         defer gpa.free(file_path);
   3008         try eb.addRootErrorMessage(.{
   3009             .msg = try eb.printString("unable to load '{s}': {s}", .{
   3010                 file_path, @errorName(err),
   3011             }),
   3012         });
   3013         return;
   3014     };
   3015     const err_span = try module_err_msg.src_loc.span(gpa);
   3016     const err_loc = std.zig.findLineColumn(err_source.bytes, err_span.main);
   3017     const file_path = try module_err_msg.src_loc.file_scope.fullPath(gpa);
   3018     defer gpa.free(file_path);
   3019 
   3020     var ref_traces: std.ArrayListUnmanaged(ErrorBundle.ReferenceTrace) = .{};
   3021     defer ref_traces.deinit(gpa);
   3022 
   3023     const remaining_references: ?u32 = remaining: {
   3024         if (mod.comp.reference_trace) |_| {
   3025             if (module_err_msg.hidden_references > 0) break :remaining module_err_msg.hidden_references;
   3026         } else {
   3027             if (module_err_msg.reference_trace.len > 0) break :remaining 0;
   3028         }
   3029         break :remaining null;
   3030     };
   3031     try ref_traces.ensureTotalCapacityPrecise(gpa, module_err_msg.reference_trace.len +
   3032         @intFromBool(remaining_references != null));
   3033 
   3034     for (module_err_msg.reference_trace) |module_reference| {
   3035         const source = try module_reference.src_loc.file_scope.getSource(gpa);
   3036         const span = try module_reference.src_loc.span(gpa);
   3037         const loc = std.zig.findLineColumn(source.bytes, span.main);
   3038         const rt_file_path = try module_reference.src_loc.file_scope.fullPath(gpa);
   3039         defer gpa.free(rt_file_path);
   3040         ref_traces.appendAssumeCapacity(.{
   3041             .decl_name = try eb.addString(ip.stringToSlice(module_reference.decl)),
   3042             .src_loc = try eb.addSourceLocation(.{
   3043                 .src_path = try eb.addString(rt_file_path),
   3044                 .span_start = span.start,
   3045                 .span_main = span.main,
   3046                 .span_end = span.end,
   3047                 .line = @intCast(loc.line),
   3048                 .column = @intCast(loc.column),
   3049                 .source_line = 0,
   3050             }),
   3051         });
   3052     }
   3053     if (remaining_references) |remaining| ref_traces.appendAssumeCapacity(
   3054         .{ .decl_name = remaining, .src_loc = .none },
   3055     );
   3056 
   3057     const src_loc = try eb.addSourceLocation(.{
   3058         .src_path = try eb.addString(file_path),
   3059         .span_start = err_span.start,
   3060         .span_main = err_span.main,
   3061         .span_end = err_span.end,
   3062         .line = @intCast(err_loc.line),
   3063         .column = @intCast(err_loc.column),
   3064         .source_line = if (module_err_msg.src_loc.lazy == .entire_file)
   3065             0
   3066         else
   3067             try eb.addString(err_loc.source_line),
   3068         .reference_trace_len = @intCast(ref_traces.items.len),
   3069     });
   3070 
   3071     for (ref_traces.items) |rt| {
   3072         try eb.addReferenceTrace(rt);
   3073     }
   3074 
   3075     // De-duplicate error notes. The main use case in mind for this is
   3076     // too many "note: called from here" notes when eval branch quota is reached.
   3077     var notes: std.ArrayHashMapUnmanaged(ErrorBundle.ErrorMessage, void, ErrorNoteHashContext, true) = .{};
   3078     defer notes.deinit(gpa);
   3079 
   3080     for (module_err_msg.notes) |module_note| {
   3081         const source = try module_note.src_loc.file_scope.getSource(gpa);
   3082         const span = try module_note.src_loc.span(gpa);
   3083         const loc = std.zig.findLineColumn(source.bytes, span.main);
   3084         const note_file_path = try module_note.src_loc.file_scope.fullPath(gpa);
   3085         defer gpa.free(note_file_path);
   3086 
   3087         const gop = try notes.getOrPutContext(gpa, .{
   3088             .msg = try eb.addString(module_note.msg),
   3089             .src_loc = try eb.addSourceLocation(.{
   3090                 .src_path = try eb.addString(note_file_path),
   3091                 .span_start = span.start,
   3092                 .span_main = span.main,
   3093                 .span_end = span.end,
   3094                 .line = @intCast(loc.line),
   3095                 .column = @intCast(loc.column),
   3096                 .source_line = if (err_loc.eql(loc)) 0 else try eb.addString(loc.source_line),
   3097             }),
   3098         }, .{ .eb = eb });
   3099         if (gop.found_existing) {
   3100             gop.key_ptr.count += 1;
   3101         }
   3102     }
   3103 
   3104     const notes_len: u32 = @intCast(notes.entries.len);
   3105 
   3106     try eb.addRootErrorMessage(.{
   3107         .msg = try eb.addString(module_err_msg.msg),
   3108         .src_loc = src_loc,
   3109         .notes_len = notes_len,
   3110     });
   3111 
   3112     const notes_start = try eb.reserveNotes(notes_len);
   3113 
   3114     for (notes_start.., notes.keys()) |i, note| {
   3115         eb.extra.items[i] = @intFromEnum(try eb.addErrorMessage(note));
   3116     }
   3117 }
   3118 
   3119 pub fn addZirErrorMessages(eb: *ErrorBundle.Wip, file: *Module.File) !void {
   3120     assert(file.zir_loaded);
   3121     assert(file.tree_loaded);
   3122     assert(file.source_loaded);
   3123     const payload_index = file.zir.extra[@intFromEnum(Zir.ExtraIndex.compile_errors)];
   3124     assert(payload_index != 0);
   3125     const gpa = eb.gpa;
   3126 
   3127     const header = file.zir.extraData(Zir.Inst.CompileErrors, payload_index);
   3128     const items_len = header.data.items_len;
   3129     var extra_index = header.end;
   3130     for (0..items_len) |_| {
   3131         const item = file.zir.extraData(Zir.Inst.CompileErrors.Item, extra_index);
   3132         extra_index = item.end;
   3133         const err_span = blk: {
   3134             if (item.data.node != 0) {
   3135                 break :blk Module.SrcLoc.nodeToSpan(&file.tree, item.data.node);
   3136             }
   3137             const token_starts = file.tree.tokens.items(.start);
   3138             const start = token_starts[item.data.token] + item.data.byte_offset;
   3139             const end = start + @as(u32, @intCast(file.tree.tokenSlice(item.data.token).len)) - item.data.byte_offset;
   3140             break :blk Module.SrcLoc.Span{ .start = start, .end = end, .main = start };
   3141         };
   3142         const err_loc = std.zig.findLineColumn(file.source, err_span.main);
   3143 
   3144         {
   3145             const msg = file.zir.nullTerminatedString(item.data.msg);
   3146             const src_path = try file.fullPath(gpa);
   3147             defer gpa.free(src_path);
   3148             try eb.addRootErrorMessage(.{
   3149                 .msg = try eb.addString(msg),
   3150                 .src_loc = try eb.addSourceLocation(.{
   3151                     .src_path = try eb.addString(src_path),
   3152                     .span_start = err_span.start,
   3153                     .span_main = err_span.main,
   3154                     .span_end = err_span.end,
   3155                     .line = @as(u32, @intCast(err_loc.line)),
   3156                     .column = @as(u32, @intCast(err_loc.column)),
   3157                     .source_line = try eb.addString(err_loc.source_line),
   3158                 }),
   3159                 .notes_len = item.data.notesLen(file.zir),
   3160             });
   3161         }
   3162 
   3163         if (item.data.notes != 0) {
   3164             const notes_start = try eb.reserveNotes(item.data.notes);
   3165             const block = file.zir.extraData(Zir.Inst.Block, item.data.notes);
   3166             const body = file.zir.extra[block.end..][0..block.data.body_len];
   3167             for (notes_start.., body) |note_i, body_elem| {
   3168                 const note_item = file.zir.extraData(Zir.Inst.CompileErrors.Item, body_elem);
   3169                 const msg = file.zir.nullTerminatedString(note_item.data.msg);
   3170                 const span = blk: {
   3171                     if (note_item.data.node != 0) {
   3172                         break :blk Module.SrcLoc.nodeToSpan(&file.tree, note_item.data.node);
   3173                     }
   3174                     const token_starts = file.tree.tokens.items(.start);
   3175                     const start = token_starts[note_item.data.token] + note_item.data.byte_offset;
   3176                     const end = start + @as(u32, @intCast(file.tree.tokenSlice(note_item.data.token).len)) - item.data.byte_offset;
   3177                     break :blk Module.SrcLoc.Span{ .start = start, .end = end, .main = start };
   3178                 };
   3179                 const loc = std.zig.findLineColumn(file.source, span.main);
   3180                 const src_path = try file.fullPath(gpa);
   3181                 defer gpa.free(src_path);
   3182 
   3183                 eb.extra.items[note_i] = @intFromEnum(try eb.addErrorMessage(.{
   3184                     .msg = try eb.addString(msg),
   3185                     .src_loc = try eb.addSourceLocation(.{
   3186                         .src_path = try eb.addString(src_path),
   3187                         .span_start = span.start,
   3188                         .span_main = span.main,
   3189                         .span_end = span.end,
   3190                         .line = @as(u32, @intCast(loc.line)),
   3191                         .column = @as(u32, @intCast(loc.column)),
   3192                         .source_line = if (loc.eql(err_loc))
   3193                             0
   3194                         else
   3195                             try eb.addString(loc.source_line),
   3196                     }),
   3197                     .notes_len = 0, // TODO rework this function to be recursive
   3198                 }));
   3199             }
   3200         }
   3201     }
   3202 }
   3203 
   3204 pub fn performAllTheWork(
   3205     comp: *Compilation,
   3206     main_progress_node: *std.Progress.Node,
   3207 ) error{ TimerUnsupported, OutOfMemory }!void {
   3208     // Here we queue up all the AstGen tasks first, followed by C object compilation.
   3209     // We wait until the AstGen tasks are all completed before proceeding to the
   3210     // (at least for now) single-threaded main work queue. However, C object compilation
   3211     // only needs to be finished by the end of this function.
   3212 
   3213     var zir_prog_node = main_progress_node.start("AST Lowering", 0);
   3214     defer zir_prog_node.end();
   3215 
   3216     var c_obj_prog_node = main_progress_node.start("Compile C Objects", comp.c_source_files.len);
   3217     defer c_obj_prog_node.end();
   3218 
   3219     var win32_resource_prog_node = main_progress_node.start("Compile Win32 Resources", comp.rc_source_files.len);
   3220     defer win32_resource_prog_node.end();
   3221 
   3222     var embed_file_prog_node = main_progress_node.start("Detect @embedFile updates", comp.embed_file_work_queue.count);
   3223     defer embed_file_prog_node.end();
   3224 
   3225     comp.work_queue_wait_group.reset();
   3226     defer comp.work_queue_wait_group.wait();
   3227 
   3228     {
   3229         const astgen_frame = tracy.namedFrame("astgen");
   3230         defer astgen_frame.end();
   3231 
   3232         comp.astgen_wait_group.reset();
   3233         defer comp.astgen_wait_group.wait();
   3234 
   3235         // builtin.zig is handled specially for two reasons:
   3236         // 1. to avoid race condition of zig processes truncating each other's builtin.zig files
   3237         // 2. optimization; in the hot path it only incurs a stat() syscall, which happens
   3238         //    in the `astgen_wait_group`.
   3239         if (comp.bin_file.options.module) |mod| {
   3240             if (mod.job_queued_update_builtin_zig) {
   3241                 mod.job_queued_update_builtin_zig = false;
   3242 
   3243                 comp.astgen_wait_group.start();
   3244                 try comp.thread_pool.spawn(workerUpdateBuiltinZigFile, .{
   3245                     comp, mod, &comp.astgen_wait_group,
   3246                 });
   3247             }
   3248         }
   3249 
   3250         while (comp.astgen_work_queue.readItem()) |file| {
   3251             comp.astgen_wait_group.start();
   3252             try comp.thread_pool.spawn(workerAstGenFile, .{
   3253                 comp, file, &zir_prog_node, &comp.astgen_wait_group, .root,
   3254             });
   3255         }
   3256 
   3257         while (comp.embed_file_work_queue.readItem()) |embed_file| {
   3258             comp.astgen_wait_group.start();
   3259             try comp.thread_pool.spawn(workerCheckEmbedFile, .{
   3260                 comp, embed_file, &embed_file_prog_node, &comp.astgen_wait_group,
   3261             });
   3262         }
   3263 
   3264         while (comp.c_object_work_queue.readItem()) |c_object| {
   3265             comp.work_queue_wait_group.start();
   3266             try comp.thread_pool.spawn(workerUpdateCObject, .{
   3267                 comp, c_object, &c_obj_prog_node, &comp.work_queue_wait_group,
   3268             });
   3269         }
   3270 
   3271         while (comp.win32_resource_work_queue.readItem()) |win32_resource| {
   3272             comp.work_queue_wait_group.start();
   3273             try comp.thread_pool.spawn(workerUpdateWin32Resource, .{
   3274                 comp, win32_resource, &win32_resource_prog_node, &comp.work_queue_wait_group,
   3275             });
   3276         }
   3277     }
   3278 
   3279     if (comp.bin_file.options.module) |mod| {
   3280         try reportMultiModuleErrors(mod);
   3281     }
   3282 
   3283     {
   3284         const outdated_and_deleted_decls_frame = tracy.namedFrame("outdated_and_deleted_decls");
   3285         defer outdated_and_deleted_decls_frame.end();
   3286 
   3287         // Iterate over all the files and look for outdated and deleted declarations.
   3288         if (comp.bin_file.options.module) |mod| {
   3289             try mod.processOutdatedAndDeletedDecls();
   3290         }
   3291     }
   3292 
   3293     if (comp.bin_file.options.module) |mod| {
   3294         mod.sema_prog_node = main_progress_node.start("Semantic Analysis", 0);
   3295         mod.sema_prog_node.activate();
   3296     }
   3297     defer if (comp.bin_file.options.module) |mod| {
   3298         mod.sema_prog_node.end();
   3299         mod.sema_prog_node = undefined;
   3300     };
   3301 
   3302     // In this main loop we give priority to non-anonymous Decls in the work queue, so
   3303     // that they can establish references to anonymous Decls, setting alive=true in the
   3304     // backend, preventing anonymous Decls from being prematurely destroyed.
   3305     while (true) {
   3306         if (comp.work_queue.readItem()) |work_item| {
   3307             try processOneJob(comp, work_item, main_progress_node);
   3308             continue;
   3309         }
   3310         if (comp.anon_work_queue.readItem()) |work_item| {
   3311             try processOneJob(comp, work_item, main_progress_node);
   3312             continue;
   3313         }
   3314         break;
   3315     }
   3316 
   3317     if (comp.job_queued_compiler_rt_lib) {
   3318         comp.job_queued_compiler_rt_lib = false;
   3319         buildCompilerRtOneShot(comp, .Lib, &comp.compiler_rt_lib, main_progress_node);
   3320     }
   3321 
   3322     if (comp.job_queued_compiler_rt_obj) {
   3323         comp.job_queued_compiler_rt_obj = false;
   3324         buildCompilerRtOneShot(comp, .Obj, &comp.compiler_rt_obj, main_progress_node);
   3325     }
   3326 }
   3327 
   3328 fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !void {
   3329     switch (job) {
   3330         .codegen_decl => |decl_index| {
   3331             const module = comp.bin_file.options.module.?;
   3332             const decl = module.declPtr(decl_index);
   3333 
   3334             switch (decl.analysis) {
   3335                 .unreferenced => unreachable,
   3336                 .in_progress => unreachable,
   3337                 .outdated => unreachable,
   3338 
   3339                 .file_failure,
   3340                 .sema_failure,
   3341                 .liveness_failure,
   3342                 .codegen_failure,
   3343                 .dependency_failure,
   3344                 .sema_failure_retryable,
   3345                 => return,
   3346 
   3347                 .complete, .codegen_failure_retryable => {
   3348                     const named_frame = tracy.namedFrame("codegen_decl");
   3349                     defer named_frame.end();
   3350 
   3351                     assert(decl.has_tv);
   3352 
   3353                     if (decl.alive) {
   3354                         try module.linkerUpdateDecl(decl_index);
   3355                         return;
   3356                     }
   3357 
   3358                     // Instead of sending this decl to the linker, we actually will delete it
   3359                     // because we found out that it in fact was never referenced.
   3360                     module.deleteUnusedDecl(decl_index);
   3361                     return;
   3362                 },
   3363             }
   3364         },
   3365         .codegen_func => |func| {
   3366             const named_frame = tracy.namedFrame("codegen_func");
   3367             defer named_frame.end();
   3368 
   3369             const module = comp.bin_file.options.module.?;
   3370             module.ensureFuncBodyAnalyzed(func) catch |err| switch (err) {
   3371                 error.OutOfMemory => return error.OutOfMemory,
   3372                 error.AnalysisFail => return,
   3373             };
   3374         },
   3375         .emit_h_decl => |decl_index| {
   3376             const module = comp.bin_file.options.module.?;
   3377             const decl = module.declPtr(decl_index);
   3378 
   3379             switch (decl.analysis) {
   3380                 .unreferenced => unreachable,
   3381                 .in_progress => unreachable,
   3382                 .outdated => unreachable,
   3383 
   3384                 .file_failure,
   3385                 .sema_failure,
   3386                 .dependency_failure,
   3387                 .sema_failure_retryable,
   3388                 => return,
   3389 
   3390                 // emit-h only requires semantic analysis of the Decl to be complete,
   3391                 // it does not depend on machine code generation to succeed.
   3392                 .liveness_failure, .codegen_failure, .codegen_failure_retryable, .complete => {
   3393                     const named_frame = tracy.namedFrame("emit_h_decl");
   3394                     defer named_frame.end();
   3395 
   3396                     const gpa = comp.gpa;
   3397                     const emit_h = module.emit_h.?;
   3398                     _ = try emit_h.decl_table.getOrPut(gpa, decl_index);
   3399                     const decl_emit_h = emit_h.declPtr(decl_index);
   3400                     const fwd_decl = &decl_emit_h.fwd_decl;
   3401                     fwd_decl.shrinkRetainingCapacity(0);
   3402                     var ctypes_arena = std.heap.ArenaAllocator.init(gpa);
   3403                     defer ctypes_arena.deinit();
   3404 
   3405                     var dg: c_codegen.DeclGen = .{
   3406                         .gpa = gpa,
   3407                         .module = module,
   3408                         .error_msg = null,
   3409                         .decl_index = decl_index.toOptional(),
   3410                         .decl = decl,
   3411                         .fwd_decl = fwd_decl.toManaged(gpa),
   3412                         .ctypes = .{},
   3413                     };
   3414                     defer {
   3415                         dg.ctypes.deinit(gpa);
   3416                         dg.fwd_decl.deinit();
   3417                     }
   3418 
   3419                     c_codegen.genHeader(&dg) catch |err| switch (err) {
   3420                         error.AnalysisFail => {
   3421                             try emit_h.failed_decls.put(gpa, decl_index, dg.error_msg.?);
   3422                             return;
   3423                         },
   3424                         else => |e| return e,
   3425                     };
   3426 
   3427                     fwd_decl.* = dg.fwd_decl.moveToUnmanaged();
   3428                     fwd_decl.shrinkAndFree(gpa, fwd_decl.items.len);
   3429                 },
   3430             }
   3431         },
   3432         .analyze_decl => |decl_index| {
   3433             const module = comp.bin_file.options.module.?;
   3434             module.ensureDeclAnalyzed(decl_index) catch |err| switch (err) {
   3435                 error.OutOfMemory => return error.OutOfMemory,
   3436                 error.AnalysisFail => return,
   3437             };
   3438             const decl = module.declPtr(decl_index);
   3439             if (decl.kind == .@"test" and comp.bin_file.options.is_test) {
   3440                 // Tests are always emitted in test binaries. The decl_refs are created by
   3441                 // Module.populateTestFunctions, but this will not queue body analysis, so do
   3442                 // that now.
   3443                 try module.ensureFuncBodyAnalysisQueued(decl.val.toIntern());
   3444             }
   3445         },
   3446         .update_embed_file => |embed_file| {
   3447             const named_frame = tracy.namedFrame("update_embed_file");
   3448             defer named_frame.end();
   3449 
   3450             const module = comp.bin_file.options.module.?;
   3451             module.updateEmbedFile(embed_file) catch |err| switch (err) {
   3452                 error.OutOfMemory => return error.OutOfMemory,
   3453                 error.AnalysisFail => return,
   3454             };
   3455         },
   3456         .update_line_number => |decl_index| {
   3457             const named_frame = tracy.namedFrame("update_line_number");
   3458             defer named_frame.end();
   3459 
   3460             const gpa = comp.gpa;
   3461             const module = comp.bin_file.options.module.?;
   3462             const decl = module.declPtr(decl_index);
   3463             comp.bin_file.updateDeclLineNumber(module, decl_index) catch |err| {
   3464                 try module.failed_decls.ensureUnusedCapacity(gpa, 1);
   3465                 module.failed_decls.putAssumeCapacityNoClobber(decl_index, try Module.ErrorMsg.create(
   3466                     gpa,
   3467                     decl.srcLoc(module),
   3468                     "unable to update line number: {s}",
   3469                     .{@errorName(err)},
   3470                 ));
   3471                 decl.analysis = .codegen_failure_retryable;
   3472             };
   3473         },
   3474         .analyze_pkg => |pkg| {
   3475             const named_frame = tracy.namedFrame("analyze_pkg");
   3476             defer named_frame.end();
   3477 
   3478             const module = comp.bin_file.options.module.?;
   3479             module.semaPkg(pkg) catch |err| switch (err) {
   3480                 error.OutOfMemory => return error.OutOfMemory,
   3481                 error.AnalysisFail => return,
   3482             };
   3483         },
   3484         .glibc_crt_file => |crt_file| {
   3485             const named_frame = tracy.namedFrame("glibc_crt_file");
   3486             defer named_frame.end();
   3487 
   3488             glibc.buildCRTFile(comp, crt_file, prog_node) catch |err| {
   3489                 // TODO Surface more error details.
   3490                 comp.lockAndSetMiscFailure(.glibc_crt_file, "unable to build glibc CRT file: {s}", .{
   3491                     @errorName(err),
   3492                 });
   3493             };
   3494         },
   3495         .glibc_shared_objects => {
   3496             const named_frame = tracy.namedFrame("glibc_shared_objects");
   3497             defer named_frame.end();
   3498 
   3499             glibc.buildSharedObjects(comp, prog_node) catch |err| {
   3500                 // TODO Surface more error details.
   3501                 comp.lockAndSetMiscFailure(
   3502                     .glibc_shared_objects,
   3503                     "unable to build glibc shared objects: {s}",
   3504                     .{@errorName(err)},
   3505                 );
   3506             };
   3507         },
   3508         .musl_crt_file => |crt_file| {
   3509             const named_frame = tracy.namedFrame("musl_crt_file");
   3510             defer named_frame.end();
   3511 
   3512             musl.buildCRTFile(comp, crt_file, prog_node) catch |err| {
   3513                 // TODO Surface more error details.
   3514                 comp.lockAndSetMiscFailure(
   3515                     .musl_crt_file,
   3516                     "unable to build musl CRT file: {s}",
   3517                     .{@errorName(err)},
   3518                 );
   3519             };
   3520         },
   3521         .mingw_crt_file => |crt_file| {
   3522             const named_frame = tracy.namedFrame("mingw_crt_file");
   3523             defer named_frame.end();
   3524 
   3525             mingw.buildCRTFile(comp, crt_file, prog_node) catch |err| {
   3526                 // TODO Surface more error details.
   3527                 comp.lockAndSetMiscFailure(
   3528                     .mingw_crt_file,
   3529                     "unable to build mingw-w64 CRT file {s}: {s}",
   3530                     .{ @tagName(crt_file), @errorName(err) },
   3531                 );
   3532             };
   3533         },
   3534         .windows_import_lib => |index| {
   3535             const named_frame = tracy.namedFrame("windows_import_lib");
   3536             defer named_frame.end();
   3537 
   3538             const link_lib = comp.bin_file.options.system_libs.keys()[index];
   3539             mingw.buildImportLib(comp, link_lib) catch |err| {
   3540                 // TODO Surface more error details.
   3541                 comp.lockAndSetMiscFailure(
   3542                     .windows_import_lib,
   3543                     "unable to generate DLL import .lib file for {s}: {s}",
   3544                     .{ link_lib, @errorName(err) },
   3545                 );
   3546             };
   3547         },
   3548         .libunwind => {
   3549             const named_frame = tracy.namedFrame("libunwind");
   3550             defer named_frame.end();
   3551 
   3552             libunwind.buildStaticLib(comp, prog_node) catch |err| {
   3553                 // TODO Surface more error details.
   3554                 comp.lockAndSetMiscFailure(
   3555                     .libunwind,
   3556                     "unable to build libunwind: {s}",
   3557                     .{@errorName(err)},
   3558                 );
   3559             };
   3560         },
   3561         .libcxx => {
   3562             const named_frame = tracy.namedFrame("libcxx");
   3563             defer named_frame.end();
   3564 
   3565             libcxx.buildLibCXX(comp, prog_node) catch |err| {
   3566                 // TODO Surface more error details.
   3567                 comp.lockAndSetMiscFailure(
   3568                     .libcxx,
   3569                     "unable to build libcxx: {s}",
   3570                     .{@errorName(err)},
   3571                 );
   3572             };
   3573         },
   3574         .libcxxabi => {
   3575             const named_frame = tracy.namedFrame("libcxxabi");
   3576             defer named_frame.end();
   3577 
   3578             libcxx.buildLibCXXABI(comp, prog_node) catch |err| {
   3579                 // TODO Surface more error details.
   3580                 comp.lockAndSetMiscFailure(
   3581                     .libcxxabi,
   3582                     "unable to build libcxxabi: {s}",
   3583                     .{@errorName(err)},
   3584                 );
   3585             };
   3586         },
   3587         .libtsan => {
   3588             const named_frame = tracy.namedFrame("libtsan");
   3589             defer named_frame.end();
   3590 
   3591             libtsan.buildTsan(comp, prog_node) catch |err| {
   3592                 // TODO Surface more error details.
   3593                 comp.lockAndSetMiscFailure(
   3594                     .libtsan,
   3595                     "unable to build TSAN library: {s}",
   3596                     .{@errorName(err)},
   3597                 );
   3598             };
   3599         },
   3600         .wasi_libc_crt_file => |crt_file| {
   3601             const named_frame = tracy.namedFrame("wasi_libc_crt_file");
   3602             defer named_frame.end();
   3603 
   3604             wasi_libc.buildCRTFile(comp, crt_file, prog_node) catch |err| {
   3605                 // TODO Surface more error details.
   3606                 comp.lockAndSetMiscFailure(
   3607                     .wasi_libc_crt_file,
   3608                     "unable to build WASI libc CRT file: {s}",
   3609                     .{@errorName(err)},
   3610                 );
   3611             };
   3612         },
   3613         .libssp => {
   3614             const named_frame = tracy.namedFrame("libssp");
   3615             defer named_frame.end();
   3616 
   3617             comp.buildOutputFromZig(
   3618                 "ssp.zig",
   3619                 .Lib,
   3620                 &comp.libssp_static_lib,
   3621                 .libssp,
   3622                 prog_node,
   3623             ) catch |err| switch (err) {
   3624                 error.OutOfMemory => return error.OutOfMemory,
   3625                 error.SubCompilationFailed => return, // error reported already
   3626                 else => comp.lockAndSetMiscFailure(
   3627                     .libssp,
   3628                     "unable to build libssp: {s}",
   3629                     .{@errorName(err)},
   3630                 ),
   3631             };
   3632         },
   3633         .zig_libc => {
   3634             const named_frame = tracy.namedFrame("zig_libc");
   3635             defer named_frame.end();
   3636 
   3637             comp.buildOutputFromZig(
   3638                 "c.zig",
   3639                 .Lib,
   3640                 &comp.libc_static_lib,
   3641                 .zig_libc,
   3642                 prog_node,
   3643             ) catch |err| switch (err) {
   3644                 error.OutOfMemory => return error.OutOfMemory,
   3645                 error.SubCompilationFailed => return, // error reported already
   3646                 else => comp.lockAndSetMiscFailure(
   3647                     .zig_libc,
   3648                     "unable to build zig's multitarget libc: {s}",
   3649                     .{@errorName(err)},
   3650                 ),
   3651             };
   3652         },
   3653     }
   3654 }
   3655 
   3656 const AstGenSrc = union(enum) {
   3657     root,
   3658     import: struct {
   3659         importing_file: *Module.File,
   3660         import_tok: std.zig.Ast.TokenIndex,
   3661     },
   3662 };
   3663 
   3664 fn workerAstGenFile(
   3665     comp: *Compilation,
   3666     file: *Module.File,
   3667     prog_node: *std.Progress.Node,
   3668     wg: *WaitGroup,
   3669     src: AstGenSrc,
   3670 ) void {
   3671     defer wg.finish();
   3672 
   3673     var child_prog_node = prog_node.start(file.sub_file_path, 0);
   3674     child_prog_node.activate();
   3675     defer child_prog_node.end();
   3676 
   3677     const mod = comp.bin_file.options.module.?;
   3678     mod.astGenFile(file) catch |err| switch (err) {
   3679         error.AnalysisFail => return,
   3680         else => {
   3681             file.status = .retryable_failure;
   3682             comp.reportRetryableAstGenError(src, file, err) catch |oom| switch (oom) {
   3683                 // Swallowing this error is OK because it's implied to be OOM when
   3684                 // there is a missing `failed_files` error message.
   3685                 error.OutOfMemory => {},
   3686             };
   3687             return;
   3688         },
   3689     };
   3690 
   3691     // Pre-emptively look for `@import` paths and queue them up.
   3692     // If we experience an error preemptively fetching the
   3693     // file, just ignore it and let it happen again later during Sema.
   3694     assert(file.zir_loaded);
   3695     const imports_index = file.zir.extra[@intFromEnum(Zir.ExtraIndex.imports)];
   3696     if (imports_index != 0) {
   3697         const extra = file.zir.extraData(Zir.Inst.Imports, imports_index);
   3698         var import_i: u32 = 0;
   3699         var extra_index = extra.end;
   3700 
   3701         while (import_i < extra.data.imports_len) : (import_i += 1) {
   3702             const item = file.zir.extraData(Zir.Inst.Imports.Item, extra_index);
   3703             extra_index = item.end;
   3704 
   3705             const import_path = file.zir.nullTerminatedString(item.data.name);
   3706             // `@import("builtin")` is handled specially.
   3707             if (mem.eql(u8, import_path, "builtin")) continue;
   3708 
   3709             const import_result = blk: {
   3710                 comp.mutex.lock();
   3711                 defer comp.mutex.unlock();
   3712 
   3713                 const res = mod.importFile(file, import_path) catch continue;
   3714                 if (!res.is_pkg) {
   3715                     res.file.addReference(mod.*, .{ .import = .{
   3716                         .file_scope = file,
   3717                         .parent_decl_node = 0,
   3718                         .lazy = .{ .token_abs = item.data.token },
   3719                     } }) catch continue;
   3720                 }
   3721                 break :blk res;
   3722             };
   3723             if (import_result.is_new) {
   3724                 log.debug("AstGen of {s} has import '{s}'; queuing AstGen of {s}", .{
   3725                     file.sub_file_path, import_path, import_result.file.sub_file_path,
   3726                 });
   3727                 const sub_src: AstGenSrc = .{ .import = .{
   3728                     .importing_file = file,
   3729                     .import_tok = item.data.token,
   3730                 } };
   3731                 wg.start();
   3732                 comp.thread_pool.spawn(workerAstGenFile, .{
   3733                     comp, import_result.file, prog_node, wg, sub_src,
   3734                 }) catch {
   3735                     wg.finish();
   3736                     continue;
   3737                 };
   3738             }
   3739         }
   3740     }
   3741 }
   3742 
   3743 fn workerUpdateBuiltinZigFile(
   3744     comp: *Compilation,
   3745     mod: *Module,
   3746     wg: *WaitGroup,
   3747 ) void {
   3748     defer wg.finish();
   3749 
   3750     mod.populateBuiltinFile() catch |err| {
   3751         const dir_path: []const u8 = mod.zig_cache_artifact_directory.path orelse ".";
   3752 
   3753         comp.mutex.lock();
   3754         defer comp.mutex.unlock();
   3755 
   3756         comp.setMiscFailure(.write_builtin_zig, "unable to write builtin.zig to {s}: {s}", .{
   3757             dir_path, @errorName(err),
   3758         });
   3759     };
   3760 }
   3761 
   3762 fn workerCheckEmbedFile(
   3763     comp: *Compilation,
   3764     embed_file: *Module.EmbedFile,
   3765     prog_node: *std.Progress.Node,
   3766     wg: *WaitGroup,
   3767 ) void {
   3768     defer wg.finish();
   3769 
   3770     var child_prog_node = prog_node.start(embed_file.sub_file_path, 0);
   3771     child_prog_node.activate();
   3772     defer child_prog_node.end();
   3773 
   3774     const mod = comp.bin_file.options.module.?;
   3775     mod.detectEmbedFileUpdate(embed_file) catch |err| {
   3776         comp.reportRetryableEmbedFileError(embed_file, err) catch |oom| switch (oom) {
   3777             // Swallowing this error is OK because it's implied to be OOM when
   3778             // there is a missing `failed_embed_files` error message.
   3779             error.OutOfMemory => {},
   3780         };
   3781         return;
   3782     };
   3783 }
   3784 
   3785 pub fn obtainCObjectCacheManifest(comp: *const Compilation) Cache.Manifest {
   3786     var man = comp.cache_parent.obtain();
   3787 
   3788     // Only things that need to be added on top of the base hash, and only things
   3789     // that apply both to @cImport and compiling C objects. No linking stuff here!
   3790     // Also nothing that applies only to compiling .zig code.
   3791     man.hash.add(comp.sanitize_c);
   3792     man.hash.addListOfBytes(comp.clang_argv);
   3793     man.hash.add(comp.bin_file.options.link_libcpp);
   3794 
   3795     // When libc_installation is null it means that Zig generated this dir list
   3796     // based on the zig library directory alone. The zig lib directory file
   3797     // path is purposefully either in the cache or not in the cache. The
   3798     // decision should not be overridden here.
   3799     if (comp.bin_file.options.libc_installation != null) {
   3800         man.hash.addListOfBytes(comp.libc_include_dir_list);
   3801     }
   3802 
   3803     return man;
   3804 }
   3805 
   3806 pub fn obtainWin32ResourceCacheManifest(comp: *const Compilation) Cache.Manifest {
   3807     var man = comp.cache_parent.obtain();
   3808 
   3809     man.hash.addListOfBytes(comp.rc_include_dir_list);
   3810 
   3811     return man;
   3812 }
   3813 
   3814 test "cImport" {
   3815     _ = cImport;
   3816 }
   3817 
   3818 const CImportResult = struct {
   3819     out_zig_path: []u8,
   3820     errors: []clang.ErrorMsg,
   3821 };
   3822 
   3823 /// Caller owns returned memory.
   3824 /// This API is currently coupled pretty tightly to stage1's needs; it will need to be reworked
   3825 /// a bit when we want to start using it from self-hosted.
   3826 pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult {
   3827     if (!build_options.have_llvm)
   3828         return error.ZigCompilerNotBuiltWithLLVMExtensions;
   3829 
   3830     const tracy_trace = trace(@src());
   3831     defer tracy_trace.end();
   3832 
   3833     const cimport_zig_basename = "cimport.zig";
   3834 
   3835     var man = comp.obtainCObjectCacheManifest();
   3836     defer man.deinit();
   3837 
   3838     man.hash.add(@as(u16, 0xb945)); // Random number to distinguish translate-c from compiling C objects
   3839     man.hash.addBytes(c_src);
   3840 
   3841     // If the previous invocation resulted in clang errors, we will see a hit
   3842     // here with 0 files in the manifest, in which case it is actually a miss.
   3843     // We need to "unhit" in this case, to keep the digests matching.
   3844     const prev_hash_state = man.hash.peekBin();
   3845     const actual_hit = hit: {
   3846         _ = try man.hit();
   3847         if (man.files.items.len == 0) {
   3848             man.unhit(prev_hash_state, 0);
   3849             break :hit false;
   3850         }
   3851         break :hit true;
   3852     };
   3853     const digest = if (!actual_hit) digest: {
   3854         var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa);
   3855         defer arena_allocator.deinit();
   3856         const arena = arena_allocator.allocator();
   3857 
   3858         const tmp_digest = man.hash.peek();
   3859         const tmp_dir_sub_path = try std.fs.path.join(arena, &[_][]const u8{ "o", &tmp_digest });
   3860         var zig_cache_tmp_dir = try comp.local_cache_directory.handle.makeOpenPath(tmp_dir_sub_path, .{});
   3861         defer zig_cache_tmp_dir.close();
   3862         const cimport_basename = "cimport.h";
   3863         const out_h_path = try comp.local_cache_directory.join(arena, &[_][]const u8{
   3864             tmp_dir_sub_path, cimport_basename,
   3865         });
   3866         const out_dep_path = try std.fmt.allocPrint(arena, "{s}.d", .{out_h_path});
   3867 
   3868         try zig_cache_tmp_dir.writeFile(cimport_basename, c_src);
   3869         if (comp.verbose_cimport) {
   3870             log.info("C import source: {s}", .{out_h_path});
   3871         }
   3872 
   3873         var argv = std.ArrayList([]const u8).init(comp.gpa);
   3874         defer argv.deinit();
   3875 
   3876         try argv.append(""); // argv[0] is program name, actual args start at [1]
   3877         try comp.addTranslateCCArgs(arena, &argv, .c, out_dep_path);
   3878 
   3879         try argv.append(out_h_path);
   3880 
   3881         if (comp.verbose_cc) {
   3882             dump_argv(argv.items);
   3883         }
   3884 
   3885         // Convert to null terminated args.
   3886         const new_argv_with_sentinel = try arena.alloc(?[*:0]const u8, argv.items.len + 1);
   3887         new_argv_with_sentinel[argv.items.len] = null;
   3888         const new_argv = new_argv_with_sentinel[0..argv.items.len :null];
   3889         for (argv.items, 0..) |arg, i| {
   3890             new_argv[i] = try arena.dupeZ(u8, arg);
   3891         }
   3892 
   3893         const c_headers_dir_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{"include"});
   3894         const c_headers_dir_path_z = try arena.dupeZ(u8, c_headers_dir_path);
   3895         var clang_errors: []clang.ErrorMsg = &[0]clang.ErrorMsg{};
   3896         var tree = translate_c.translate(
   3897             comp.gpa,
   3898             new_argv.ptr,
   3899             new_argv.ptr + new_argv.len,
   3900             &clang_errors,
   3901             c_headers_dir_path_z,
   3902         ) catch |err| switch (err) {
   3903             error.OutOfMemory => return error.OutOfMemory,
   3904             error.ASTUnitFailure => {
   3905                 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", .{});
   3906                 return error.ASTUnitFailure;
   3907             },
   3908             error.SemanticAnalyzeFail => {
   3909                 return CImportResult{
   3910                     .out_zig_path = "",
   3911                     .errors = clang_errors,
   3912                 };
   3913             },
   3914         };
   3915         defer tree.deinit(comp.gpa);
   3916 
   3917         if (comp.verbose_cimport) {
   3918             log.info("C import .d file: {s}", .{out_dep_path});
   3919         }
   3920 
   3921         const dep_basename = std.fs.path.basename(out_dep_path);
   3922         try man.addDepFilePost(zig_cache_tmp_dir, dep_basename);
   3923         if (comp.whole_cache_manifest) |whole_cache_manifest| {
   3924             comp.whole_cache_manifest_mutex.lock();
   3925             defer comp.whole_cache_manifest_mutex.unlock();
   3926             try whole_cache_manifest.addDepFilePost(zig_cache_tmp_dir, dep_basename);
   3927         }
   3928 
   3929         const digest = man.final();
   3930         const o_sub_path = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest });
   3931         var o_dir = try comp.local_cache_directory.handle.makeOpenPath(o_sub_path, .{});
   3932         defer o_dir.close();
   3933 
   3934         var out_zig_file = try o_dir.createFile(cimport_zig_basename, .{});
   3935         defer out_zig_file.close();
   3936 
   3937         const formatted = try tree.render(comp.gpa);
   3938         defer comp.gpa.free(formatted);
   3939 
   3940         try out_zig_file.writeAll(formatted);
   3941 
   3942         break :digest digest;
   3943     } else man.final();
   3944 
   3945     if (man.have_exclusive_lock) {
   3946         // Write the updated manifest. This is a no-op if the manifest is not dirty. Note that it is
   3947         // possible we had a hit and the manifest is dirty, for example if the file mtime changed but
   3948         // the contents were the same, we hit the cache but the manifest is dirty and we need to update
   3949         // it to prevent doing a full file content comparison the next time around.
   3950         man.writeManifest() catch |err| {
   3951             log.warn("failed to write cache manifest for C import: {s}", .{@errorName(err)});
   3952         };
   3953     }
   3954 
   3955     const out_zig_path = try comp.local_cache_directory.join(comp.gpa, &[_][]const u8{
   3956         "o", &digest, cimport_zig_basename,
   3957     });
   3958     if (comp.verbose_cimport) {
   3959         log.info("C import output: {s}", .{out_zig_path});
   3960     }
   3961     return CImportResult{
   3962         .out_zig_path = out_zig_path,
   3963         .errors = &[0]clang.ErrorMsg{},
   3964     };
   3965 }
   3966 
   3967 fn workerUpdateCObject(
   3968     comp: *Compilation,
   3969     c_object: *CObject,
   3970     progress_node: *std.Progress.Node,
   3971     wg: *WaitGroup,
   3972 ) void {
   3973     defer wg.finish();
   3974 
   3975     comp.updateCObject(c_object, progress_node) catch |err| switch (err) {
   3976         error.AnalysisFail => return,
   3977         else => {
   3978             comp.reportRetryableCObjectError(c_object, err) catch |oom| switch (oom) {
   3979                 // Swallowing this error is OK because it's implied to be OOM when
   3980                 // there is a missing failed_c_objects error message.
   3981                 error.OutOfMemory => {},
   3982             };
   3983         },
   3984     };
   3985 }
   3986 
   3987 fn workerUpdateWin32Resource(
   3988     comp: *Compilation,
   3989     win32_resource: *Win32Resource,
   3990     progress_node: *std.Progress.Node,
   3991     wg: *WaitGroup,
   3992 ) void {
   3993     defer wg.finish();
   3994 
   3995     comp.updateWin32Resource(win32_resource, progress_node) catch |err| switch (err) {
   3996         error.AnalysisFail => return,
   3997         else => {
   3998             comp.reportRetryableWin32ResourceError(win32_resource, err) catch |oom| switch (oom) {
   3999                 // Swallowing this error is OK because it's implied to be OOM when
   4000                 // there is a missing failed_win32_resources error message.
   4001                 error.OutOfMemory => {},
   4002             };
   4003         },
   4004     };
   4005 }
   4006 
   4007 fn buildCompilerRtOneShot(
   4008     comp: *Compilation,
   4009     output_mode: std.builtin.OutputMode,
   4010     out: *?CRTFile,
   4011     prog_node: *std.Progress.Node,
   4012 ) void {
   4013     comp.buildOutputFromZig(
   4014         "compiler_rt.zig",
   4015         output_mode,
   4016         out,
   4017         .compiler_rt,
   4018         prog_node,
   4019     ) catch |err| switch (err) {
   4020         error.SubCompilationFailed => return, // error reported already
   4021         else => comp.lockAndSetMiscFailure(
   4022             .compiler_rt,
   4023             "unable to build compiler_rt: {s}",
   4024             .{@errorName(err)},
   4025         ),
   4026     };
   4027 }
   4028 
   4029 fn reportRetryableCObjectError(
   4030     comp: *Compilation,
   4031     c_object: *CObject,
   4032     err: anyerror,
   4033 ) error{OutOfMemory}!void {
   4034     c_object.status = .failure_retryable;
   4035 
   4036     const c_obj_err_msg = try comp.gpa.create(CObject.ErrorMsg);
   4037     errdefer comp.gpa.destroy(c_obj_err_msg);
   4038     const msg = try std.fmt.allocPrint(comp.gpa, "{s}", .{@errorName(err)});
   4039     errdefer comp.gpa.free(msg);
   4040     c_obj_err_msg.* = .{
   4041         .msg = msg,
   4042         .line = 0,
   4043         .column = 0,
   4044     };
   4045     {
   4046         comp.mutex.lock();
   4047         defer comp.mutex.unlock();
   4048         try comp.failed_c_objects.putNoClobber(comp.gpa, c_object, c_obj_err_msg);
   4049     }
   4050 }
   4051 
   4052 fn reportRetryableWin32ResourceError(
   4053     comp: *Compilation,
   4054     win32_resource: *Win32Resource,
   4055     err: anyerror,
   4056 ) error{OutOfMemory}!void {
   4057     win32_resource.status = .failure_retryable;
   4058 
   4059     // TODO: something
   4060     _ = comp;
   4061     _ = @errorName(err);
   4062 }
   4063 
   4064 fn reportRetryableAstGenError(
   4065     comp: *Compilation,
   4066     src: AstGenSrc,
   4067     file: *Module.File,
   4068     err: anyerror,
   4069 ) error{OutOfMemory}!void {
   4070     const mod = comp.bin_file.options.module.?;
   4071     const gpa = mod.gpa;
   4072 
   4073     file.status = .retryable_failure;
   4074 
   4075     const src_loc: Module.SrcLoc = switch (src) {
   4076         .root => .{
   4077             .file_scope = file,
   4078             .parent_decl_node = 0,
   4079             .lazy = .entire_file,
   4080         },
   4081         .import => |info| blk: {
   4082             const importing_file = info.importing_file;
   4083 
   4084             break :blk .{
   4085                 .file_scope = importing_file,
   4086                 .parent_decl_node = 0,
   4087                 .lazy = .{ .token_abs = info.import_tok },
   4088             };
   4089         },
   4090     };
   4091 
   4092     const err_msg = if (file.pkg.root_src_directory.path) |dir_path|
   4093         try Module.ErrorMsg.create(
   4094             gpa,
   4095             src_loc,
   4096             "unable to load '{s}" ++ std.fs.path.sep_str ++ "{s}': {s}",
   4097             .{ dir_path, file.sub_file_path, @errorName(err) },
   4098         )
   4099     else
   4100         try Module.ErrorMsg.create(gpa, src_loc, "unable to load '{s}': {s}", .{
   4101             file.sub_file_path, @errorName(err),
   4102         });
   4103     errdefer err_msg.destroy(gpa);
   4104 
   4105     {
   4106         comp.mutex.lock();
   4107         defer comp.mutex.unlock();
   4108         try mod.failed_files.putNoClobber(gpa, file, err_msg);
   4109     }
   4110 }
   4111 
   4112 fn reportRetryableEmbedFileError(
   4113     comp: *Compilation,
   4114     embed_file: *Module.EmbedFile,
   4115     err: anyerror,
   4116 ) error{OutOfMemory}!void {
   4117     const mod = comp.bin_file.options.module.?;
   4118     const gpa = mod.gpa;
   4119 
   4120     const src_loc: Module.SrcLoc = mod.declPtr(embed_file.owner_decl).srcLoc(mod);
   4121 
   4122     const err_msg = if (embed_file.pkg.root_src_directory.path) |dir_path|
   4123         try Module.ErrorMsg.create(
   4124             gpa,
   4125             src_loc,
   4126             "unable to load '{s}" ++ std.fs.path.sep_str ++ "{s}': {s}",
   4127             .{ dir_path, embed_file.sub_file_path, @errorName(err) },
   4128         )
   4129     else
   4130         try Module.ErrorMsg.create(gpa, src_loc, "unable to load '{s}': {s}", .{
   4131             embed_file.sub_file_path, @errorName(err),
   4132         });
   4133     errdefer err_msg.destroy(gpa);
   4134 
   4135     {
   4136         comp.mutex.lock();
   4137         defer comp.mutex.unlock();
   4138         try mod.failed_embed_files.putNoClobber(gpa, embed_file, err_msg);
   4139     }
   4140 }
   4141 
   4142 fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.Progress.Node) !void {
   4143     if (!build_options.have_llvm) {
   4144         return comp.failCObj(c_object, "clang not available: compiler built without LLVM extensions", .{});
   4145     }
   4146     const self_exe_path = comp.self_exe_path orelse
   4147         return comp.failCObj(c_object, "clang compilation disabled", .{});
   4148 
   4149     const tracy_trace = trace(@src());
   4150     defer tracy_trace.end();
   4151 
   4152     log.debug("updating C object: {s}", .{c_object.src.src_path});
   4153 
   4154     if (c_object.clearStatus(comp.gpa)) {
   4155         // There was previous failure.
   4156         comp.mutex.lock();
   4157         defer comp.mutex.unlock();
   4158         // If the failure was OOM, there will not be an entry here, so we do
   4159         // not assert discard.
   4160         _ = comp.failed_c_objects.swapRemove(c_object);
   4161     }
   4162 
   4163     var man = comp.obtainCObjectCacheManifest();
   4164     defer man.deinit();
   4165 
   4166     man.hash.add(comp.clang_preprocessor_mode);
   4167     cache_helpers.addOptionalEmitLoc(&man.hash, comp.emit_asm);
   4168     cache_helpers.addOptionalEmitLoc(&man.hash, comp.emit_llvm_ir);
   4169     cache_helpers.addOptionalEmitLoc(&man.hash, comp.emit_llvm_bc);
   4170 
   4171     try cache_helpers.hashCSource(&man, c_object.src);
   4172 
   4173     var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa);
   4174     defer arena_allocator.deinit();
   4175     const arena = arena_allocator.allocator();
   4176 
   4177     const c_source_basename = std.fs.path.basename(c_object.src.src_path);
   4178 
   4179     c_obj_prog_node.activate();
   4180     var child_progress_node = c_obj_prog_node.start(c_source_basename, 0);
   4181     child_progress_node.activate();
   4182     defer child_progress_node.end();
   4183 
   4184     // Special case when doing build-obj for just one C file. When there are more than one object
   4185     // file and building an object we need to link them together, but with just one it should go
   4186     // directly to the output file.
   4187     const direct_o = comp.c_source_files.len == 1 and comp.bin_file.options.module == null and
   4188         comp.bin_file.options.output_mode == .Obj and comp.bin_file.options.objects.len == 0;
   4189     const o_basename_noext = if (direct_o)
   4190         comp.bin_file.options.root_name
   4191     else
   4192         c_source_basename[0 .. c_source_basename.len - std.fs.path.extension(c_source_basename).len];
   4193 
   4194     const target = comp.getTarget();
   4195     const o_ext = target.ofmt.fileExt(target.cpu.arch);
   4196     const digest = if (!comp.disable_c_depfile and try man.hit()) man.final() else blk: {
   4197         var argv = std.ArrayList([]const u8).init(comp.gpa);
   4198         defer argv.deinit();
   4199 
   4200         // In case we are doing passthrough mode, we need to detect -S and -emit-llvm.
   4201         const out_ext = e: {
   4202             if (!comp.clang_passthrough_mode)
   4203                 break :e o_ext;
   4204             if (comp.emit_asm != null)
   4205                 break :e ".s";
   4206             if (comp.emit_llvm_ir != null)
   4207                 break :e ".ll";
   4208             if (comp.emit_llvm_bc != null)
   4209                 break :e ".bc";
   4210 
   4211             break :e o_ext;
   4212         };
   4213         const o_basename = try std.fmt.allocPrint(arena, "{s}{s}", .{ o_basename_noext, out_ext });
   4214         const ext = c_object.src.ext orelse classifyFileExt(c_object.src.src_path);
   4215 
   4216         try argv.appendSlice(&[_][]const u8{ self_exe_path, "clang" });
   4217         // if "ext" is explicit, add "-x <lang>". Otherwise let clang do its thing.
   4218         if (c_object.src.ext != null) {
   4219             try argv.appendSlice(&[_][]const u8{ "-x", switch (ext) {
   4220                 .assembly => "assembler",
   4221                 .assembly_with_cpp => "assembler-with-cpp",
   4222                 .c => "c",
   4223                 .cpp => "c++",
   4224                 .cu => "cuda",
   4225                 .m => "objective-c",
   4226                 .mm => "objective-c++",
   4227                 else => fatal("language '{s}' is unsupported in this context", .{@tagName(ext)}),
   4228             } });
   4229         }
   4230         try argv.append(c_object.src.src_path);
   4231 
   4232         // When all these flags are true, it means that the entire purpose of
   4233         // this compilation is to perform a single zig cc operation. This means
   4234         // that we could "tail call" clang by doing an execve, and any use of
   4235         // the caching system would actually be problematic since the user is
   4236         // presumably doing their own caching by using dep file flags.
   4237         if (std.process.can_execv and direct_o and
   4238             comp.disable_c_depfile and comp.clang_passthrough_mode)
   4239         {
   4240             try comp.addCCArgs(arena, &argv, ext, null);
   4241             try argv.appendSlice(c_object.src.extra_flags);
   4242             try argv.appendSlice(c_object.src.cache_exempt_flags);
   4243 
   4244             const out_obj_path = if (comp.bin_file.options.emit) |emit|
   4245                 try emit.directory.join(arena, &.{emit.sub_path})
   4246             else
   4247                 "/dev/null";
   4248 
   4249             try argv.ensureUnusedCapacity(5);
   4250             switch (comp.clang_preprocessor_mode) {
   4251                 .no => argv.appendSliceAssumeCapacity(&[_][]const u8{ "-c", "-o", out_obj_path }),
   4252                 .yes => argv.appendSliceAssumeCapacity(&[_][]const u8{ "-E", "-o", out_obj_path }),
   4253                 .stdout => argv.appendAssumeCapacity("-E"),
   4254             }
   4255 
   4256             if (comp.emit_asm != null) {
   4257                 argv.appendAssumeCapacity("-S");
   4258             } else if (comp.emit_llvm_ir != null) {
   4259                 argv.appendSliceAssumeCapacity(&[_][]const u8{ "-emit-llvm", "-S" });
   4260             } else if (comp.emit_llvm_bc != null) {
   4261                 argv.appendAssumeCapacity("-emit-llvm");
   4262             }
   4263 
   4264             if (comp.verbose_cc) {
   4265                 dump_argv(argv.items);
   4266             }
   4267 
   4268             const err = std.process.execv(arena, argv.items);
   4269             fatal("unable to execv clang: {s}", .{@errorName(err)});
   4270         }
   4271 
   4272         // We can't know the digest until we do the C compiler invocation,
   4273         // so we need a temporary filename.
   4274         const out_obj_path = try comp.tmpFilePath(arena, o_basename);
   4275         var zig_cache_tmp_dir = try comp.local_cache_directory.handle.makeOpenPath("tmp", .{});
   4276         defer zig_cache_tmp_dir.close();
   4277 
   4278         const out_dep_path: ?[]const u8 = if (comp.disable_c_depfile or !ext.clangSupportsDepFile())
   4279             null
   4280         else
   4281             try std.fmt.allocPrint(arena, "{s}.d", .{out_obj_path});
   4282         try comp.addCCArgs(arena, &argv, ext, out_dep_path);
   4283         try argv.appendSlice(c_object.src.extra_flags);
   4284         try argv.appendSlice(c_object.src.cache_exempt_flags);
   4285 
   4286         try argv.ensureUnusedCapacity(5);
   4287         switch (comp.clang_preprocessor_mode) {
   4288             .no => argv.appendSliceAssumeCapacity(&[_][]const u8{ "-c", "-o", out_obj_path }),
   4289             .yes => argv.appendSliceAssumeCapacity(&[_][]const u8{ "-E", "-o", out_obj_path }),
   4290             .stdout => argv.appendAssumeCapacity("-E"),
   4291         }
   4292         if (comp.clang_passthrough_mode) {
   4293             if (comp.emit_asm != null) {
   4294                 argv.appendAssumeCapacity("-S");
   4295             } else if (comp.emit_llvm_ir != null) {
   4296                 argv.appendSliceAssumeCapacity(&[_][]const u8{ "-emit-llvm", "-S" });
   4297             } else if (comp.emit_llvm_bc != null) {
   4298                 argv.appendAssumeCapacity("-emit-llvm");
   4299             }
   4300         }
   4301 
   4302         if (comp.verbose_cc) {
   4303             dump_argv(argv.items);
   4304         }
   4305 
   4306         if (std.process.can_spawn) {
   4307             var child = std.ChildProcess.init(argv.items, arena);
   4308             if (comp.clang_passthrough_mode) {
   4309                 child.stdin_behavior = .Inherit;
   4310                 child.stdout_behavior = .Inherit;
   4311                 child.stderr_behavior = .Inherit;
   4312 
   4313                 const term = child.spawnAndWait() catch |err| {
   4314                     return comp.failCObj(c_object, "unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) });
   4315                 };
   4316                 switch (term) {
   4317                     .Exited => |code| {
   4318                         if (code != 0) {
   4319                             std.process.exit(code);
   4320                         }
   4321                         if (comp.clang_preprocessor_mode == .stdout)
   4322                             std.process.exit(0);
   4323                     },
   4324                     else => std.process.abort(),
   4325                 }
   4326             } else {
   4327                 child.stdin_behavior = .Ignore;
   4328                 child.stdout_behavior = .Ignore;
   4329                 child.stderr_behavior = .Pipe;
   4330 
   4331                 try child.spawn();
   4332 
   4333                 const stderr = try child.stderr.?.reader().readAllAlloc(arena, std.math.maxInt(usize));
   4334 
   4335                 const term = child.wait() catch |err| {
   4336                     return comp.failCObj(c_object, "unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) });
   4337                 };
   4338 
   4339                 switch (term) {
   4340                     .Exited => |code| {
   4341                         if (code != 0) {
   4342                             // TODO parse clang stderr and turn it into an error message
   4343                             // and then call failCObjWithOwnedErrorMsg
   4344                             log.err("clang failed with stderr: {s}", .{stderr});
   4345                             return comp.failCObj(c_object, "clang exited with code {d}", .{code});
   4346                         }
   4347                     },
   4348                     else => {
   4349                         log.err("clang terminated with stderr: {s}", .{stderr});
   4350                         return comp.failCObj(c_object, "clang terminated unexpectedly", .{});
   4351                     },
   4352                 }
   4353             }
   4354         } else {
   4355             const exit_code = try clangMain(arena, argv.items);
   4356             if (exit_code != 0) {
   4357                 if (comp.clang_passthrough_mode) {
   4358                     std.process.exit(exit_code);
   4359                 } else {
   4360                     return comp.failCObj(c_object, "clang exited with code {d}", .{exit_code});
   4361                 }
   4362             }
   4363             if (comp.clang_passthrough_mode and
   4364                 comp.clang_preprocessor_mode == .stdout)
   4365             {
   4366                 std.process.exit(0);
   4367             }
   4368         }
   4369 
   4370         if (out_dep_path) |dep_file_path| {
   4371             const dep_basename = std.fs.path.basename(dep_file_path);
   4372             // Add the files depended on to the cache system.
   4373             try man.addDepFilePost(zig_cache_tmp_dir, dep_basename);
   4374             if (comp.whole_cache_manifest) |whole_cache_manifest| {
   4375                 comp.whole_cache_manifest_mutex.lock();
   4376                 defer comp.whole_cache_manifest_mutex.unlock();
   4377                 try whole_cache_manifest.addDepFilePost(zig_cache_tmp_dir, dep_basename);
   4378             }
   4379             // Just to save disk space, we delete the file because it is never needed again.
   4380             zig_cache_tmp_dir.deleteFile(dep_basename) catch |err| {
   4381                 log.warn("failed to delete '{s}': {s}", .{ dep_file_path, @errorName(err) });
   4382             };
   4383         }
   4384 
   4385         // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.
   4386         if (comp.disable_c_depfile) _ = try man.hit();
   4387 
   4388         // Rename into place.
   4389         const digest = man.final();
   4390         const o_sub_path = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest });
   4391         var o_dir = try comp.local_cache_directory.handle.makeOpenPath(o_sub_path, .{});
   4392         defer o_dir.close();
   4393         const tmp_basename = std.fs.path.basename(out_obj_path);
   4394         try std.fs.rename(zig_cache_tmp_dir, tmp_basename, o_dir, o_basename);
   4395         break :blk digest;
   4396     };
   4397 
   4398     if (man.have_exclusive_lock) {
   4399         // Write the updated manifest. This is a no-op if the manifest is not dirty. Note that it is
   4400         // possible we had a hit and the manifest is dirty, for example if the file mtime changed but
   4401         // the contents were the same, we hit the cache but the manifest is dirty and we need to update
   4402         // it to prevent doing a full file content comparison the next time around.
   4403         man.writeManifest() catch |err| {
   4404             log.warn("failed to write cache manifest when compiling '{s}': {s}", .{ c_object.src.src_path, @errorName(err) });
   4405         };
   4406     }
   4407 
   4408     const o_basename = try std.fmt.allocPrint(arena, "{s}{s}", .{ o_basename_noext, o_ext });
   4409 
   4410     c_object.status = .{
   4411         .success = .{
   4412             .object_path = try comp.local_cache_directory.join(comp.gpa, &[_][]const u8{
   4413                 "o", &digest, o_basename,
   4414             }),
   4415             .lock = man.toOwnedLock(),
   4416         },
   4417     };
   4418 }
   4419 
   4420 fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32_resource_prog_node: *std.Progress.Node) !void {
   4421     if (!build_options.have_llvm) {
   4422         return comp.failWin32Resource(win32_resource, "clang not available: compiler built without LLVM extensions", .{});
   4423     }
   4424     const self_exe_path = comp.self_exe_path orelse
   4425         return comp.failWin32Resource(win32_resource, "clang compilation disabled", .{});
   4426 
   4427     const tracy_trace = trace(@src());
   4428     defer tracy_trace.end();
   4429 
   4430     log.debug("updating win32 resource: {s}", .{win32_resource.src.src_path});
   4431 
   4432     if (win32_resource.clearStatus(comp.gpa)) {
   4433         // There was previous failure.
   4434         comp.mutex.lock();
   4435         defer comp.mutex.unlock();
   4436         // If the failure was OOM, there will not be an entry here, so we do
   4437         // not assert discard.
   4438         _ = comp.failed_win32_resources.swapRemove(win32_resource);
   4439     }
   4440 
   4441     var man = comp.obtainWin32ResourceCacheManifest();
   4442     defer man.deinit();
   4443 
   4444     _ = try man.addFile(win32_resource.src.src_path, null);
   4445     man.hash.addListOfBytes(win32_resource.src.extra_flags);
   4446 
   4447     var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa);
   4448     defer arena_allocator.deinit();
   4449     const arena = arena_allocator.allocator();
   4450 
   4451     const rc_basename = std.fs.path.basename(win32_resource.src.src_path);
   4452 
   4453     win32_resource_prog_node.activate();
   4454     var child_progress_node = win32_resource_prog_node.start(rc_basename, 0);
   4455     child_progress_node.activate();
   4456     defer child_progress_node.end();
   4457 
   4458     const rc_basename_noext = rc_basename[0 .. rc_basename.len - std.fs.path.extension(rc_basename).len];
   4459 
   4460     const digest = if (try man.hit()) man.final() else blk: {
   4461         const rcpp_filename = try std.fmt.allocPrint(arena, "{s}.rcpp", .{rc_basename_noext});
   4462 
   4463         const out_rcpp_path = try comp.tmpFilePath(arena, rcpp_filename);
   4464         var zig_cache_tmp_dir = try comp.local_cache_directory.handle.makeOpenPath("tmp", .{});
   4465         defer zig_cache_tmp_dir.close();
   4466 
   4467         const res_filename = try std.fmt.allocPrint(arena, "{s}.res", .{rc_basename_noext});
   4468 
   4469         // We can't know the digest until we do the compilation,
   4470         // so we need a temporary filename.
   4471         const out_res_path = try comp.tmpFilePath(arena, res_filename);
   4472 
   4473         var options = options: {
   4474             var resinator_args = try std.ArrayListUnmanaged([]const u8).initCapacity(comp.gpa, win32_resource.src.extra_flags.len + 4);
   4475             defer resinator_args.deinit(comp.gpa);
   4476 
   4477             resinator_args.appendAssumeCapacity(""); // dummy 'process name' arg
   4478             resinator_args.appendSliceAssumeCapacity(win32_resource.src.extra_flags);
   4479             resinator_args.appendSliceAssumeCapacity(&.{ "--", out_rcpp_path, out_res_path });
   4480 
   4481             var cli_diagnostics = resinator.cli.Diagnostics.init(comp.gpa);
   4482             defer cli_diagnostics.deinit();
   4483             var options = resinator.cli.parse(comp.gpa, resinator_args.items, &cli_diagnostics) catch |err| switch (err) {
   4484                 error.ParseError => {
   4485                     return comp.failWin32ResourceCli(win32_resource, &cli_diagnostics);
   4486                 },
   4487                 else => |e| return e,
   4488             };
   4489             break :options options;
   4490         };
   4491         defer options.deinit();
   4492 
   4493         var argv = std.ArrayList([]const u8).init(comp.gpa);
   4494         defer argv.deinit();
   4495         var temp_strings = std.ArrayList([]const u8).init(comp.gpa);
   4496         defer {
   4497             for (temp_strings.items) |temp_string| {
   4498                 comp.gpa.free(temp_string);
   4499             }
   4500             temp_strings.deinit();
   4501         }
   4502 
   4503         // TODO: support options.preprocess == .no and .only
   4504         //       alternatively, error if those options are used
   4505         try argv.appendSlice(&[_][]const u8{
   4506             self_exe_path,
   4507             "clang",
   4508             "-E", // preprocessor only
   4509             "--comments",
   4510             "-fuse-line-directives", // #line <num> instead of # <num>
   4511             "-xc", // output c
   4512             "-Werror=null-character", // error on null characters instead of converting them to spaces
   4513             "-fms-compatibility", // Allow things like "header.h" to be resolved relative to the 'root' .rc file, among other things
   4514             "-DRC_INVOKED", // https://learn.microsoft.com/en-us/windows/win32/menurc/predefined-macros
   4515         });
   4516         // Using -fms-compatibility and targeting the gnu abi interact in a strange way:
   4517         // - Targeting the GNU abi stops _MSC_VER from being defined
   4518         // - Passing -fms-compatibility stops __GNUC__ from being defined
   4519         // Neither being defined is a problem for things like things like MinGW's
   4520         // vadefs.h, which will fail during preprocessing if neither are defined.
   4521         // So, when targeting the GNU abi, we need to force __GNUC__ to be defined.
   4522         //
   4523         // TODO: This is a workaround that should be removed if possible.
   4524         if (comp.getTarget().isGnu()) {
   4525             // This is the same default gnuc version that Clang uses:
   4526             // https://github.com/llvm/llvm-project/blob/4b5366c9512aa273a5272af1d833961e1ed156e7/clang/lib/Driver/ToolChains/Clang.cpp#L6738
   4527             try argv.append("-fgnuc-version=4.2.1");
   4528         }
   4529         for (options.extra_include_paths.items) |extra_include_path| {
   4530             try argv.append("--include-directory");
   4531             try argv.append(extra_include_path);
   4532         }
   4533         var symbol_it = options.symbols.iterator();
   4534         while (symbol_it.next()) |entry| {
   4535             switch (entry.value_ptr.*) {
   4536                 .define => |value| {
   4537                     try argv.append("-D");
   4538                     const define_arg = arg: {
   4539                         const arg = try std.fmt.allocPrint(comp.gpa, "{s}={s}", .{ entry.key_ptr.*, value });
   4540                         errdefer comp.gpa.free(arg);
   4541                         try temp_strings.append(arg);
   4542                         break :arg arg;
   4543                     };
   4544                     try argv.append(define_arg);
   4545                 },
   4546                 .undefine => {
   4547                     try argv.append("-U");
   4548                     try argv.append(entry.key_ptr.*);
   4549                 },
   4550             }
   4551         }
   4552         try argv.append(win32_resource.src.src_path);
   4553         try argv.appendSlice(&[_][]const u8{
   4554             "-o",
   4555             out_rcpp_path,
   4556         });
   4557 
   4558         const out_dep_path = try std.fmt.allocPrint(arena, "{s}.d", .{out_rcpp_path});
   4559         // Note: addCCArgs will implicitly add _DEBUG/NDEBUG depending on the optimization
   4560         // mode. While these defines are not normally present when calling rc.exe directly,
   4561         // them being defined matches the behavior of how MSVC calls rc.exe which is the more
   4562         // relevant behavior in this case.
   4563         try comp.addCCArgs(arena, &argv, .rc, out_dep_path);
   4564 
   4565         if (comp.verbose_cc) {
   4566             dump_argv(argv.items);
   4567         }
   4568 
   4569         if (std.process.can_spawn) {
   4570             var child = std.ChildProcess.init(argv.items, arena);
   4571             child.stdin_behavior = .Ignore;
   4572             child.stdout_behavior = .Ignore;
   4573             child.stderr_behavior = .Pipe;
   4574 
   4575             try child.spawn();
   4576 
   4577             const stderr_reader = child.stderr.?.reader();
   4578 
   4579             const stderr = try stderr_reader.readAllAlloc(arena, 10 * 1024 * 1024);
   4580 
   4581             const term = child.wait() catch |err| {
   4582                 return comp.failWin32Resource(win32_resource, "unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) });
   4583             };
   4584 
   4585             switch (term) {
   4586                 .Exited => |code| {
   4587                     if (code != 0) {
   4588                         // TODO parse clang stderr and turn it into an error message
   4589                         // and then call failCObjWithOwnedErrorMsg
   4590                         log.err("clang preprocessor failed with stderr:\n{s}", .{stderr});
   4591                         return comp.failWin32Resource(win32_resource, "clang preprocessor exited with code {d}", .{code});
   4592                     }
   4593                 },
   4594                 else => {
   4595                     log.err("clang preprocessor terminated with stderr:\n{s}", .{stderr});
   4596                     return comp.failWin32Resource(win32_resource, "clang preprocessor terminated unexpectedly", .{});
   4597                 },
   4598             }
   4599         } else {
   4600             const exit_code = try clangMain(arena, argv.items);
   4601             if (exit_code != 0) {
   4602                 return comp.failWin32Resource(win32_resource, "clang preprocessor exited with code {d}", .{exit_code});
   4603             }
   4604         }
   4605 
   4606         const dep_basename = std.fs.path.basename(out_dep_path);
   4607         // Add the files depended on to the cache system.
   4608         try man.addDepFilePost(zig_cache_tmp_dir, dep_basename);
   4609         if (comp.whole_cache_manifest) |whole_cache_manifest| {
   4610             comp.whole_cache_manifest_mutex.lock();
   4611             defer comp.whole_cache_manifest_mutex.unlock();
   4612             try whole_cache_manifest.addDepFilePost(zig_cache_tmp_dir, dep_basename);
   4613         }
   4614         // Just to save disk space, we delete the file because it is never needed again.
   4615         zig_cache_tmp_dir.deleteFile(dep_basename) catch |err| {
   4616             log.warn("failed to delete '{s}': {s}", .{ out_dep_path, @errorName(err) });
   4617         };
   4618 
   4619         var full_input = std.fs.cwd().readFileAlloc(arena, out_rcpp_path, std.math.maxInt(usize)) catch |err| switch (err) {
   4620             error.OutOfMemory => return error.OutOfMemory,
   4621             else => |e| {
   4622                 return comp.failWin32Resource(win32_resource, "failed to read preprocessed file '{s}': {s}", .{ out_rcpp_path, @errorName(e) });
   4623             },
   4624         };
   4625 
   4626         var mapping_results = try resinator.source_mapping.parseAndRemoveLineCommands(arena, full_input, full_input, .{ .initial_filename = win32_resource.src.src_path });
   4627         defer mapping_results.mappings.deinit(arena);
   4628 
   4629         var final_input = resinator.comments.removeComments(mapping_results.result, mapping_results.result, &mapping_results.mappings);
   4630 
   4631         var output_file = zig_cache_tmp_dir.createFile(out_res_path, .{}) catch |err| {
   4632             return comp.failWin32Resource(win32_resource, "failed to create output file '{s}': {s}", .{ out_res_path, @errorName(err) });
   4633         };
   4634         var output_file_closed = false;
   4635         defer if (!output_file_closed) output_file.close();
   4636 
   4637         var diagnostics = resinator.errors.Diagnostics.init(arena);
   4638         defer diagnostics.deinit();
   4639 
   4640         var dependencies_list = std.ArrayList([]const u8).init(comp.gpa);
   4641         defer {
   4642             for (dependencies_list.items) |item| {
   4643                 comp.gpa.free(item);
   4644             }
   4645             dependencies_list.deinit();
   4646         }
   4647 
   4648         var output_buffered_stream = std.io.bufferedWriter(output_file.writer());
   4649 
   4650         resinator.compile.compile(arena, final_input, output_buffered_stream.writer(), .{
   4651             .cwd = std.fs.cwd(),
   4652             .diagnostics = &diagnostics,
   4653             .source_mappings = &mapping_results.mappings,
   4654             .dependencies_list = &dependencies_list,
   4655             .system_include_paths = comp.rc_include_dir_list,
   4656             .ignore_include_env_var = true,
   4657             // options
   4658             .extra_include_paths = options.extra_include_paths.items,
   4659             .default_language_id = options.default_language_id,
   4660             .default_code_page = options.default_code_page orelse .windows1252,
   4661             .verbose = options.verbose,
   4662             .null_terminate_string_table_strings = options.null_terminate_string_table_strings,
   4663             .max_string_literal_codepoints = options.max_string_literal_codepoints,
   4664             .silent_duplicate_control_ids = options.silent_duplicate_control_ids,
   4665             .warn_instead_of_error_on_invalid_code_page = options.warn_instead_of_error_on_invalid_code_page,
   4666         }) catch |err| switch (err) {
   4667             error.ParseError, error.CompileError => {
   4668                 // Delete the output file on error
   4669                 output_file.close();
   4670                 output_file_closed = true;
   4671                 // Failing to delete is not really a big deal, so swallow any errors
   4672                 zig_cache_tmp_dir.deleteFile(out_res_path) catch {
   4673                     log.warn("failed to delete '{s}': {s}", .{ out_res_path, @errorName(err) });
   4674                 };
   4675                 return comp.failWin32ResourceCompile(win32_resource, final_input, &diagnostics, mapping_results.mappings);
   4676             },
   4677             else => |e| return e,
   4678         };
   4679 
   4680         try output_buffered_stream.flush();
   4681 
   4682         for (dependencies_list.items) |dep_file_path| {
   4683             try man.addFilePost(dep_file_path);
   4684             if (comp.whole_cache_manifest) |whole_cache_manifest| {
   4685                 comp.whole_cache_manifest_mutex.lock();
   4686                 defer comp.whole_cache_manifest_mutex.unlock();
   4687                 try whole_cache_manifest.addFilePost(dep_file_path);
   4688             }
   4689         }
   4690 
   4691         // Rename into place.
   4692         const digest = man.final();
   4693         const o_sub_path = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest });
   4694         var o_dir = try comp.local_cache_directory.handle.makeOpenPath(o_sub_path, .{});
   4695         defer o_dir.close();
   4696         const tmp_basename = std.fs.path.basename(out_res_path);
   4697         try std.fs.rename(zig_cache_tmp_dir, tmp_basename, o_dir, res_filename);
   4698         const tmp_rcpp_basename = std.fs.path.basename(out_rcpp_path);
   4699         try std.fs.rename(zig_cache_tmp_dir, tmp_rcpp_basename, o_dir, rcpp_filename);
   4700         break :blk digest;
   4701     };
   4702 
   4703     if (man.have_exclusive_lock) {
   4704         // Write the updated manifest. This is a no-op if the manifest is not dirty. Note that it is
   4705         // possible we had a hit and the manifest is dirty, for example if the file mtime changed but
   4706         // the contents were the same, we hit the cache but the manifest is dirty and we need to update
   4707         // it to prevent doing a full file content comparison the next time around.
   4708         man.writeManifest() catch |err| {
   4709             log.warn("failed to write cache manifest when compiling '{s}': {s}", .{ win32_resource.src.src_path, @errorName(err) });
   4710         };
   4711     }
   4712 
   4713     const res_basename = try std.fmt.allocPrint(arena, "{s}.res", .{rc_basename_noext});
   4714 
   4715     win32_resource.status = .{
   4716         .success = .{
   4717             .res_path = try comp.local_cache_directory.join(comp.gpa, &[_][]const u8{
   4718                 "o", &digest, res_basename,
   4719             }),
   4720             .lock = man.toOwnedLock(),
   4721         },
   4722     };
   4723 }
   4724 
   4725 pub fn tmpFilePath(comp: *Compilation, ally: Allocator, suffix: []const u8) error{OutOfMemory}![]const u8 {
   4726     const s = std.fs.path.sep_str;
   4727     const rand_int = std.crypto.random.int(u64);
   4728     if (comp.local_cache_directory.path) |p| {
   4729         return std.fmt.allocPrint(ally, "{s}" ++ s ++ "tmp" ++ s ++ "{x}-{s}", .{ p, rand_int, suffix });
   4730     } else {
   4731         return std.fmt.allocPrint(ally, "tmp" ++ s ++ "{x}-{s}", .{ rand_int, suffix });
   4732     }
   4733 }
   4734 
   4735 pub fn addTranslateCCArgs(
   4736     comp: *Compilation,
   4737     arena: Allocator,
   4738     argv: *std.ArrayList([]const u8),
   4739     ext: FileExt,
   4740     out_dep_path: ?[]const u8,
   4741 ) !void {
   4742     try argv.appendSlice(&[_][]const u8{ "-x", "c" });
   4743     try comp.addCCArgs(arena, argv, ext, out_dep_path);
   4744     // This gives us access to preprocessing entities, presumably at the cost of performance.
   4745     try argv.appendSlice(&[_][]const u8{ "-Xclang", "-detailed-preprocessing-record" });
   4746 }
   4747 
   4748 /// Add common C compiler args between translate-c and C object compilation.
   4749 pub fn addCCArgs(
   4750     comp: *const Compilation,
   4751     arena: Allocator,
   4752     argv: *std.ArrayList([]const u8),
   4753     ext: FileExt,
   4754     out_dep_path: ?[]const u8,
   4755 ) !void {
   4756     const target = comp.getTarget();
   4757 
   4758     // As of Clang 16.x, it will by default read extra flags from /etc/clang.
   4759     // I'm sure the person who implemented this means well, but they have a lot
   4760     // to learn about abstractions and where the appropriate boundaries between
   4761     // them are. The road to hell is paved with good intentions. Fortunately it
   4762     // can be disabled.
   4763     try argv.append("--no-default-config");
   4764 
   4765     if (ext == .cpp) {
   4766         try argv.append("-nostdinc++");
   4767     }
   4768 
   4769     // We don't ever put `-fcolor-diagnostics` or `-fno-color-diagnostics` because in passthrough mode
   4770     // we want Clang to infer it, and in normal mode we always want it off, which will be true since
   4771     // clang will detect stderr as a pipe rather than a terminal.
   4772     if (!comp.clang_passthrough_mode) {
   4773         // Make stderr more easily parseable.
   4774         try argv.append("-fno-caret-diagnostics");
   4775     }
   4776 
   4777     if (comp.bin_file.options.function_sections) {
   4778         try argv.append("-ffunction-sections");
   4779     }
   4780 
   4781     if (comp.bin_file.options.no_builtin) {
   4782         try argv.append("-fno-builtin");
   4783     }
   4784 
   4785     if (comp.bin_file.options.link_libcpp) {
   4786         const libcxx_include_path = try std.fs.path.join(arena, &[_][]const u8{
   4787             comp.zig_lib_directory.path.?, "libcxx", "include",
   4788         });
   4789         const libcxxabi_include_path = try std.fs.path.join(arena, &[_][]const u8{
   4790             comp.zig_lib_directory.path.?, "libcxxabi", "include",
   4791         });
   4792 
   4793         try argv.append("-isystem");
   4794         try argv.append(libcxx_include_path);
   4795 
   4796         try argv.append("-isystem");
   4797         try argv.append(libcxxabi_include_path);
   4798 
   4799         if (target.abi.isMusl()) {
   4800             try argv.append("-D_LIBCPP_HAS_MUSL_LIBC");
   4801         }
   4802         try argv.append("-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS");
   4803         try argv.append("-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS");
   4804         try argv.append("-D_LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS");
   4805 
   4806         if (comp.bin_file.options.single_threaded) {
   4807             try argv.append("-D_LIBCPP_HAS_NO_THREADS");
   4808         }
   4809 
   4810         // See the comment in libcxx.zig for more details about this.
   4811         try argv.append("-D_LIBCPP_PSTL_CPU_BACKEND_SERIAL");
   4812 
   4813         try argv.append(try std.fmt.allocPrint(arena, "-D_LIBCPP_ABI_VERSION={d}", .{
   4814             @intFromEnum(comp.libcxx_abi_version),
   4815         }));
   4816         try argv.append(try std.fmt.allocPrint(arena, "-D_LIBCPP_ABI_NAMESPACE=__{d}", .{
   4817             @intFromEnum(comp.libcxx_abi_version),
   4818         }));
   4819     }
   4820 
   4821     if (comp.bin_file.options.link_libunwind) {
   4822         const libunwind_include_path = try std.fs.path.join(arena, &[_][]const u8{
   4823             comp.zig_lib_directory.path.?, "libunwind", "include",
   4824         });
   4825 
   4826         try argv.append("-isystem");
   4827         try argv.append(libunwind_include_path);
   4828     }
   4829 
   4830     if (comp.bin_file.options.link_libc and target.isGnuLibC()) {
   4831         const target_version = target.os.version_range.linux.glibc;
   4832         const glibc_minor_define = try std.fmt.allocPrint(arena, "-D__GLIBC_MINOR__={d}", .{
   4833             target_version.minor,
   4834         });
   4835         try argv.append(glibc_minor_define);
   4836     }
   4837 
   4838     const llvm_triple = try @import("codegen/llvm.zig").targetTriple(arena, target);
   4839     try argv.appendSlice(&[_][]const u8{ "-target", llvm_triple });
   4840 
   4841     switch (ext) {
   4842         .c, .cpp, .m, .mm, .h, .cu, .rc => {
   4843             try argv.appendSlice(&[_][]const u8{
   4844                 "-nostdinc",
   4845                 "-fno-spell-checking",
   4846             });
   4847             if (comp.bin_file.options.lto) {
   4848                 try argv.append("-flto");
   4849             }
   4850 
   4851             if (ext == .mm) {
   4852                 try argv.append("-ObjC++");
   4853             }
   4854 
   4855             for (comp.libc_framework_dir_list) |framework_dir| {
   4856                 try argv.appendSlice(&.{ "-iframework", framework_dir });
   4857             }
   4858 
   4859             for (comp.bin_file.options.framework_dirs) |framework_dir| {
   4860                 try argv.appendSlice(&.{ "-F", framework_dir });
   4861             }
   4862 
   4863             // According to Rich Felker libc headers are supposed to go before C language headers.
   4864             // However as noted by @dimenus, appending libc headers before c_headers breaks intrinsics
   4865             // and other compiler specific items.
   4866             const c_headers_dir = try std.fs.path.join(arena, &[_][]const u8{ comp.zig_lib_directory.path.?, "include" });
   4867             try argv.append("-isystem");
   4868             try argv.append(c_headers_dir);
   4869 
   4870             if (ext == .rc) {
   4871                 for (comp.rc_include_dir_list) |include_dir| {
   4872                     try argv.append("-isystem");
   4873                     try argv.append(include_dir);
   4874                 }
   4875             } else {
   4876                 for (comp.libc_include_dir_list) |include_dir| {
   4877                     try argv.append("-isystem");
   4878                     try argv.append(include_dir);
   4879                 }
   4880             }
   4881 
   4882             if (target.cpu.model.llvm_name) |llvm_name| {
   4883                 try argv.appendSlice(&[_][]const u8{
   4884                     "-Xclang", "-target-cpu", "-Xclang", llvm_name,
   4885                 });
   4886             }
   4887 
   4888             // It would be really nice if there was a more compact way to communicate this info to Clang.
   4889             const all_features_list = target.cpu.arch.allFeaturesList();
   4890             try argv.ensureUnusedCapacity(all_features_list.len * 4);
   4891             for (all_features_list, 0..) |feature, index_usize| {
   4892                 const index = @as(std.Target.Cpu.Feature.Set.Index, @intCast(index_usize));
   4893                 const is_enabled = target.cpu.features.isEnabled(index);
   4894 
   4895                 if (feature.llvm_name) |llvm_name| {
   4896                     argv.appendSliceAssumeCapacity(&[_][]const u8{ "-Xclang", "-target-feature", "-Xclang" });
   4897                     const plus_or_minus = "-+"[@intFromBool(is_enabled)];
   4898                     const arg = try std.fmt.allocPrint(arena, "{c}{s}", .{ plus_or_minus, llvm_name });
   4899                     argv.appendAssumeCapacity(arg);
   4900                 }
   4901             }
   4902             const mcmodel = comp.bin_file.options.machine_code_model;
   4903             if (mcmodel != .default) {
   4904                 try argv.append(try std.fmt.allocPrint(arena, "-mcmodel={s}", .{@tagName(mcmodel)}));
   4905             }
   4906 
   4907             switch (target.os.tag) {
   4908                 .windows => {
   4909                     // windows.h has files such as pshpack1.h which do #pragma packing,
   4910                     // triggering a clang warning. So for this target, we disable this warning.
   4911                     if (target.abi.isGnu()) {
   4912                         try argv.append("-Wno-pragma-pack");
   4913                     }
   4914                 },
   4915                 .macos => {
   4916                     try argv.ensureUnusedCapacity(2);
   4917                     // Pass the proper -m<os>-version-min argument for darwin.
   4918                     const ver = target.os.version_range.semver.min;
   4919                     argv.appendAssumeCapacity(try std.fmt.allocPrint(arena, "-mmacos-version-min={d}.{d}.{d}", .{
   4920                         ver.major, ver.minor, ver.patch,
   4921                     }));
   4922                     // This avoids a warning that sometimes occurs when
   4923                     // providing both a -target argument that contains a
   4924                     // version as well as the -mmacosx-version-min argument.
   4925                     // Zig provides the correct value in both places, so it
   4926                     // doesn't matter which one gets overridden.
   4927                     argv.appendAssumeCapacity("-Wno-overriding-t-option");
   4928                 },
   4929                 .ios, .tvos, .watchos => switch (target.cpu.arch) {
   4930                     // Pass the proper -m<os>-version-min argument for darwin.
   4931                     .x86, .x86_64 => {
   4932                         const ver = target.os.version_range.semver.min;
   4933                         try argv.append(try std.fmt.allocPrint(
   4934                             arena,
   4935                             "-m{s}-simulator-version-min={d}.{d}.{d}",
   4936                             .{ @tagName(target.os.tag), ver.major, ver.minor, ver.patch },
   4937                         ));
   4938                     },
   4939                     else => {
   4940                         const ver = target.os.version_range.semver.min;
   4941                         try argv.append(try std.fmt.allocPrint(arena, "-m{s}-version-min={d}.{d}.{d}", .{
   4942                             @tagName(target.os.tag), ver.major, ver.minor, ver.patch,
   4943                         }));
   4944                     },
   4945                 },
   4946                 else => {},
   4947             }
   4948 
   4949             if (target.cpu.arch.isThumb()) {
   4950                 try argv.append("-mthumb");
   4951             }
   4952 
   4953             if (comp.sanitize_c and !comp.bin_file.options.tsan) {
   4954                 try argv.append("-fsanitize=undefined");
   4955                 try argv.append("-fsanitize-trap=undefined");
   4956                 // It is very common, and well-defined, for a pointer on one side of a C ABI
   4957                 // to have a different but compatible element type. Examples include:
   4958                 // `char*` vs `uint8_t*` on a system with 8-bit bytes
   4959                 // `const char*` vs `char*`
   4960                 // `char*` vs `unsigned char*`
   4961                 // Without this flag, Clang would invoke UBSAN when such an extern
   4962                 // function was called.
   4963                 try argv.append("-fno-sanitize=function");
   4964             } else if (comp.sanitize_c and comp.bin_file.options.tsan) {
   4965                 try argv.append("-fsanitize=undefined,thread");
   4966                 try argv.append("-fsanitize-trap=undefined");
   4967                 try argv.append("-fno-sanitize=function");
   4968             } else if (!comp.sanitize_c and comp.bin_file.options.tsan) {
   4969                 try argv.append("-fsanitize=thread");
   4970             }
   4971 
   4972             if (comp.bin_file.options.red_zone) {
   4973                 try argv.append("-mred-zone");
   4974             } else if (target_util.hasRedZone(target)) {
   4975                 try argv.append("-mno-red-zone");
   4976             }
   4977 
   4978             if (comp.bin_file.options.omit_frame_pointer) {
   4979                 try argv.append("-fomit-frame-pointer");
   4980             } else {
   4981                 try argv.append("-fno-omit-frame-pointer");
   4982             }
   4983 
   4984             const ssp_buf_size = comp.bin_file.options.stack_protector;
   4985             if (ssp_buf_size != 0) {
   4986                 try argv.appendSlice(&[_][]const u8{
   4987                     "-fstack-protector-strong",
   4988                     "--param",
   4989                     try std.fmt.allocPrint(arena, "ssp-buffer-size={d}", .{ssp_buf_size}),
   4990                 });
   4991             } else {
   4992                 try argv.append("-fno-stack-protector");
   4993             }
   4994 
   4995             switch (comp.bin_file.options.optimize_mode) {
   4996                 .Debug => {
   4997                     // windows c runtime requires -D_DEBUG if using debug libraries
   4998                     try argv.append("-D_DEBUG");
   4999                     // Clang has -Og for compatibility with GCC, but currently it is just equivalent
   5000                     // to -O1. Besides potentially impairing debugging, -O1/-Og significantly
   5001                     // increases compile times.
   5002                     try argv.append("-O0");
   5003                 },
   5004                 .ReleaseSafe => {
   5005                     // See the comment in the BuildModeFastRelease case for why we pass -O2 rather
   5006                     // than -O3 here.
   5007                     try argv.append("-O2");
   5008                     try argv.append("-D_FORTIFY_SOURCE=2");
   5009                 },
   5010                 .ReleaseFast => {
   5011                     try argv.append("-DNDEBUG");
   5012                     // Here we pass -O2 rather than -O3 because, although we do the equivalent of
   5013                     // -O3 in Zig code, the justification for the difference here is that Zig
   5014                     // has better detection and prevention of undefined behavior, so -O3 is safer for
   5015                     // Zig code than it is for C code. Also, C programmers are used to their code
   5016                     // running in -O2 and thus the -O3 path has been tested less.
   5017                     try argv.append("-O2");
   5018                 },
   5019                 .ReleaseSmall => {
   5020                     try argv.append("-DNDEBUG");
   5021                     try argv.append("-Os");
   5022                 },
   5023             }
   5024 
   5025             if (target_util.supports_fpic(target) and comp.bin_file.options.pic) {
   5026                 try argv.append("-fPIC");
   5027             }
   5028 
   5029             if (comp.unwind_tables) {
   5030                 try argv.append("-funwind-tables");
   5031             } else {
   5032                 try argv.append("-fno-unwind-tables");
   5033             }
   5034         },
   5035         .shared_library, .ll, .bc, .unknown, .static_library, .object, .def, .zig, .res => {},
   5036         .assembly, .assembly_with_cpp => {
   5037             if (ext == .assembly_with_cpp) {
   5038                 const c_headers_dir = try std.fs.path.join(arena, &[_][]const u8{ comp.zig_lib_directory.path.?, "include" });
   5039                 try argv.append("-isystem");
   5040                 try argv.append(c_headers_dir);
   5041             }
   5042 
   5043             // The Clang assembler does not accept the list of CPU features like the
   5044             // compiler frontend does. Therefore we must hard-code the -m flags for
   5045             // all CPU features here.
   5046             switch (target.cpu.arch) {
   5047                 .riscv32, .riscv64 => {
   5048                     const RvArchFeat = struct { char: u8, feat: std.Target.riscv.Feature };
   5049                     const letters = [_]RvArchFeat{
   5050                         .{ .char = 'm', .feat = .m },
   5051                         .{ .char = 'a', .feat = .a },
   5052                         .{ .char = 'f', .feat = .f },
   5053                         .{ .char = 'd', .feat = .d },
   5054                         .{ .char = 'c', .feat = .c },
   5055                     };
   5056                     const prefix: []const u8 = if (target.cpu.arch == .riscv64) "rv64" else "rv32";
   5057                     const prefix_len = 4;
   5058                     assert(prefix.len == prefix_len);
   5059                     var march_buf: [prefix_len + letters.len + 1]u8 = undefined;
   5060                     var march_index: usize = prefix_len;
   5061                     @memcpy(march_buf[0..prefix.len], prefix);
   5062 
   5063                     if (std.Target.riscv.featureSetHas(target.cpu.features, .e)) {
   5064                         march_buf[march_index] = 'e';
   5065                     } else {
   5066                         march_buf[march_index] = 'i';
   5067                     }
   5068                     march_index += 1;
   5069 
   5070                     for (letters) |letter| {
   5071                         if (std.Target.riscv.featureSetHas(target.cpu.features, letter.feat)) {
   5072                             march_buf[march_index] = letter.char;
   5073                             march_index += 1;
   5074                         }
   5075                     }
   5076 
   5077                     const march_arg = try std.fmt.allocPrint(arena, "-march={s}", .{
   5078                         march_buf[0..march_index],
   5079                     });
   5080                     try argv.append(march_arg);
   5081 
   5082                     if (std.Target.riscv.featureSetHas(target.cpu.features, .relax)) {
   5083                         try argv.append("-mrelax");
   5084                     } else {
   5085                         try argv.append("-mno-relax");
   5086                     }
   5087                     if (std.Target.riscv.featureSetHas(target.cpu.features, .save_restore)) {
   5088                         try argv.append("-msave-restore");
   5089                     } else {
   5090                         try argv.append("-mno-save-restore");
   5091                     }
   5092                 },
   5093                 .mips, .mipsel, .mips64, .mips64el => {
   5094                     if (target.cpu.model.llvm_name) |llvm_name| {
   5095                         try argv.append(try std.fmt.allocPrint(arena, "-march={s}", .{llvm_name}));
   5096                     }
   5097 
   5098                     if (std.Target.mips.featureSetHas(target.cpu.features, .soft_float)) {
   5099                         try argv.append("-msoft-float");
   5100                     }
   5101                 },
   5102                 else => {
   5103                     // TODO
   5104                 },
   5105             }
   5106             if (target_util.clangAssemblerSupportsMcpuArg(target)) {
   5107                 if (target.cpu.model.llvm_name) |llvm_name| {
   5108                     try argv.append(try std.fmt.allocPrint(arena, "-mcpu={s}", .{llvm_name}));
   5109                 }
   5110             }
   5111         },
   5112     }
   5113 
   5114     if (!comp.bin_file.options.strip) {
   5115         switch (target.ofmt) {
   5116             .coff => {
   5117                 // -g is required here because -gcodeview doesn't trigger debug info
   5118                 // generation, it only changes the type of information generated.
   5119                 try argv.appendSlice(&.{ "-g", "-gcodeview" });
   5120             },
   5121             .elf, .macho => {
   5122                 try argv.append("-gdwarf-4");
   5123                 if (comp.bin_file.options.dwarf_format) |f| switch (f) {
   5124                     .@"32" => try argv.append("-gdwarf32"),
   5125                     .@"64" => try argv.append("-gdwarf64"),
   5126                 };
   5127             },
   5128             else => try argv.append("-g"),
   5129         }
   5130     }
   5131 
   5132     if (target_util.llvmMachineAbi(target)) |mabi| {
   5133         try argv.append(try std.fmt.allocPrint(arena, "-mabi={s}", .{mabi}));
   5134     }
   5135 
   5136     if (out_dep_path) |p| {
   5137         try argv.appendSlice(&[_][]const u8{ "-MD", "-MV", "-MF", p });
   5138     }
   5139 
   5140     // We never want clang to invoke the system assembler for anything. So we would want
   5141     // this option always enabled. However, it only matters for some targets. To avoid
   5142     // "unused parameter" warnings, and to keep CLI spam to a minimum, we only put this
   5143     // flag on the command line if it is necessary.
   5144     if (target_util.clangMightShellOutForAssembly(target)) {
   5145         try argv.append("-integrated-as");
   5146     }
   5147 
   5148     if (target.os.tag == .freestanding) {
   5149         try argv.append("-ffreestanding");
   5150     }
   5151 
   5152     try argv.appendSlice(comp.clang_argv);
   5153 }
   5154 
   5155 fn failCObj(comp: *Compilation, c_object: *CObject, comptime format: []const u8, args: anytype) SemaError {
   5156     @setCold(true);
   5157     const err_msg = blk: {
   5158         const msg = try std.fmt.allocPrint(comp.gpa, format, args);
   5159         errdefer comp.gpa.free(msg);
   5160         const err_msg = try comp.gpa.create(CObject.ErrorMsg);
   5161         errdefer comp.gpa.destroy(err_msg);
   5162         err_msg.* = .{
   5163             .msg = msg,
   5164             .line = 0,
   5165             .column = 0,
   5166         };
   5167         break :blk err_msg;
   5168     };
   5169     return comp.failCObjWithOwnedErrorMsg(c_object, err_msg);
   5170 }
   5171 
   5172 fn failCObjWithOwnedErrorMsg(
   5173     comp: *Compilation,
   5174     c_object: *CObject,
   5175     err_msg: *CObject.ErrorMsg,
   5176 ) SemaError {
   5177     @setCold(true);
   5178     {
   5179         comp.mutex.lock();
   5180         defer comp.mutex.unlock();
   5181         {
   5182             errdefer err_msg.destroy(comp.gpa);
   5183             try comp.failed_c_objects.ensureUnusedCapacity(comp.gpa, 1);
   5184         }
   5185         comp.failed_c_objects.putAssumeCapacityNoClobber(c_object, err_msg);
   5186     }
   5187     c_object.status = .failure;
   5188     return error.AnalysisFail;
   5189 }
   5190 
   5191 /// The include directories used when preprocessing .rc files are separate from the
   5192 /// target. Which include directories are used is determined by `options.rc_includes`.
   5193 ///
   5194 /// Note: It should be okay that the include directories used when compiling .rc
   5195 /// files differ from the include directories used when compiling the main
   5196 /// binary, since the .res format is not dependent on anything ABI-related. The
   5197 /// only relevant differences would be things like `#define` constants being
   5198 /// different in the MinGW headers vs the MSVC headers, but any such
   5199 /// differences would likely be a MinGW bug.
   5200 fn detectWin32ResourceIncludeDirs(arena: Allocator, options: InitOptions) !LibCDirs {
   5201     // Set the includes to .none here when there are no rc files to compile
   5202     var includes = if (options.rc_source_files.len > 0) options.rc_includes else .none;
   5203     if (builtin.target.os.tag != .windows) {
   5204         switch (includes) {
   5205             // MSVC can't be found when the host isn't Windows, so short-circuit.
   5206             .msvc => return error.WindowsSdkNotFound,
   5207             // Skip straight to gnu since we won't be able to detect MSVC on non-Windows hosts.
   5208             .any => includes = .gnu,
   5209             .none, .gnu => {},
   5210         }
   5211     }
   5212     while (true) {
   5213         switch (includes) {
   5214             .any, .msvc => return detectLibCIncludeDirs(
   5215                 arena,
   5216                 options.zig_lib_directory.path.?,
   5217                 .{
   5218                     .cpu = options.target.cpu,
   5219                     .os = options.target.os,
   5220                     .abi = .msvc,
   5221                     .ofmt = options.target.ofmt,
   5222                 },
   5223                 options.is_native_abi,
   5224                 // The .rc preprocessor will need to know the libc include dirs even if we
   5225                 // are not linking libc, so force 'link_libc' to true
   5226                 true,
   5227                 options.libc_installation,
   5228             ) catch |err| {
   5229                 if (includes == .any) {
   5230                     // fall back to mingw
   5231                     includes = .gnu;
   5232                     continue;
   5233                 }
   5234                 return err;
   5235             },
   5236             .gnu => return detectLibCFromBuilding(arena, options.zig_lib_directory.path.?, .{
   5237                 .cpu = options.target.cpu,
   5238                 .os = options.target.os,
   5239                 .abi = .gnu,
   5240                 .ofmt = options.target.ofmt,
   5241             }),
   5242             .none => return LibCDirs{
   5243                 .libc_include_dir_list = &[0][]u8{},
   5244                 .libc_installation = null,
   5245                 .libc_framework_dir_list = &.{},
   5246                 .sysroot = null,
   5247             },
   5248         }
   5249     }
   5250 }
   5251 
   5252 fn failWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, comptime format: []const u8, args: anytype) SemaError {
   5253     @setCold(true);
   5254     var bundle: ErrorBundle.Wip = undefined;
   5255     try bundle.init(comp.gpa);
   5256     errdefer bundle.deinit();
   5257     try bundle.addRootErrorMessage(.{
   5258         .msg = try bundle.printString(format, args),
   5259         .src_loc = try bundle.addSourceLocation(.{
   5260             .src_path = try bundle.addString(win32_resource.src.src_path),
   5261             .line = 0,
   5262             .column = 0,
   5263             .span_start = 0,
   5264             .span_main = 0,
   5265             .span_end = 0,
   5266         }),
   5267     });
   5268     const finished_bundle = try bundle.toOwnedBundle("");
   5269     return comp.failWin32ResourceWithOwnedBundle(win32_resource, finished_bundle);
   5270 }
   5271 
   5272 fn failWin32ResourceWithOwnedBundle(
   5273     comp: *Compilation,
   5274     win32_resource: *Win32Resource,
   5275     err_bundle: ErrorBundle,
   5276 ) SemaError {
   5277     @setCold(true);
   5278     {
   5279         comp.mutex.lock();
   5280         defer comp.mutex.unlock();
   5281         try comp.failed_win32_resources.putNoClobber(comp.gpa, win32_resource, err_bundle);
   5282     }
   5283     win32_resource.status = .failure;
   5284     return error.AnalysisFail;
   5285 }
   5286 
   5287 fn failWin32ResourceCli(
   5288     comp: *Compilation,
   5289     win32_resource: *Win32Resource,
   5290     diagnostics: *resinator.cli.Diagnostics,
   5291 ) SemaError {
   5292     @setCold(true);
   5293 
   5294     var bundle: ErrorBundle.Wip = undefined;
   5295     try bundle.init(comp.gpa);
   5296     errdefer bundle.deinit();
   5297 
   5298     try bundle.addRootErrorMessage(.{
   5299         .msg = try bundle.addString("invalid command line option(s)"),
   5300         .src_loc = try bundle.addSourceLocation(.{
   5301             .src_path = try bundle.addString(win32_resource.src.src_path),
   5302             .line = 0,
   5303             .column = 0,
   5304             .span_start = 0,
   5305             .span_main = 0,
   5306             .span_end = 0,
   5307         }),
   5308     });
   5309 
   5310     var cur_err: ?ErrorBundle.ErrorMessage = null;
   5311     var cur_notes: std.ArrayListUnmanaged(ErrorBundle.ErrorMessage) = .{};
   5312     defer cur_notes.deinit(comp.gpa);
   5313     for (diagnostics.errors.items) |err_details| {
   5314         switch (err_details.type) {
   5315             .err => {
   5316                 if (cur_err) |err| {
   5317                     try win32ResourceFlushErrorMessage(&bundle, err, cur_notes.items);
   5318                 }
   5319                 cur_err = .{
   5320                     .msg = try bundle.addString(err_details.msg.items),
   5321                 };
   5322                 cur_notes.clearRetainingCapacity();
   5323             },
   5324             .warning => cur_err = null,
   5325             .note => {
   5326                 if (cur_err == null) continue;
   5327                 cur_err.?.notes_len += 1;
   5328                 try cur_notes.append(comp.gpa, .{
   5329                     .msg = try bundle.addString(err_details.msg.items),
   5330                 });
   5331             },
   5332         }
   5333     }
   5334     if (cur_err) |err| {
   5335         try win32ResourceFlushErrorMessage(&bundle, err, cur_notes.items);
   5336     }
   5337 
   5338     const finished_bundle = try bundle.toOwnedBundle("");
   5339     return comp.failWin32ResourceWithOwnedBundle(win32_resource, finished_bundle);
   5340 }
   5341 
   5342 fn failWin32ResourceCompile(
   5343     comp: *Compilation,
   5344     win32_resource: *Win32Resource,
   5345     source: []const u8,
   5346     diagnostics: *resinator.errors.Diagnostics,
   5347     mappings: resinator.source_mapping.SourceMappings,
   5348 ) SemaError {
   5349     @setCold(true);
   5350 
   5351     var bundle: ErrorBundle.Wip = undefined;
   5352     try bundle.init(comp.gpa);
   5353     errdefer bundle.deinit();
   5354 
   5355     var msg_buf: std.ArrayListUnmanaged(u8) = .{};
   5356     defer msg_buf.deinit(comp.gpa);
   5357     var cur_err: ?ErrorBundle.ErrorMessage = null;
   5358     var cur_notes: std.ArrayListUnmanaged(ErrorBundle.ErrorMessage) = .{};
   5359     defer cur_notes.deinit(comp.gpa);
   5360     for (diagnostics.errors.items) |err_details| {
   5361         switch (err_details.type) {
   5362             .hint => continue,
   5363             // Clear the current error so that notes don't bleed into unassociated errors
   5364             .warning => {
   5365                 cur_err = null;
   5366                 continue;
   5367             },
   5368             .note => if (cur_err == null) continue,
   5369             .err => {},
   5370         }
   5371         const corresponding_span = mappings.get(err_details.token.line_number);
   5372         const corresponding_file = mappings.files.get(corresponding_span.filename_offset);
   5373 
   5374         const source_line_start = err_details.token.getLineStart(source);
   5375         const column = err_details.token.calculateColumn(source, 1, source_line_start);
   5376         const err_line = corresponding_span.start_line;
   5377 
   5378         msg_buf.clearRetainingCapacity();
   5379         try err_details.render(msg_buf.writer(comp.gpa), source, diagnostics.strings.items);
   5380 
   5381         const src_loc = src_loc: {
   5382             var src_loc: ErrorBundle.SourceLocation = .{
   5383                 .src_path = try bundle.addString(corresponding_file),
   5384                 .line = @intCast(err_line - 1), // 1-based -> 0-based
   5385                 .column = @intCast(column),
   5386                 .span_start = 0,
   5387                 .span_main = 0,
   5388                 .span_end = 0,
   5389             };
   5390             if (err_details.print_source_line) {
   5391                 const source_line = err_details.token.getLine(source, source_line_start);
   5392                 const visual_info = err_details.visualTokenInfo(source_line_start, source_line_start + source_line.len);
   5393                 src_loc.span_start = @intCast(visual_info.point_offset - visual_info.before_len);
   5394                 src_loc.span_main = @intCast(visual_info.point_offset);
   5395                 src_loc.span_end = @intCast(visual_info.point_offset + 1 + visual_info.after_len);
   5396                 src_loc.source_line = try bundle.addString(source_line);
   5397             }
   5398             break :src_loc try bundle.addSourceLocation(src_loc);
   5399         };
   5400 
   5401         switch (err_details.type) {
   5402             .err => {
   5403                 if (cur_err) |err| {
   5404                     try win32ResourceFlushErrorMessage(&bundle, err, cur_notes.items);
   5405                 }
   5406                 cur_err = .{
   5407                     .msg = try bundle.addString(msg_buf.items),
   5408                     .src_loc = src_loc,
   5409                 };
   5410                 cur_notes.clearRetainingCapacity();
   5411             },
   5412             .note => {
   5413                 cur_err.?.notes_len += 1;
   5414                 try cur_notes.append(comp.gpa, .{
   5415                     .msg = try bundle.addString(msg_buf.items),
   5416                     .src_loc = src_loc,
   5417                 });
   5418             },
   5419             .warning, .hint => unreachable,
   5420         }
   5421     }
   5422     if (cur_err) |err| {
   5423         try win32ResourceFlushErrorMessage(&bundle, err, cur_notes.items);
   5424     }
   5425 
   5426     const finished_bundle = try bundle.toOwnedBundle("");
   5427     return comp.failWin32ResourceWithOwnedBundle(win32_resource, finished_bundle);
   5428 }
   5429 
   5430 fn win32ResourceFlushErrorMessage(wip: *ErrorBundle.Wip, msg: ErrorBundle.ErrorMessage, notes: []const ErrorBundle.ErrorMessage) !void {
   5431     try wip.addRootErrorMessage(msg);
   5432     const notes_start = try wip.reserveNotes(@intCast(notes.len));
   5433     for (notes_start.., notes) |i, note| {
   5434         wip.extra.items[i] = @intFromEnum(wip.addErrorMessageAssumeCapacity(note));
   5435     }
   5436 }
   5437 
   5438 pub const FileExt = enum {
   5439     c,
   5440     cpp,
   5441     cu,
   5442     h,
   5443     m,
   5444     mm,
   5445     ll,
   5446     bc,
   5447     assembly,
   5448     assembly_with_cpp,
   5449     shared_library,
   5450     object,
   5451     static_library,
   5452     zig,
   5453     def,
   5454     rc,
   5455     res,
   5456     unknown,
   5457 
   5458     pub fn clangSupportsDepFile(ext: FileExt) bool {
   5459         return switch (ext) {
   5460             .c, .cpp, .h, .m, .mm, .cu => true,
   5461 
   5462             .ll,
   5463             .bc,
   5464             .assembly,
   5465             .assembly_with_cpp,
   5466             .shared_library,
   5467             .object,
   5468             .static_library,
   5469             .zig,
   5470             .def,
   5471             .rc,
   5472             .res,
   5473             .unknown,
   5474             => false,
   5475         };
   5476     }
   5477 
   5478     pub fn canonicalName(ext: FileExt, target: Target) [:0]const u8 {
   5479         return switch (ext) {
   5480             .c => ".c",
   5481             .cpp => ".cpp",
   5482             .cu => ".cu",
   5483             .h => ".h",
   5484             .m => ".m",
   5485             .mm => ".mm",
   5486             .ll => ".ll",
   5487             .bc => ".bc",
   5488             .assembly => ".s",
   5489             .assembly_with_cpp => ".S",
   5490             .shared_library => target.dynamicLibSuffix(),
   5491             .object => target.ofmt.fileExt(target.cpu.arch),
   5492             .static_library => target.staticLibSuffix(),
   5493             .zig => ".zig",
   5494             .def => ".def",
   5495             .rc => ".rc",
   5496             .res => ".res",
   5497             .unknown => "",
   5498         };
   5499     }
   5500 };
   5501 
   5502 pub fn hasObjectExt(filename: []const u8) bool {
   5503     return mem.endsWith(u8, filename, ".o") or mem.endsWith(u8, filename, ".obj");
   5504 }
   5505 
   5506 pub fn hasStaticLibraryExt(filename: []const u8) bool {
   5507     return mem.endsWith(u8, filename, ".a") or mem.endsWith(u8, filename, ".lib");
   5508 }
   5509 
   5510 pub fn hasCExt(filename: []const u8) bool {
   5511     return mem.endsWith(u8, filename, ".c");
   5512 }
   5513 
   5514 pub fn hasCppExt(filename: []const u8) bool {
   5515     return mem.endsWith(u8, filename, ".C") or
   5516         mem.endsWith(u8, filename, ".cc") or
   5517         mem.endsWith(u8, filename, ".cpp") or
   5518         mem.endsWith(u8, filename, ".cxx") or
   5519         mem.endsWith(u8, filename, ".stub");
   5520 }
   5521 
   5522 pub fn hasObjCExt(filename: []const u8) bool {
   5523     return mem.endsWith(u8, filename, ".m");
   5524 }
   5525 
   5526 pub fn hasObjCppExt(filename: []const u8) bool {
   5527     return mem.endsWith(u8, filename, ".mm");
   5528 }
   5529 
   5530 pub fn hasSharedLibraryExt(filename: []const u8) bool {
   5531     if (mem.endsWith(u8, filename, ".so") or
   5532         mem.endsWith(u8, filename, ".dll") or
   5533         mem.endsWith(u8, filename, ".dylib") or
   5534         mem.endsWith(u8, filename, ".tbd"))
   5535     {
   5536         return true;
   5537     }
   5538     // Look for .so.X, .so.X.Y, .so.X.Y.Z
   5539     var it = mem.splitScalar(u8, filename, '.');
   5540     _ = it.first();
   5541     var so_txt = it.next() orelse return false;
   5542     while (!mem.eql(u8, so_txt, "so")) {
   5543         so_txt = it.next() orelse return false;
   5544     }
   5545     const n1 = it.next() orelse return false;
   5546     const n2 = it.next();
   5547     const n3 = it.next();
   5548 
   5549     _ = std.fmt.parseInt(u32, n1, 10) catch return false;
   5550     if (n2) |x| _ = std.fmt.parseInt(u32, x, 10) catch return false;
   5551     if (n3) |x| _ = std.fmt.parseInt(u32, x, 10) catch return false;
   5552     if (it.next() != null) return false;
   5553 
   5554     return true;
   5555 }
   5556 
   5557 pub fn classifyFileExt(filename: []const u8) FileExt {
   5558     if (hasCExt(filename)) {
   5559         return .c;
   5560     } else if (hasCppExt(filename)) {
   5561         return .cpp;
   5562     } else if (hasObjCExt(filename)) {
   5563         return .m;
   5564     } else if (hasObjCppExt(filename)) {
   5565         return .mm;
   5566     } else if (mem.endsWith(u8, filename, ".ll")) {
   5567         return .ll;
   5568     } else if (mem.endsWith(u8, filename, ".bc")) {
   5569         return .bc;
   5570     } else if (mem.endsWith(u8, filename, ".s")) {
   5571         return .assembly;
   5572     } else if (mem.endsWith(u8, filename, ".S")) {
   5573         return .assembly_with_cpp;
   5574     } else if (mem.endsWith(u8, filename, ".h")) {
   5575         return .h;
   5576     } else if (mem.endsWith(u8, filename, ".zig")) {
   5577         return .zig;
   5578     } else if (hasSharedLibraryExt(filename)) {
   5579         return .shared_library;
   5580     } else if (hasStaticLibraryExt(filename)) {
   5581         return .static_library;
   5582     } else if (hasObjectExt(filename)) {
   5583         return .object;
   5584     } else if (mem.endsWith(u8, filename, ".cu")) {
   5585         return .cu;
   5586     } else if (mem.endsWith(u8, filename, ".def")) {
   5587         return .def;
   5588     } else if (std.ascii.endsWithIgnoreCase(filename, ".rc")) {
   5589         return .rc;
   5590     } else if (std.ascii.endsWithIgnoreCase(filename, ".res")) {
   5591         return .res;
   5592     } else {
   5593         return .unknown;
   5594     }
   5595 }
   5596 
   5597 test "classifyFileExt" {
   5598     try std.testing.expectEqual(FileExt.cpp, classifyFileExt("foo.cc"));
   5599     try std.testing.expectEqual(FileExt.m, classifyFileExt("foo.m"));
   5600     try std.testing.expectEqual(FileExt.mm, classifyFileExt("foo.mm"));
   5601     try std.testing.expectEqual(FileExt.unknown, classifyFileExt("foo.nim"));
   5602     try std.testing.expectEqual(FileExt.shared_library, classifyFileExt("foo.so"));
   5603     try std.testing.expectEqual(FileExt.shared_library, classifyFileExt("foo.so.1"));
   5604     try std.testing.expectEqual(FileExt.shared_library, classifyFileExt("foo.so.1.2"));
   5605     try std.testing.expectEqual(FileExt.shared_library, classifyFileExt("foo.so.1.2.3"));
   5606     try std.testing.expectEqual(FileExt.unknown, classifyFileExt("foo.so.1.2.3~"));
   5607     try std.testing.expectEqual(FileExt.zig, classifyFileExt("foo.zig"));
   5608 }
   5609 
   5610 const LibCDirs = struct {
   5611     libc_include_dir_list: []const []const u8,
   5612     libc_installation: ?*const LibCInstallation,
   5613     libc_framework_dir_list: []const []const u8,
   5614     sysroot: ?[]const u8,
   5615 };
   5616 
   5617 fn getZigShippedLibCIncludeDirsDarwin(arena: Allocator, zig_lib_dir: []const u8, target: Target) !LibCDirs {
   5618     const arch_name = @tagName(target.cpu.arch);
   5619     const os_name = try std.fmt.allocPrint(arena, "{s}.{d}", .{
   5620         @tagName(target.os.tag),
   5621         target.os.version_range.semver.min.major,
   5622     });
   5623     const s = std.fs.path.sep_str;
   5624     const list = try arena.alloc([]const u8, 3);
   5625 
   5626     list[0] = try std.fmt.allocPrint(
   5627         arena,
   5628         "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "{s}-{s}-none",
   5629         .{ zig_lib_dir, arch_name, os_name },
   5630     );
   5631     list[1] = try std.fmt.allocPrint(
   5632         arena,
   5633         "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "any-{s}-any",
   5634         .{ zig_lib_dir, os_name },
   5635     );
   5636     list[2] = try std.fmt.allocPrint(
   5637         arena,
   5638         "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "any-macos-any",
   5639         .{zig_lib_dir},
   5640     );
   5641 
   5642     return LibCDirs{
   5643         .libc_include_dir_list = list,
   5644         .libc_installation = null,
   5645         .libc_framework_dir_list = &.{},
   5646         .sysroot = null,
   5647     };
   5648 }
   5649 
   5650 pub fn detectLibCIncludeDirs(
   5651     arena: Allocator,
   5652     zig_lib_dir: []const u8,
   5653     target: Target,
   5654     is_native_abi: bool,
   5655     link_libc: bool,
   5656     libc_installation: ?*const LibCInstallation,
   5657 ) !LibCDirs {
   5658     if (!link_libc) {
   5659         return LibCDirs{
   5660             .libc_include_dir_list = &[0][]u8{},
   5661             .libc_installation = null,
   5662             .libc_framework_dir_list = &.{},
   5663             .sysroot = null,
   5664         };
   5665     }
   5666 
   5667     if (libc_installation) |lci| {
   5668         return detectLibCFromLibCInstallation(arena, target, lci);
   5669     }
   5670 
   5671     // If linking system libraries and targeting the native abi, default to
   5672     // using the system libc installation.
   5673     if (is_native_abi and !target.isMinGW()) {
   5674         const libc = try arena.create(LibCInstallation);
   5675         libc.* = LibCInstallation.findNative(.{ .allocator = arena, .target = target }) catch |err| switch (err) {
   5676             error.CCompilerExitCode,
   5677             error.CCompilerCrashed,
   5678             error.CCompilerCannotFindHeaders,
   5679             error.UnableToSpawnCCompiler,
   5680             error.DarwinSdkNotFound,
   5681             => |e| {
   5682                 // We tried to integrate with the native system C compiler,
   5683                 // however, it is not installed. So we must rely on our bundled
   5684                 // libc files.
   5685                 if (target_util.canBuildLibC(target)) {
   5686                     return detectLibCFromBuilding(arena, zig_lib_dir, target);
   5687                 }
   5688                 return e;
   5689             },
   5690             else => |e| return e,
   5691         };
   5692         return detectLibCFromLibCInstallation(arena, target, libc);
   5693     }
   5694 
   5695     // If not linking system libraries, build and provide our own libc by
   5696     // default if possible.
   5697     if (target_util.canBuildLibC(target)) {
   5698         return detectLibCFromBuilding(arena, zig_lib_dir, target);
   5699     }
   5700 
   5701     // If zig can't build the libc for the target and we are targeting the
   5702     // native abi, fall back to using the system libc installation.
   5703     // On windows, instead of the native (mingw) abi, we want to check
   5704     // for the MSVC abi as a fallback.
   5705     const use_system_abi = if (builtin.target.os.tag == .windows)
   5706         target.abi == .msvc
   5707     else
   5708         is_native_abi;
   5709 
   5710     if (use_system_abi) {
   5711         const libc = try arena.create(LibCInstallation);
   5712         libc.* = try LibCInstallation.findNative(.{ .allocator = arena, .verbose = true, .target = target });
   5713         return detectLibCFromLibCInstallation(arena, target, libc);
   5714     }
   5715 
   5716     return LibCDirs{
   5717         .libc_include_dir_list = &[0][]u8{},
   5718         .libc_installation = null,
   5719         .libc_framework_dir_list = &.{},
   5720         .sysroot = null,
   5721     };
   5722 }
   5723 
   5724 fn detectLibCFromLibCInstallation(arena: Allocator, target: Target, lci: *const LibCInstallation) !LibCDirs {
   5725     var list = try std.ArrayList([]const u8).initCapacity(arena, 5);
   5726     var framework_list = std.ArrayList([]const u8).init(arena);
   5727 
   5728     list.appendAssumeCapacity(lci.include_dir.?);
   5729 
   5730     const is_redundant = mem.eql(u8, lci.sys_include_dir.?, lci.include_dir.?);
   5731     if (!is_redundant) list.appendAssumeCapacity(lci.sys_include_dir.?);
   5732 
   5733     if (target.os.tag == .windows) {
   5734         if (std.fs.path.dirname(lci.sys_include_dir.?)) |sys_include_dir_parent| {
   5735             // This include path will only exist when the optional "Desktop development with C++"
   5736             // is installed. It contains headers, .rc files, and resources. It is especially
   5737             // necessary when working with Windows resources.
   5738             const atlmfc_dir = try std.fs.path.join(arena, &[_][]const u8{ sys_include_dir_parent, "atlmfc", "include" });
   5739             list.appendAssumeCapacity(atlmfc_dir);
   5740         }
   5741         if (std.fs.path.dirname(lci.include_dir.?)) |include_dir_parent| {
   5742             const um_dir = try std.fs.path.join(arena, &[_][]const u8{ include_dir_parent, "um" });
   5743             list.appendAssumeCapacity(um_dir);
   5744 
   5745             const shared_dir = try std.fs.path.join(arena, &[_][]const u8{ include_dir_parent, "shared" });
   5746             list.appendAssumeCapacity(shared_dir);
   5747         }
   5748     }
   5749     if (target.os.tag == .haiku) {
   5750         const include_dir_path = lci.include_dir orelse return error.LibCInstallationNotAvailable;
   5751         const os_dir = try std.fs.path.join(arena, &[_][]const u8{ include_dir_path, "os" });
   5752         list.appendAssumeCapacity(os_dir);
   5753         // Errors.h
   5754         const os_support_dir = try std.fs.path.join(arena, &[_][]const u8{ include_dir_path, "os/support" });
   5755         list.appendAssumeCapacity(os_support_dir);
   5756 
   5757         const config_dir = try std.fs.path.join(arena, &[_][]const u8{ include_dir_path, "config" });
   5758         list.appendAssumeCapacity(config_dir);
   5759     }
   5760 
   5761     var sysroot: ?[]const u8 = null;
   5762 
   5763     if (target.isDarwin()) d: {
   5764         const down1 = std.fs.path.dirname(lci.sys_include_dir.?) orelse break :d;
   5765         const down2 = std.fs.path.dirname(down1) orelse break :d;
   5766         try framework_list.append(try std.fs.path.join(arena, &.{ down2, "System", "Library", "Frameworks" }));
   5767         sysroot = down2;
   5768     }
   5769 
   5770     return LibCDirs{
   5771         .libc_include_dir_list = list.items,
   5772         .libc_installation = lci,
   5773         .libc_framework_dir_list = framework_list.items,
   5774         .sysroot = sysroot,
   5775     };
   5776 }
   5777 
   5778 fn detectLibCFromBuilding(
   5779     arena: Allocator,
   5780     zig_lib_dir: []const u8,
   5781     target: std.Target,
   5782 ) !LibCDirs {
   5783     if (target.isDarwin())
   5784         return getZigShippedLibCIncludeDirsDarwin(arena, zig_lib_dir, target);
   5785 
   5786     const generic_name = target_util.libCGenericName(target);
   5787     // Some architectures are handled by the same set of headers.
   5788     const arch_name = if (target.abi.isMusl())
   5789         musl.archNameHeaders(target.cpu.arch)
   5790     else if (target.cpu.arch.isThumb())
   5791         // ARM headers are valid for Thumb too.
   5792         switch (target.cpu.arch) {
   5793             .thumb => "arm",
   5794             .thumbeb => "armeb",
   5795             else => unreachable,
   5796         }
   5797     else
   5798         @tagName(target.cpu.arch);
   5799     const os_name = @tagName(target.os.tag);
   5800     // Musl's headers are ABI-agnostic and so they all have the "musl" ABI name.
   5801     const abi_name = if (target.abi.isMusl()) "musl" else @tagName(target.abi);
   5802     const s = std.fs.path.sep_str;
   5803     const arch_include_dir = try std.fmt.allocPrint(
   5804         arena,
   5805         "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "{s}-{s}-{s}",
   5806         .{ zig_lib_dir, arch_name, os_name, abi_name },
   5807     );
   5808     const generic_include_dir = try std.fmt.allocPrint(
   5809         arena,
   5810         "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "generic-{s}",
   5811         .{ zig_lib_dir, generic_name },
   5812     );
   5813     const generic_arch_name = target_util.osArchName(target);
   5814     const arch_os_include_dir = try std.fmt.allocPrint(
   5815         arena,
   5816         "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "{s}-{s}-any",
   5817         .{ zig_lib_dir, generic_arch_name, os_name },
   5818     );
   5819     const generic_os_include_dir = try std.fmt.allocPrint(
   5820         arena,
   5821         "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "any-{s}-any",
   5822         .{ zig_lib_dir, os_name },
   5823     );
   5824 
   5825     const list = try arena.alloc([]const u8, 4);
   5826     list[0] = arch_include_dir;
   5827     list[1] = generic_include_dir;
   5828     list[2] = arch_os_include_dir;
   5829     list[3] = generic_os_include_dir;
   5830 
   5831     return LibCDirs{
   5832         .libc_include_dir_list = list,
   5833         .libc_installation = null,
   5834         .libc_framework_dir_list = &.{},
   5835         .sysroot = null,
   5836     };
   5837 }
   5838 
   5839 pub fn get_libc_crt_file(comp: *Compilation, arena: Allocator, basename: []const u8) ![]const u8 {
   5840     if (comp.wantBuildGLibCFromSource() or
   5841         comp.wantBuildMuslFromSource() or
   5842         comp.wantBuildMinGWFromSource() or
   5843         comp.wantBuildWasiLibcFromSource())
   5844     {
   5845         return comp.crt_files.get(basename).?.full_object_path;
   5846     }
   5847     const lci = comp.bin_file.options.libc_installation orelse return error.LibCInstallationNotAvailable;
   5848     const crt_dir_path = lci.crt_dir orelse return error.LibCInstallationMissingCRTDir;
   5849     const full_path = try std.fs.path.join(arena, &[_][]const u8{ crt_dir_path, basename });
   5850     return full_path;
   5851 }
   5852 
   5853 fn wantBuildLibCFromSource(comp: Compilation) bool {
   5854     const is_exe_or_dyn_lib = switch (comp.bin_file.options.output_mode) {
   5855         .Obj => false,
   5856         .Lib => comp.bin_file.options.link_mode == .Dynamic,
   5857         .Exe => true,
   5858     };
   5859     return comp.bin_file.options.link_libc and is_exe_or_dyn_lib and
   5860         comp.bin_file.options.libc_installation == null and
   5861         comp.bin_file.options.target.ofmt != .c;
   5862 }
   5863 
   5864 fn wantBuildGLibCFromSource(comp: Compilation) bool {
   5865     return comp.wantBuildLibCFromSource() and comp.getTarget().isGnuLibC();
   5866 }
   5867 
   5868 fn wantBuildMuslFromSource(comp: Compilation) bool {
   5869     return comp.wantBuildLibCFromSource() and comp.getTarget().isMusl() and
   5870         !comp.getTarget().isWasm();
   5871 }
   5872 
   5873 fn wantBuildWasiLibcFromSource(comp: Compilation) bool {
   5874     return comp.wantBuildLibCFromSource() and comp.getTarget().isWasm() and
   5875         comp.getTarget().os.tag == .wasi;
   5876 }
   5877 
   5878 fn wantBuildMinGWFromSource(comp: Compilation) bool {
   5879     return comp.wantBuildLibCFromSource() and comp.getTarget().isMinGW();
   5880 }
   5881 
   5882 fn wantBuildLibUnwindFromSource(comp: *Compilation) bool {
   5883     const is_exe_or_dyn_lib = switch (comp.bin_file.options.output_mode) {
   5884         .Obj => false,
   5885         .Lib => comp.bin_file.options.link_mode == .Dynamic,
   5886         .Exe => true,
   5887     };
   5888     return is_exe_or_dyn_lib and comp.bin_file.options.link_libunwind and
   5889         comp.bin_file.options.target.ofmt != .c;
   5890 }
   5891 
   5892 fn setAllocFailure(comp: *Compilation) void {
   5893     log.debug("memory allocation failure", .{});
   5894     comp.alloc_failure_occurred = true;
   5895 }
   5896 
   5897 /// Assumes that Compilation mutex is locked.
   5898 /// See also `lockAndSetMiscFailure`.
   5899 pub fn setMiscFailure(
   5900     comp: *Compilation,
   5901     tag: MiscTask,
   5902     comptime format: []const u8,
   5903     args: anytype,
   5904 ) void {
   5905     comp.misc_failures.ensureUnusedCapacity(comp.gpa, 1) catch return comp.setAllocFailure();
   5906     const msg = std.fmt.allocPrint(comp.gpa, format, args) catch return comp.setAllocFailure();
   5907     const gop = comp.misc_failures.getOrPutAssumeCapacity(tag);
   5908     if (gop.found_existing) {
   5909         gop.value_ptr.deinit(comp.gpa);
   5910     }
   5911     gop.value_ptr.* = .{ .msg = msg };
   5912 }
   5913 
   5914 /// See also `setMiscFailure`.
   5915 pub fn lockAndSetMiscFailure(
   5916     comp: *Compilation,
   5917     tag: MiscTask,
   5918     comptime format: []const u8,
   5919     args: anytype,
   5920 ) void {
   5921     comp.mutex.lock();
   5922     defer comp.mutex.unlock();
   5923 
   5924     return setMiscFailure(comp, tag, format, args);
   5925 }
   5926 
   5927 fn parseLldStderr(comp: *Compilation, comptime prefix: []const u8, stderr: []const u8) Allocator.Error!void {
   5928     var context_lines = std.ArrayList([]const u8).init(comp.gpa);
   5929     defer context_lines.deinit();
   5930 
   5931     var current_err: ?*LldError = null;
   5932     var lines = mem.splitSequence(u8, stderr, if (builtin.os.tag == .windows) "\r\n" else "\n");
   5933     while (lines.next()) |line| {
   5934         if (mem.startsWith(u8, line, prefix ++ ":")) {
   5935             if (current_err) |err| {
   5936                 err.context_lines = try context_lines.toOwnedSlice();
   5937             }
   5938 
   5939             var split = std.mem.splitSequence(u8, line, "error: ");
   5940             _ = split.first();
   5941 
   5942             const duped_msg = try std.fmt.allocPrint(comp.gpa, "{s}: {s}", .{ prefix, split.rest() });
   5943             errdefer comp.gpa.free(duped_msg);
   5944 
   5945             current_err = try comp.lld_errors.addOne(comp.gpa);
   5946             current_err.?.* = .{ .msg = duped_msg };
   5947         } else if (current_err != null) {
   5948             const context_prefix = ">>> ";
   5949             var trimmed = mem.trimRight(u8, line, &std.ascii.whitespace);
   5950             if (mem.startsWith(u8, trimmed, context_prefix)) {
   5951                 trimmed = trimmed[context_prefix.len..];
   5952             }
   5953 
   5954             if (trimmed.len > 0) {
   5955                 const duped_line = try comp.gpa.dupe(u8, trimmed);
   5956                 try context_lines.append(duped_line);
   5957             }
   5958         }
   5959     }
   5960 
   5961     if (current_err) |err| {
   5962         err.context_lines = try context_lines.toOwnedSlice();
   5963     }
   5964 }
   5965 
   5966 pub fn lockAndParseLldStderr(comp: *Compilation, comptime prefix: []const u8, stderr: []const u8) void {
   5967     comp.mutex.lock();
   5968     defer comp.mutex.unlock();
   5969 
   5970     comp.parseLldStderr(prefix, stderr) catch comp.setAllocFailure();
   5971 }
   5972 
   5973 pub fn dump_argv(argv: []const []const u8) void {
   5974     std.debug.getStderrMutex().lock();
   5975     defer std.debug.getStderrMutex().unlock();
   5976     const stderr = std.io.getStdErr().writer();
   5977     for (argv[0 .. argv.len - 1]) |arg| {
   5978         nosuspend stderr.print("{s} ", .{arg}) catch return;
   5979     }
   5980     nosuspend stderr.print("{s}\n", .{argv[argv.len - 1]}) catch {};
   5981 }
   5982 
   5983 pub fn getZigBackend(comp: Compilation) std.builtin.CompilerBackend {
   5984     if (comp.bin_file.options.use_llvm) return .stage2_llvm;
   5985     const target = comp.bin_file.options.target;
   5986     if (target.ofmt == .c) return .stage2_c;
   5987     return switch (target.cpu.arch) {
   5988         .wasm32, .wasm64 => std.builtin.CompilerBackend.stage2_wasm,
   5989         .arm, .armeb, .thumb, .thumbeb => .stage2_arm,
   5990         .x86_64 => .stage2_x86_64,
   5991         .x86 => .stage2_x86,
   5992         .aarch64, .aarch64_be, .aarch64_32 => .stage2_aarch64,
   5993         .riscv64 => .stage2_riscv64,
   5994         .sparc64 => .stage2_sparc64,
   5995         .spirv64 => .stage2_spirv64,
   5996         else => .other,
   5997     };
   5998 }
   5999 
   6000 pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Allocator.Error![:0]u8 {
   6001     const tracy_trace = trace(@src());
   6002     defer tracy_trace.end();
   6003 
   6004     var buffer = std.ArrayList(u8).init(allocator);
   6005     defer buffer.deinit();
   6006 
   6007     const target = comp.getTarget();
   6008     const generic_arch_name = target.cpu.arch.genericName();
   6009     const zig_backend = comp.getZigBackend();
   6010 
   6011     @setEvalBranchQuota(4000);
   6012     try buffer.writer().print(
   6013         \\const std = @import("std");
   6014         \\/// Zig version. When writing code that supports multiple versions of Zig, prefer
   6015         \\/// feature detection (i.e. with `@hasDecl` or `@hasField`) over version checks.
   6016         \\pub const zig_version = std.SemanticVersion.parse(zig_version_string) catch unreachable;
   6017         \\pub const zig_version_string = "{s}";
   6018         \\pub const zig_backend = std.builtin.CompilerBackend.{};
   6019         \\
   6020         \\pub const output_mode = std.builtin.OutputMode.{};
   6021         \\pub const link_mode = std.builtin.LinkMode.{};
   6022         \\pub const is_test = {};
   6023         \\pub const single_threaded = {};
   6024         \\pub const abi = std.Target.Abi.{};
   6025         \\pub const cpu: std.Target.Cpu = .{{
   6026         \\    .arch = .{},
   6027         \\    .model = &std.Target.{}.cpu.{},
   6028         \\    .features = std.Target.{}.featureSet(&[_]std.Target.{}.Feature{{
   6029         \\
   6030     , .{
   6031         build_options.version,
   6032         std.zig.fmtId(@tagName(zig_backend)),
   6033         std.zig.fmtId(@tagName(comp.bin_file.options.output_mode)),
   6034         std.zig.fmtId(@tagName(comp.bin_file.options.link_mode)),
   6035         comp.bin_file.options.is_test,
   6036         comp.bin_file.options.single_threaded,
   6037         std.zig.fmtId(@tagName(target.abi)),
   6038         std.zig.fmtId(@tagName(target.cpu.arch)),
   6039         std.zig.fmtId(generic_arch_name),
   6040         std.zig.fmtId(target.cpu.model.name),
   6041         std.zig.fmtId(generic_arch_name),
   6042         std.zig.fmtId(generic_arch_name),
   6043     });
   6044 
   6045     for (target.cpu.arch.allFeaturesList(), 0..) |feature, index_usize| {
   6046         const index = @as(std.Target.Cpu.Feature.Set.Index, @intCast(index_usize));
   6047         const is_enabled = target.cpu.features.isEnabled(index);
   6048         if (is_enabled) {
   6049             try buffer.writer().print("        .{},\n", .{std.zig.fmtId(feature.name)});
   6050         }
   6051     }
   6052 
   6053     try buffer.writer().print(
   6054         \\    }}),
   6055         \\}};
   6056         \\pub const os = std.Target.Os{{
   6057         \\    .tag = .{},
   6058         \\    .version_range = .{{
   6059     ,
   6060         .{std.zig.fmtId(@tagName(target.os.tag))},
   6061     );
   6062 
   6063     switch (target.os.getVersionRange()) {
   6064         .none => try buffer.appendSlice(" .none = {} },\n"),
   6065         .semver => |semver| try buffer.writer().print(
   6066             \\ .semver = .{{
   6067             \\        .min = .{{
   6068             \\            .major = {},
   6069             \\            .minor = {},
   6070             \\            .patch = {},
   6071             \\        }},
   6072             \\        .max = .{{
   6073             \\            .major = {},
   6074             \\            .minor = {},
   6075             \\            .patch = {},
   6076             \\        }},
   6077             \\    }}}},
   6078             \\
   6079         , .{
   6080             semver.min.major,
   6081             semver.min.minor,
   6082             semver.min.patch,
   6083 
   6084             semver.max.major,
   6085             semver.max.minor,
   6086             semver.max.patch,
   6087         }),
   6088         .linux => |linux| try buffer.writer().print(
   6089             \\ .linux = .{{
   6090             \\        .range = .{{
   6091             \\            .min = .{{
   6092             \\                .major = {},
   6093             \\                .minor = {},
   6094             \\                .patch = {},
   6095             \\            }},
   6096             \\            .max = .{{
   6097             \\                .major = {},
   6098             \\                .minor = {},
   6099             \\                .patch = {},
   6100             \\            }},
   6101             \\        }},
   6102             \\        .glibc = .{{
   6103             \\            .major = {},
   6104             \\            .minor = {},
   6105             \\            .patch = {},
   6106             \\        }},
   6107             \\    }}}},
   6108             \\
   6109         , .{
   6110             linux.range.min.major,
   6111             linux.range.min.minor,
   6112             linux.range.min.patch,
   6113 
   6114             linux.range.max.major,
   6115             linux.range.max.minor,
   6116             linux.range.max.patch,
   6117 
   6118             linux.glibc.major,
   6119             linux.glibc.minor,
   6120             linux.glibc.patch,
   6121         }),
   6122         .windows => |windows| try buffer.writer().print(
   6123             \\ .windows = .{{
   6124             \\        .min = {s},
   6125             \\        .max = {s},
   6126             \\    }}}},
   6127             \\
   6128         ,
   6129             .{ windows.min, windows.max },
   6130         ),
   6131     }
   6132     try buffer.appendSlice("};\n");
   6133 
   6134     // This is so that compiler_rt and libc.zig libraries know whether they
   6135     // will eventually be linked with libc. They make different decisions
   6136     // about what to export depending on whether another libc will be linked
   6137     // in. For example, compiler_rt will not export the __chkstk symbol if it
   6138     // knows libc will provide it, and likewise c.zig will not export memcpy.
   6139     const link_libc = comp.bin_file.options.link_libc or
   6140         (comp.bin_file.options.skip_linker_dependencies and comp.bin_file.options.parent_compilation_link_libc);
   6141 
   6142     try buffer.writer().print(
   6143         \\pub const target = std.Target{{
   6144         \\    .cpu = cpu,
   6145         \\    .os = os,
   6146         \\    .abi = abi,
   6147         \\    .ofmt = object_format,
   6148         \\}};
   6149         \\pub const object_format = std.Target.ObjectFormat.{};
   6150         \\pub const mode = std.builtin.OptimizeMode.{};
   6151         \\pub const link_libc = {};
   6152         \\pub const link_libcpp = {};
   6153         \\pub const have_error_return_tracing = {};
   6154         \\pub const valgrind_support = {};
   6155         \\pub const sanitize_thread = {};
   6156         \\pub const position_independent_code = {};
   6157         \\pub const position_independent_executable = {};
   6158         \\pub const strip_debug_info = {};
   6159         \\pub const code_model = std.builtin.CodeModel.{};
   6160         \\pub const omit_frame_pointer = {};
   6161         \\
   6162     , .{
   6163         std.zig.fmtId(@tagName(target.ofmt)),
   6164         std.zig.fmtId(@tagName(comp.bin_file.options.optimize_mode)),
   6165         link_libc,
   6166         comp.bin_file.options.link_libcpp,
   6167         comp.bin_file.options.error_return_tracing,
   6168         comp.bin_file.options.valgrind,
   6169         comp.bin_file.options.tsan,
   6170         comp.bin_file.options.pic,
   6171         comp.bin_file.options.pie,
   6172         comp.bin_file.options.strip,
   6173         std.zig.fmtId(@tagName(comp.bin_file.options.machine_code_model)),
   6174         comp.bin_file.options.omit_frame_pointer,
   6175     });
   6176 
   6177     if (target.os.tag == .wasi) {
   6178         const wasi_exec_model_fmt = std.zig.fmtId(@tagName(comp.bin_file.options.wasi_exec_model));
   6179         try buffer.writer().print(
   6180             \\pub const wasi_exec_model = std.builtin.WasiExecModel.{};
   6181             \\
   6182         , .{wasi_exec_model_fmt});
   6183     }
   6184 
   6185     if (comp.bin_file.options.is_test) {
   6186         try buffer.appendSlice(
   6187             \\pub var test_functions: []const std.builtin.TestFn = undefined; // overwritten later
   6188             \\
   6189         );
   6190         if (comp.test_evented_io) {
   6191             try buffer.appendSlice(
   6192                 \\pub const test_io_mode = .evented;
   6193                 \\
   6194             );
   6195         } else {
   6196             try buffer.appendSlice(
   6197                 \\pub const test_io_mode = .blocking;
   6198                 \\
   6199             );
   6200         }
   6201     }
   6202 
   6203     return buffer.toOwnedSliceSentinel(0);
   6204 }
   6205 
   6206 pub fn updateSubCompilation(
   6207     parent_comp: *Compilation,
   6208     sub_comp: *Compilation,
   6209     misc_task: MiscTask,
   6210     prog_node: *std.Progress.Node,
   6211 ) !void {
   6212     {
   6213         var sub_node = prog_node.start(@tagName(misc_task), 0);
   6214         sub_node.activate();
   6215         defer sub_node.end();
   6216 
   6217         try sub_comp.update(prog_node);
   6218     }
   6219 
   6220     // Look for compilation errors in this sub compilation
   6221     const gpa = parent_comp.gpa;
   6222     var keep_errors = false;
   6223     var errors = try sub_comp.getAllErrorsAlloc();
   6224     defer if (!keep_errors) errors.deinit(gpa);
   6225 
   6226     if (errors.errorMessageCount() > 0) {
   6227         try parent_comp.misc_failures.ensureUnusedCapacity(gpa, 1);
   6228         parent_comp.misc_failures.putAssumeCapacityNoClobber(misc_task, .{
   6229             .msg = try std.fmt.allocPrint(gpa, "sub-compilation of {s} failed", .{
   6230                 @tagName(misc_task),
   6231             }),
   6232             .children = errors,
   6233         });
   6234         keep_errors = true;
   6235         return error.SubCompilationFailed;
   6236     }
   6237 }
   6238 
   6239 fn buildOutputFromZig(
   6240     comp: *Compilation,
   6241     src_basename: []const u8,
   6242     output_mode: std.builtin.OutputMode,
   6243     out: *?CRTFile,
   6244     misc_task_tag: MiscTask,
   6245     prog_node: *std.Progress.Node,
   6246 ) !void {
   6247     const tracy_trace = trace(@src());
   6248     defer tracy_trace.end();
   6249 
   6250     std.debug.assert(output_mode != .Exe);
   6251 
   6252     var main_pkg: Package = .{
   6253         .root_src_directory = comp.zig_lib_directory,
   6254         .root_src_path = src_basename,
   6255     };
   6256     defer main_pkg.deinitTable(comp.gpa);
   6257     const root_name = src_basename[0 .. src_basename.len - std.fs.path.extension(src_basename).len];
   6258     const target = comp.getTarget();
   6259     const bin_basename = try std.zig.binNameAlloc(comp.gpa, .{
   6260         .root_name = root_name,
   6261         .target = target,
   6262         .output_mode = output_mode,
   6263     });
   6264     defer comp.gpa.free(bin_basename);
   6265 
   6266     const emit_bin = Compilation.EmitLoc{
   6267         .directory = null, // Put it in the cache directory.
   6268         .basename = bin_basename,
   6269     };
   6270     const sub_compilation = try Compilation.create(comp.gpa, .{
   6271         .global_cache_directory = comp.global_cache_directory,
   6272         .local_cache_directory = comp.global_cache_directory,
   6273         .zig_lib_directory = comp.zig_lib_directory,
   6274         .cache_mode = .whole,
   6275         .target = target,
   6276         .root_name = root_name,
   6277         .main_pkg = &main_pkg,
   6278         .output_mode = output_mode,
   6279         .thread_pool = comp.thread_pool,
   6280         .libc_installation = comp.bin_file.options.libc_installation,
   6281         .emit_bin = emit_bin,
   6282         .optimize_mode = comp.compilerRtOptMode(),
   6283         .link_mode = .Static,
   6284         .function_sections = true,
   6285         .no_builtin = true,
   6286         .want_sanitize_c = false,
   6287         .want_stack_check = false,
   6288         .want_stack_protector = 0,
   6289         .want_red_zone = comp.bin_file.options.red_zone,
   6290         .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer,
   6291         .want_valgrind = false,
   6292         .want_tsan = false,
   6293         .want_unwind_tables = comp.bin_file.options.eh_frame_hdr,
   6294         .want_pic = comp.bin_file.options.pic,
   6295         .want_pie = comp.bin_file.options.pie,
   6296         .emit_h = null,
   6297         .strip = comp.compilerRtStrip(),
   6298         .is_native_os = comp.bin_file.options.is_native_os,
   6299         .is_native_abi = comp.bin_file.options.is_native_abi,
   6300         .self_exe_path = comp.self_exe_path,
   6301         .verbose_cc = comp.verbose_cc,
   6302         .verbose_link = comp.bin_file.options.verbose_link,
   6303         .verbose_air = comp.verbose_air,
   6304         .verbose_intern_pool = comp.verbose_intern_pool,
   6305         .verbose_generic_instances = comp.verbose_intern_pool,
   6306         .verbose_llvm_ir = comp.verbose_llvm_ir,
   6307         .verbose_llvm_bc = comp.verbose_llvm_bc,
   6308         .verbose_cimport = comp.verbose_cimport,
   6309         .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
   6310         .clang_passthrough_mode = comp.clang_passthrough_mode,
   6311         .skip_linker_dependencies = true,
   6312         .parent_compilation_link_libc = comp.bin_file.options.link_libc,
   6313     });
   6314     defer sub_compilation.destroy();
   6315 
   6316     try comp.updateSubCompilation(sub_compilation, misc_task_tag, prog_node);
   6317 
   6318     assert(out.* == null);
   6319     out.* = Compilation.CRTFile{
   6320         .full_object_path = try sub_compilation.bin_file.options.emit.?.directory.join(comp.gpa, &[_][]const u8{
   6321             sub_compilation.bin_file.options.emit.?.sub_path,
   6322         }),
   6323         .lock = sub_compilation.bin_file.toOwnedLock(),
   6324     };
   6325 }
   6326 
   6327 pub fn build_crt_file(
   6328     comp: *Compilation,
   6329     root_name: []const u8,
   6330     output_mode: std.builtin.OutputMode,
   6331     misc_task_tag: MiscTask,
   6332     prog_node: *std.Progress.Node,
   6333     c_source_files: []const Compilation.CSourceFile,
   6334 ) !void {
   6335     const tracy_trace = trace(@src());
   6336     defer tracy_trace.end();
   6337 
   6338     const target = comp.getTarget();
   6339     const basename = try std.zig.binNameAlloc(comp.gpa, .{
   6340         .root_name = root_name,
   6341         .target = target,
   6342         .output_mode = output_mode,
   6343     });
   6344     errdefer comp.gpa.free(basename);
   6345 
   6346     const sub_compilation = try Compilation.create(comp.gpa, .{
   6347         .local_cache_directory = comp.global_cache_directory,
   6348         .global_cache_directory = comp.global_cache_directory,
   6349         .zig_lib_directory = comp.zig_lib_directory,
   6350         .cache_mode = .whole,
   6351         .target = target,
   6352         .root_name = root_name,
   6353         .main_pkg = null,
   6354         .output_mode = output_mode,
   6355         .thread_pool = comp.thread_pool,
   6356         .libc_installation = comp.bin_file.options.libc_installation,
   6357         .emit_bin = .{
   6358             .directory = null, // Put it in the cache directory.
   6359             .basename = basename,
   6360         },
   6361         .optimize_mode = comp.compilerRtOptMode(),
   6362         .want_sanitize_c = false,
   6363         .want_stack_check = false,
   6364         .want_stack_protector = 0,
   6365         .want_red_zone = comp.bin_file.options.red_zone,
   6366         .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer,
   6367         .want_valgrind = false,
   6368         .want_tsan = false,
   6369         .want_pic = comp.bin_file.options.pic,
   6370         .want_pie = comp.bin_file.options.pie,
   6371         .want_lto = switch (output_mode) {
   6372             .Lib => comp.bin_file.options.lto,
   6373             .Obj, .Exe => false,
   6374         },
   6375         .emit_h = null,
   6376         .strip = comp.compilerRtStrip(),
   6377         .is_native_os = comp.bin_file.options.is_native_os,
   6378         .is_native_abi = comp.bin_file.options.is_native_abi,
   6379         .self_exe_path = comp.self_exe_path,
   6380         .c_source_files = c_source_files,
   6381         .verbose_cc = comp.verbose_cc,
   6382         .verbose_link = comp.bin_file.options.verbose_link,
   6383         .verbose_air = comp.verbose_air,
   6384         .verbose_intern_pool = comp.verbose_intern_pool,
   6385         .verbose_generic_instances = comp.verbose_generic_instances,
   6386         .verbose_llvm_ir = comp.verbose_llvm_ir,
   6387         .verbose_llvm_bc = comp.verbose_llvm_bc,
   6388         .verbose_cimport = comp.verbose_cimport,
   6389         .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
   6390         .clang_passthrough_mode = comp.clang_passthrough_mode,
   6391         .skip_linker_dependencies = true,
   6392         .parent_compilation_link_libc = comp.bin_file.options.link_libc,
   6393     });
   6394     defer sub_compilation.destroy();
   6395 
   6396     try comp.updateSubCompilation(sub_compilation, misc_task_tag, prog_node);
   6397 
   6398     try comp.crt_files.ensureUnusedCapacity(comp.gpa, 1);
   6399 
   6400     comp.crt_files.putAssumeCapacityNoClobber(basename, .{
   6401         .full_object_path = try sub_compilation.bin_file.options.emit.?.directory.join(comp.gpa, &[_][]const u8{
   6402             sub_compilation.bin_file.options.emit.?.sub_path,
   6403         }),
   6404         .lock = sub_compilation.bin_file.toOwnedLock(),
   6405     });
   6406 }
   6407 
   6408 pub fn addLinkLib(comp: *Compilation, lib_name: []const u8) !void {
   6409     // Avoid deadlocking on building import libs such as kernel32.lib
   6410     // This can happen when the user uses `build-exe foo.obj -lkernel32` and
   6411     // then when we create a sub-Compilation for zig libc, it also tries to
   6412     // build kernel32.lib.
   6413     if (comp.bin_file.options.skip_linker_dependencies) return;
   6414 
   6415     // This happens when an `extern "foo"` function is referenced.
   6416     // If we haven't seen this library yet and we're targeting Windows, we need
   6417     // to queue up a work item to produce the DLL import library for this.
   6418     const gop = try comp.bin_file.options.system_libs.getOrPut(comp.gpa, lib_name);
   6419     if (!gop.found_existing and comp.getTarget().os.tag == .windows) {
   6420         gop.value_ptr.* = .{
   6421             .needed = true,
   6422             .weak = false,
   6423             .path = null,
   6424         };
   6425         try comp.work_queue.writeItem(.{
   6426             .windows_import_lib = comp.bin_file.options.system_libs.count() - 1,
   6427         });
   6428     }
   6429 }
   6430 
   6431 /// This decides the optimization mode for all zig-provided libraries, including
   6432 /// compiler-rt, libcxx, libc, libunwind, etc.
   6433 pub fn compilerRtOptMode(comp: Compilation) std.builtin.OptimizeMode {
   6434     if (comp.debug_compiler_runtime_libs) {
   6435         return comp.bin_file.options.optimize_mode;
   6436     }
   6437     switch (comp.bin_file.options.optimize_mode) {
   6438         .Debug, .ReleaseSafe => return target_util.defaultCompilerRtOptimizeMode(comp.getTarget()),
   6439         .ReleaseFast => return .ReleaseFast,
   6440         .ReleaseSmall => return .ReleaseSmall,
   6441     }
   6442 }
   6443 
   6444 /// This decides whether to strip debug info for all zig-provided libraries, including
   6445 /// compiler-rt, libcxx, libc, libunwind, etc.
   6446 pub fn compilerRtStrip(comp: Compilation) bool {
   6447     return comp.bin_file.options.strip;
   6448 }