motiejus/zig

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

src/main.zig (349981B) - Raw


      1 const std = @import("std");
      2 const builtin = @import("builtin");
      3 const assert = std.debug.assert;
      4 const fs = std.fs;
      5 const mem = std.mem;
      6 const process = std.process;
      7 const Allocator = mem.Allocator;
      8 const Ast = std.zig.Ast;
      9 const Color = std.zig.Color;
     10 const warn = std.log.warn;
     11 const ThreadPool = std.Thread.Pool;
     12 const cleanExit = std.process.cleanExit;
     13 const native_os = builtin.os.tag;
     14 const Cache = std.Build.Cache;
     15 const Path = std.Build.Cache.Path;
     16 const Directory = std.Build.Cache.Directory;
     17 const EnvVar = std.zig.EnvVar;
     18 const LibCInstallation = std.zig.LibCInstallation;
     19 const AstGen = std.zig.AstGen;
     20 const ZonGen = std.zig.ZonGen;
     21 const Server = std.zig.Server;
     22 
     23 const tracy = @import("tracy.zig");
     24 const Compilation = @import("Compilation.zig");
     25 const link = @import("link.zig");
     26 const Package = @import("Package.zig");
     27 const build_options = @import("build_options");
     28 const introspect = @import("introspect.zig");
     29 const wasi_libc = @import("libs/wasi_libc.zig");
     30 const target_util = @import("target.zig");
     31 const crash_report = @import("crash_report.zig");
     32 const Zcu = @import("Zcu.zig");
     33 const mingw = @import("libs/mingw.zig");
     34 const dev = @import("dev.zig");
     35 
     36 test {
     37     _ = Package;
     38     _ = @import("codegen.zig");
     39 }
     40 
     41 const thread_stack_size = 60 << 20;
     42 
     43 pub const std_options: std.Options = .{
     44     .wasiCwd = wasi_cwd,
     45     .logFn = log,
     46 
     47     .log_level = switch (builtin.mode) {
     48         .Debug => .debug,
     49         .ReleaseSafe, .ReleaseFast => .info,
     50         .ReleaseSmall => .err,
     51     },
     52 };
     53 
     54 pub const panic = crash_report.panic;
     55 pub const debug = crash_report.debug;
     56 
     57 var wasi_preopens: fs.wasi.Preopens = undefined;
     58 pub fn wasi_cwd() std.os.wasi.fd_t {
     59     // Expect the first preopen to be current working directory.
     60     const cwd_fd: std.posix.fd_t = 3;
     61     assert(mem.eql(u8, wasi_preopens.names[cwd_fd], "."));
     62     return cwd_fd;
     63 }
     64 
     65 const fatal = std.process.fatal;
     66 
     67 /// This can be global since stdin is a singleton.
     68 var stdin_buffer: [4096]u8 align(std.heap.page_size_min) = undefined;
     69 /// This can be global since stdout is a singleton.
     70 var stdout_buffer: [4096]u8 align(std.heap.page_size_min) = undefined;
     71 
     72 /// Shaming all the locations that inappropriately use an O(N) search algorithm.
     73 /// Please delete this and fix the compilation errors!
     74 pub const @"bad O(N)" = void;
     75 
     76 const normal_usage =
     77     \\Usage: zig [command] [options]
     78     \\
     79     \\Commands:
     80     \\
     81     \\  build            Build project from build.zig
     82     \\  fetch            Copy a package into global cache and print its hash
     83     \\  init             Initialize a Zig package in the current directory
     84     \\
     85     \\  build-exe        Create executable from source or object files
     86     \\  build-lib        Create library from source or object files
     87     \\  build-obj        Create object from source or object files
     88     \\  test             Perform unit testing
     89     \\  test-obj         Create object for unit testing
     90     \\  run              Create executable and run immediately
     91     \\
     92     \\  ast-check        Look for simple compile errors in any set of files
     93     \\  fmt              Reformat Zig source into canonical form
     94     \\  reduce           Minimize a bug report
     95     \\  translate-c      Convert C code to Zig code
     96     \\
     97     \\  ar               Use Zig as a drop-in archiver
     98     \\  cc               Use Zig as a drop-in C compiler
     99     \\  c++              Use Zig as a drop-in C++ compiler
    100     \\  dlltool          Use Zig as a drop-in dlltool.exe
    101     \\  lib              Use Zig as a drop-in lib.exe
    102     \\  ranlib           Use Zig as a drop-in ranlib
    103     \\  objcopy          Use Zig as a drop-in objcopy
    104     \\  rc               Use Zig as a drop-in rc.exe
    105     \\
    106     \\  env              Print lib path, std path, cache directory, and version
    107     \\  help             Print this help and exit
    108     \\  std              View standard library documentation in a browser
    109     \\  libc             Display native libc paths file or validate one
    110     \\  targets          List available compilation targets
    111     \\  version          Print version number and exit
    112     \\  zen              Print Zen of Zig and exit
    113     \\
    114     \\General Options:
    115     \\
    116     \\  -h, --help       Print command-specific usage
    117     \\
    118 ;
    119 
    120 const debug_usage = normal_usage ++
    121     \\
    122     \\Debug Commands:
    123     \\
    124     \\  changelist       Compute mappings from old ZIR to new ZIR
    125     \\  dump-zir         Dump a file containing cached ZIR
    126     \\  detect-cpu       Compare Zig's CPU feature detection vs LLVM
    127     \\  llvm-ints        Dump a list of LLVMABIAlignmentOfType for all integers
    128     \\
    129 ;
    130 
    131 const usage = if (build_options.enable_debug_extensions) debug_usage else normal_usage;
    132 
    133 var log_scopes: std.ArrayListUnmanaged([]const u8) = .empty;
    134 
    135 pub fn log(
    136     comptime level: std.log.Level,
    137     comptime scope: @Type(.enum_literal),
    138     comptime format: []const u8,
    139     args: anytype,
    140 ) void {
    141     // Hide debug messages unless:
    142     // * logging enabled with `-Dlog`.
    143     // * the --debug-log arg for the scope has been provided
    144     if (@intFromEnum(level) > @intFromEnum(std.options.log_level) or
    145         @intFromEnum(level) > @intFromEnum(std.log.Level.info))
    146     {
    147         if (!build_options.enable_logging) return;
    148 
    149         const scope_name = @tagName(scope);
    150         for (log_scopes.items) |log_scope| {
    151             if (mem.eql(u8, log_scope, scope_name))
    152                 break;
    153         } else return;
    154     }
    155 
    156     const prefix1 = comptime level.asText();
    157     const prefix2 = if (scope == .default) ": " else "(" ++ @tagName(scope) ++ "): ";
    158 
    159     // Print the message to stderr, silently ignoring any errors
    160     std.debug.print(prefix1 ++ prefix2 ++ format ++ "\n", args);
    161 }
    162 
    163 var debug_allocator: std.heap.DebugAllocator(.{
    164     .stack_trace_frames = build_options.mem_leak_frames,
    165 }) = .init;
    166 
    167 pub fn main() anyerror!void {
    168     const gpa, const is_debug = gpa: {
    169         if (build_options.debug_gpa) break :gpa .{ debug_allocator.allocator(), true };
    170         if (native_os == .wasi) break :gpa .{ std.heap.wasm_allocator, false };
    171         if (builtin.link_libc) {
    172             // We would prefer to use raw libc allocator here, but cannot use
    173             // it if it won't support the alignment we need.
    174             if (@alignOf(std.c.max_align_t) < @max(@alignOf(i128), std.atomic.cache_line)) {
    175                 break :gpa .{ std.heap.c_allocator, false };
    176             }
    177             break :gpa .{ std.heap.raw_c_allocator, false };
    178         }
    179         break :gpa switch (builtin.mode) {
    180             .Debug, .ReleaseSafe => .{ debug_allocator.allocator(), true },
    181             .ReleaseFast, .ReleaseSmall => .{ std.heap.smp_allocator, false },
    182         };
    183     };
    184     defer if (is_debug) {
    185         _ = debug_allocator.deinit();
    186     };
    187     var arena_instance = std.heap.ArenaAllocator.init(gpa);
    188     defer arena_instance.deinit();
    189     const arena = arena_instance.allocator();
    190 
    191     const args = try process.argsAlloc(arena);
    192 
    193     if (args.len > 0) crash_report.zig_argv0 = args[0];
    194 
    195     if (tracy.enable_allocation) {
    196         var gpa_tracy = tracy.tracyAllocator(gpa);
    197         return mainArgs(gpa_tracy.allocator(), arena, args);
    198     }
    199 
    200     if (native_os == .wasi) {
    201         wasi_preopens = try fs.wasi.preopensAlloc(arena);
    202     }
    203 
    204     return mainArgs(gpa, arena, args);
    205 }
    206 
    207 fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
    208     const tr = tracy.trace(@src());
    209     defer tr.end();
    210 
    211     if (args.len <= 1) {
    212         std.log.info("{s}", .{usage});
    213         fatal("expected command argument", .{});
    214     }
    215 
    216     if (process.can_execv and std.posix.getenvZ("ZIG_IS_DETECTING_LIBC_PATHS") != null) {
    217         dev.check(.cc_command);
    218         // In this case we have accidentally invoked ourselves as "the system C compiler"
    219         // to figure out where libc is installed. This is essentially infinite recursion
    220         // via child process execution due to the CC environment variable pointing to Zig.
    221         // Here we ignore the CC environment variable and exec `cc` as a child process.
    222         // However it's possible Zig is installed as *that* C compiler as well, which is
    223         // why we have this additional environment variable here to check.
    224         var env_map = try process.getEnvMap(arena);
    225 
    226         const inf_loop_env_key = "ZIG_IS_TRYING_TO_NOT_CALL_ITSELF";
    227         if (env_map.get(inf_loop_env_key) != null) {
    228             fatal("The compilation links against libc, but Zig is unable to provide a libc " ++
    229                 "for this operating system, and no --libc " ++
    230                 "parameter was provided, so Zig attempted to invoke the system C compiler " ++
    231                 "in order to determine where libc is installed. However the system C " ++
    232                 "compiler is `zig cc`, so no libc installation was found.", .{});
    233         }
    234         try env_map.put(inf_loop_env_key, "1");
    235 
    236         // Some programs such as CMake will strip the `cc` and subsequent args from the
    237         // CC environment variable. We detect and support this scenario here because of
    238         // the ZIG_IS_DETECTING_LIBC_PATHS environment variable.
    239         if (mem.eql(u8, args[1], "cc")) {
    240             return process.execve(arena, args[1..], &env_map);
    241         } else {
    242             const modified_args = try arena.dupe([]const u8, args);
    243             modified_args[0] = "cc";
    244             return process.execve(arena, modified_args, &env_map);
    245         }
    246     }
    247 
    248     const cmd = args[1];
    249     const cmd_args = args[2..];
    250     if (mem.eql(u8, cmd, "build-exe")) {
    251         dev.check(.build_exe_command);
    252         return buildOutputType(gpa, arena, args, .{ .build = .Exe });
    253     } else if (mem.eql(u8, cmd, "build-lib")) {
    254         dev.check(.build_lib_command);
    255         return buildOutputType(gpa, arena, args, .{ .build = .Lib });
    256     } else if (mem.eql(u8, cmd, "build-obj")) {
    257         dev.check(.build_obj_command);
    258         return buildOutputType(gpa, arena, args, .{ .build = .Obj });
    259     } else if (mem.eql(u8, cmd, "test")) {
    260         dev.check(.test_command);
    261         return buildOutputType(gpa, arena, args, .zig_test);
    262     } else if (mem.eql(u8, cmd, "test-obj")) {
    263         dev.check(.test_command);
    264         return buildOutputType(gpa, arena, args, .zig_test_obj);
    265     } else if (mem.eql(u8, cmd, "run")) {
    266         dev.check(.run_command);
    267         return buildOutputType(gpa, arena, args, .run);
    268     } else if (mem.eql(u8, cmd, "dlltool") or
    269         mem.eql(u8, cmd, "ranlib") or
    270         mem.eql(u8, cmd, "lib") or
    271         mem.eql(u8, cmd, "ar"))
    272     {
    273         dev.check(.ar_command);
    274         return process.exit(try llvmArMain(arena, args));
    275     } else if (mem.eql(u8, cmd, "build")) {
    276         dev.check(.build_command);
    277         return cmdBuild(gpa, arena, cmd_args);
    278     } else if (mem.eql(u8, cmd, "clang") or
    279         mem.eql(u8, cmd, "-cc1") or mem.eql(u8, cmd, "-cc1as"))
    280     {
    281         dev.check(.clang_command);
    282         return process.exit(try clangMain(arena, args));
    283     } else if (mem.eql(u8, cmd, "ld.lld") or
    284         mem.eql(u8, cmd, "lld-link") or
    285         mem.eql(u8, cmd, "wasm-ld"))
    286     {
    287         dev.check(.lld_linker);
    288         return process.exit(try lldMain(arena, args, true));
    289     } else if (mem.eql(u8, cmd, "cc")) {
    290         dev.check(.cc_command);
    291         return buildOutputType(gpa, arena, args, .cc);
    292     } else if (mem.eql(u8, cmd, "c++")) {
    293         dev.check(.cc_command);
    294         return buildOutputType(gpa, arena, args, .cpp);
    295     } else if (mem.eql(u8, cmd, "translate-c")) {
    296         dev.check(.translate_c_command);
    297         return buildOutputType(gpa, arena, args, .translate_c);
    298     } else if (mem.eql(u8, cmd, "rc")) {
    299         const use_server = cmd_args.len > 0 and std.mem.eql(u8, cmd_args[0], "--zig-integration");
    300         return jitCmd(gpa, arena, cmd_args, .{
    301             .cmd_name = "resinator",
    302             .root_src_path = "resinator/main.zig",
    303             .depend_on_aro = true,
    304             .prepend_zig_lib_dir_path = true,
    305             .server = use_server,
    306         });
    307     } else if (mem.eql(u8, cmd, "fmt")) {
    308         dev.check(.fmt_command);
    309         return @import("fmt.zig").run(gpa, arena, cmd_args);
    310     } else if (mem.eql(u8, cmd, "objcopy")) {
    311         return jitCmd(gpa, arena, cmd_args, .{
    312             .cmd_name = "objcopy",
    313             .root_src_path = "objcopy.zig",
    314         });
    315     } else if (mem.eql(u8, cmd, "fetch")) {
    316         return cmdFetch(gpa, arena, cmd_args);
    317     } else if (mem.eql(u8, cmd, "libc")) {
    318         return jitCmd(gpa, arena, cmd_args, .{
    319             .cmd_name = "libc",
    320             .root_src_path = "libc.zig",
    321             .prepend_zig_lib_dir_path = true,
    322         });
    323     } else if (mem.eql(u8, cmd, "std")) {
    324         return jitCmd(gpa, arena, cmd_args, .{
    325             .cmd_name = "std",
    326             .root_src_path = "std-docs.zig",
    327             .prepend_zig_lib_dir_path = true,
    328             .prepend_zig_exe_path = true,
    329             .prepend_global_cache_path = true,
    330         });
    331     } else if (mem.eql(u8, cmd, "init")) {
    332         return cmdInit(gpa, arena, cmd_args);
    333     } else if (mem.eql(u8, cmd, "targets")) {
    334         dev.check(.targets_command);
    335         const host = std.zig.resolveTargetQueryOrFatal(.{});
    336         var stdout_writer = fs.File.stdout().writer(&stdout_buffer);
    337         try @import("print_targets.zig").cmdTargets(arena, cmd_args, &stdout_writer.interface, &host);
    338         return stdout_writer.interface.flush();
    339     } else if (mem.eql(u8, cmd, "version")) {
    340         dev.check(.version_command);
    341         try fs.File.stdout().writeAll(build_options.version ++ "\n");
    342         return;
    343     } else if (mem.eql(u8, cmd, "env")) {
    344         dev.check(.env_command);
    345         var stdout_writer = fs.File.stdout().writer(&stdout_buffer);
    346         try @import("print_env.zig").cmdEnv(
    347             arena,
    348             &stdout_writer.interface,
    349             args,
    350             if (native_os == .wasi) wasi_preopens,
    351         );
    352         return stdout_writer.interface.flush();
    353     } else if (mem.eql(u8, cmd, "reduce")) {
    354         return jitCmd(gpa, arena, cmd_args, .{
    355             .cmd_name = "reduce",
    356             .root_src_path = "reduce.zig",
    357         });
    358     } else if (mem.eql(u8, cmd, "zen")) {
    359         dev.check(.zen_command);
    360         return fs.File.stdout().writeAll(info_zen);
    361     } else if (mem.eql(u8, cmd, "help") or mem.eql(u8, cmd, "-h") or mem.eql(u8, cmd, "--help")) {
    362         dev.check(.help_command);
    363         return fs.File.stdout().writeAll(usage);
    364     } else if (mem.eql(u8, cmd, "ast-check")) {
    365         return cmdAstCheck(arena, cmd_args);
    366     } else if (mem.eql(u8, cmd, "detect-cpu")) {
    367         return cmdDetectCpu(cmd_args);
    368     } else if (build_options.enable_debug_extensions and mem.eql(u8, cmd, "changelist")) {
    369         return cmdChangelist(arena, cmd_args);
    370     } else if (build_options.enable_debug_extensions and mem.eql(u8, cmd, "dump-zir")) {
    371         return cmdDumpZir(arena, cmd_args);
    372     } else if (build_options.enable_debug_extensions and mem.eql(u8, cmd, "llvm-ints")) {
    373         return cmdDumpLlvmInts(gpa, arena, cmd_args);
    374     } else {
    375         std.log.info("{s}", .{usage});
    376         fatal("unknown command: {s}", .{args[1]});
    377     }
    378 }
    379 
    380 const usage_build_generic =
    381     \\Usage: zig build-exe   [options] [files]
    382     \\       zig build-lib   [options] [files]
    383     \\       zig build-obj   [options] [files]
    384     \\       zig test        [options] [files]
    385     \\       zig run         [options] [files] [-- [args]]
    386     \\       zig translate-c [options] [file]
    387     \\
    388     \\Supported file types:
    389     \\                         .zig    Zig source code
    390     \\                           .o    ELF object file
    391     \\                           .o    Mach-O (macOS) object file
    392     \\                           .o    WebAssembly object file
    393     \\                         .obj    COFF (Windows) object file
    394     \\                         .lib    COFF (Windows) static library
    395     \\                           .a    ELF static library
    396     \\                           .a    Mach-O (macOS) static library
    397     \\                           .a    WebAssembly static library
    398     \\                          .so    ELF shared object (dynamic link)
    399     \\                         .dll    Windows Dynamic Link Library
    400     \\                       .dylib    Mach-O (macOS) dynamic library
    401     \\                         .tbd    (macOS) text-based dylib definition
    402     \\                           .s    Target-specific assembly source code
    403     \\                           .S    Assembly with C preprocessor (requires LLVM extensions)
    404     \\                           .c    C source code (requires LLVM extensions)
    405     \\        .cxx .cc .C .cpp .c++    C++ source code (requires LLVM extensions)
    406     \\                           .m    Objective-C source code (requires LLVM extensions)
    407     \\                          .mm    Objective-C++ source code (requires LLVM extensions)
    408     \\                          .bc    LLVM IR Module (requires LLVM extensions)
    409     \\
    410     \\General Options:
    411     \\  -h, --help                Print this help and exit
    412     \\  --color [auto|off|on]     Enable or disable colored error messages
    413     \\  -j<N>                     Limit concurrent jobs (default is to use all CPU cores)
    414     \\  -fincremental             Enable incremental compilation
    415     \\  -fno-incremental          Disable incremental compilation
    416     \\  -femit-bin[=path]         (default) Output machine code
    417     \\  -fno-emit-bin             Do not output machine code
    418     \\  -femit-asm[=path]         Output .s (assembly code)
    419     \\  -fno-emit-asm             (default) Do not output .s (assembly code)
    420     \\  -femit-llvm-ir[=path]     Produce a .ll file with optimized LLVM IR (requires LLVM extensions)
    421     \\  -fno-emit-llvm-ir         (default) Do not produce a .ll file with optimized LLVM IR
    422     \\  -femit-llvm-bc[=path]     Produce an optimized LLVM module as a .bc file (requires LLVM extensions)
    423     \\  -fno-emit-llvm-bc         (default) Do not produce an optimized LLVM module as a .bc file
    424     \\  -femit-h[=path]           Generate a C header file (.h)
    425     \\  -fno-emit-h               (default) Do not generate a C header file (.h)
    426     \\  -femit-docs[=path]        Create a docs/ dir with html documentation
    427     \\  -fno-emit-docs            (default) Do not produce docs/ dir with html documentation
    428     \\  -femit-implib[=path]      (default) Produce an import .lib when building a Windows DLL
    429     \\  -fno-emit-implib          Do not produce an import .lib when building a Windows DLL
    430     \\  --show-builtin            Output the source of @import("builtin") then exit
    431     \\  --cache-dir [path]        Override the local cache directory
    432     \\  --global-cache-dir [path] Override the global cache directory
    433     \\  --zig-lib-dir [path]      Override path to Zig installation lib directory
    434     \\
    435     \\Global Compile Options:
    436     \\  --name [name]             Compilation unit name (not a file path)
    437     \\  --libc [file]             Provide a file which specifies libc paths
    438     \\  -x language               Treat subsequent input files as having type <language>
    439     \\  --dep [[import=]name]     Add an entry to the next module's import table
    440     \\  -M[name][=src]            Create a module based on the current per-module settings.
    441     \\                            The first module is the main module.
    442     \\                            "std" can be configured by omitting src
    443     \\                            After a -M argument, per-module settings are reset.
    444     \\  --error-limit [num]       Set the maximum amount of distinct error values
    445     \\  -fllvm                    Force using LLVM as the codegen backend
    446     \\  -fno-llvm                 Prevent using LLVM as the codegen backend
    447     \\  -flibllvm                 Force using the LLVM API in the codegen backend
    448     \\  -fno-libllvm              Prevent using the LLVM API in the codegen backend
    449     \\  -fclang                   Force using Clang as the C/C++ compilation backend
    450     \\  -fno-clang                Prevent using Clang as the C/C++ compilation backend
    451     \\  -fPIE                     Force-enable Position Independent Executable
    452     \\  -fno-PIE                  Force-disable Position Independent Executable
    453     \\  -flto                     Force-enable Link Time Optimization (requires LLVM extensions)
    454     \\  -fno-lto                  Force-disable Link Time Optimization
    455     \\  -fdll-export-fns          Mark exported functions as DLL exports (Windows)
    456     \\  -fno-dll-export-fns       Force-disable marking exported functions as DLL exports
    457     \\  -freference-trace[=num]   Show num lines of reference trace per compile error
    458     \\  -fno-reference-trace      Disable reference trace
    459     \\  -ffunction-sections       Places each function in a separate section
    460     \\  -fno-function-sections    All functions go into same section
    461     \\  -fdata-sections           Places each data in a separate section
    462     \\  -fno-data-sections        All data go into same section
    463     \\  -fformatted-panics        Enable formatted safety panics
    464     \\  -fno-formatted-panics     Disable formatted safety panics
    465     \\  -fstructured-cfg          (SPIR-V) force SPIR-V kernels to use structured control flow
    466     \\  -fno-structured-cfg       (SPIR-V) force SPIR-V kernels to not use structured control flow
    467     \\  -mexec-model=[value]      (WASI) Execution model
    468     \\  -municode                 (Windows) Use wmain/wWinMain as entry point
    469     \\  --time-report             Send timing diagnostics to '--listen' clients
    470     \\
    471     \\Per-Module Compile Options:
    472     \\  -target [name]            <arch><sub>-<os>-<abi> see the targets command
    473     \\  -O [mode]                 Choose what to optimize for
    474     \\    Debug                   (default) Optimizations off, safety on
    475     \\    ReleaseFast             Optimize for performance, safety off
    476     \\    ReleaseSafe             Optimize for performance, safety on
    477     \\    ReleaseSmall            Optimize for small binary, safety off
    478     \\  -ofmt=[fmt]               Override target object format
    479     \\    elf                     Executable and Linking Format
    480     \\    c                       C source code
    481     \\    wasm                    WebAssembly
    482     \\    coff                    Common Object File Format (Windows)
    483     \\    macho                   macOS relocatables
    484     \\    spirv                   Standard, Portable Intermediate Representation V (SPIR-V)
    485     \\    plan9                   Plan 9 from Bell Labs object format
    486     \\    hex  (planned feature)  Intel IHEX
    487     \\    raw  (planned feature)  Dump machine code directly
    488     \\  -mcpu [cpu]               Specify target CPU and feature set
    489     \\  -mcmodel=[model]          Limit range of code and data virtual addresses
    490     \\    default
    491     \\    extreme
    492     \\    kernel
    493     \\    large
    494     \\    medany
    495     \\    medium
    496     \\    medlow
    497     \\    medmid
    498     \\    normal
    499     \\    small
    500     \\    tiny
    501     \\  -mred-zone                Force-enable the "red-zone"
    502     \\  -mno-red-zone             Force-disable the "red-zone"
    503     \\  -fomit-frame-pointer      Omit the stack frame pointer
    504     \\  -fno-omit-frame-pointer   Store the stack frame pointer
    505     \\  -fPIC                     Force-enable Position Independent Code
    506     \\  -fno-PIC                  Force-disable Position Independent Code
    507     \\  -fstack-check             Enable stack probing in unsafe builds
    508     \\  -fno-stack-check          Disable stack probing in safe builds
    509     \\  -fstack-protector         Enable stack protection in unsafe builds
    510     \\  -fno-stack-protector      Disable stack protection in safe builds
    511     \\  -fvalgrind                Include valgrind client requests in release builds
    512     \\  -fno-valgrind             Omit valgrind client requests in debug builds
    513     \\  -fsanitize-c[=mode]       Enable C undefined behavior detection in unsafe builds
    514     \\    trap                    Insert trap instructions on undefined behavior
    515     \\    full                    (Default) Insert runtime calls on undefined behavior
    516     \\  -fno-sanitize-c           Disable C undefined behavior detection in safe builds
    517     \\  -fsanitize-thread         Enable Thread Sanitizer
    518     \\  -fno-sanitize-thread      Disable Thread Sanitizer
    519     \\  -ffuzz                    Enable fuzz testing instrumentation
    520     \\  -fno-fuzz                 Disable fuzz testing instrumentation
    521     \\  -fbuiltin                 Enable implicit builtin knowledge of functions
    522     \\  -fno-builtin              Disable implicit builtin knowledge of functions
    523     \\  -funwind-tables           Always produce unwind table entries for all functions
    524     \\  -fasync-unwind-tables     Always produce asynchronous unwind table entries for all functions
    525     \\  -fno-unwind-tables        Never produce unwind table entries
    526     \\  -ferror-tracing           Enable error tracing in release builds
    527     \\  -fno-error-tracing        Disable error tracing in debug builds
    528     \\  -fsingle-threaded         Code assumes there is only one thread
    529     \\  -fno-single-threaded      Code may not assume there is only one thread
    530     \\  -fstrip                   Omit debug symbols
    531     \\  -fno-strip                Keep debug symbols
    532     \\  -idirafter [dir]          Add directory to AFTER include search path
    533     \\  -isystem  [dir]           Add directory to SYSTEM include search path
    534     \\  -I[dir]                   Add directory to include search path
    535     \\  --embed-dir=[dir]         Add directory to embed search path
    536     \\  -D[macro]=[value]         Define C [macro] to [value] (1 if [value] omitted)
    537     \\  -cflags [flags] --        Set extra flags for the next positional C source files
    538     \\  -rcflags [flags] --       Set extra flags for the next positional .rc source files
    539     \\  -rcincludes=[type]        Set the type of includes to use when compiling .rc source files
    540     \\    any                     (default) Use msvc if available, fall back to gnu
    541     \\    msvc                    Use msvc include paths (must be present on the system)
    542     \\    gnu                     Use mingw include paths (distributed with Zig)
    543     \\    none                    Do not use any autodetected include paths
    544     \\
    545     \\Global Link Options:
    546     \\  -T[script], --script [script]  Use a custom linker script
    547     \\  --version-script [path]        Provide a version .map file
    548     \\  --undefined-version            Allow version scripts to refer to undefined symbols
    549     \\  --no-undefined-version         (default) Disallow version scripts from referring to undefined symbols
    550     \\  --enable-new-dtags             Use the new behavior for dynamic tags (RUNPATH)
    551     \\  --disable-new-dtags            Use the old behavior for dynamic tags (RPATH)
    552     \\  --dynamic-linker [path]        Set the dynamic interpreter path (usually ld.so)
    553     \\  --sysroot [path]               Set the system root directory (usually /)
    554     \\  --version [ver]                Dynamic library semver
    555     \\  -fentry                        Enable entry point with default symbol name
    556     \\  -fentry=[name]                 Override the entry point symbol name
    557     \\  -fno-entry                     Do not output any entry point
    558     \\  --force_undefined [name]       Specify the symbol must be defined for the link to succeed
    559     \\  -fsoname[=name]                Override the default SONAME value
    560     \\  -fno-soname                    Disable emitting a SONAME
    561     \\  -flld                          Force using LLD as the linker
    562     \\  -fno-lld                       Prevent using LLD as the linker
    563     \\  -fcompiler-rt                  Always include compiler-rt symbols in output
    564     \\  -fno-compiler-rt               Prevent including compiler-rt symbols in output
    565     \\  -fubsan-rt                     Always include ubsan-rt symbols in the output
    566     \\  -fno-ubsan-rt                  Prevent including ubsan-rt symbols in the output
    567     \\  -rdynamic                      Add all symbols to the dynamic symbol table
    568     \\  -feach-lib-rpath               Ensure adding rpath for each used dynamic library
    569     \\  -fno-each-lib-rpath            Prevent adding rpath for each used dynamic library
    570     \\  -fallow-shlib-undefined        Allows undefined symbols in shared libraries
    571     \\  -fno-allow-shlib-undefined     Disallows undefined symbols in shared libraries
    572     \\  -fallow-so-scripts             Allows .so files to be GNU ld scripts
    573     \\  -fno-allow-so-scripts          (default) .so files must be ELF files
    574     \\  --build-id[=style]             At a minor link-time expense, embeds a build ID in binaries
    575     \\      fast                       8-byte non-cryptographic hash (COFF, ELF, WASM)
    576     \\      sha1, tree                 20-byte cryptographic hash (ELF, WASM)
    577     \\      md5                        16-byte cryptographic hash (ELF)
    578     \\      uuid                       16-byte random UUID (ELF, WASM)
    579     \\      0x[hexstring]              Constant ID, maximum 32 bytes (ELF, WASM)
    580     \\      none                     (default) No build ID
    581     \\  --eh-frame-hdr                 Enable C++ exception handling by passing --eh-frame-hdr to linker
    582     \\  --no-eh-frame-hdr              Disable C++ exception handling by passing --no-eh-frame-hdr to linker
    583     \\  --emit-relocs                  Enable output of relocation sections for post build tools
    584     \\  -z [arg]                       Set linker extension flags
    585     \\    nodelete                     Indicate that the object cannot be deleted from a process
    586     \\    notext                       Permit read-only relocations in read-only segments
    587     \\    defs                         Force a fatal error if any undefined symbols remain
    588     \\    undefs                       Reverse of -z defs
    589     \\    origin                       Indicate that the object must have its origin processed
    590     \\    nocopyreloc                  Disable the creation of copy relocations
    591     \\    now                          (default) Force all relocations to be processed on load
    592     \\    lazy                         Don't force all relocations to be processed on load
    593     \\    relro                        (default) Force all relocations to be read-only after processing
    594     \\    norelro                      Don't force all relocations to be read-only after processing
    595     \\    common-page-size=[bytes]     Set the common page size for ELF binaries
    596     \\    max-page-size=[bytes]        Set the max page size for ELF binaries
    597     \\  -dynamic                       Force output to be dynamically linked
    598     \\  -static                        Force output to be statically linked
    599     \\  -Bsymbolic                     Bind global references locally
    600     \\  --compress-debug-sections=[e]  Debug section compression settings
    601     \\      none                       No compression
    602     \\      zlib                       Compression with deflate/inflate
    603     \\      zstd                       Compression with zstandard
    604     \\  --gc-sections                  Force removal of functions and data that are unreachable by the entry point or exported symbols
    605     \\  --no-gc-sections               Don't force removal of unreachable functions and data
    606     \\  --sort-section=[value]         Sort wildcard section patterns by 'name' or 'alignment'
    607     \\  --subsystem [subsystem]        (Windows) /SUBSYSTEM:<subsystem> to the linker
    608     \\  --stack [size]                 Override default stack size
    609     \\  --image-base [addr]            Set base address for executable image
    610     \\  -install_name=[value]          (Darwin) add dylib's install name
    611     \\  --entitlements [path]          (Darwin) add path to entitlements file for embedding in code signature
    612     \\  -pagezero_size [value]         (Darwin) size of the __PAGEZERO segment in hexadecimal notation
    613     \\  -headerpad [value]             (Darwin) set minimum space for future expansion of the load commands in hexadecimal notation
    614     \\  -headerpad_max_install_names   (Darwin) set enough space as if all paths were MAXPATHLEN
    615     \\  -dead_strip                    (Darwin) remove functions and data that are unreachable by the entry point or exported symbols
    616     \\  -dead_strip_dylibs             (Darwin) remove dylibs that are unreachable by the entry point or exported symbols
    617     \\  -ObjC                          (Darwin) force load all members of static archives that implement an Objective-C class or category
    618     \\  --import-memory                (WebAssembly) import memory from the environment
    619     \\  --export-memory                (WebAssembly) export memory to the host (Default unless --import-memory used)
    620     \\  --import-symbols               (WebAssembly) import missing symbols from the host environment
    621     \\  --import-table                 (WebAssembly) import function table from the host environment
    622     \\  --export-table                 (WebAssembly) export function table to the host environment
    623     \\  --initial-memory=[bytes]       (WebAssembly) initial size of the linear memory
    624     \\  --max-memory=[bytes]           (WebAssembly) maximum size of the linear memory
    625     \\  --shared-memory                (WebAssembly) use shared linear memory
    626     \\  --global-base=[addr]           (WebAssembly) where to start to place global data
    627     \\
    628     \\Per-Module Link Options:
    629     \\  -l[lib], --library [lib]       Link against system library (only if actually used)
    630     \\  -needed-l[lib],                Link against system library (even if unused)
    631     \\    --needed-library [lib]
    632     \\  -weak-l[lib]                   link against system library marking it and all
    633     \\    -weak_library [lib]          referenced symbols as weak
    634     \\  -L[d], --library-directory [d] Add a directory to the library search path
    635     \\  -search_paths_first            For each library search path, check for dynamic
    636     \\                                 lib then static lib before proceeding to next path.
    637     \\  -search_paths_first_static     For each library search path, check for static
    638     \\                                 lib then dynamic lib before proceeding to next path.
    639     \\  -search_dylibs_first           Search for dynamic libs in all library search
    640     \\                                 paths, then static libs.
    641     \\  -search_static_first           Search for static libs in all library search
    642     \\                                 paths, then dynamic libs.
    643     \\  -search_dylibs_only            Only search for dynamic libs.
    644     \\  -search_static_only            Only search for static libs.
    645     \\  -rpath [path]                  Add directory to the runtime library search path
    646     \\  -framework [name]              (Darwin) link against framework
    647     \\  -needed_framework [name]       (Darwin) link against framework (even if unused)
    648     \\  -needed_library [lib]          (Darwin) link against system library (even if unused)
    649     \\  -weak_framework [name]         (Darwin) link against framework and mark it and all referenced symbols as weak
    650     \\  -F[dir]                        (Darwin) add search path for frameworks
    651     \\  --export=[value]               (WebAssembly) Force a symbol to be exported
    652     \\
    653     \\Test Options:
    654     \\  --test-filter [text]           Skip tests that do not match any filter
    655     \\  --test-cmd [arg]               Specify test execution command one arg at a time
    656     \\  --test-cmd-bin                 Appends test binary path to test cmd args
    657     \\  --test-no-exec                 Compiles test binary without running it
    658     \\  --test-runner [path]           Specify a custom test runner
    659     \\
    660     \\Debug Options (Zig Compiler Development):
    661     \\  -fopt-bisect-limit=[limit]   Only run [limit] first LLVM optimization passes
    662     \\  -fstack-report               Print stack size diagnostics
    663     \\  --verbose-link               Display linker invocations
    664     \\  --verbose-cc                 Display C compiler invocations
    665     \\  --verbose-air                Enable compiler debug output for Zig AIR
    666     \\  --verbose-intern-pool        Enable compiler debug output for InternPool
    667     \\  --verbose-generic-instances  Enable compiler debug output for generic instance generation
    668     \\  --verbose-llvm-ir[=path]     Enable compiler debug output for unoptimized LLVM IR
    669     \\  --verbose-llvm-bc=[path]     Enable compiler debug output for unoptimized LLVM BC
    670     \\  --verbose-cimport            Enable compiler debug output for C imports
    671     \\  --verbose-llvm-cpu-features  Enable compiler debug output for LLVM CPU features
    672     \\  --debug-log [scope]          Enable printing debug/info log messages for scope
    673     \\  --debug-compile-errors       Crash with helpful diagnostics at the first compile error
    674     \\  --debug-link-snapshot        Enable dumping of the linker's state in JSON format
    675     \\  --debug-rt                   Debug compiler runtime libraries
    676     \\  --debug-incremental          Enable incremental compilation debug features
    677     \\
    678 ;
    679 
    680 const SOName = union(enum) {
    681     no,
    682     yes_default_value,
    683     yes: []const u8,
    684 };
    685 
    686 const EmitBin = union(enum) {
    687     no,
    688     yes_default_path,
    689     yes: []const u8,
    690     yes_a_out,
    691 };
    692 
    693 const Emit = union(enum) {
    694     no,
    695     yes_default_path,
    696     yes: []const u8,
    697 
    698     const OutputToCacheReason = enum { listen, @"zig run", @"zig test" };
    699     fn resolve(emit: Emit, default_basename: []const u8, output_to_cache: ?OutputToCacheReason) Compilation.CreateOptions.Emit {
    700         return switch (emit) {
    701             .no => .no,
    702             .yes_default_path => if (output_to_cache != null) .yes_cache else .{ .yes_path = default_basename },
    703             .yes => |path| if (output_to_cache) |reason| {
    704                 switch (reason) {
    705                     .listen => fatal("--listen incompatible with explicit output path '{s}'", .{path}),
    706                     .@"zig run", .@"zig test" => fatal(
    707                         "'{s}' with explicit output path '{s}' requires explicit '-femit-bin=path' or '-fno-emit-bin'",
    708                         .{ @tagName(reason), path },
    709                     ),
    710                 }
    711             } else e: {
    712                 // If there's a dirname, check that dir exists. This will give a more descriptive error than `Compilation` otherwise would.
    713                 if (fs.path.dirname(path)) |dir_path| {
    714                     var dir = fs.cwd().openDir(dir_path, .{}) catch |err| {
    715                         fatal("unable to open output directory '{s}': {s}", .{ dir_path, @errorName(err) });
    716                     };
    717                     dir.close();
    718                 }
    719                 break :e .{ .yes_path = path };
    720             },
    721         };
    722     }
    723 };
    724 
    725 const ArgMode = union(enum) {
    726     build: std.builtin.OutputMode,
    727     cc,
    728     cpp,
    729     translate_c,
    730     zig_test,
    731     zig_test_obj,
    732     run,
    733 };
    734 
    735 const Listen = union(enum) {
    736     none,
    737     stdio: if (dev.env.supports(.stdio_listen)) void else noreturn,
    738     ip4: if (dev.env.supports(.network_listen)) std.net.Ip4Address else noreturn,
    739 };
    740 
    741 const ArgsIterator = struct {
    742     resp_file: ?ArgIteratorResponseFile = null,
    743     args: []const []const u8,
    744     i: usize = 0,
    745     fn next(it: *@This()) ?[]const u8 {
    746         if (it.i >= it.args.len) {
    747             if (it.resp_file) |*resp| return resp.next();
    748             return null;
    749         }
    750         defer it.i += 1;
    751         return it.args[it.i];
    752     }
    753     fn nextOrFatal(it: *@This()) []const u8 {
    754         if (it.i >= it.args.len) {
    755             if (it.resp_file) |*resp| if (resp.next()) |ret| return ret;
    756             fatal("expected parameter after {s}", .{it.args[it.i - 1]});
    757         }
    758         defer it.i += 1;
    759         return it.args[it.i];
    760     }
    761 };
    762 
    763 /// Similar to `link.Framework` except it doesn't store yet unresolved
    764 /// path to the framework.
    765 const Framework = struct {
    766     needed: bool = false,
    767     weak: bool = false,
    768 };
    769 
    770 const CliModule = struct {
    771     root_path: []const u8,
    772     root_src_path: []const u8,
    773     cc_argv: []const []const u8,
    774     inherited: Package.Module.CreateOptions.Inherited,
    775     target_arch_os_abi: ?[]const u8,
    776     target_mcpu: ?[]const u8,
    777 
    778     deps: []const Dep,
    779     resolved: ?*Package.Module,
    780 
    781     c_source_files_start: usize,
    782     c_source_files_end: usize,
    783     rc_source_files_start: usize,
    784     rc_source_files_end: usize,
    785 
    786     const Dep = struct {
    787         key: []const u8,
    788         value: []const u8,
    789     };
    790 };
    791 
    792 fn buildOutputType(
    793     gpa: Allocator,
    794     arena: Allocator,
    795     all_args: []const []const u8,
    796     arg_mode: ArgMode,
    797 ) !void {
    798     var provided_name: ?[]const u8 = null;
    799     var root_src_file: ?[]const u8 = null;
    800     var version: std.SemanticVersion = .{ .major = 0, .minor = 0, .patch = 0 };
    801     var have_version = false;
    802     var compatibility_version: ?std.SemanticVersion = null;
    803     var function_sections = false;
    804     var data_sections = false;
    805     var listen: Listen = .none;
    806     var debug_compile_errors = false;
    807     var debug_incremental = false;
    808     var verbose_link = (native_os != .wasi or builtin.link_libc) and
    809         EnvVar.ZIG_VERBOSE_LINK.isSet();
    810     var verbose_cc = (native_os != .wasi or builtin.link_libc) and
    811         EnvVar.ZIG_VERBOSE_CC.isSet();
    812     var verbose_air = false;
    813     var verbose_intern_pool = false;
    814     var verbose_generic_instances = false;
    815     var verbose_llvm_ir: ?[]const u8 = null;
    816     var verbose_llvm_bc: ?[]const u8 = null;
    817     var verbose_cimport = false;
    818     var verbose_llvm_cpu_features = false;
    819     var time_report = false;
    820     var stack_report = false;
    821     var show_builtin = false;
    822     var emit_bin: EmitBin = .yes_default_path;
    823     var emit_asm: Emit = .no;
    824     var emit_llvm_ir: Emit = .no;
    825     var emit_llvm_bc: Emit = .no;
    826     var emit_docs: Emit = .no;
    827     var emit_implib: Emit = .yes_default_path;
    828     var emit_implib_arg_provided = false;
    829     var target_arch_os_abi: ?[]const u8 = null;
    830     var target_mcpu: ?[]const u8 = null;
    831     var emit_h: Emit = .no;
    832     var soname: SOName = undefined;
    833     var want_compiler_rt: ?bool = null;
    834     var want_ubsan_rt: ?bool = null;
    835     var linker_script: ?[]const u8 = null;
    836     var version_script: ?[]const u8 = null;
    837     var linker_repro: ?bool = null;
    838     var linker_allow_undefined_version: bool = false;
    839     var linker_enable_new_dtags: ?bool = null;
    840     var disable_c_depfile = false;
    841     var linker_sort_section: ?link.File.Lld.Elf.SortSection = null;
    842     var linker_gc_sections: ?bool = null;
    843     var linker_compress_debug_sections: ?link.File.Lld.Elf.CompressDebugSections = null;
    844     var linker_allow_shlib_undefined: ?bool = null;
    845     var allow_so_scripts: bool = false;
    846     var linker_bind_global_refs_locally: ?bool = null;
    847     var linker_import_symbols: bool = false;
    848     var linker_import_table: bool = false;
    849     var linker_export_table: bool = false;
    850     var linker_initial_memory: ?u64 = null;
    851     var linker_max_memory: ?u64 = null;
    852     var linker_global_base: ?u64 = null;
    853     var linker_print_gc_sections: bool = false;
    854     var linker_print_icf_sections: bool = false;
    855     var linker_print_map: bool = false;
    856     var llvm_opt_bisect_limit: c_int = -1;
    857     var linker_z_nocopyreloc = false;
    858     var linker_z_nodelete = false;
    859     var linker_z_notext = false;
    860     var linker_z_defs = false;
    861     var linker_z_origin = false;
    862     var linker_z_now = true;
    863     var linker_z_relro = true;
    864     var linker_z_common_page_size: ?u64 = null;
    865     var linker_z_max_page_size: ?u64 = null;
    866     var linker_tsaware = false;
    867     var linker_nxcompat = false;
    868     var linker_dynamicbase = true;
    869     var linker_optimization: ?[]const u8 = null;
    870     var linker_module_definition_file: ?[]const u8 = null;
    871     var test_no_exec = false;
    872     var entry: Compilation.CreateOptions.Entry = .default;
    873     var force_undefined_symbols: std.StringArrayHashMapUnmanaged(void) = .empty;
    874     var stack_size: ?u64 = null;
    875     var image_base: ?u64 = null;
    876     var link_eh_frame_hdr = false;
    877     var link_emit_relocs = false;
    878     var build_id: ?std.zig.BuildId = null;
    879     var runtime_args_start: ?usize = null;
    880     var test_filters: std.ArrayListUnmanaged([]const u8) = .empty;
    881     var test_runner_path: ?[]const u8 = null;
    882     var override_local_cache_dir: ?[]const u8 = try EnvVar.ZIG_LOCAL_CACHE_DIR.get(arena);
    883     var override_global_cache_dir: ?[]const u8 = try EnvVar.ZIG_GLOBAL_CACHE_DIR.get(arena);
    884     var override_lib_dir: ?[]const u8 = try EnvVar.ZIG_LIB_DIR.get(arena);
    885     var clang_preprocessor_mode: Compilation.ClangPreprocessorMode = .no;
    886     var subsystem: ?std.Target.SubSystem = null;
    887     var major_subsystem_version: ?u16 = null;
    888     var minor_subsystem_version: ?u16 = null;
    889     var mingw_unicode_entry_point: bool = false;
    890     var enable_link_snapshots: bool = false;
    891     var debug_compiler_runtime_libs = false;
    892     var install_name: ?[]const u8 = null;
    893     var hash_style: link.File.Lld.Elf.HashStyle = .both;
    894     var entitlements: ?[]const u8 = null;
    895     var pagezero_size: ?u64 = null;
    896     var lib_search_strategy: link.UnresolvedInput.SearchStrategy = .paths_first;
    897     var lib_preferred_mode: std.builtin.LinkMode = .dynamic;
    898     var headerpad_size: ?u32 = null;
    899     var headerpad_max_install_names: bool = false;
    900     var dead_strip_dylibs: bool = false;
    901     var force_load_objc: bool = false;
    902     var discard_local_symbols: bool = false;
    903     var contains_res_file: bool = false;
    904     var reference_trace: ?u32 = null;
    905     var pdb_out_path: ?[]const u8 = null;
    906     var error_limit: ?Zcu.ErrorInt = null;
    907     // These are before resolving sysroot.
    908     var extra_cflags: std.ArrayListUnmanaged([]const u8) = .empty;
    909     var extra_rcflags: std.ArrayListUnmanaged([]const u8) = .empty;
    910     var symbol_wrap_set: std.StringArrayHashMapUnmanaged(void) = .empty;
    911     var rc_includes: Compilation.RcIncludes = .any;
    912     var manifest_file: ?[]const u8 = null;
    913     var linker_export_symbol_names: std.ArrayListUnmanaged([]const u8) = .empty;
    914 
    915     // Tracks the position in c_source_files which have already their owner populated.
    916     var c_source_files_owner_index: usize = 0;
    917     // Tracks the position in rc_source_files which have already their owner populated.
    918     var rc_source_files_owner_index: usize = 0;
    919 
    920     // null means replace with the test executable binary
    921     var test_exec_args: std.ArrayListUnmanaged(?[]const u8) = .empty;
    922 
    923     // These get set by CLI flags and then snapshotted when a `-M` flag is
    924     // encountered.
    925     var mod_opts: Package.Module.CreateOptions.Inherited = .{};
    926 
    927     // These get appended to by CLI flags and then slurped when a `-M` flag
    928     // is encountered.
    929     var cssan: ClangSearchSanitizer = .{};
    930     var cc_argv: std.ArrayListUnmanaged([]const u8) = .empty;
    931     var deps: std.ArrayListUnmanaged(CliModule.Dep) = .empty;
    932 
    933     // Contains every module specified via -M. The dependencies are added
    934     // after argument parsing is completed. We use a StringArrayHashMap to make
    935     // error output consistent. "root" is special.
    936     var create_module: CreateModule = .{
    937         // Populated just before the call to `createModule`.
    938         .dirs = undefined,
    939         .object_format = null,
    940         .dynamic_linker = null,
    941         .modules = .{},
    942         .opts = .{
    943             .is_test = switch (arg_mode) {
    944                 .zig_test, .zig_test_obj => true,
    945                 .build, .cc, .cpp, .translate_c, .run => false,
    946             },
    947             // Populated while parsing CLI args.
    948             .output_mode = undefined,
    949             // Populated in the call to `createModule` for the root module.
    950             .resolved_target = undefined,
    951             .have_zcu = false,
    952             // Populated just before the call to `createModule`.
    953             .emit_llvm_ir = undefined,
    954             // Populated just before the call to `createModule`.
    955             .emit_llvm_bc = undefined,
    956             // Populated just before the call to `createModule`.
    957             .emit_bin = undefined,
    958             // Populated just before the call to `createModule`.
    959             .any_c_source_files = undefined,
    960         },
    961         // Populated in the call to `createModule` for the root module.
    962         .resolved_options = undefined,
    963 
    964         .cli_link_inputs = .empty,
    965         .windows_libs = .empty,
    966         .link_inputs = .empty,
    967 
    968         .c_source_files = .{},
    969         .rc_source_files = .{},
    970 
    971         .llvm_m_args = .{},
    972         .sysroot = null,
    973         .lib_directories = .{}, // populated by createModule()
    974         .lib_dir_args = .{}, // populated from CLI arg parsing
    975         .libc_installation = null,
    976         .want_native_include_dirs = false,
    977         .frameworks = .{},
    978         .framework_dirs = .{},
    979         .rpath_list = .{},
    980         .each_lib_rpath = null,
    981         .libc_paths_file = try EnvVar.ZIG_LIBC.get(arena),
    982         .native_system_include_paths = &.{},
    983     };
    984     defer create_module.link_inputs.deinit(gpa);
    985 
    986     // before arg parsing, check for the NO_COLOR and CLICOLOR_FORCE environment variables
    987     // if set, default the color setting to .off or .on, respectively
    988     // explicit --color arguments will still override this setting.
    989     // Disable color on WASI per https://github.com/WebAssembly/WASI/issues/162
    990     var color: Color = if (native_os == .wasi or EnvVar.NO_COLOR.isSet())
    991         .off
    992     else if (EnvVar.CLICOLOR_FORCE.isSet())
    993         .on
    994     else
    995         .auto;
    996     var n_jobs: ?u32 = null;
    997 
    998     switch (arg_mode) {
    999         .build, .translate_c, .zig_test, .zig_test_obj, .run => {
   1000             switch (arg_mode) {
   1001                 .build => |m| {
   1002                     create_module.opts.output_mode = m;
   1003                 },
   1004                 .translate_c => {
   1005                     emit_bin = .no;
   1006                     create_module.opts.output_mode = .Obj;
   1007                 },
   1008                 .zig_test, .run => {
   1009                     create_module.opts.output_mode = .Exe;
   1010                 },
   1011                 .zig_test_obj => {
   1012                     create_module.opts.output_mode = .Obj;
   1013                 },
   1014                 else => unreachable,
   1015             }
   1016 
   1017             soname = .yes_default_value;
   1018 
   1019             var args_iter = ArgsIterator{
   1020                 .args = all_args[2..],
   1021             };
   1022 
   1023             var file_ext: ?Compilation.FileExt = null;
   1024             args_loop: while (args_iter.next()) |arg| {
   1025                 if (mem.cutPrefix(u8, arg, "@")) |resp_file_path| {
   1026                     // This is a "compiler response file". We must parse the file and treat its
   1027                     // contents as command line parameters.
   1028                     args_iter.resp_file = initArgIteratorResponseFile(arena, resp_file_path) catch |err| {
   1029                         fatal("unable to read response file '{s}': {s}", .{ resp_file_path, @errorName(err) });
   1030                     };
   1031                 } else if (mem.startsWith(u8, arg, "-")) {
   1032                     if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
   1033                         try fs.File.stdout().writeAll(usage_build_generic);
   1034                         return cleanExit();
   1035                     } else if (mem.eql(u8, arg, "--")) {
   1036                         if (arg_mode == .run) {
   1037                             // args_iter.i is 1, referring the next arg after "--" in ["--", ...]
   1038                             // Add +2 to the index so it is relative to all_args
   1039                             runtime_args_start = args_iter.i + 2;
   1040                             break :args_loop;
   1041                         } else {
   1042                             fatal("unexpected end-of-parameter mark: --", .{});
   1043                         }
   1044                     } else if (mem.eql(u8, arg, "--dep")) {
   1045                         const next_arg = args_iter.nextOrFatal();
   1046                         const key, const value = mem.cutScalar(u8, next_arg, '=') orelse .{ next_arg, next_arg };
   1047                         if (mem.eql(u8, key, "std") and !mem.eql(u8, value, "std")) {
   1048                             fatal("unable to import as '{s}': conflicts with builtin module", .{
   1049                                 key,
   1050                             });
   1051                         }
   1052                         for ([_][]const u8{ "root", "builtin" }) |name| {
   1053                             if (mem.eql(u8, key, name)) {
   1054                                 fatal("unable to import as '{s}': conflicts with builtin module", .{
   1055                                     key,
   1056                                 });
   1057                             }
   1058                         }
   1059                         try deps.append(arena, .{
   1060                             .key = key,
   1061                             .value = value,
   1062                         });
   1063                     } else if (mem.cutPrefix(u8, arg, "-M")) |rest| {
   1064                         const mod_name, const root_src_orig = mem.cutScalar(u8, rest, '=') orelse .{ rest, null };
   1065                         try handleModArg(
   1066                             arena,
   1067                             mod_name,
   1068                             root_src_orig,
   1069                             &create_module,
   1070                             &mod_opts,
   1071                             &cc_argv,
   1072                             &target_arch_os_abi,
   1073                             &target_mcpu,
   1074                             &deps,
   1075                             &c_source_files_owner_index,
   1076                             &rc_source_files_owner_index,
   1077                             &cssan,
   1078                         );
   1079                     } else if (mem.eql(u8, arg, "--error-limit")) {
   1080                         const next_arg = args_iter.nextOrFatal();
   1081                         error_limit = std.fmt.parseUnsigned(Zcu.ErrorInt, next_arg, 0) catch |err| {
   1082                             fatal("unable to parse error limit '{s}': {s}", .{ next_arg, @errorName(err) });
   1083                         };
   1084                     } else if (mem.eql(u8, arg, "-cflags")) {
   1085                         extra_cflags.shrinkRetainingCapacity(0);
   1086                         while (true) {
   1087                             const next_arg = args_iter.next() orelse {
   1088                                 fatal("expected -- after -cflags", .{});
   1089                             };
   1090                             if (mem.eql(u8, next_arg, "--")) break;
   1091                             try extra_cflags.append(arena, next_arg);
   1092                         }
   1093                     } else if (mem.eql(u8, arg, "-rcincludes")) {
   1094                         rc_includes = parseRcIncludes(args_iter.nextOrFatal());
   1095                     } else if (mem.cutPrefix(u8, arg, "-rcincludes=")) |rest| {
   1096                         rc_includes = parseRcIncludes(rest);
   1097                     } else if (mem.eql(u8, arg, "-rcflags")) {
   1098                         extra_rcflags.shrinkRetainingCapacity(0);
   1099                         while (true) {
   1100                             const next_arg = args_iter.next() orelse {
   1101                                 fatal("expected -- after -rcflags", .{});
   1102                             };
   1103                             if (mem.eql(u8, next_arg, "--")) break;
   1104                             try extra_rcflags.append(arena, next_arg);
   1105                         }
   1106                     } else if (mem.eql(u8, arg, "-fstructured-cfg")) {
   1107                         mod_opts.structured_cfg = true;
   1108                     } else if (mem.eql(u8, arg, "-fno-structured-cfg")) {
   1109                         mod_opts.structured_cfg = false;
   1110                     } else if (mem.eql(u8, arg, "--color")) {
   1111                         const next_arg = args_iter.next() orelse {
   1112                             fatal("expected [auto|on|off] after --color", .{});
   1113                         };
   1114                         color = std.meta.stringToEnum(Color, next_arg) orelse {
   1115                             fatal("expected [auto|on|off] after --color, found '{s}'", .{next_arg});
   1116                         };
   1117                     } else if (mem.cutPrefix(u8, arg, "-j")) |str| {
   1118                         const num = std.fmt.parseUnsigned(u32, str, 10) catch |err| {
   1119                             fatal("unable to parse jobs count '{s}': {s}", .{
   1120                                 str, @errorName(err),
   1121                             });
   1122                         };
   1123                         if (num < 1) {
   1124                             fatal("number of jobs must be at least 1\n", .{});
   1125                         }
   1126                         n_jobs = num;
   1127                     } else if (mem.eql(u8, arg, "--subsystem")) {
   1128                         subsystem = try parseSubSystem(args_iter.nextOrFatal());
   1129                     } else if (mem.eql(u8, arg, "-O")) {
   1130                         mod_opts.optimize_mode = parseOptimizeMode(args_iter.nextOrFatal());
   1131                     } else if (mem.cutPrefix(u8, arg, "-fentry=")) |rest| {
   1132                         entry = .{ .named = rest };
   1133                     } else if (mem.eql(u8, arg, "--force_undefined")) {
   1134                         try force_undefined_symbols.put(arena, args_iter.nextOrFatal(), {});
   1135                     } else if (mem.eql(u8, arg, "--discard-all")) {
   1136                         discard_local_symbols = true;
   1137                     } else if (mem.eql(u8, arg, "--stack")) {
   1138                         stack_size = parseStackSize(args_iter.nextOrFatal());
   1139                     } else if (mem.eql(u8, arg, "--image-base")) {
   1140                         image_base = parseImageBase(args_iter.nextOrFatal());
   1141                     } else if (mem.eql(u8, arg, "--name")) {
   1142                         provided_name = args_iter.nextOrFatal();
   1143                         if (!mem.eql(u8, provided_name.?, fs.path.basename(provided_name.?)))
   1144                             fatal("invalid package name '{s}': cannot contain folder separators", .{provided_name.?});
   1145                     } else if (mem.eql(u8, arg, "-rpath")) {
   1146                         try create_module.rpath_list.append(arena, args_iter.nextOrFatal());
   1147                     } else if (mem.eql(u8, arg, "--library-directory") or mem.eql(u8, arg, "-L")) {
   1148                         try create_module.lib_dir_args.append(arena, args_iter.nextOrFatal());
   1149                     } else if (mem.eql(u8, arg, "-F")) {
   1150                         try create_module.framework_dirs.append(arena, args_iter.nextOrFatal());
   1151                     } else if (mem.eql(u8, arg, "-framework")) {
   1152                         try create_module.frameworks.put(arena, args_iter.nextOrFatal(), .{});
   1153                     } else if (mem.eql(u8, arg, "-weak_framework")) {
   1154                         try create_module.frameworks.put(arena, args_iter.nextOrFatal(), .{ .weak = true });
   1155                     } else if (mem.eql(u8, arg, "-needed_framework")) {
   1156                         try create_module.frameworks.put(arena, args_iter.nextOrFatal(), .{ .needed = true });
   1157                     } else if (mem.eql(u8, arg, "-install_name")) {
   1158                         install_name = args_iter.nextOrFatal();
   1159                     } else if (mem.cutPrefix(u8, arg, "--compress-debug-sections=")) |param| {
   1160                         linker_compress_debug_sections = std.meta.stringToEnum(link.File.Lld.Elf.CompressDebugSections, param) orelse {
   1161                             fatal("expected --compress-debug-sections=[none|zlib|zstd], found '{s}'", .{param});
   1162                         };
   1163                     } else if (mem.eql(u8, arg, "--compress-debug-sections")) {
   1164                         linker_compress_debug_sections = link.File.Lld.Elf.CompressDebugSections.zlib;
   1165                     } else if (mem.eql(u8, arg, "-pagezero_size")) {
   1166                         const next_arg = args_iter.nextOrFatal();
   1167                         pagezero_size = std.fmt.parseUnsigned(u64, eatIntPrefix(next_arg, 16), 16) catch |err| {
   1168                             fatal("unable to parse pagezero size'{s}': {s}", .{ next_arg, @errorName(err) });
   1169                         };
   1170                     } else if (mem.eql(u8, arg, "-search_paths_first")) {
   1171                         lib_search_strategy = .paths_first;
   1172                         lib_preferred_mode = .dynamic;
   1173                     } else if (mem.eql(u8, arg, "-search_paths_first_static")) {
   1174                         lib_search_strategy = .paths_first;
   1175                         lib_preferred_mode = .static;
   1176                     } else if (mem.eql(u8, arg, "-search_dylibs_first")) {
   1177                         lib_search_strategy = .mode_first;
   1178                         lib_preferred_mode = .dynamic;
   1179                     } else if (mem.eql(u8, arg, "-search_static_first")) {
   1180                         lib_search_strategy = .mode_first;
   1181                         lib_preferred_mode = .static;
   1182                     } else if (mem.eql(u8, arg, "-search_dylibs_only")) {
   1183                         lib_search_strategy = .no_fallback;
   1184                         lib_preferred_mode = .dynamic;
   1185                     } else if (mem.eql(u8, arg, "-search_static_only")) {
   1186                         lib_search_strategy = .no_fallback;
   1187                         lib_preferred_mode = .static;
   1188                     } else if (mem.eql(u8, arg, "-headerpad")) {
   1189                         const next_arg = args_iter.nextOrFatal();
   1190                         headerpad_size = std.fmt.parseUnsigned(u32, eatIntPrefix(next_arg, 16), 16) catch |err| {
   1191                             fatal("unable to parse headerpad size '{s}': {s}", .{ next_arg, @errorName(err) });
   1192                         };
   1193                     } else if (mem.eql(u8, arg, "-headerpad_max_install_names")) {
   1194                         headerpad_max_install_names = true;
   1195                     } else if (mem.eql(u8, arg, "-dead_strip")) {
   1196                         linker_gc_sections = true;
   1197                     } else if (mem.eql(u8, arg, "-dead_strip_dylibs")) {
   1198                         dead_strip_dylibs = true;
   1199                     } else if (mem.eql(u8, arg, "-ObjC")) {
   1200                         force_load_objc = true;
   1201                     } else if (mem.eql(u8, arg, "-T") or mem.eql(u8, arg, "--script")) {
   1202                         linker_script = args_iter.nextOrFatal();
   1203                     } else if (mem.eql(u8, arg, "-version-script") or mem.eql(u8, arg, "--version-script")) {
   1204                         version_script = args_iter.nextOrFatal();
   1205                     } else if (mem.eql(u8, arg, "--undefined-version")) {
   1206                         linker_allow_undefined_version = true;
   1207                     } else if (mem.eql(u8, arg, "--no-undefined-version")) {
   1208                         linker_allow_undefined_version = false;
   1209                     } else if (mem.eql(u8, arg, "--enable-new-dtags")) {
   1210                         linker_enable_new_dtags = true;
   1211                     } else if (mem.eql(u8, arg, "--disable-new-dtags")) {
   1212                         linker_enable_new_dtags = false;
   1213                     } else if (mem.eql(u8, arg, "--library") or mem.eql(u8, arg, "-l")) {
   1214                         // We don't know whether this library is part of libc
   1215                         // or libc++ until we resolve the target, so we append
   1216                         // to the list for now.
   1217                         try create_module.cli_link_inputs.append(arena, .{ .name_query = .{
   1218                             .name = args_iter.nextOrFatal(),
   1219                             .query = .{
   1220                                 .needed = false,
   1221                                 .weak = false,
   1222                                 .preferred_mode = lib_preferred_mode,
   1223                                 .search_strategy = lib_search_strategy,
   1224                                 .allow_so_scripts = allow_so_scripts,
   1225                             },
   1226                         } });
   1227                     } else if (mem.eql(u8, arg, "--needed-library") or
   1228                         mem.eql(u8, arg, "-needed-l") or
   1229                         mem.eql(u8, arg, "-needed_library"))
   1230                     {
   1231                         const next_arg = args_iter.nextOrFatal();
   1232                         try create_module.cli_link_inputs.append(arena, .{ .name_query = .{
   1233                             .name = next_arg,
   1234                             .query = .{
   1235                                 .needed = true,
   1236                                 .weak = false,
   1237                                 .preferred_mode = lib_preferred_mode,
   1238                                 .search_strategy = lib_search_strategy,
   1239                                 .allow_so_scripts = allow_so_scripts,
   1240                             },
   1241                         } });
   1242                     } else if (mem.eql(u8, arg, "-weak_library") or mem.eql(u8, arg, "-weak-l")) {
   1243                         try create_module.cli_link_inputs.append(arena, .{ .name_query = .{
   1244                             .name = args_iter.nextOrFatal(),
   1245                             .query = .{
   1246                                 .needed = false,
   1247                                 .weak = true,
   1248                                 .preferred_mode = lib_preferred_mode,
   1249                                 .search_strategy = lib_search_strategy,
   1250                                 .allow_so_scripts = allow_so_scripts,
   1251                             },
   1252                         } });
   1253                     } else if (mem.eql(u8, arg, "-D")) {
   1254                         try cc_argv.appendSlice(arena, &.{ arg, args_iter.nextOrFatal() });
   1255                     } else if (mem.eql(u8, arg, "-I")) {
   1256                         try cssan.addIncludePath(arena, &cc_argv, .I, arg, args_iter.nextOrFatal(), false);
   1257                     } else if (mem.cutPrefix(u8, arg, "--embed-dir=")) |rest| {
   1258                         try cssan.addIncludePath(arena, &cc_argv, .embed_dir, arg, rest, true);
   1259                     } else if (mem.eql(u8, arg, "-isystem")) {
   1260                         try cssan.addIncludePath(arena, &cc_argv, .isystem, arg, args_iter.nextOrFatal(), false);
   1261                     } else if (mem.eql(u8, arg, "-iwithsysroot")) {
   1262                         try cssan.addIncludePath(arena, &cc_argv, .iwithsysroot, arg, args_iter.nextOrFatal(), false);
   1263                     } else if (mem.eql(u8, arg, "-idirafter")) {
   1264                         try cssan.addIncludePath(arena, &cc_argv, .idirafter, arg, args_iter.nextOrFatal(), false);
   1265                     } else if (mem.eql(u8, arg, "-iframework")) {
   1266                         const path = args_iter.nextOrFatal();
   1267                         try cssan.addIncludePath(arena, &cc_argv, .iframework, arg, path, false);
   1268                         try create_module.framework_dirs.append(arena, path); // Forward to the backend as -F
   1269                     } else if (mem.eql(u8, arg, "-iframeworkwithsysroot")) {
   1270                         const path = args_iter.nextOrFatal();
   1271                         try cssan.addIncludePath(arena, &cc_argv, .iframeworkwithsysroot, arg, path, false);
   1272                         try create_module.framework_dirs.append(arena, path); // Forward to the backend as -F
   1273                     } else if (mem.eql(u8, arg, "--version")) {
   1274                         const next_arg = args_iter.nextOrFatal();
   1275                         version = std.SemanticVersion.parse(next_arg) catch |err| {
   1276                             fatal("unable to parse --version '{s}': {s}", .{ next_arg, @errorName(err) });
   1277                         };
   1278                         have_version = true;
   1279                     } else if (mem.eql(u8, arg, "-target")) {
   1280                         target_arch_os_abi = args_iter.nextOrFatal();
   1281                     } else if (mem.eql(u8, arg, "-mcpu")) {
   1282                         target_mcpu = args_iter.nextOrFatal();
   1283                     } else if (mem.eql(u8, arg, "-mcmodel")) {
   1284                         mod_opts.code_model = parseCodeModel(args_iter.nextOrFatal());
   1285                     } else if (mem.cutPrefix(u8, arg, "-mcmodel=")) |rest| {
   1286                         mod_opts.code_model = parseCodeModel(rest);
   1287                     } else if (mem.cutPrefix(u8, arg, "-ofmt=")) |rest| {
   1288                         create_module.object_format = rest;
   1289                     } else if (mem.cutPrefix(u8, arg, "-mcpu=")) |rest| {
   1290                         target_mcpu = rest;
   1291                     } else if (mem.cutPrefix(u8, arg, "-O")) |rest| {
   1292                         mod_opts.optimize_mode = parseOptimizeMode(rest);
   1293                     } else if (mem.eql(u8, arg, "--dynamic-linker")) {
   1294                         create_module.dynamic_linker = args_iter.nextOrFatal();
   1295                     } else if (mem.eql(u8, arg, "--sysroot")) {
   1296                         const next_arg = args_iter.nextOrFatal();
   1297                         create_module.sysroot = next_arg;
   1298                         try cc_argv.appendSlice(arena, &.{ "-isysroot", next_arg });
   1299                     } else if (mem.eql(u8, arg, "--libc")) {
   1300                         create_module.libc_paths_file = args_iter.nextOrFatal();
   1301                     } else if (mem.eql(u8, arg, "--test-filter")) {
   1302                         try test_filters.append(arena, args_iter.nextOrFatal());
   1303                     } else if (mem.eql(u8, arg, "--test-runner")) {
   1304                         test_runner_path = args_iter.nextOrFatal();
   1305                     } else if (mem.eql(u8, arg, "--test-cmd")) {
   1306                         try test_exec_args.append(arena, args_iter.nextOrFatal());
   1307                     } else if (mem.eql(u8, arg, "--cache-dir")) {
   1308                         override_local_cache_dir = args_iter.nextOrFatal();
   1309                     } else if (mem.eql(u8, arg, "--global-cache-dir")) {
   1310                         override_global_cache_dir = args_iter.nextOrFatal();
   1311                     } else if (mem.eql(u8, arg, "--zig-lib-dir")) {
   1312                         override_lib_dir = args_iter.nextOrFatal();
   1313                     } else if (mem.eql(u8, arg, "--debug-log")) {
   1314                         if (!build_options.enable_logging) {
   1315                             warn("Zig was compiled without logging enabled (-Dlog). --debug-log has no effect.", .{});
   1316                             _ = args_iter.nextOrFatal();
   1317                         } else {
   1318                             try log_scopes.append(arena, args_iter.nextOrFatal());
   1319                         }
   1320                     } else if (mem.eql(u8, arg, "--listen")) {
   1321                         const next_arg = args_iter.nextOrFatal();
   1322                         if (mem.eql(u8, next_arg, "-")) {
   1323                             dev.check(.stdio_listen);
   1324                             listen = .stdio;
   1325                         } else {
   1326                             dev.check(.network_listen);
   1327                             // example: --listen 127.0.0.1:9000
   1328                             const host, const port_text = mem.cutScalar(u8, next_arg, ':') orelse .{ next_arg, "14735" };
   1329                             const port = std.fmt.parseInt(u16, port_text, 10) catch |err|
   1330                                 fatal("invalid port number: '{s}': {s}", .{ port_text, @errorName(err) });
   1331                             listen = .{ .ip4 = std.net.Ip4Address.parse(host, port) catch |err|
   1332                                 fatal("invalid host: '{s}': {s}", .{ host, @errorName(err) }) };
   1333                         }
   1334                     } else if (mem.eql(u8, arg, "--listen=-")) {
   1335                         dev.check(.stdio_listen);
   1336                         listen = .stdio;
   1337                     } else if (mem.eql(u8, arg, "--debug-link-snapshot")) {
   1338                         if (!build_options.enable_link_snapshots) {
   1339                             warn("Zig was compiled without linker snapshots enabled (-Dlink-snapshot). --debug-link-snapshot has no effect.", .{});
   1340                         } else {
   1341                             enable_link_snapshots = true;
   1342                         }
   1343                     } else if (mem.eql(u8, arg, "--debug-rt")) {
   1344                         debug_compiler_runtime_libs = true;
   1345                     } else if (mem.eql(u8, arg, "--debug-incremental")) {
   1346                         if (build_options.enable_debug_extensions) {
   1347                             debug_incremental = true;
   1348                         } else {
   1349                             warn("Zig was compiled without debug extensions. --debug-incremental has no effect.", .{});
   1350                         }
   1351                     } else if (mem.eql(u8, arg, "-fincremental")) {
   1352                         dev.check(.incremental);
   1353                         create_module.opts.incremental = true;
   1354                     } else if (mem.eql(u8, arg, "-fno-incremental")) {
   1355                         create_module.opts.incremental = false;
   1356                     } else if (mem.eql(u8, arg, "--entitlements")) {
   1357                         entitlements = args_iter.nextOrFatal();
   1358                     } else if (mem.eql(u8, arg, "-fcompiler-rt")) {
   1359                         want_compiler_rt = true;
   1360                     } else if (mem.eql(u8, arg, "-fno-compiler-rt")) {
   1361                         want_compiler_rt = false;
   1362                     } else if (mem.eql(u8, arg, "-fubsan-rt")) {
   1363                         want_ubsan_rt = true;
   1364                     } else if (mem.eql(u8, arg, "-fno-ubsan-rt")) {
   1365                         want_ubsan_rt = false;
   1366                     } else if (mem.eql(u8, arg, "-feach-lib-rpath")) {
   1367                         create_module.each_lib_rpath = true;
   1368                     } else if (mem.eql(u8, arg, "-fno-each-lib-rpath")) {
   1369                         create_module.each_lib_rpath = false;
   1370                     } else if (mem.eql(u8, arg, "--test-cmd-bin")) {
   1371                         try test_exec_args.append(arena, null);
   1372                     } else if (mem.eql(u8, arg, "--test-no-exec")) {
   1373                         test_no_exec = true;
   1374                     } else if (mem.eql(u8, arg, "--time-report")) {
   1375                         time_report = true;
   1376                     } else if (mem.eql(u8, arg, "-fstack-report")) {
   1377                         stack_report = true;
   1378                     } else if (mem.eql(u8, arg, "-fPIC")) {
   1379                         mod_opts.pic = true;
   1380                     } else if (mem.eql(u8, arg, "-fno-PIC")) {
   1381                         mod_opts.pic = false;
   1382                     } else if (mem.eql(u8, arg, "-fPIE")) {
   1383                         create_module.opts.pie = true;
   1384                     } else if (mem.eql(u8, arg, "-fno-PIE")) {
   1385                         create_module.opts.pie = false;
   1386                     } else if (mem.eql(u8, arg, "-flto")) {
   1387                         create_module.opts.lto = .full;
   1388                     } else if (mem.cutPrefix(u8, arg, "-flto=")) |mode| {
   1389                         if (mem.eql(u8, mode, "full")) {
   1390                             create_module.opts.lto = .full;
   1391                         } else if (mem.eql(u8, mode, "thin")) {
   1392                             create_module.opts.lto = .thin;
   1393                         } else {
   1394                             fatal("Invalid -flto mode: '{s}'. Must be 'full'or 'thin'.", .{mode});
   1395                         }
   1396                     } else if (mem.eql(u8, arg, "-fno-lto")) {
   1397                         create_module.opts.lto = .none;
   1398                     } else if (mem.eql(u8, arg, "-funwind-tables")) {
   1399                         mod_opts.unwind_tables = .sync;
   1400                     } else if (mem.eql(u8, arg, "-fasync-unwind-tables")) {
   1401                         mod_opts.unwind_tables = .async;
   1402                     } else if (mem.eql(u8, arg, "-fno-unwind-tables")) {
   1403                         mod_opts.unwind_tables = .none;
   1404                     } else if (mem.eql(u8, arg, "-fstack-check")) {
   1405                         mod_opts.stack_check = true;
   1406                     } else if (mem.eql(u8, arg, "-fno-stack-check")) {
   1407                         mod_opts.stack_check = false;
   1408                     } else if (mem.eql(u8, arg, "-fstack-protector")) {
   1409                         mod_opts.stack_protector = Compilation.default_stack_protector_buffer_size;
   1410                     } else if (mem.eql(u8, arg, "-fno-stack-protector")) {
   1411                         mod_opts.stack_protector = 0;
   1412                     } else if (mem.eql(u8, arg, "-mred-zone")) {
   1413                         mod_opts.red_zone = true;
   1414                     } else if (mem.eql(u8, arg, "-mno-red-zone")) {
   1415                         mod_opts.red_zone = false;
   1416                     } else if (mem.eql(u8, arg, "-fomit-frame-pointer")) {
   1417                         mod_opts.omit_frame_pointer = true;
   1418                     } else if (mem.eql(u8, arg, "-fno-omit-frame-pointer")) {
   1419                         mod_opts.omit_frame_pointer = false;
   1420                     } else if (mem.eql(u8, arg, "-fsanitize-c")) {
   1421                         mod_opts.sanitize_c = .full;
   1422                     } else if (mem.cutPrefix(u8, arg, "-fsanitize-c=")) |mode| {
   1423                         if (mem.eql(u8, mode, "trap")) {
   1424                             mod_opts.sanitize_c = .trap;
   1425                         } else if (mem.eql(u8, mode, "full")) {
   1426                             mod_opts.sanitize_c = .full;
   1427                         } else {
   1428                             fatal("Invalid -fsanitize-c mode: '{s}'. Must be 'trap' or 'full'.", .{mode});
   1429                         }
   1430                     } else if (mem.eql(u8, arg, "-fno-sanitize-c")) {
   1431                         mod_opts.sanitize_c = .off;
   1432                     } else if (mem.eql(u8, arg, "-fvalgrind")) {
   1433                         mod_opts.valgrind = true;
   1434                     } else if (mem.eql(u8, arg, "-fno-valgrind")) {
   1435                         mod_opts.valgrind = false;
   1436                     } else if (mem.eql(u8, arg, "-fsanitize-thread")) {
   1437                         mod_opts.sanitize_thread = true;
   1438                     } else if (mem.eql(u8, arg, "-fno-sanitize-thread")) {
   1439                         mod_opts.sanitize_thread = false;
   1440                     } else if (mem.eql(u8, arg, "-ffuzz")) {
   1441                         mod_opts.fuzz = true;
   1442                     } else if (mem.eql(u8, arg, "-fno-fuzz")) {
   1443                         mod_opts.fuzz = false;
   1444                     } else if (mem.eql(u8, arg, "-fllvm")) {
   1445                         create_module.opts.use_llvm = true;
   1446                     } else if (mem.eql(u8, arg, "-fno-llvm")) {
   1447                         create_module.opts.use_llvm = false;
   1448                     } else if (mem.eql(u8, arg, "-flibllvm")) {
   1449                         create_module.opts.use_lib_llvm = true;
   1450                     } else if (mem.eql(u8, arg, "-fno-libllvm")) {
   1451                         create_module.opts.use_lib_llvm = false;
   1452                     } else if (mem.eql(u8, arg, "-flld")) {
   1453                         create_module.opts.use_lld = true;
   1454                     } else if (mem.eql(u8, arg, "-fno-lld")) {
   1455                         create_module.opts.use_lld = false;
   1456                     } else if (mem.eql(u8, arg, "-fnew-linker")) {
   1457                         create_module.opts.use_new_linker = true;
   1458                     } else if (mem.eql(u8, arg, "-fno-new-linker")) {
   1459                         create_module.opts.use_new_linker = false;
   1460                     } else if (mem.eql(u8, arg, "-fclang")) {
   1461                         create_module.opts.use_clang = true;
   1462                     } else if (mem.eql(u8, arg, "-fno-clang")) {
   1463                         create_module.opts.use_clang = false;
   1464                     } else if (mem.eql(u8, arg, "-fsanitize-coverage-trace-pc-guard")) {
   1465                         create_module.opts.san_cov_trace_pc_guard = true;
   1466                     } else if (mem.eql(u8, arg, "-fno-sanitize-coverage-trace-pc-guard")) {
   1467                         create_module.opts.san_cov_trace_pc_guard = false;
   1468                     } else if (mem.eql(u8, arg, "-freference-trace")) {
   1469                         reference_trace = 256;
   1470                     } else if (mem.cutPrefix(u8, arg, "-freference-trace=")) |num| {
   1471                         reference_trace = std.fmt.parseUnsigned(u32, num, 10) catch |err| {
   1472                             fatal("unable to parse reference_trace count '{s}': {s}", .{ num, @errorName(err) });
   1473                         };
   1474                     } else if (mem.eql(u8, arg, "-fno-reference-trace")) {
   1475                         reference_trace = null;
   1476                     } else if (mem.eql(u8, arg, "-ferror-tracing")) {
   1477                         mod_opts.error_tracing = true;
   1478                     } else if (mem.eql(u8, arg, "-fno-error-tracing")) {
   1479                         mod_opts.error_tracing = false;
   1480                     } else if (mem.eql(u8, arg, "-rdynamic")) {
   1481                         create_module.opts.rdynamic = true;
   1482                     } else if (mem.eql(u8, arg, "-fsoname")) {
   1483                         soname = .yes_default_value;
   1484                     } else if (mem.cutPrefix(u8, arg, "-fsoname=")) |rest| {
   1485                         soname = .{ .yes = rest };
   1486                     } else if (mem.eql(u8, arg, "-fno-soname")) {
   1487                         soname = .no;
   1488                     } else if (mem.eql(u8, arg, "-femit-bin")) {
   1489                         emit_bin = .yes_default_path;
   1490                     } else if (mem.cutPrefix(u8, arg, "-femit-bin=")) |rest| {
   1491                         emit_bin = .{ .yes = rest };
   1492                     } else if (mem.eql(u8, arg, "-fno-emit-bin")) {
   1493                         emit_bin = .no;
   1494                     } else if (mem.eql(u8, arg, "-femit-h")) {
   1495                         emit_h = .yes_default_path;
   1496                     } else if (mem.cutPrefix(u8, arg, "-femit-h=")) |rest| {
   1497                         emit_h = .{ .yes = rest };
   1498                     } else if (mem.eql(u8, arg, "-fno-emit-h")) {
   1499                         emit_h = .no;
   1500                     } else if (mem.eql(u8, arg, "-femit-asm")) {
   1501                         emit_asm = .yes_default_path;
   1502                     } else if (mem.cutPrefix(u8, arg, "-femit-asm=")) |rest| {
   1503                         emit_asm = .{ .yes = rest };
   1504                     } else if (mem.eql(u8, arg, "-fno-emit-asm")) {
   1505                         emit_asm = .no;
   1506                     } else if (mem.eql(u8, arg, "-femit-llvm-ir")) {
   1507                         emit_llvm_ir = .yes_default_path;
   1508                     } else if (mem.cutPrefix(u8, arg, "-femit-llvm-ir=")) |rest| {
   1509                         emit_llvm_ir = .{ .yes = rest };
   1510                     } else if (mem.eql(u8, arg, "-fno-emit-llvm-ir")) {
   1511                         emit_llvm_ir = .no;
   1512                     } else if (mem.eql(u8, arg, "-femit-llvm-bc")) {
   1513                         emit_llvm_bc = .yes_default_path;
   1514                     } else if (mem.cutPrefix(u8, arg, "-femit-llvm-bc=")) |rest| {
   1515                         emit_llvm_bc = .{ .yes = rest };
   1516                     } else if (mem.eql(u8, arg, "-fno-emit-llvm-bc")) {
   1517                         emit_llvm_bc = .no;
   1518                     } else if (mem.eql(u8, arg, "-femit-docs")) {
   1519                         emit_docs = .yes_default_path;
   1520                     } else if (mem.cutPrefix(u8, arg, "-femit-docs=")) |rest| {
   1521                         emit_docs = .{ .yes = rest };
   1522                     } else if (mem.eql(u8, arg, "-fno-emit-docs")) {
   1523                         emit_docs = .no;
   1524                     } else if (mem.eql(u8, arg, "-femit-implib")) {
   1525                         emit_implib = .yes_default_path;
   1526                         emit_implib_arg_provided = true;
   1527                     } else if (mem.cutPrefix(u8, arg, "-femit-implib=")) |rest| {
   1528                         emit_implib = .{ .yes = rest };
   1529                         emit_implib_arg_provided = true;
   1530                     } else if (mem.eql(u8, arg, "-fno-emit-implib")) {
   1531                         emit_implib = .no;
   1532                         emit_implib_arg_provided = true;
   1533                     } else if (mem.eql(u8, arg, "-dynamic")) {
   1534                         create_module.opts.link_mode = .dynamic;
   1535                         lib_preferred_mode = .dynamic;
   1536                         lib_search_strategy = .mode_first;
   1537                     } else if (mem.eql(u8, arg, "-static")) {
   1538                         create_module.opts.link_mode = .static;
   1539                         lib_preferred_mode = .static;
   1540                         lib_search_strategy = .no_fallback;
   1541                     } else if (mem.eql(u8, arg, "-fdll-export-fns")) {
   1542                         create_module.opts.dll_export_fns = true;
   1543                     } else if (mem.eql(u8, arg, "-fno-dll-export-fns")) {
   1544                         create_module.opts.dll_export_fns = false;
   1545                     } else if (mem.eql(u8, arg, "--show-builtin")) {
   1546                         show_builtin = true;
   1547                         emit_bin = .no;
   1548                     } else if (mem.eql(u8, arg, "-fstrip")) {
   1549                         mod_opts.strip = true;
   1550                     } else if (mem.eql(u8, arg, "-fno-strip")) {
   1551                         mod_opts.strip = false;
   1552                     } else if (mem.eql(u8, arg, "-gdwarf32")) {
   1553                         create_module.opts.debug_format = .{ .dwarf = .@"32" };
   1554                     } else if (mem.eql(u8, arg, "-gdwarf64")) {
   1555                         create_module.opts.debug_format = .{ .dwarf = .@"64" };
   1556                     } else if (mem.eql(u8, arg, "-fformatted-panics")) {
   1557                         // Remove this after 0.15.0 is tagged.
   1558                         warn("-fformatted-panics is deprecated and does nothing", .{});
   1559                     } else if (mem.eql(u8, arg, "-fno-formatted-panics")) {
   1560                         // Remove this after 0.15.0 is tagged.
   1561                         warn("-fno-formatted-panics is deprecated and does nothing", .{});
   1562                     } else if (mem.eql(u8, arg, "-fsingle-threaded")) {
   1563                         mod_opts.single_threaded = true;
   1564                     } else if (mem.eql(u8, arg, "-fno-single-threaded")) {
   1565                         mod_opts.single_threaded = false;
   1566                     } else if (mem.eql(u8, arg, "-ffunction-sections")) {
   1567                         function_sections = true;
   1568                     } else if (mem.eql(u8, arg, "-fno-function-sections")) {
   1569                         function_sections = false;
   1570                     } else if (mem.eql(u8, arg, "-fdata-sections")) {
   1571                         data_sections = true;
   1572                     } else if (mem.eql(u8, arg, "-fno-data-sections")) {
   1573                         data_sections = false;
   1574                     } else if (mem.eql(u8, arg, "-fbuiltin")) {
   1575                         mod_opts.no_builtin = false;
   1576                     } else if (mem.eql(u8, arg, "-fno-builtin")) {
   1577                         mod_opts.no_builtin = true;
   1578                     } else if (mem.cutPrefix(u8, arg, "-fopt-bisect-limit=")) |next_arg| {
   1579                         llvm_opt_bisect_limit = std.fmt.parseInt(c_int, next_arg, 0) catch |err|
   1580                             fatal("unable to parse '{s}': {s}", .{ arg, @errorName(err) });
   1581                     } else if (mem.eql(u8, arg, "--eh-frame-hdr")) {
   1582                         link_eh_frame_hdr = true;
   1583                     } else if (mem.eql(u8, arg, "--no-eh-frame-hdr")) {
   1584                         link_eh_frame_hdr = false;
   1585                     } else if (mem.eql(u8, arg, "--dynamicbase")) {
   1586                         linker_dynamicbase = true;
   1587                     } else if (mem.eql(u8, arg, "--no-dynamicbase")) {
   1588                         linker_dynamicbase = false;
   1589                     } else if (mem.eql(u8, arg, "--emit-relocs")) {
   1590                         link_emit_relocs = true;
   1591                     } else if (mem.eql(u8, arg, "-fallow-shlib-undefined")) {
   1592                         linker_allow_shlib_undefined = true;
   1593                     } else if (mem.eql(u8, arg, "-fno-allow-shlib-undefined")) {
   1594                         linker_allow_shlib_undefined = false;
   1595                     } else if (mem.eql(u8, arg, "-fallow-so-scripts")) {
   1596                         allow_so_scripts = true;
   1597                     } else if (mem.eql(u8, arg, "-fno-allow-so-scripts")) {
   1598                         allow_so_scripts = false;
   1599                     } else if (mem.eql(u8, arg, "-z")) {
   1600                         const z_arg = args_iter.nextOrFatal();
   1601                         if (mem.eql(u8, z_arg, "nodelete")) {
   1602                             linker_z_nodelete = true;
   1603                         } else if (mem.eql(u8, z_arg, "notext")) {
   1604                             linker_z_notext = true;
   1605                         } else if (mem.eql(u8, z_arg, "defs")) {
   1606                             linker_z_defs = true;
   1607                         } else if (mem.eql(u8, z_arg, "undefs")) {
   1608                             linker_z_defs = false;
   1609                         } else if (mem.eql(u8, z_arg, "origin")) {
   1610                             linker_z_origin = true;
   1611                         } else if (mem.eql(u8, z_arg, "nocopyreloc")) {
   1612                             linker_z_nocopyreloc = true;
   1613                         } else if (mem.eql(u8, z_arg, "now")) {
   1614                             linker_z_now = true;
   1615                         } else if (mem.eql(u8, z_arg, "lazy")) {
   1616                             linker_z_now = false;
   1617                         } else if (mem.eql(u8, z_arg, "relro")) {
   1618                             linker_z_relro = true;
   1619                         } else if (mem.eql(u8, z_arg, "norelro")) {
   1620                             linker_z_relro = false;
   1621                         } else if (prefixedIntArg(z_arg, "common-page-size=")) |int| {
   1622                             linker_z_common_page_size = int;
   1623                         } else if (prefixedIntArg(z_arg, "max-page-size=")) |int| {
   1624                             linker_z_max_page_size = int;
   1625                         } else {
   1626                             fatal("unsupported linker extension flag: -z {s}", .{z_arg});
   1627                         }
   1628                     } else if (mem.eql(u8, arg, "--import-memory")) {
   1629                         create_module.opts.import_memory = true;
   1630                     } else if (mem.eql(u8, arg, "-fentry")) {
   1631                         switch (entry) {
   1632                             .default, .disabled => entry = .enabled,
   1633                             .enabled, .named => {},
   1634                         }
   1635                     } else if (mem.eql(u8, arg, "-fno-entry")) {
   1636                         entry = .disabled;
   1637                     } else if (mem.eql(u8, arg, "--export-memory")) {
   1638                         create_module.opts.export_memory = true;
   1639                     } else if (mem.eql(u8, arg, "--import-symbols")) {
   1640                         linker_import_symbols = true;
   1641                     } else if (mem.eql(u8, arg, "--import-table")) {
   1642                         linker_import_table = true;
   1643                     } else if (mem.eql(u8, arg, "--export-table")) {
   1644                         linker_export_table = true;
   1645                     } else if (prefixedIntArg(arg, "--initial-memory=")) |int| {
   1646                         linker_initial_memory = int;
   1647                     } else if (prefixedIntArg(arg, "--max-memory=")) |int| {
   1648                         linker_max_memory = int;
   1649                     } else if (mem.eql(u8, arg, "--shared-memory")) {
   1650                         create_module.opts.shared_memory = true;
   1651                     } else if (prefixedIntArg(arg, "--global-base=")) |int| {
   1652                         linker_global_base = int;
   1653                     } else if (mem.cutPrefix(u8, arg, "--export=")) |rest| {
   1654                         try linker_export_symbol_names.append(arena, rest);
   1655                     } else if (mem.eql(u8, arg, "-Bsymbolic")) {
   1656                         linker_bind_global_refs_locally = true;
   1657                     } else if (mem.eql(u8, arg, "--gc-sections")) {
   1658                         linker_gc_sections = true;
   1659                     } else if (mem.eql(u8, arg, "--no-gc-sections")) {
   1660                         linker_gc_sections = false;
   1661                     } else if (mem.eql(u8, arg, "--build-id")) {
   1662                         build_id = .fast;
   1663                     } else if (mem.cutPrefix(u8, arg, "--build-id=")) |style| {
   1664                         build_id = std.zig.BuildId.parse(style) catch |err| {
   1665                             fatal("unable to parse --build-id style '{s}': {s}", .{
   1666                                 style, @errorName(err),
   1667                             });
   1668                         };
   1669                     } else if (mem.eql(u8, arg, "--debug-compile-errors")) {
   1670                         if (build_options.enable_debug_extensions) {
   1671                             debug_compile_errors = true;
   1672                         } else {
   1673                             warn("Zig was compiled without debug extensions. --debug-compile-errors has no effect.", .{});
   1674                         }
   1675                     } else if (mem.eql(u8, arg, "--verbose-link")) {
   1676                         verbose_link = true;
   1677                     } else if (mem.eql(u8, arg, "--verbose-cc")) {
   1678                         verbose_cc = true;
   1679                     } else if (mem.eql(u8, arg, "--verbose-air")) {
   1680                         verbose_air = true;
   1681                     } else if (mem.eql(u8, arg, "--verbose-intern-pool")) {
   1682                         verbose_intern_pool = true;
   1683                     } else if (mem.eql(u8, arg, "--verbose-generic-instances")) {
   1684                         verbose_generic_instances = true;
   1685                     } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) {
   1686                         verbose_llvm_ir = "-";
   1687                     } else if (mem.cutPrefix(u8, arg, "--verbose-llvm-ir=")) |rest| {
   1688                         verbose_llvm_ir = rest;
   1689                     } else if (mem.cutPrefix(u8, arg, "--verbose-llvm-bc=")) |rest| {
   1690                         verbose_llvm_bc = rest;
   1691                     } else if (mem.eql(u8, arg, "--verbose-cimport")) {
   1692                         verbose_cimport = true;
   1693                     } else if (mem.eql(u8, arg, "--verbose-llvm-cpu-features")) {
   1694                         verbose_llvm_cpu_features = true;
   1695                     } else if (mem.cutPrefix(u8, arg, "-T")) |rest| {
   1696                         linker_script = rest;
   1697                     } else if (mem.cutPrefix(u8, arg, "-L")) |rest| {
   1698                         try create_module.lib_dir_args.append(arena, rest);
   1699                     } else if (mem.cutPrefix(u8, arg, "-F")) |rest| {
   1700                         try create_module.framework_dirs.append(arena, rest);
   1701                     } else if (mem.cutPrefix(u8, arg, "-l")) |name| {
   1702                         // We don't know whether this library is part of libc
   1703                         // or libc++ until we resolve the target, so we append
   1704                         // to the list for now.
   1705                         try create_module.cli_link_inputs.append(arena, .{ .name_query = .{
   1706                             .name = name,
   1707                             .query = .{
   1708                                 .needed = false,
   1709                                 .weak = false,
   1710                                 .preferred_mode = lib_preferred_mode,
   1711                                 .search_strategy = lib_search_strategy,
   1712                                 .allow_so_scripts = allow_so_scripts,
   1713                             },
   1714                         } });
   1715                     } else if (mem.cutPrefix(u8, arg, "-needed-l")) |name| {
   1716                         try create_module.cli_link_inputs.append(arena, .{ .name_query = .{
   1717                             .name = name,
   1718                             .query = .{
   1719                                 .needed = true,
   1720                                 .weak = false,
   1721                                 .preferred_mode = lib_preferred_mode,
   1722                                 .search_strategy = lib_search_strategy,
   1723                                 .allow_so_scripts = allow_so_scripts,
   1724                             },
   1725                         } });
   1726                     } else if (mem.cutPrefix(u8, arg, "-weak-l")) |name| {
   1727                         try create_module.cli_link_inputs.append(arena, .{ .name_query = .{
   1728                             .name = name,
   1729                             .query = .{
   1730                                 .needed = false,
   1731                                 .weak = true,
   1732                                 .preferred_mode = lib_preferred_mode,
   1733                                 .search_strategy = lib_search_strategy,
   1734                                 .allow_so_scripts = allow_so_scripts,
   1735                             },
   1736                         } });
   1737                     } else if (mem.startsWith(u8, arg, "-D")) {
   1738                         try cc_argv.append(arena, arg);
   1739                     } else if (mem.cutPrefix(u8, arg, "-I")) |rest| {
   1740                         try cssan.addIncludePath(arena, &cc_argv, .I, arg, rest, true);
   1741                     } else if (mem.cutPrefix(u8, arg, "-x")) |rest| {
   1742                         const lang = if (rest.len == 0) args_iter.nextOrFatal() else rest;
   1743                         if (mem.eql(u8, lang, "none")) {
   1744                             file_ext = null;
   1745                         } else if (Compilation.LangToExt.get(lang)) |got_ext| {
   1746                             file_ext = got_ext;
   1747                         } else {
   1748                             fatal("language not recognized: '{s}'", .{lang});
   1749                         }
   1750                     } else if (mem.cutPrefix(u8, arg, "-mexec-model=")) |rest| {
   1751                         create_module.opts.wasi_exec_model = parseWasiExecModel(rest);
   1752                     } else if (mem.eql(u8, arg, "-municode")) {
   1753                         mingw_unicode_entry_point = true;
   1754                     } else {
   1755                         fatal("unrecognized parameter: '{s}'", .{arg});
   1756                     }
   1757                 } else switch (file_ext orelse Compilation.classifyFileExt(arg)) {
   1758                     .shared_library, .object, .static_library => {
   1759                         try create_module.cli_link_inputs.append(arena, .{ .path_query = .{
   1760                             .path = Path.initCwd(arg),
   1761                             .query = .{
   1762                                 .preferred_mode = lib_preferred_mode,
   1763                                 .search_strategy = lib_search_strategy,
   1764                                 .allow_so_scripts = allow_so_scripts,
   1765                             },
   1766                         } });
   1767                         // We do not set `any_dyn_libs` yet because a .so file
   1768                         // may actually resolve to a GNU ld script which ends
   1769                         // up being a static library.
   1770                     },
   1771                     .res => {
   1772                         try create_module.cli_link_inputs.append(arena, .{ .path_query = .{
   1773                             .path = Path.initCwd(arg),
   1774                             .query = .{
   1775                                 .preferred_mode = lib_preferred_mode,
   1776                                 .search_strategy = lib_search_strategy,
   1777                                 .allow_so_scripts = allow_so_scripts,
   1778                             },
   1779                         } });
   1780                         contains_res_file = true;
   1781                     },
   1782                     .manifest => {
   1783                         if (manifest_file) |other| {
   1784                             fatal("only one manifest file can be specified, found '{s}' after '{s}'", .{ arg, other });
   1785                         } else manifest_file = arg;
   1786                     },
   1787                     .assembly, .assembly_with_cpp, .c, .cpp, .h, .hpp, .hm, .hmm, .ll, .bc, .m, .mm => {
   1788                         dev.check(.c_compiler);
   1789                         try create_module.c_source_files.append(arena, .{
   1790                             // Populated after module creation.
   1791                             .owner = undefined,
   1792                             .src_path = arg,
   1793                             .extra_flags = try arena.dupe([]const u8, extra_cflags.items),
   1794                             // duped when parsing the args.
   1795                             .ext = file_ext,
   1796                         });
   1797                     },
   1798                     .rc => {
   1799                         dev.check(.win32_resource);
   1800                         try create_module.rc_source_files.append(arena, .{
   1801                             // Populated after module creation.
   1802                             .owner = undefined,
   1803                             .src_path = arg,
   1804                             .extra_flags = try arena.dupe([]const u8, extra_rcflags.items),
   1805                         });
   1806                     },
   1807                     .zig => {
   1808                         if (root_src_file) |other| {
   1809                             fatal("found another zig file '{s}' after root source file '{s}'", .{ arg, other });
   1810                         } else root_src_file = arg;
   1811                     },
   1812                     .def, .unknown => {
   1813                         if (std.ascii.eqlIgnoreCase(".xml", fs.path.extension(arg))) {
   1814                             warn("embedded manifest files must have the extension '.manifest'", .{});
   1815                         }
   1816                         fatal("unrecognized file extension of parameter '{s}'", .{arg});
   1817                     },
   1818                 }
   1819             }
   1820         },
   1821         .cc, .cpp => {
   1822             dev.check(.cc_command);
   1823 
   1824             emit_h = .no;
   1825             soname = .no;
   1826             create_module.opts.ensure_libc_on_non_freestanding = true;
   1827             create_module.opts.ensure_libcpp_on_non_freestanding = arg_mode == .cpp;
   1828             create_module.want_native_include_dirs = true;
   1829             // Clang's driver enables this switch unconditionally.
   1830             // Disabling the emission of .eh_frame_hdr can unexpectedly break
   1831             // some functionality that depend on it, such as C++ exceptions and
   1832             // DWARF-based stack traces.
   1833             link_eh_frame_hdr = true;
   1834             allow_so_scripts = true;
   1835 
   1836             const COutMode = enum {
   1837                 link,
   1838                 object,
   1839                 assembly,
   1840                 preprocessor,
   1841             };
   1842             var c_out_mode: ?COutMode = null;
   1843             var out_path: ?[]const u8 = null;
   1844             var is_shared_lib = false;
   1845             var preprocessor_args = std.array_list.Managed([]const u8).init(arena);
   1846             var linker_args = std.array_list.Managed([]const u8).init(arena);
   1847             var it = ClangArgIterator.init(arena, all_args);
   1848             var emit_llvm = false;
   1849             var needed = false;
   1850             var must_link = false;
   1851             var file_ext: ?Compilation.FileExt = null;
   1852             while (it.has_next) {
   1853                 it.next() catch |err| {
   1854                     fatal("unable to parse command line parameters: {s}", .{@errorName(err)});
   1855                 };
   1856                 switch (it.zig_equivalent) {
   1857                     .target => target_arch_os_abi = it.only_arg, // example: -target riscv64-linux-unknown
   1858                     .o => {
   1859                         // We handle -o /dev/null equivalent to -fno-emit-bin because
   1860                         // otherwise our atomic rename into place will fail. This also
   1861                         // makes Zig do less work, avoiding pointless file system operations.
   1862                         if (mem.eql(u8, it.only_arg, "/dev/null")) {
   1863                             emit_bin = .no;
   1864                         } else {
   1865                             out_path = it.only_arg;
   1866                         }
   1867                     },
   1868                     .c, .r => c_out_mode = .object, // -c or -r
   1869                     .asm_only => c_out_mode = .assembly, // -S
   1870                     .preprocess_only => c_out_mode = .preprocessor, // -E
   1871                     .emit_llvm => emit_llvm = true,
   1872                     .x => {
   1873                         const lang = mem.sliceTo(it.only_arg, 0);
   1874                         if (mem.eql(u8, lang, "none")) {
   1875                             file_ext = null;
   1876                         } else if (Compilation.LangToExt.get(lang)) |got_ext| {
   1877                             file_ext = got_ext;
   1878                         } else {
   1879                             fatal("language not recognized: '{s}'", .{lang});
   1880                         }
   1881                     },
   1882                     .other => {
   1883                         try cc_argv.appendSlice(arena, it.other_args);
   1884                     },
   1885                     .positional => switch (file_ext orelse Compilation.classifyFileExt(mem.sliceTo(it.only_arg, 0))) {
   1886                         .assembly, .assembly_with_cpp, .c, .cpp, .ll, .bc, .h, .hpp, .hm, .hmm, .m, .mm => {
   1887                             try create_module.c_source_files.append(arena, .{
   1888                                 // Populated after module creation.
   1889                                 .owner = undefined,
   1890                                 .src_path = it.only_arg,
   1891                                 .ext = file_ext, // duped while parsing the args.
   1892                             });
   1893                         },
   1894                         .unknown, .object, .static_library, .shared_library => {
   1895                             try create_module.cli_link_inputs.append(arena, .{ .path_query = .{
   1896                                 .path = Path.initCwd(it.only_arg),
   1897                                 .query = .{
   1898                                     .must_link = must_link,
   1899                                     .needed = needed,
   1900                                     .preferred_mode = lib_preferred_mode,
   1901                                     .search_strategy = lib_search_strategy,
   1902                                     .allow_so_scripts = allow_so_scripts,
   1903                                 },
   1904                             } });
   1905                             // We do not set `any_dyn_libs` yet because a .so file
   1906                             // may actually resolve to a GNU ld script which ends
   1907                             // up being a static library.
   1908                         },
   1909                         .res => {
   1910                             try create_module.cli_link_inputs.append(arena, .{ .path_query = .{
   1911                                 .path = Path.initCwd(it.only_arg),
   1912                                 .query = .{
   1913                                     .must_link = must_link,
   1914                                     .needed = needed,
   1915                                     .preferred_mode = lib_preferred_mode,
   1916                                     .search_strategy = lib_search_strategy,
   1917                                     .allow_so_scripts = allow_so_scripts,
   1918                                 },
   1919                             } });
   1920                             contains_res_file = true;
   1921                         },
   1922                         .manifest => {
   1923                             if (manifest_file) |other| {
   1924                                 fatal("only one manifest file can be specified, found '{s}' after previously specified manifest '{s}'", .{ it.only_arg, other });
   1925                             } else manifest_file = it.only_arg;
   1926                         },
   1927                         .def => {
   1928                             linker_module_definition_file = it.only_arg;
   1929                         },
   1930                         .rc => {
   1931                             try create_module.rc_source_files.append(arena, .{
   1932                                 // Populated after module creation.
   1933                                 .owner = undefined,
   1934                                 .src_path = it.only_arg,
   1935                             });
   1936                         },
   1937                         .zig => {
   1938                             if (root_src_file) |other| {
   1939                                 fatal("found another zig file '{s}' after root source file '{s}'", .{ it.only_arg, other });
   1940                             } else root_src_file = it.only_arg;
   1941                         },
   1942                     },
   1943                     .l => {
   1944                         // -l
   1945                         // We don't know whether this library is part of libc or libc++ until
   1946                         // we resolve the target, so we simply append to the list for now.
   1947                         if (mem.startsWith(u8, it.only_arg, ":")) {
   1948                             // -l :path/to/filename is used when callers need
   1949                             // more control over what's in the resulting
   1950                             // binary: no extra rpaths and DSO filename exactly
   1951                             // as provided. CGo compilation depends on this.
   1952                             try create_module.cli_link_inputs.append(arena, .{ .dso_exact = .{
   1953                                 .name = it.only_arg,
   1954                             } });
   1955                         } else {
   1956                             try create_module.cli_link_inputs.append(arena, .{ .name_query = .{
   1957                                 .name = it.only_arg,
   1958                                 .query = .{
   1959                                     .must_link = must_link,
   1960                                     .needed = needed,
   1961                                     .weak = false,
   1962                                     .preferred_mode = lib_preferred_mode,
   1963                                     .search_strategy = lib_search_strategy,
   1964                                     .allow_so_scripts = allow_so_scripts,
   1965                                 },
   1966                             } });
   1967                         }
   1968                     },
   1969                     .ignore => {},
   1970                     .driver_punt => {
   1971                         // Never mind what we're doing, just pass the args directly. For example --help.
   1972                         return process.exit(try clangMain(arena, all_args));
   1973                     },
   1974                     .pic => mod_opts.pic = true,
   1975                     .no_pic => mod_opts.pic = false,
   1976                     .pie => create_module.opts.pie = true,
   1977                     .no_pie => create_module.opts.pie = false,
   1978                     .lto => {
   1979                         if (mem.eql(u8, it.only_arg, "flto") or
   1980                             mem.eql(u8, it.only_arg, "auto") or
   1981                             mem.eql(u8, it.only_arg, "full") or
   1982                             mem.eql(u8, it.only_arg, "jobserver"))
   1983                         {
   1984                             create_module.opts.lto = .full;
   1985                         } else if (mem.eql(u8, it.only_arg, "thin")) {
   1986                             create_module.opts.lto = .thin;
   1987                         } else {
   1988                             fatal("Invalid -flto mode: '{s}'. Must be 'auto', 'full', 'thin', or 'jobserver'.", .{it.only_arg});
   1989                         }
   1990                     },
   1991                     .no_lto => create_module.opts.lto = .none,
   1992                     .red_zone => mod_opts.red_zone = true,
   1993                     .no_red_zone => mod_opts.red_zone = false,
   1994                     .omit_frame_pointer => mod_opts.omit_frame_pointer = true,
   1995                     .no_omit_frame_pointer => mod_opts.omit_frame_pointer = false,
   1996                     .function_sections => function_sections = true,
   1997                     .no_function_sections => function_sections = false,
   1998                     .data_sections => data_sections = true,
   1999                     .no_data_sections => data_sections = false,
   2000                     .builtin => mod_opts.no_builtin = false,
   2001                     .no_builtin => mod_opts.no_builtin = true,
   2002                     .color_diagnostics => color = .on,
   2003                     .no_color_diagnostics => color = .off,
   2004                     .stack_check => mod_opts.stack_check = true,
   2005                     .no_stack_check => mod_opts.stack_check = false,
   2006                     .stack_protector => {
   2007                         if (mod_opts.stack_protector == null) {
   2008                             mod_opts.stack_protector = Compilation.default_stack_protector_buffer_size;
   2009                         }
   2010                     },
   2011                     .no_stack_protector => mod_opts.stack_protector = 0,
   2012                     // The way these unwind table options are processed in GCC and Clang is crazy
   2013                     // convoluted, and we also don't know the target triple here, so this is all
   2014                     // best-effort.
   2015                     .unwind_tables => if (mod_opts.unwind_tables) |uwt| switch (uwt) {
   2016                         .none => {
   2017                             mod_opts.unwind_tables = .sync;
   2018                         },
   2019                         .sync, .async => {},
   2020                     } else {
   2021                         mod_opts.unwind_tables = .sync;
   2022                     },
   2023                     .no_unwind_tables => mod_opts.unwind_tables = .none,
   2024                     .asynchronous_unwind_tables => mod_opts.unwind_tables = .async,
   2025                     .no_asynchronous_unwind_tables => if (mod_opts.unwind_tables) |uwt| switch (uwt) {
   2026                         .none, .sync => {},
   2027                         .async => {
   2028                             mod_opts.unwind_tables = .sync;
   2029                         },
   2030                     } else {
   2031                         mod_opts.unwind_tables = .sync;
   2032                     },
   2033                     .nostdlib => {
   2034                         create_module.opts.ensure_libc_on_non_freestanding = false;
   2035                         create_module.opts.ensure_libcpp_on_non_freestanding = false;
   2036                     },
   2037                     .nostdlib_cpp => create_module.opts.ensure_libcpp_on_non_freestanding = false,
   2038                     .shared => {
   2039                         create_module.opts.link_mode = .dynamic;
   2040                         is_shared_lib = true;
   2041                     },
   2042                     .rdynamic => create_module.opts.rdynamic = true,
   2043                     .wp => {
   2044                         var split_it = mem.splitScalar(u8, it.only_arg, ',');
   2045                         while (split_it.next()) |preprocessor_arg| {
   2046                             if (preprocessor_arg.len >= 3 and
   2047                                 preprocessor_arg[0] == '-' and
   2048                                 preprocessor_arg[2] != '-')
   2049                             {
   2050                                 if (mem.indexOfScalar(u8, preprocessor_arg, '=')) |equals_pos| {
   2051                                     const key = preprocessor_arg[0..equals_pos];
   2052                                     const value = preprocessor_arg[equals_pos + 1 ..];
   2053                                     try preprocessor_args.append(key);
   2054                                     try preprocessor_args.append(value);
   2055                                     continue;
   2056                                 }
   2057                             }
   2058                             try preprocessor_args.append(preprocessor_arg);
   2059                         }
   2060                     },
   2061                     .wl => {
   2062                         var split_it = mem.splitScalar(u8, it.only_arg, ',');
   2063                         while (split_it.next()) |linker_arg| {
   2064                             // Handle nested-joined args like `-Wl,-rpath=foo`.
   2065                             // Must be prefixed with 1 or 2 dashes.
   2066                             if (linker_arg.len >= 3 and
   2067                                 linker_arg[0] == '-' and
   2068                                 linker_arg[2] != '-')
   2069                             {
   2070                                 if (mem.indexOfScalar(u8, linker_arg, '=')) |equals_pos| {
   2071                                     const key = linker_arg[0..equals_pos];
   2072                                     const value = linker_arg[equals_pos + 1 ..];
   2073                                     if (mem.eql(u8, key, "--build-id")) {
   2074                                         build_id = std.zig.BuildId.parse(value) catch |err| {
   2075                                             fatal("unable to parse --build-id style '{s}': {s}", .{
   2076                                                 value, @errorName(err),
   2077                                             });
   2078                                         };
   2079                                         continue;
   2080                                     } else if (mem.eql(u8, key, "--sort-common")) {
   2081                                         // this ignores --sort=common=<anything>; ignoring plain --sort-common
   2082                                         // is done below.
   2083                                         continue;
   2084                                     }
   2085                                     try linker_args.append(key);
   2086                                     try linker_args.append(value);
   2087                                     continue;
   2088                                 }
   2089                             }
   2090                             if (mem.eql(u8, linker_arg, "--build-id")) {
   2091                                 build_id = .fast;
   2092                             } else if (mem.eql(u8, linker_arg, "--as-needed")) {
   2093                                 needed = false;
   2094                             } else if (mem.eql(u8, linker_arg, "--no-as-needed")) {
   2095                                 needed = true;
   2096                             } else if (mem.eql(u8, linker_arg, "-no-pie")) {
   2097                                 create_module.opts.pie = false;
   2098                             } else if (mem.eql(u8, linker_arg, "--sort-common")) {
   2099                                 // from ld.lld(1): --sort-common is ignored for GNU compatibility,
   2100                                 // this ignores plain --sort-common
   2101                             } else if (mem.eql(u8, linker_arg, "--whole-archive") or
   2102                                 mem.eql(u8, linker_arg, "-whole-archive"))
   2103                             {
   2104                                 must_link = true;
   2105                             } else if (mem.eql(u8, linker_arg, "--no-whole-archive") or
   2106                                 mem.eql(u8, linker_arg, "-no-whole-archive"))
   2107                             {
   2108                                 must_link = false;
   2109                             } else if (mem.eql(u8, linker_arg, "-Bdynamic") or
   2110                                 mem.eql(u8, linker_arg, "-dy") or
   2111                                 mem.eql(u8, linker_arg, "-call_shared"))
   2112                             {
   2113                                 lib_search_strategy = .no_fallback;
   2114                                 lib_preferred_mode = .dynamic;
   2115                             } else if (mem.eql(u8, linker_arg, "-Bstatic") or
   2116                                 mem.eql(u8, linker_arg, "-dn") or
   2117                                 mem.eql(u8, linker_arg, "-non_shared") or
   2118                                 mem.eql(u8, linker_arg, "-static"))
   2119                             {
   2120                                 lib_search_strategy = .no_fallback;
   2121                                 lib_preferred_mode = .static;
   2122                             } else if (mem.eql(u8, linker_arg, "-search_paths_first")) {
   2123                                 lib_search_strategy = .paths_first;
   2124                                 lib_preferred_mode = .dynamic;
   2125                             } else if (mem.eql(u8, linker_arg, "-search_dylibs_first")) {
   2126                                 lib_search_strategy = .mode_first;
   2127                                 lib_preferred_mode = .dynamic;
   2128                             } else {
   2129                                 try linker_args.append(linker_arg);
   2130                             }
   2131                         }
   2132                     },
   2133                     .san_cov_trace_pc_guard => create_module.opts.san_cov_trace_pc_guard = true,
   2134                     .san_cov => {
   2135                         var split_it = mem.splitScalar(u8, it.only_arg, ',');
   2136                         while (split_it.next()) |san_arg| {
   2137                             if (std.mem.eql(u8, san_arg, "trace-pc-guard")) {
   2138                                 create_module.opts.san_cov_trace_pc_guard = true;
   2139                             }
   2140                         }
   2141                         try cc_argv.appendSlice(arena, it.other_args);
   2142                     },
   2143                     .no_san_cov => {
   2144                         var split_it = mem.splitScalar(u8, it.only_arg, ',');
   2145                         while (split_it.next()) |san_arg| {
   2146                             if (std.mem.eql(u8, san_arg, "trace-pc-guard")) {
   2147                                 create_module.opts.san_cov_trace_pc_guard = false;
   2148                             }
   2149                         }
   2150                         try cc_argv.appendSlice(arena, it.other_args);
   2151                     },
   2152                     .optimize => {
   2153                         // Alright, what release mode do they want?
   2154                         const level = if (it.only_arg.len >= 1 and it.only_arg[0] == 'O') it.only_arg[1..] else it.only_arg;
   2155                         if (mem.eql(u8, level, "s") or
   2156                             mem.eql(u8, level, "z"))
   2157                         {
   2158                             mod_opts.optimize_mode = .ReleaseSmall;
   2159                         } else if (mem.eql(u8, level, "1") or
   2160                             mem.eql(u8, level, "2") or
   2161                             mem.eql(u8, level, "3") or
   2162                             mem.eql(u8, level, "4") or
   2163                             mem.eql(u8, level, "fast"))
   2164                         {
   2165                             mod_opts.optimize_mode = .ReleaseFast;
   2166                         } else if (mem.eql(u8, level, "g") or
   2167                             mem.eql(u8, level, "0"))
   2168                         {
   2169                             mod_opts.optimize_mode = .Debug;
   2170                         } else {
   2171                             try cc_argv.appendSlice(arena, it.other_args);
   2172                         }
   2173                     },
   2174                     .debug => {
   2175                         mod_opts.strip = false;
   2176                         if (mem.eql(u8, it.only_arg, "g")) {
   2177                             // We handled with strip = false above.
   2178                         } else if (mem.eql(u8, it.only_arg, "g1") or
   2179                             mem.eql(u8, it.only_arg, "gline-tables-only"))
   2180                         {
   2181                             // We handled with strip = false above. but we also want reduced debug info.
   2182                             try cc_argv.append(arena, "-gline-tables-only");
   2183                         } else {
   2184                             try cc_argv.appendSlice(arena, it.other_args);
   2185                         }
   2186                     },
   2187                     .gdwarf32 => {
   2188                         mod_opts.strip = false;
   2189                         create_module.opts.debug_format = .{ .dwarf = .@"32" };
   2190                     },
   2191                     .gdwarf64 => {
   2192                         mod_opts.strip = false;
   2193                         create_module.opts.debug_format = .{ .dwarf = .@"64" };
   2194                     },
   2195                     .sanitize, .no_sanitize => |t| {
   2196                         const enable = t == .sanitize;
   2197                         var san_it = std.mem.splitScalar(u8, it.only_arg, ',');
   2198                         var recognized_any = false;
   2199                         while (san_it.next()) |sub_arg| {
   2200                             if (mem.eql(u8, sub_arg, "undefined")) {
   2201                                 mod_opts.sanitize_c = if (enable) .full else .off;
   2202                                 recognized_any = true;
   2203                             } else if (mem.eql(u8, sub_arg, "thread")) {
   2204                                 mod_opts.sanitize_thread = enable;
   2205                                 recognized_any = true;
   2206                             } else if (mem.eql(u8, sub_arg, "fuzzer") or mem.eql(u8, sub_arg, "fuzzer-no-link")) {
   2207                                 mod_opts.fuzz = enable;
   2208                                 recognized_any = true;
   2209                             }
   2210                         }
   2211                         if (!recognized_any) {
   2212                             try cc_argv.appendSlice(arena, it.other_args);
   2213                         }
   2214                     },
   2215                     .sanitize_trap, .no_sanitize_trap => |t| {
   2216                         const enable = t == .sanitize_trap;
   2217                         var san_it = std.mem.splitScalar(u8, it.only_arg, ',');
   2218                         var recognized_any = false;
   2219                         while (san_it.next()) |sub_arg| {
   2220                             // This logic doesn't match Clang 1:1, but it's probably good enough, and avoids
   2221                             // significantly complicating the resolution of the options.
   2222                             if (mem.eql(u8, sub_arg, "undefined")) {
   2223                                 if (mod_opts.sanitize_c) |sc| switch (sc) {
   2224                                     .off => if (enable) {
   2225                                         mod_opts.sanitize_c = .trap;
   2226                                     },
   2227                                     .trap => if (!enable) {
   2228                                         mod_opts.sanitize_c = .full;
   2229                                     },
   2230                                     .full => if (enable) {
   2231                                         mod_opts.sanitize_c = .trap;
   2232                                     },
   2233                                 } else {
   2234                                     if (enable) {
   2235                                         mod_opts.sanitize_c = .trap;
   2236                                     } else {
   2237                                         // This means we were passed `-fno-sanitize-trap=undefined` and nothing else. In
   2238                                         // this case, ideally, we should use whatever value `sanitize_c` resolves to by
   2239                                         // default, except change `trap` to `full`. However, we don't yet know what
   2240                                         // `sanitize_c` will resolve to! So we either have to pick `off` or `full`.
   2241                                         //
   2242                                         // `full` has the potential to be problematic if `optimize_mode` turns out to
   2243                                         // be `ReleaseFast`/`ReleaseSmall` because the user will get a slower and larger
   2244                                         // binary than expected. On the other hand, if `optimize_mode` turns out to be
   2245                                         // `Debug`/`ReleaseSafe`, `off` would mean UBSan would unexpectedly be disabled.
   2246                                         //
   2247                                         // `off` seems very slightly less bad, so let's go with that.
   2248                                         mod_opts.sanitize_c = .off;
   2249                                     }
   2250                                 }
   2251                                 recognized_any = true;
   2252                             }
   2253                         }
   2254                         if (!recognized_any) {
   2255                             try cc_argv.appendSlice(arena, it.other_args);
   2256                         }
   2257                     },
   2258                     .linker_script => linker_script = it.only_arg,
   2259                     .verbose => {
   2260                         verbose_link = true;
   2261                         // Have Clang print more infos, some tools such as CMake
   2262                         // parse this to discover any implicit include and
   2263                         // library dir to look-up into.
   2264                         try cc_argv.append(arena, "-v");
   2265                     },
   2266                     .dry_run => {
   2267                         // This flag means "dry run". Clang will not actually output anything
   2268                         // to the file system.
   2269                         verbose_link = true;
   2270                         disable_c_depfile = true;
   2271                         try cc_argv.append(arena, "-###");
   2272                     },
   2273                     .for_linker => try linker_args.append(it.only_arg),
   2274                     .linker_input_z => {
   2275                         try linker_args.append("-z");
   2276                         try linker_args.append(it.only_arg);
   2277                     },
   2278                     .lib_dir => try create_module.lib_dir_args.append(arena, it.only_arg),
   2279                     .mcpu => target_mcpu = it.only_arg,
   2280                     .m => try create_module.llvm_m_args.append(arena, it.only_arg),
   2281                     .dep_file => {
   2282                         disable_c_depfile = true;
   2283                         try cc_argv.appendSlice(arena, it.other_args);
   2284                     },
   2285                     .dep_file_to_stdout => { // -M, -MM
   2286                         // "Like -MD, but also implies -E and writes to stdout by default"
   2287                         // "Like -MMD, but also implies -E and writes to stdout by default"
   2288                         c_out_mode = .preprocessor;
   2289                         disable_c_depfile = true;
   2290                         try cc_argv.appendSlice(arena, it.other_args);
   2291                     },
   2292                     .framework_dir => try create_module.framework_dirs.append(arena, it.only_arg),
   2293                     .framework => try create_module.frameworks.put(arena, it.only_arg, .{}),
   2294                     .nostdlibinc => create_module.want_native_include_dirs = false,
   2295                     .strip => mod_opts.strip = true,
   2296                     .exec_model => {
   2297                         create_module.opts.wasi_exec_model = parseWasiExecModel(it.only_arg);
   2298                     },
   2299                     .sysroot => {
   2300                         create_module.sysroot = it.only_arg;
   2301                     },
   2302                     .entry => {
   2303                         entry = .{ .named = it.only_arg };
   2304                     },
   2305                     .force_undefined_symbol => {
   2306                         try force_undefined_symbols.put(arena, it.only_arg, {});
   2307                     },
   2308                     .force_load_objc => force_load_objc = true,
   2309                     .mingw_unicode_entry_point => mingw_unicode_entry_point = true,
   2310                     .weak_library => try create_module.cli_link_inputs.append(arena, .{ .name_query = .{
   2311                         .name = it.only_arg,
   2312                         .query = .{
   2313                             .needed = false,
   2314                             .weak = true,
   2315                             .preferred_mode = lib_preferred_mode,
   2316                             .search_strategy = lib_search_strategy,
   2317                             .allow_so_scripts = allow_so_scripts,
   2318                         },
   2319                     } }),
   2320                     .weak_framework => try create_module.frameworks.put(arena, it.only_arg, .{ .weak = true }),
   2321                     .headerpad_max_install_names => headerpad_max_install_names = true,
   2322                     .compress_debug_sections => {
   2323                         if (it.only_arg.len == 0) {
   2324                             linker_compress_debug_sections = .zlib;
   2325                         } else {
   2326                             linker_compress_debug_sections = std.meta.stringToEnum(link.File.Lld.Elf.CompressDebugSections, it.only_arg) orelse {
   2327                                 fatal("expected [none|zlib|zstd] after --compress-debug-sections, found '{s}'", .{it.only_arg});
   2328                             };
   2329                         }
   2330                     },
   2331                     .install_name => {
   2332                         install_name = it.only_arg;
   2333                     },
   2334                     .undefined => {
   2335                         if (mem.eql(u8, "dynamic_lookup", it.only_arg)) {
   2336                             linker_allow_shlib_undefined = true;
   2337                         } else if (mem.eql(u8, "error", it.only_arg)) {
   2338                             linker_allow_shlib_undefined = false;
   2339                         } else {
   2340                             fatal("unsupported -undefined option '{s}'", .{it.only_arg});
   2341                         }
   2342                     },
   2343                     .rtlib => {
   2344                         // Unlike Clang, we support `none` for explicitly omitting compiler-rt.
   2345                         if (mem.eql(u8, "none", it.only_arg)) {
   2346                             want_compiler_rt = false;
   2347                         } else if (mem.eql(u8, "compiler-rt", it.only_arg) or
   2348                             mem.eql(u8, "libgcc", it.only_arg))
   2349                         {
   2350                             want_compiler_rt = true;
   2351                         } else {
   2352                             // Note that we don't support `platform`.
   2353                             fatal("unsupported -rtlib option '{s}'", .{it.only_arg});
   2354                         }
   2355                     },
   2356                     .static => {
   2357                         create_module.opts.link_mode = .static;
   2358                         lib_preferred_mode = .static;
   2359                         lib_search_strategy = .no_fallback;
   2360                     },
   2361                     .dynamic => {
   2362                         create_module.opts.link_mode = .dynamic;
   2363                         lib_preferred_mode = .dynamic;
   2364                         lib_search_strategy = .mode_first;
   2365                     },
   2366                 }
   2367             }
   2368             // Parse linker args.
   2369             var linker_args_it = ArgsIterator{
   2370                 .args = linker_args.items,
   2371             };
   2372             while (linker_args_it.next()) |arg| {
   2373                 if (mem.eql(u8, arg, "-soname") or
   2374                     mem.eql(u8, arg, "--soname"))
   2375                 {
   2376                     const name = linker_args_it.nextOrFatal();
   2377                     soname = .{ .yes = name };
   2378                     // Use it as --name.
   2379                     // Example: libsoundio.so.2
   2380                     var prefix: usize = 0;
   2381                     if (mem.startsWith(u8, name, "lib")) {
   2382                         prefix = 3;
   2383                     }
   2384                     var end: usize = name.len;
   2385                     if (mem.endsWith(u8, name, ".so")) {
   2386                         end -= 3;
   2387                     } else {
   2388                         var found_digit = false;
   2389                         while (end > 0 and std.ascii.isDigit(name[end - 1])) {
   2390                             found_digit = true;
   2391                             end -= 1;
   2392                         }
   2393                         if (found_digit and end > 0 and name[end - 1] == '.') {
   2394                             end -= 1;
   2395                         } else {
   2396                             end = name.len;
   2397                         }
   2398                         if (mem.endsWith(u8, name[prefix..end], ".so")) {
   2399                             end -= 3;
   2400                         }
   2401                     }
   2402                     provided_name = name[prefix..end];
   2403                 } else if (mem.eql(u8, arg, "-rpath") or mem.eql(u8, arg, "--rpath") or mem.eql(u8, arg, "-R")) {
   2404                     try create_module.rpath_list.append(arena, linker_args_it.nextOrFatal());
   2405                 } else if (mem.eql(u8, arg, "--subsystem")) {
   2406                     subsystem = try parseSubSystem(linker_args_it.nextOrFatal());
   2407                 } else if (mem.eql(u8, arg, "-I") or
   2408                     mem.eql(u8, arg, "--dynamic-linker") or
   2409                     mem.eql(u8, arg, "-dynamic-linker"))
   2410                 {
   2411                     create_module.dynamic_linker = linker_args_it.nextOrFatal();
   2412                 } else if (mem.eql(u8, arg, "-E") or
   2413                     mem.eql(u8, arg, "--export-dynamic") or
   2414                     mem.eql(u8, arg, "-export-dynamic"))
   2415                 {
   2416                     create_module.opts.rdynamic = true;
   2417                 } else if (mem.eql(u8, arg, "-version-script") or mem.eql(u8, arg, "--version-script")) {
   2418                     version_script = linker_args_it.nextOrFatal();
   2419                 } else if (mem.eql(u8, arg, "--undefined-version")) {
   2420                     linker_allow_undefined_version = true;
   2421                 } else if (mem.eql(u8, arg, "--no-undefined-version")) {
   2422                     linker_allow_undefined_version = false;
   2423                 } else if (mem.eql(u8, arg, "--enable-new-dtags")) {
   2424                     linker_enable_new_dtags = true;
   2425                 } else if (mem.eql(u8, arg, "--disable-new-dtags")) {
   2426                     linker_enable_new_dtags = false;
   2427                 } else if (mem.eql(u8, arg, "-O")) {
   2428                     linker_optimization = linker_args_it.nextOrFatal();
   2429                 } else if (mem.cutPrefix(u8, arg, "-O")) |rest| {
   2430                     linker_optimization = rest;
   2431                 } else if (mem.eql(u8, arg, "-pagezero_size")) {
   2432                     const next_arg = linker_args_it.nextOrFatal();
   2433                     pagezero_size = std.fmt.parseUnsigned(u64, eatIntPrefix(next_arg, 16), 16) catch |err| {
   2434                         fatal("unable to parse pagezero size '{s}': {s}", .{ next_arg, @errorName(err) });
   2435                     };
   2436                 } else if (mem.eql(u8, arg, "-headerpad")) {
   2437                     const next_arg = linker_args_it.nextOrFatal();
   2438                     headerpad_size = std.fmt.parseUnsigned(u32, eatIntPrefix(next_arg, 16), 16) catch |err| {
   2439                         fatal("unable to parse  headerpad size '{s}': {s}", .{ next_arg, @errorName(err) });
   2440                     };
   2441                 } else if (mem.eql(u8, arg, "-headerpad_max_install_names")) {
   2442                     headerpad_max_install_names = true;
   2443                 } else if (mem.eql(u8, arg, "-dead_strip")) {
   2444                     linker_gc_sections = true;
   2445                 } else if (mem.eql(u8, arg, "-dead_strip_dylibs")) {
   2446                     dead_strip_dylibs = true;
   2447                 } else if (mem.eql(u8, arg, "-ObjC")) {
   2448                     force_load_objc = true;
   2449                 } else if (mem.eql(u8, arg, "--no-undefined")) {
   2450                     linker_z_defs = true;
   2451                 } else if (mem.eql(u8, arg, "--gc-sections")) {
   2452                     linker_gc_sections = true;
   2453                 } else if (mem.eql(u8, arg, "--no-gc-sections")) {
   2454                     linker_gc_sections = false;
   2455                 } else if (mem.eql(u8, arg, "--print-gc-sections")) {
   2456                     linker_print_gc_sections = true;
   2457                 } else if (mem.eql(u8, arg, "--print-icf-sections")) {
   2458                     linker_print_icf_sections = true;
   2459                 } else if (mem.eql(u8, arg, "--print-map")) {
   2460                     linker_print_map = true;
   2461                 } else if (mem.eql(u8, arg, "--sort-section")) {
   2462                     const arg1 = linker_args_it.nextOrFatal();
   2463                     linker_sort_section = std.meta.stringToEnum(link.File.Lld.Elf.SortSection, arg1) orelse {
   2464                         fatal("expected [name|alignment] after --sort-section, found '{s}'", .{arg1});
   2465                     };
   2466                 } else if (mem.eql(u8, arg, "--allow-shlib-undefined") or
   2467                     mem.eql(u8, arg, "-allow-shlib-undefined"))
   2468                 {
   2469                     linker_allow_shlib_undefined = true;
   2470                 } else if (mem.eql(u8, arg, "--no-allow-shlib-undefined") or
   2471                     mem.eql(u8, arg, "-no-allow-shlib-undefined"))
   2472                 {
   2473                     linker_allow_shlib_undefined = false;
   2474                 } else if (mem.eql(u8, arg, "-Bsymbolic")) {
   2475                     linker_bind_global_refs_locally = true;
   2476                 } else if (mem.eql(u8, arg, "--import-memory")) {
   2477                     create_module.opts.import_memory = true;
   2478                 } else if (mem.eql(u8, arg, "--export-memory")) {
   2479                     create_module.opts.export_memory = true;
   2480                 } else if (mem.eql(u8, arg, "--import-symbols")) {
   2481                     linker_import_symbols = true;
   2482                 } else if (mem.eql(u8, arg, "--import-table")) {
   2483                     linker_import_table = true;
   2484                 } else if (mem.eql(u8, arg, "--export-table")) {
   2485                     linker_export_table = true;
   2486                 } else if (mem.eql(u8, arg, "--no-entry")) {
   2487                     entry = .disabled;
   2488                 } else if (mem.eql(u8, arg, "--initial-memory")) {
   2489                     const next_arg = linker_args_it.nextOrFatal();
   2490                     linker_initial_memory = std.fmt.parseUnsigned(u32, next_arg, 10) catch |err| {
   2491                         fatal("unable to parse initial memory size '{s}': {s}", .{ next_arg, @errorName(err) });
   2492                     };
   2493                 } else if (mem.eql(u8, arg, "--max-memory")) {
   2494                     const next_arg = linker_args_it.nextOrFatal();
   2495                     linker_max_memory = std.fmt.parseUnsigned(u32, next_arg, 10) catch |err| {
   2496                         fatal("unable to parse max memory size '{s}': {s}", .{ next_arg, @errorName(err) });
   2497                     };
   2498                 } else if (mem.eql(u8, arg, "--shared-memory")) {
   2499                     create_module.opts.shared_memory = true;
   2500                 } else if (mem.eql(u8, arg, "--global-base")) {
   2501                     const next_arg = linker_args_it.nextOrFatal();
   2502                     linker_global_base = std.fmt.parseUnsigned(u32, next_arg, 10) catch |err| {
   2503                         fatal("unable to parse global base '{s}': {s}", .{ next_arg, @errorName(err) });
   2504                     };
   2505                 } else if (mem.eql(u8, arg, "--export")) {
   2506                     try linker_export_symbol_names.append(arena, linker_args_it.nextOrFatal());
   2507                 } else if (mem.eql(u8, arg, "--compress-debug-sections")) {
   2508                     const arg1 = linker_args_it.nextOrFatal();
   2509                     linker_compress_debug_sections = std.meta.stringToEnum(link.File.Lld.Elf.CompressDebugSections, arg1) orelse {
   2510                         fatal("expected [none|zlib|zstd] after --compress-debug-sections, found '{s}'", .{arg1});
   2511                     };
   2512                 } else if (mem.cutPrefix(u8, arg, "-z")) |z_rest| {
   2513                     const z_arg = if (z_rest.len == 0) linker_args_it.nextOrFatal() else z_rest;
   2514                     if (mem.eql(u8, z_arg, "nodelete")) {
   2515                         linker_z_nodelete = true;
   2516                     } else if (mem.eql(u8, z_arg, "notext")) {
   2517                         linker_z_notext = true;
   2518                     } else if (mem.eql(u8, z_arg, "defs")) {
   2519                         linker_z_defs = true;
   2520                     } else if (mem.eql(u8, z_arg, "undefs")) {
   2521                         linker_z_defs = false;
   2522                     } else if (mem.eql(u8, z_arg, "origin")) {
   2523                         linker_z_origin = true;
   2524                     } else if (mem.eql(u8, z_arg, "nocopyreloc")) {
   2525                         linker_z_nocopyreloc = true;
   2526                     } else if (mem.eql(u8, z_arg, "noexecstack")) {
   2527                         // noexecstack is the default when linking with LLD
   2528                     } else if (mem.eql(u8, z_arg, "now")) {
   2529                         linker_z_now = true;
   2530                     } else if (mem.eql(u8, z_arg, "lazy")) {
   2531                         linker_z_now = false;
   2532                     } else if (mem.eql(u8, z_arg, "relro")) {
   2533                         linker_z_relro = true;
   2534                     } else if (mem.eql(u8, z_arg, "norelro")) {
   2535                         linker_z_relro = false;
   2536                     } else if (mem.cutPrefix(u8, z_arg, "stack-size=")) |rest| {
   2537                         stack_size = parseStackSize(rest);
   2538                     } else if (prefixedIntArg(z_arg, "common-page-size=")) |int| {
   2539                         linker_z_common_page_size = int;
   2540                     } else if (prefixedIntArg(z_arg, "max-page-size=")) |int| {
   2541                         linker_z_max_page_size = int;
   2542                     } else {
   2543                         fatal("unsupported linker extension flag: -z {s}", .{z_arg});
   2544                     }
   2545                 } else if (mem.eql(u8, arg, "--major-image-version")) {
   2546                     const major = linker_args_it.nextOrFatal();
   2547                     version.major = std.fmt.parseUnsigned(u32, major, 10) catch |err| {
   2548                         fatal("unable to parse major image version '{s}': {s}", .{ major, @errorName(err) });
   2549                     };
   2550                     have_version = true;
   2551                 } else if (mem.eql(u8, arg, "--minor-image-version")) {
   2552                     const minor = linker_args_it.nextOrFatal();
   2553                     version.minor = std.fmt.parseUnsigned(u32, minor, 10) catch |err| {
   2554                         fatal("unable to parse minor image version '{s}': {s}", .{ minor, @errorName(err) });
   2555                     };
   2556                     have_version = true;
   2557                 } else if (mem.eql(u8, arg, "-e") or mem.eql(u8, arg, "--entry")) {
   2558                     entry = .{ .named = linker_args_it.nextOrFatal() };
   2559                 } else if (mem.eql(u8, arg, "-u")) {
   2560                     try force_undefined_symbols.put(arena, linker_args_it.nextOrFatal(), {});
   2561                 } else if (mem.eql(u8, arg, "-x") or mem.eql(u8, arg, "--discard-all")) {
   2562                     discard_local_symbols = true;
   2563                 } else if (mem.eql(u8, arg, "--stack") or mem.eql(u8, arg, "-stack_size")) {
   2564                     stack_size = parseStackSize(linker_args_it.nextOrFatal());
   2565                 } else if (mem.eql(u8, arg, "--image-base")) {
   2566                     image_base = parseImageBase(linker_args_it.nextOrFatal());
   2567                 } else if (mem.eql(u8, arg, "--enable-auto-image-base") or
   2568                     mem.eql(u8, arg, "--disable-auto-image-base"))
   2569                 {
   2570                     // `--enable-auto-image-base` is a flag that binutils added in ~2000 for MinGW.
   2571                     // It does a hash of the file and uses that as part of the image base value.
   2572                     // Presumably the idea was to avoid DLLs needing to be relocated when loaded.
   2573                     // This is practically irrelevant today as all PEs produced since Windows Vista
   2574                     // have ASLR enabled by default anyway, and Windows 10+ has Mandatory ASLR which
   2575                     // doesn't even care what the PE file wants and relocates it anyway.
   2576                     //
   2577                     // Unfortunately, Libtool hardcodes usage of this archaic flag when targeting
   2578                     // MinGW, so to make `zig cc` for that use case work, accept and ignore the
   2579                     // flag, and warn the user that it has no effect.
   2580                     warn("auto-image-base options are unimplemented and ignored", .{});
   2581                 } else if (mem.eql(u8, arg, "-T") or mem.eql(u8, arg, "--script")) {
   2582                     linker_script = linker_args_it.nextOrFatal();
   2583                 } else if (mem.eql(u8, arg, "--eh-frame-hdr")) {
   2584                     link_eh_frame_hdr = true;
   2585                 } else if (mem.eql(u8, arg, "--no-eh-frame-hdr")) {
   2586                     link_eh_frame_hdr = false;
   2587                 } else if (mem.eql(u8, arg, "--tsaware")) {
   2588                     linker_tsaware = true;
   2589                 } else if (mem.eql(u8, arg, "--nxcompat")) {
   2590                     linker_nxcompat = true;
   2591                 } else if (mem.eql(u8, arg, "--dynamicbase")) {
   2592                     linker_dynamicbase = true;
   2593                 } else if (mem.eql(u8, arg, "--no-dynamicbase")) {
   2594                     linker_dynamicbase = false;
   2595                 } else if (mem.eql(u8, arg, "--high-entropy-va")) {
   2596                     // This option does not do anything.
   2597                 } else if (mem.eql(u8, arg, "--export-all-symbols")) {
   2598                     create_module.opts.rdynamic = true;
   2599                 } else if (mem.eql(u8, arg, "--color-diagnostics") or
   2600                     mem.eql(u8, arg, "--color-diagnostics=always"))
   2601                 {
   2602                     color = .on;
   2603                 } else if (mem.eql(u8, arg, "--no-color-diagnostics") or
   2604                     mem.eql(u8, arg, "--color-diagnostics=never"))
   2605                 {
   2606                     color = .off;
   2607                 } else if (mem.eql(u8, arg, "-s") or mem.eql(u8, arg, "--strip-all") or
   2608                     mem.eql(u8, arg, "-S") or mem.eql(u8, arg, "--strip-debug"))
   2609                 {
   2610                     // -s, --strip-all             Strip all symbols
   2611                     // -S, --strip-debug           Strip debugging symbols
   2612                     mod_opts.strip = true;
   2613                 } else if (mem.eql(u8, arg, "--start-group") or
   2614                     mem.eql(u8, arg, "--end-group"))
   2615                 {
   2616                     // We don't need to care about these because these args are
   2617                     // for resolving circular dependencies but our linker takes
   2618                     // care of this without explicit args.
   2619                 } else if (mem.eql(u8, arg, "--major-os-version") or
   2620                     mem.eql(u8, arg, "--minor-os-version"))
   2621                 {
   2622                     // This option does not do anything.
   2623                     _ = linker_args_it.nextOrFatal();
   2624                 } else if (mem.eql(u8, arg, "--major-subsystem-version")) {
   2625                     const major = linker_args_it.nextOrFatal();
   2626                     major_subsystem_version = std.fmt.parseUnsigned(u16, major, 10) catch |err| {
   2627                         fatal("unable to parse major subsystem version '{s}': {s}", .{
   2628                             major, @errorName(err),
   2629                         });
   2630                     };
   2631                 } else if (mem.eql(u8, arg, "--minor-subsystem-version")) {
   2632                     const minor = linker_args_it.nextOrFatal();
   2633                     minor_subsystem_version = std.fmt.parseUnsigned(u16, minor, 10) catch |err| {
   2634                         fatal("unable to parse minor subsystem version '{s}': {s}", .{
   2635                             minor, @errorName(err),
   2636                         });
   2637                     };
   2638                 } else if (mem.eql(u8, arg, "-framework")) {
   2639                     try create_module.frameworks.put(arena, linker_args_it.nextOrFatal(), .{});
   2640                 } else if (mem.eql(u8, arg, "-weak_framework")) {
   2641                     try create_module.frameworks.put(arena, linker_args_it.nextOrFatal(), .{ .weak = true });
   2642                 } else if (mem.eql(u8, arg, "-needed_framework")) {
   2643                     try create_module.frameworks.put(arena, linker_args_it.nextOrFatal(), .{ .needed = true });
   2644                 } else if (mem.eql(u8, arg, "-needed_library")) {
   2645                     try create_module.cli_link_inputs.append(arena, .{ .name_query = .{
   2646                         .name = linker_args_it.nextOrFatal(),
   2647                         .query = .{
   2648                             .weak = false,
   2649                             .needed = true,
   2650                             .preferred_mode = lib_preferred_mode,
   2651                             .search_strategy = lib_search_strategy,
   2652                             .allow_so_scripts = allow_so_scripts,
   2653                         },
   2654                     } });
   2655                 } else if (mem.cutPrefix(u8, arg, "-weak-l")) |rest| {
   2656                     try create_module.cli_link_inputs.append(arena, .{ .name_query = .{
   2657                         .name = rest,
   2658                         .query = .{
   2659                             .weak = true,
   2660                             .needed = false,
   2661                             .preferred_mode = lib_preferred_mode,
   2662                             .search_strategy = lib_search_strategy,
   2663                             .allow_so_scripts = allow_so_scripts,
   2664                         },
   2665                     } });
   2666                 } else if (mem.eql(u8, arg, "-weak_library")) {
   2667                     try create_module.cli_link_inputs.append(arena, .{ .name_query = .{
   2668                         .name = linker_args_it.nextOrFatal(),
   2669                         .query = .{
   2670                             .weak = true,
   2671                             .needed = false,
   2672                             .preferred_mode = lib_preferred_mode,
   2673                             .search_strategy = lib_search_strategy,
   2674                             .allow_so_scripts = allow_so_scripts,
   2675                         },
   2676                     } });
   2677                 } else if (mem.eql(u8, arg, "-compatibility_version")) {
   2678                     const compat_version = linker_args_it.nextOrFatal();
   2679                     compatibility_version = std.SemanticVersion.parse(compat_version) catch |err| {
   2680                         fatal("unable to parse -compatibility_version '{s}': {s}", .{ compat_version, @errorName(err) });
   2681                     };
   2682                 } else if (mem.eql(u8, arg, "-current_version")) {
   2683                     const curr_version = linker_args_it.nextOrFatal();
   2684                     version = std.SemanticVersion.parse(curr_version) catch |err| {
   2685                         fatal("unable to parse -current_version '{s}': {s}", .{ curr_version, @errorName(err) });
   2686                     };
   2687                     have_version = true;
   2688                 } else if (mem.eql(u8, arg, "--out-implib") or
   2689                     mem.eql(u8, arg, "-implib"))
   2690                 {
   2691                     emit_implib = .{ .yes = linker_args_it.nextOrFatal() };
   2692                     emit_implib_arg_provided = true;
   2693                 } else if (mem.eql(u8, arg, "-Brepro") or mem.eql(u8, arg, "/Brepro")) {
   2694                     linker_repro = true;
   2695                 } else if (mem.eql(u8, arg, "-undefined")) {
   2696                     const lookup_type = linker_args_it.nextOrFatal();
   2697                     if (mem.eql(u8, "dynamic_lookup", lookup_type)) {
   2698                         linker_allow_shlib_undefined = true;
   2699                     } else if (mem.eql(u8, "error", lookup_type)) {
   2700                         linker_allow_shlib_undefined = false;
   2701                     } else {
   2702                         fatal("unsupported -undefined option '{s}'", .{lookup_type});
   2703                     }
   2704                 } else if (mem.eql(u8, arg, "-install_name")) {
   2705                     install_name = linker_args_it.nextOrFatal();
   2706                 } else if (mem.eql(u8, arg, "-force_load")) {
   2707                     try create_module.cli_link_inputs.append(arena, .{ .path_query = .{
   2708                         .path = Path.initCwd(linker_args_it.nextOrFatal()),
   2709                         .query = .{
   2710                             .must_link = true,
   2711                             .preferred_mode = .static,
   2712                             .search_strategy = .no_fallback,
   2713                         },
   2714                     } });
   2715                 } else if (mem.eql(u8, arg, "-hash-style") or
   2716                     mem.eql(u8, arg, "--hash-style"))
   2717                 {
   2718                     const next_arg = linker_args_it.nextOrFatal();
   2719                     hash_style = std.meta.stringToEnum(link.File.Lld.Elf.HashStyle, next_arg) orelse {
   2720                         fatal("expected [sysv|gnu|both] after --hash-style, found '{s}'", .{
   2721                             next_arg,
   2722                         });
   2723                     };
   2724                 } else if (mem.eql(u8, arg, "-wrap")) {
   2725                     const next_arg = linker_args_it.nextOrFatal();
   2726                     try symbol_wrap_set.put(arena, next_arg, {});
   2727                 } else if (mem.startsWith(u8, arg, "/subsystem:")) {
   2728                     var split_it = mem.splitBackwardsScalar(u8, arg, ':');
   2729                     subsystem = try parseSubSystem(split_it.first());
   2730                 } else if (mem.startsWith(u8, arg, "/implib:")) {
   2731                     var split_it = mem.splitBackwardsScalar(u8, arg, ':');
   2732                     emit_implib = .{ .yes = split_it.first() };
   2733                     emit_implib_arg_provided = true;
   2734                 } else if (mem.startsWith(u8, arg, "/pdb:")) {
   2735                     var split_it = mem.splitBackwardsScalar(u8, arg, ':');
   2736                     pdb_out_path = split_it.first();
   2737                 } else if (mem.startsWith(u8, arg, "/version:")) {
   2738                     var split_it = mem.splitBackwardsScalar(u8, arg, ':');
   2739                     const version_arg = split_it.first();
   2740                     version = std.SemanticVersion.parse(version_arg) catch |err| {
   2741                         fatal("unable to parse /version '{s}': {s}", .{ arg, @errorName(err) });
   2742                     };
   2743                     have_version = true;
   2744                 } else if (mem.eql(u8, arg, "-V")) {
   2745                     warn("ignoring request for supported emulations: unimplemented", .{});
   2746                 } else if (mem.eql(u8, arg, "-v")) {
   2747                     try fs.File.stdout().writeAll("zig ld " ++ build_options.version ++ "\n");
   2748                 } else if (mem.eql(u8, arg, "--version")) {
   2749                     try fs.File.stdout().writeAll("zig ld " ++ build_options.version ++ "\n");
   2750                     process.exit(0);
   2751                 } else {
   2752                     fatal("unsupported linker arg: {s}", .{arg});
   2753                 }
   2754             }
   2755 
   2756             // Parse preprocessor args.
   2757             var preprocessor_args_it = ArgsIterator{
   2758                 .args = preprocessor_args.items,
   2759             };
   2760             while (preprocessor_args_it.next()) |arg| {
   2761                 if (mem.eql(u8, arg, "-MD") or mem.eql(u8, arg, "-MMD") or mem.eql(u8, arg, "-MT")) {
   2762                     disable_c_depfile = true;
   2763                     const cc_arg = try std.fmt.allocPrint(arena, "-Wp,{s},{s}", .{ arg, preprocessor_args_it.nextOrFatal() });
   2764                     try cc_argv.append(arena, cc_arg);
   2765                 } else {
   2766                     fatal("unsupported preprocessor arg: {s}", .{arg});
   2767                 }
   2768             }
   2769 
   2770             if (mod_opts.sanitize_c) |wsc| {
   2771                 if (wsc != .off and mod_opts.optimize_mode == .ReleaseFast) {
   2772                     mod_opts.optimize_mode = .ReleaseSafe;
   2773                 }
   2774             }
   2775 
   2776             // precompiled header syntax: "zig cc -x c-header test.h -o test.pch"
   2777             const emit_pch = ((file_ext == .h or file_ext == .hpp or file_ext == .hm or file_ext == .hmm) and c_out_mode == null);
   2778             if (emit_pch)
   2779                 c_out_mode = .preprocessor;
   2780 
   2781             switch (c_out_mode orelse .link) {
   2782                 .link => {
   2783                     create_module.opts.output_mode = if (is_shared_lib) .Lib else .Exe;
   2784                     if (emit_bin != .no) {
   2785                         emit_bin = if (out_path) |p| .{ .yes = p } else .yes_a_out;
   2786                     }
   2787                     if (emit_llvm) {
   2788                         fatal("-emit-llvm cannot be used when linking", .{});
   2789                     }
   2790                 },
   2791                 .object => {
   2792                     create_module.opts.output_mode = .Obj;
   2793                     if (emit_llvm) {
   2794                         emit_bin = .no;
   2795                         if (out_path) |p| {
   2796                             emit_llvm_bc = .{ .yes = p };
   2797                         } else {
   2798                             emit_llvm_bc = .yes_default_path;
   2799                         }
   2800                     } else {
   2801                         if (out_path) |p| {
   2802                             emit_bin = .{ .yes = p };
   2803                         } else {
   2804                             emit_bin = .yes_default_path;
   2805                         }
   2806                     }
   2807                 },
   2808                 .assembly => {
   2809                     create_module.opts.output_mode = .Obj;
   2810                     emit_bin = .no;
   2811                     if (emit_llvm) {
   2812                         if (out_path) |p| {
   2813                             emit_llvm_ir = .{ .yes = p };
   2814                         } else {
   2815                             emit_llvm_ir = .yes_default_path;
   2816                         }
   2817                     } else {
   2818                         if (out_path) |p| {
   2819                             emit_asm = .{ .yes = p };
   2820                         } else {
   2821                             emit_asm = .yes_default_path;
   2822                         }
   2823                     }
   2824                 },
   2825                 .preprocessor => {
   2826                     create_module.opts.output_mode = .Obj;
   2827                     // An error message is generated when there is more than 1 C source file.
   2828                     if (create_module.c_source_files.items.len != 1) {
   2829                         // For example `zig cc` and no args should print the "no input files" message.
   2830                         return process.exit(try clangMain(arena, all_args));
   2831                     }
   2832                     if (emit_pch) {
   2833                         emit_bin = if (out_path) |p| .{ .yes = p } else .yes_default_path;
   2834                         clang_preprocessor_mode = .pch;
   2835                     } else {
   2836                         // If the output path is "-" (stdout), then we need to emit the preprocessed output to stdout
   2837                         // like "clang -E main.c -o -" does.
   2838                         if (out_path != null and !mem.eql(u8, out_path.?, "-")) {
   2839                             emit_bin = .{ .yes = out_path.? };
   2840                             clang_preprocessor_mode = .yes;
   2841                         } else {
   2842                             emit_bin = .no;
   2843                             clang_preprocessor_mode = .stdout;
   2844                         }
   2845                     }
   2846                 },
   2847             }
   2848             if (create_module.c_source_files.items.len == 0 and
   2849                 !anyObjectLinkInputs(create_module.cli_link_inputs.items) and
   2850                 root_src_file == null)
   2851             {
   2852                 // For example `zig cc` and no args should print the "no input files" message.
   2853                 // There could be other reasons to punt to clang, for example, --help.
   2854                 return process.exit(try clangMain(arena, all_args));
   2855             }
   2856         },
   2857     }
   2858 
   2859     if (arg_mode == .zig_test_obj and !test_no_exec and listen == .none) {
   2860         fatal("test-obj requires --test-no-exec", .{});
   2861     }
   2862 
   2863     if (time_report and listen == .none) {
   2864         fatal("--time-report requires --listen", .{});
   2865     }
   2866 
   2867     if (arg_mode == .translate_c and create_module.c_source_files.items.len != 1) {
   2868         fatal("translate-c expects exactly 1 source file (found {d})", .{create_module.c_source_files.items.len});
   2869     }
   2870 
   2871     if (show_builtin and root_src_file == null) {
   2872         // Without this, there will be no main module created and no zig
   2873         // compilation unit, and therefore also no builtin.zig contents
   2874         // created.
   2875         root_src_file = "builtin.zig";
   2876     }
   2877 
   2878     implicit_root_mod: {
   2879         const src_path = b: {
   2880             if (root_src_file) |src_path| {
   2881                 if (create_module.modules.count() != 0) {
   2882                     fatal("main module provided both by '-M{s}={s}{c}{s}' and by positional argument '{s}'", .{
   2883                         create_module.modules.keys()[0],
   2884                         create_module.modules.values()[0].root_path,
   2885                         fs.path.sep,
   2886                         create_module.modules.values()[0].root_src_path,
   2887                         src_path,
   2888                     });
   2889                 }
   2890                 create_module.opts.have_zcu = true;
   2891                 break :b src_path;
   2892             }
   2893 
   2894             if (create_module.modules.count() != 0)
   2895                 break :implicit_root_mod;
   2896 
   2897             if (create_module.c_source_files.items.len >= 1)
   2898                 break :b create_module.c_source_files.items[0].src_path;
   2899 
   2900             for (create_module.cli_link_inputs.items) |unresolved_link_input| switch (unresolved_link_input) {
   2901                 // Intentionally includes dynamic libraries provided by file path.
   2902                 .path_query => |pq| break :b pq.path.sub_path,
   2903                 else => continue,
   2904             };
   2905 
   2906             if (emit_bin == .yes)
   2907                 break :b emit_bin.yes;
   2908 
   2909             if (create_module.rc_source_files.items.len >= 1)
   2910                 break :b create_module.rc_source_files.items[0].src_path;
   2911 
   2912             if (arg_mode == .run)
   2913                 fatal("`zig run` expects at least one positional argument", .{});
   2914 
   2915             fatal("expected a positional argument, -femit-bin=[path], --show-builtin, or --name [name]", .{});
   2916 
   2917             break :implicit_root_mod;
   2918         };
   2919 
   2920         // See duplicate logic: ModCreationGlobalFlags
   2921         if (mod_opts.single_threaded == false)
   2922             create_module.opts.any_non_single_threaded = true;
   2923         if (mod_opts.sanitize_thread == true)
   2924             create_module.opts.any_sanitize_thread = true;
   2925         if (mod_opts.sanitize_c) |sc| switch (sc) {
   2926             .off => {},
   2927             .trap => if (create_module.opts.any_sanitize_c == .off) {
   2928                 create_module.opts.any_sanitize_c = .trap;
   2929             },
   2930             .full => create_module.opts.any_sanitize_c = .full,
   2931         };
   2932         if (mod_opts.fuzz == true)
   2933             create_module.opts.any_fuzz = true;
   2934         if (mod_opts.unwind_tables) |uwt| switch (uwt) {
   2935             .none => {},
   2936             .sync, .async => create_module.opts.any_unwind_tables = true,
   2937         };
   2938         if (mod_opts.strip == false)
   2939             create_module.opts.any_non_stripped = true;
   2940         if (mod_opts.error_tracing == true)
   2941             create_module.opts.any_error_tracing = true;
   2942 
   2943         const name = switch (arg_mode) {
   2944             .zig_test => "test",
   2945             .build, .cc, .cpp, .translate_c, .zig_test_obj, .run => fs.path.stem(fs.path.basename(src_path)),
   2946         };
   2947 
   2948         try create_module.modules.put(arena, name, .{
   2949             .root_path = fs.path.dirname(src_path) orelse ".",
   2950             .root_src_path = fs.path.basename(src_path),
   2951             .cc_argv = try cc_argv.toOwnedSlice(arena),
   2952             .inherited = mod_opts,
   2953             .target_arch_os_abi = target_arch_os_abi,
   2954             .target_mcpu = target_mcpu,
   2955             .deps = try deps.toOwnedSlice(arena),
   2956             .resolved = null,
   2957             .c_source_files_start = c_source_files_owner_index,
   2958             .c_source_files_end = create_module.c_source_files.items.len,
   2959             .rc_source_files_start = rc_source_files_owner_index,
   2960             .rc_source_files_end = create_module.rc_source_files.items.len,
   2961         });
   2962         cssan.reset();
   2963         mod_opts = .{};
   2964         target_arch_os_abi = null;
   2965         target_mcpu = null;
   2966         c_source_files_owner_index = create_module.c_source_files.items.len;
   2967         rc_source_files_owner_index = create_module.rc_source_files.items.len;
   2968     }
   2969 
   2970     if (!create_module.opts.have_zcu and create_module.opts.is_test) {
   2971         fatal("`zig test` expects a zig source file argument", .{});
   2972     }
   2973 
   2974     if (c_source_files_owner_index != create_module.c_source_files.items.len) {
   2975         fatal("C source file '{s}' has no parent module", .{
   2976             create_module.c_source_files.items[c_source_files_owner_index].src_path,
   2977         });
   2978     }
   2979 
   2980     if (rc_source_files_owner_index != create_module.rc_source_files.items.len) {
   2981         fatal("resource file '{s}' has no parent module", .{
   2982             create_module.rc_source_files.items[rc_source_files_owner_index].src_path,
   2983         });
   2984     }
   2985 
   2986     const self_exe_path = switch (native_os) {
   2987         .wasi => {},
   2988         else => fs.selfExePathAlloc(arena) catch |err| {
   2989             fatal("unable to find zig self exe path: {s}", .{@errorName(err)});
   2990         },
   2991     };
   2992 
   2993     // This `init` calls `fatal` on error.
   2994     var dirs: Compilation.Directories = .init(
   2995         arena,
   2996         override_lib_dir,
   2997         override_global_cache_dir,
   2998         s: {
   2999             if (override_local_cache_dir) |p| break :s .{ .override = p };
   3000             break :s switch (arg_mode) {
   3001                 .run => .global,
   3002                 else => .search,
   3003             };
   3004         },
   3005         if (native_os == .wasi) wasi_preopens,
   3006         self_exe_path,
   3007     );
   3008     defer dirs.deinit();
   3009 
   3010     if (linker_optimization) |o| {
   3011         warn("ignoring deprecated linker optimization setting '{s}'", .{o});
   3012     }
   3013 
   3014     create_module.dirs = dirs;
   3015     create_module.opts.emit_llvm_ir = emit_llvm_ir != .no;
   3016     create_module.opts.emit_llvm_bc = emit_llvm_bc != .no;
   3017     create_module.opts.emit_bin = emit_bin != .no;
   3018     create_module.opts.any_c_source_files = create_module.c_source_files.items.len != 0;
   3019 
   3020     const main_mod = try createModule(gpa, arena, &create_module, 0, null, color);
   3021     for (create_module.modules.keys(), create_module.modules.values()) |key, cli_mod| {
   3022         if (cli_mod.resolved == null)
   3023             fatal("module '{s}' declared but not used", .{key});
   3024     }
   3025 
   3026     // When you're testing std, the main module is std, and we need to avoid duplicating the module.
   3027     const main_mod_is_std = main_mod.root.root == .zig_lib and
   3028         mem.eql(u8, main_mod.root.sub_path, "std") and
   3029         mem.eql(u8, main_mod.root_src_path, "std.zig");
   3030 
   3031     const std_mod = m: {
   3032         if (main_mod_is_std) break :m main_mod;
   3033         if (create_module.modules.get("std")) |cli_mod| break :m cli_mod.resolved.?;
   3034         break :m null;
   3035     };
   3036 
   3037     const root_mod = switch (arg_mode) {
   3038         .zig_test, .zig_test_obj => root_mod: {
   3039             const test_mod = if (test_runner_path) |test_runner| test_mod: {
   3040                 const test_mod = try Package.Module.create(arena, .{
   3041                     .paths = .{
   3042                         .root = try .fromUnresolved(arena, dirs, &.{fs.path.dirname(test_runner) orelse "."}),
   3043                         .root_src_path = fs.path.basename(test_runner),
   3044                     },
   3045                     .fully_qualified_name = "root",
   3046                     .cc_argv = &.{},
   3047                     .inherited = .{},
   3048                     .global = create_module.resolved_options,
   3049                     .parent = main_mod,
   3050                 });
   3051                 test_mod.deps = try main_mod.deps.clone(arena);
   3052                 break :test_mod test_mod;
   3053             } else try Package.Module.create(arena, .{
   3054                 .paths = .{
   3055                     .root = try .fromRoot(arena, dirs, .zig_lib, "compiler"),
   3056                     .root_src_path = "test_runner.zig",
   3057                 },
   3058                 .fully_qualified_name = "root",
   3059                 .cc_argv = &.{},
   3060                 .inherited = .{},
   3061                 .global = create_module.resolved_options,
   3062                 .parent = main_mod,
   3063             });
   3064 
   3065             break :root_mod test_mod;
   3066         },
   3067         else => main_mod,
   3068     };
   3069 
   3070     const target = &main_mod.resolved_target.result;
   3071 
   3072     if (target.cpu.arch == .arc or target.cpu.arch.isNvptx()) {
   3073         if (emit_bin != .no and create_module.resolved_options.use_llvm) {
   3074             fatal("cannot emit {s} binary with the LLVM backend; only '-femit-asm' is supported", .{
   3075                 @tagName(target.cpu.arch),
   3076             });
   3077         }
   3078     }
   3079 
   3080     if (target.os.tag == .windows and major_subsystem_version == null and minor_subsystem_version == null) {
   3081         major_subsystem_version, minor_subsystem_version = switch (target.os.version_range.windows.min) {
   3082             .nt4 => .{ 4, 0 },
   3083             .win2k => .{ 5, 0 },
   3084             .xp => if (target.cpu.arch == .x86_64) .{ 5, 2 } else .{ 5, 1 },
   3085             .ws2003 => .{ 5, 2 },
   3086             else => .{ null, null },
   3087         };
   3088     }
   3089 
   3090     if (target.ofmt != .coff) {
   3091         if (manifest_file != null) {
   3092             fatal("manifest file is not allowed unless the target object format is coff (Windows/UEFI)", .{});
   3093         }
   3094         if (create_module.rc_source_files.items.len != 0) {
   3095             fatal("rc files are not allowed unless the target object format is coff (Windows/UEFI)", .{});
   3096         }
   3097         if (contains_res_file) {
   3098             fatal("res files are not allowed unless the target object format is coff (Windows/UEFI)", .{});
   3099         }
   3100     }
   3101 
   3102     var resolved_frameworks = std.array_list.Managed(Compilation.Framework).init(arena);
   3103 
   3104     if (create_module.frameworks.keys().len > 0) {
   3105         var test_path = std.array_list.Managed(u8).init(gpa);
   3106         defer test_path.deinit();
   3107 
   3108         var checked_paths = std.array_list.Managed(u8).init(gpa);
   3109         defer checked_paths.deinit();
   3110 
   3111         var failed_frameworks = std.array_list.Managed(struct {
   3112             name: []const u8,
   3113             checked_paths: []const u8,
   3114         }).init(arena);
   3115 
   3116         framework: for (create_module.frameworks.keys(), create_module.frameworks.values()) |framework_name, info| {
   3117             checked_paths.clearRetainingCapacity();
   3118 
   3119             for (create_module.framework_dirs.items) |framework_dir_path| {
   3120                 if (try accessFrameworkPath(
   3121                     &test_path,
   3122                     &checked_paths,
   3123                     framework_dir_path,
   3124                     framework_name,
   3125                 )) {
   3126                     const path = Path.initCwd(try arena.dupe(u8, test_path.items));
   3127                     try resolved_frameworks.append(.{
   3128                         .needed = info.needed,
   3129                         .weak = info.weak,
   3130                         .path = path,
   3131                     });
   3132                     continue :framework;
   3133                 }
   3134             }
   3135 
   3136             try failed_frameworks.append(.{
   3137                 .name = framework_name,
   3138                 .checked_paths = try arena.dupe(u8, checked_paths.items),
   3139             });
   3140         }
   3141 
   3142         if (failed_frameworks.items.len > 0) {
   3143             for (failed_frameworks.items) |f| {
   3144                 const searched_paths = if (f.checked_paths.len == 0) " none" else f.checked_paths;
   3145                 std.log.err("unable to find framework '{s}'. searched paths: {s}", .{
   3146                     f.name, searched_paths,
   3147                 });
   3148             }
   3149             process.exit(1);
   3150         }
   3151     }
   3152     // After this point, resolved_frameworks is used instead of frameworks.
   3153 
   3154     if (create_module.resolved_options.output_mode == .Obj and target.ofmt == .coff) {
   3155         const total_obj_count = create_module.c_source_files.items.len +
   3156             @intFromBool(root_src_file != null) +
   3157             create_module.rc_source_files.items.len +
   3158             link.countObjectInputs(create_module.link_inputs.items);
   3159         if (total_obj_count > 1) {
   3160             fatal("{s} does not support linking multiple objects into one", .{@tagName(target.ofmt)});
   3161         }
   3162     }
   3163 
   3164     var cleanup_emit_bin_dir: ?fs.Dir = null;
   3165     defer if (cleanup_emit_bin_dir) |*dir| dir.close();
   3166 
   3167     // For `zig run` and `zig test`, we don't want to put the binary in the cwd by default. So, if
   3168     // the binary is requested with no explicit path (as is the default), we emit to the cache.
   3169     const output_to_cache: ?Emit.OutputToCacheReason = switch (listen) {
   3170         .stdio, .ip4 => .listen,
   3171         .none => if (arg_mode == .run and emit_bin == .yes_default_path)
   3172             .@"zig run"
   3173         else if (arg_mode == .zig_test and emit_bin == .yes_default_path)
   3174             .@"zig test"
   3175         else
   3176             null,
   3177     };
   3178     const optional_version = if (have_version) version else null;
   3179 
   3180     const root_name = if (provided_name) |n| n else main_mod.fully_qualified_name;
   3181 
   3182     const resolved_soname: ?[]const u8 = switch (soname) {
   3183         .yes => |explicit| explicit,
   3184         .no => null,
   3185         .yes_default_value => switch (target.ofmt) {
   3186             .elf => if (have_version)
   3187                 try std.fmt.allocPrint(arena, "lib{s}.so.{d}", .{ root_name, version.major })
   3188             else
   3189                 try std.fmt.allocPrint(arena, "lib{s}.so", .{root_name}),
   3190             else => null,
   3191         },
   3192     };
   3193 
   3194     const emit_bin_resolved: Compilation.CreateOptions.Emit = switch (emit_bin) {
   3195         .no => .no,
   3196         .yes_default_path => emit: {
   3197             if (output_to_cache != null) break :emit .yes_cache;
   3198             const name = switch (clang_preprocessor_mode) {
   3199                 .pch => try std.fmt.allocPrint(arena, "{s}.pch", .{root_name}),
   3200                 else => try std.zig.binNameAlloc(arena, .{
   3201                     .root_name = root_name,
   3202                     .target = target,
   3203                     .output_mode = create_module.resolved_options.output_mode,
   3204                     .link_mode = create_module.resolved_options.link_mode,
   3205                     .version = optional_version,
   3206                 }),
   3207             };
   3208             break :emit .{ .yes_path = name };
   3209         },
   3210         .yes => |path| if (output_to_cache != null) {
   3211             assert(output_to_cache == .listen); // there was an explicit bin path
   3212             fatal("--listen incompatible with explicit output path '{s}'", .{path});
   3213         } else emit: {
   3214             // If there's a dirname, check that dir exists. This will give a more descriptive error than `Compilation` otherwise would.
   3215             if (fs.path.dirname(path)) |dir_path| {
   3216                 var dir = fs.cwd().openDir(dir_path, .{}) catch |err| {
   3217                     fatal("unable to open output directory '{s}': {s}", .{ dir_path, @errorName(err) });
   3218                 };
   3219                 dir.close();
   3220             }
   3221             break :emit .{ .yes_path = path };
   3222         },
   3223         .yes_a_out => emit: {
   3224             assert(output_to_cache == null);
   3225             break :emit .{ .yes_path = switch (target.ofmt) {
   3226                 .coff => "a.exe",
   3227                 else => "a.out",
   3228             } };
   3229         },
   3230     };
   3231 
   3232     const default_h_basename = try std.fmt.allocPrint(arena, "{s}.h", .{root_name});
   3233     const emit_h_resolved = emit_h.resolve(default_h_basename, output_to_cache);
   3234 
   3235     const default_asm_basename = try std.fmt.allocPrint(arena, "{s}.s", .{root_name});
   3236     const emit_asm_resolved = emit_asm.resolve(default_asm_basename, output_to_cache);
   3237 
   3238     const default_llvm_ir_basename = try std.fmt.allocPrint(arena, "{s}.ll", .{root_name});
   3239     const emit_llvm_ir_resolved = emit_llvm_ir.resolve(default_llvm_ir_basename, output_to_cache);
   3240 
   3241     const default_llvm_bc_basename = try std.fmt.allocPrint(arena, "{s}.bc", .{root_name});
   3242     const emit_llvm_bc_resolved = emit_llvm_bc.resolve(default_llvm_bc_basename, output_to_cache);
   3243 
   3244     const emit_docs_resolved = emit_docs.resolve("docs", output_to_cache);
   3245 
   3246     const is_exe_or_dyn_lib = switch (create_module.resolved_options.output_mode) {
   3247         .Obj => false,
   3248         .Lib => create_module.resolved_options.link_mode == .dynamic,
   3249         .Exe => true,
   3250     };
   3251     // Note that cmake when targeting Windows will try to execute
   3252     // zig cc to make an executable and output an implib too.
   3253     const implib_eligible = is_exe_or_dyn_lib and
   3254         emit_bin_resolved != .no and target.os.tag == .windows;
   3255     if (!implib_eligible) {
   3256         if (!emit_implib_arg_provided) {
   3257             emit_implib = .no;
   3258         } else if (emit_implib != .no) {
   3259             fatal("the argument -femit-implib is allowed only when building a Windows DLL", .{});
   3260         }
   3261     }
   3262     const default_implib_basename = try std.fmt.allocPrint(arena, "{s}.lib", .{root_name});
   3263     const emit_implib_resolved: Compilation.CreateOptions.Emit = switch (emit_implib) {
   3264         .no => .no,
   3265         .yes => emit_implib.resolve(default_implib_basename, output_to_cache),
   3266         .yes_default_path => emit: {
   3267             if (output_to_cache != null) break :emit .yes_cache;
   3268             const p = try fs.path.join(arena, &.{
   3269                 fs.path.dirname(emit_bin_resolved.yes_path) orelse ".",
   3270                 default_implib_basename,
   3271             });
   3272             break :emit .{ .yes_path = p };
   3273         },
   3274     };
   3275 
   3276     var thread_pool: ThreadPool = undefined;
   3277     try thread_pool.init(.{
   3278         .allocator = gpa,
   3279         .n_jobs = @min(@max(n_jobs orelse std.Thread.getCpuCount() catch 1, 1), std.math.maxInt(Zcu.PerThread.IdBacking)),
   3280         .track_ids = true,
   3281         .stack_size = thread_stack_size,
   3282     });
   3283     defer thread_pool.deinit();
   3284 
   3285     for (create_module.c_source_files.items) |*src| {
   3286         dev.check(.c_compiler);
   3287         if (!mem.eql(u8, src.src_path, "-")) continue;
   3288 
   3289         const ext = src.ext orelse
   3290             fatal("-E or -x is required when reading from a non-regular file", .{});
   3291 
   3292         // "-" is stdin. Dump it to a real file.
   3293         const sep = fs.path.sep_str;
   3294         const dump_path = try std.fmt.allocPrint(arena, "tmp" ++ sep ++ "{x}-dump-stdin{s}", .{
   3295             std.crypto.random.int(u64), ext.canonicalName(target),
   3296         });
   3297         try dirs.local_cache.handle.makePath("tmp");
   3298 
   3299         // Note that in one of the happy paths, execve() is used to switch to
   3300         // clang in which case any cleanup logic that exists for this temporary
   3301         // file will not run and this temp file will be leaked. The filename
   3302         // will be a hash of its contents — so multiple invocations of
   3303         // `zig cc -` will result in the same temp file name.
   3304         var f = try dirs.local_cache.handle.createFile(dump_path, .{});
   3305         defer f.close();
   3306 
   3307         // Re-using the hasher from Cache, since the functional requirements
   3308         // for the hashing algorithm here and in the cache are the same.
   3309         // We are providing our own cache key, because this file has nothing
   3310         // to do with the cache manifest.
   3311         var file_writer = f.writer(&.{});
   3312         var buffer: [1000]u8 = undefined;
   3313         var hasher = file_writer.interface.hashed(Cache.Hasher.init("0123456789abcdef"), &buffer);
   3314         var stdin_reader = fs.File.stdin().readerStreaming(&.{});
   3315         _ = hasher.writer.sendFileAll(&stdin_reader, .unlimited) catch |err| switch (err) {
   3316             error.WriteFailed => fatal("failed to write {s}: {t}", .{ dump_path, file_writer.err.? }),
   3317             else => fatal("failed to pipe stdin to {s}: {t}", .{ dump_path, err }),
   3318         };
   3319         try hasher.writer.flush();
   3320 
   3321         const bin_digest: Cache.BinDigest = hasher.hasher.finalResult();
   3322 
   3323         const sub_path = try std.fmt.allocPrint(arena, "tmp" ++ sep ++ "{x}-stdin{s}", .{
   3324             &bin_digest, ext.canonicalName(target),
   3325         });
   3326         try dirs.local_cache.handle.rename(dump_path, sub_path);
   3327 
   3328         // Convert `sub_path` to be relative to current working directory.
   3329         src.src_path = try dirs.local_cache.join(arena, &.{sub_path});
   3330     }
   3331 
   3332     if (build_options.have_llvm and emit_asm_resolved != .no) {
   3333         // LLVM has no way to set this non-globally.
   3334         const argv = [_][*:0]const u8{ "zig (LLVM option parsing)", "--x86-asm-syntax=intel" };
   3335         @import("codegen/llvm/bindings.zig").ParseCommandLineOptions(argv.len, &argv);
   3336     }
   3337 
   3338     const clang_passthrough_mode = switch (arg_mode) {
   3339         .cc, .cpp, .translate_c => true,
   3340         else => false,
   3341     };
   3342 
   3343     const incremental = create_module.resolved_options.incremental;
   3344     if (debug_incremental and !incremental) {
   3345         fatal("--debug-incremental requires -fincremental", .{});
   3346     }
   3347 
   3348     const cache_mode: Compilation.CacheMode = b: {
   3349         // Once incremental compilation is the default, we'll want some smarter logic here,
   3350         // considering things like the backend in use and whether there's a ZCU.
   3351         if (output_to_cache == null) break :b .none;
   3352         if (incremental) break :b .incremental;
   3353         break :b .whole;
   3354     };
   3355 
   3356     process.raiseFileDescriptorLimit();
   3357 
   3358     var file_system_inputs: std.ArrayListUnmanaged(u8) = .empty;
   3359     defer file_system_inputs.deinit(gpa);
   3360 
   3361     // Deduplicate rpath entries
   3362     var rpath_dedup = std.StringArrayHashMapUnmanaged(void){};
   3363     for (create_module.rpath_list.items) |rpath| {
   3364         try rpath_dedup.put(arena, rpath, {});
   3365     }
   3366     create_module.rpath_list.clearRetainingCapacity();
   3367     try create_module.rpath_list.appendSlice(arena, rpath_dedup.keys());
   3368 
   3369     var create_diag: Compilation.CreateDiagnostic = undefined;
   3370     const comp = Compilation.create(gpa, arena, &create_diag, .{
   3371         .dirs = dirs,
   3372         .thread_pool = &thread_pool,
   3373         .self_exe_path = switch (native_os) {
   3374             .wasi => null,
   3375             else => self_exe_path,
   3376         },
   3377         .config = create_module.resolved_options,
   3378         .root_name = root_name,
   3379         .sysroot = create_module.sysroot,
   3380         .main_mod = main_mod,
   3381         .root_mod = root_mod,
   3382         .std_mod = std_mod,
   3383         .emit_bin = emit_bin_resolved,
   3384         .emit_h = emit_h_resolved,
   3385         .emit_asm = emit_asm_resolved,
   3386         .emit_llvm_ir = emit_llvm_ir_resolved,
   3387         .emit_llvm_bc = emit_llvm_bc_resolved,
   3388         .emit_docs = emit_docs_resolved,
   3389         .emit_implib = emit_implib_resolved,
   3390         .lib_directories = create_module.lib_directories.items,
   3391         .rpath_list = create_module.rpath_list.items,
   3392         .symbol_wrap_set = symbol_wrap_set,
   3393         .c_source_files = create_module.c_source_files.items,
   3394         .rc_source_files = create_module.rc_source_files.items,
   3395         .manifest_file = manifest_file,
   3396         .rc_includes = rc_includes,
   3397         .mingw_unicode_entry_point = mingw_unicode_entry_point,
   3398         .link_inputs = create_module.link_inputs.items,
   3399         .framework_dirs = create_module.framework_dirs.items,
   3400         .frameworks = resolved_frameworks.items,
   3401         .windows_lib_names = create_module.windows_libs.keys(),
   3402         .want_compiler_rt = want_compiler_rt,
   3403         .want_ubsan_rt = want_ubsan_rt,
   3404         .hash_style = hash_style,
   3405         .linker_script = linker_script,
   3406         .version_script = version_script,
   3407         .linker_allow_undefined_version = linker_allow_undefined_version,
   3408         .linker_enable_new_dtags = linker_enable_new_dtags,
   3409         .disable_c_depfile = disable_c_depfile,
   3410         .soname = resolved_soname,
   3411         .linker_sort_section = linker_sort_section,
   3412         .linker_gc_sections = linker_gc_sections,
   3413         .linker_repro = linker_repro,
   3414         .linker_allow_shlib_undefined = linker_allow_shlib_undefined,
   3415         .linker_bind_global_refs_locally = linker_bind_global_refs_locally,
   3416         .linker_import_symbols = linker_import_symbols,
   3417         .linker_import_table = linker_import_table,
   3418         .linker_export_table = linker_export_table,
   3419         .linker_initial_memory = linker_initial_memory,
   3420         .linker_max_memory = linker_max_memory,
   3421         .linker_print_gc_sections = linker_print_gc_sections,
   3422         .linker_print_icf_sections = linker_print_icf_sections,
   3423         .linker_print_map = linker_print_map,
   3424         .llvm_opt_bisect_limit = llvm_opt_bisect_limit,
   3425         .linker_global_base = linker_global_base,
   3426         .linker_export_symbol_names = linker_export_symbol_names.items,
   3427         .linker_z_nocopyreloc = linker_z_nocopyreloc,
   3428         .linker_z_nodelete = linker_z_nodelete,
   3429         .linker_z_notext = linker_z_notext,
   3430         .linker_z_defs = linker_z_defs,
   3431         .linker_z_origin = linker_z_origin,
   3432         .linker_z_now = linker_z_now,
   3433         .linker_z_relro = linker_z_relro,
   3434         .linker_z_common_page_size = linker_z_common_page_size,
   3435         .linker_z_max_page_size = linker_z_max_page_size,
   3436         .linker_tsaware = linker_tsaware,
   3437         .linker_nxcompat = linker_nxcompat,
   3438         .linker_dynamicbase = linker_dynamicbase,
   3439         .linker_compress_debug_sections = linker_compress_debug_sections,
   3440         .linker_module_definition_file = linker_module_definition_file,
   3441         .major_subsystem_version = major_subsystem_version,
   3442         .minor_subsystem_version = minor_subsystem_version,
   3443         .link_eh_frame_hdr = link_eh_frame_hdr,
   3444         .link_emit_relocs = link_emit_relocs,
   3445         .entry = entry,
   3446         .force_undefined_symbols = force_undefined_symbols,
   3447         .stack_size = stack_size,
   3448         .image_base = image_base,
   3449         .function_sections = function_sections,
   3450         .data_sections = data_sections,
   3451         .clang_passthrough_mode = clang_passthrough_mode,
   3452         .clang_preprocessor_mode = clang_preprocessor_mode,
   3453         .version = optional_version,
   3454         .compatibility_version = compatibility_version,
   3455         .libc_installation = if (create_module.libc_installation) |*lci| lci else null,
   3456         .verbose_cc = verbose_cc,
   3457         .verbose_link = verbose_link,
   3458         .verbose_air = verbose_air,
   3459         .verbose_intern_pool = verbose_intern_pool,
   3460         .verbose_generic_instances = verbose_generic_instances,
   3461         .verbose_llvm_ir = verbose_llvm_ir,
   3462         .verbose_llvm_bc = verbose_llvm_bc,
   3463         .verbose_cimport = verbose_cimport,
   3464         .verbose_llvm_cpu_features = verbose_llvm_cpu_features,
   3465         .time_report = time_report,
   3466         .stack_report = stack_report,
   3467         .build_id = build_id,
   3468         .test_filters = test_filters.items,
   3469         .test_runner_path = test_runner_path,
   3470         .cache_mode = cache_mode,
   3471         .subsystem = subsystem,
   3472         .debug_compile_errors = debug_compile_errors,
   3473         .debug_incremental = debug_incremental,
   3474         .enable_link_snapshots = enable_link_snapshots,
   3475         .install_name = install_name,
   3476         .entitlements = entitlements,
   3477         .pagezero_size = pagezero_size,
   3478         .headerpad_size = headerpad_size,
   3479         .headerpad_max_install_names = headerpad_max_install_names,
   3480         .dead_strip_dylibs = dead_strip_dylibs,
   3481         .force_load_objc = force_load_objc,
   3482         .discard_local_symbols = discard_local_symbols,
   3483         .reference_trace = reference_trace,
   3484         .pdb_out_path = pdb_out_path,
   3485         .error_limit = error_limit,
   3486         .native_system_include_paths = create_module.native_system_include_paths,
   3487         // Any leftover C compilation args (such as -I) apply globally rather
   3488         // than to any particular module. This feature can greatly reduce CLI
   3489         // noise when --search-prefix and -M are combined.
   3490         .global_cc_argv = try cc_argv.toOwnedSlice(arena),
   3491         .file_system_inputs = &file_system_inputs,
   3492         .debug_compiler_runtime_libs = debug_compiler_runtime_libs,
   3493     }) catch |err| switch (err) {
   3494         error.CreateFail => switch (create_diag) {
   3495             .cross_libc_unavailable => {
   3496                 // We can emit a more informative error for this.
   3497                 const triple_name = try target.zigTriple(arena);
   3498                 std.log.err("unable to provide libc for target '{s}'", .{triple_name});
   3499 
   3500                 for (std.zig.target.available_libcs) |t| {
   3501                     if (t.arch == target.cpu.arch and t.os == target.os.tag) {
   3502                         // If there's a `glibc_min`, there's also an `os_ver`.
   3503                         if (t.glibc_min) |glibc_min| {
   3504                             std.log.info("zig can provide libc for related target {s}-{s}.{f}-{s}.{d}.{d}", .{
   3505                                 @tagName(t.arch),
   3506                                 @tagName(t.os),
   3507                                 t.os_ver.?,
   3508                                 @tagName(t.abi),
   3509                                 glibc_min.major,
   3510                                 glibc_min.minor,
   3511                             });
   3512                         } else if (t.os_ver) |os_ver| {
   3513                             std.log.info("zig can provide libc for related target {s}-{s}.{f}-{s}", .{
   3514                                 @tagName(t.arch),
   3515                                 @tagName(t.os),
   3516                                 os_ver,
   3517                                 @tagName(t.abi),
   3518                             });
   3519                         } else {
   3520                             std.log.info("zig can provide libc for related target {s}-{s}-{s}", .{
   3521                                 @tagName(t.arch),
   3522                                 @tagName(t.os),
   3523                                 @tagName(t.abi),
   3524                             });
   3525                         }
   3526                     }
   3527                 }
   3528                 process.exit(1);
   3529             },
   3530             else => fatal("{f}", .{create_diag}),
   3531         },
   3532         else => fatal("failed to create compilation: {s}", .{@errorName(err)}),
   3533     };
   3534     var comp_destroyed = false;
   3535     defer if (!comp_destroyed) comp.destroy();
   3536 
   3537     if (show_builtin) {
   3538         const builtin_opts = comp.root_mod.getBuiltinOptions(comp.config);
   3539         const source = try builtin_opts.generate(arena);
   3540         return fs.File.stdout().writeAll(source);
   3541     }
   3542     switch (listen) {
   3543         .none => {},
   3544         .stdio => {
   3545             var stdin_reader = fs.File.stdin().reader(&stdin_buffer);
   3546             var stdout_writer = fs.File.stdout().writer(&stdout_buffer);
   3547             try serve(
   3548                 comp,
   3549                 &stdin_reader.interface,
   3550                 &stdout_writer.interface,
   3551                 test_exec_args.items,
   3552                 self_exe_path,
   3553                 arg_mode,
   3554                 all_args,
   3555                 runtime_args_start,
   3556             );
   3557             return cleanExit();
   3558         },
   3559         .ip4 => |ip4_addr| {
   3560             const addr: std.net.Address = .{ .in = ip4_addr };
   3561 
   3562             var server = try addr.listen(.{
   3563                 .reuse_address = true,
   3564             });
   3565             defer server.deinit();
   3566 
   3567             const conn = try server.accept();
   3568             defer conn.stream.close();
   3569 
   3570             var input = conn.stream.reader(&stdin_buffer);
   3571             var output = conn.stream.writer(&stdout_buffer);
   3572 
   3573             try serve(
   3574                 comp,
   3575                 input.interface(),
   3576                 &output.interface,
   3577                 test_exec_args.items,
   3578                 self_exe_path,
   3579                 arg_mode,
   3580                 all_args,
   3581                 runtime_args_start,
   3582             );
   3583             return cleanExit();
   3584         },
   3585     }
   3586 
   3587     {
   3588         const root_prog_node = std.Progress.start(.{
   3589             .disable_printing = (color == .off),
   3590         });
   3591         defer root_prog_node.end();
   3592 
   3593         if (arg_mode == .translate_c) {
   3594             return cmdTranslateC(comp, arena, null, null, root_prog_node);
   3595         }
   3596 
   3597         updateModule(comp, color, root_prog_node) catch |err| switch (err) {
   3598             error.CompileErrorsReported => {
   3599                 assert(listen == .none);
   3600                 saveState(comp, incremental);
   3601                 process.exit(1);
   3602             },
   3603             else => |e| return e,
   3604         };
   3605     }
   3606     try comp.makeBinFileExecutable();
   3607     saveState(comp, incremental);
   3608 
   3609     if (switch (arg_mode) {
   3610         .run => true,
   3611         .zig_test => !test_no_exec,
   3612         else => false,
   3613     }) {
   3614         dev.checkAny(&.{ .run_command, .test_command });
   3615 
   3616         if (test_exec_args.items.len == 0 and target.ofmt == .c and emit_bin_resolved != .no) {
   3617             // Default to using `zig run` to execute the produced .c code from `zig test`.
   3618             try test_exec_args.appendSlice(arena, &.{ self_exe_path, "run" });
   3619             if (dirs.zig_lib.path) |p| {
   3620                 try test_exec_args.appendSlice(arena, &.{ "-I", p });
   3621             }
   3622 
   3623             if (create_module.resolved_options.link_libc) {
   3624                 try test_exec_args.append(arena, "-lc");
   3625             } else if (target.os.tag == .windows) {
   3626                 try test_exec_args.appendSlice(arena, &.{
   3627                     "--subsystem", "console",
   3628                     "-lkernel32",  "-lntdll",
   3629                 });
   3630             }
   3631 
   3632             const first_cli_mod = create_module.modules.values()[0];
   3633             if (first_cli_mod.target_arch_os_abi) |triple| {
   3634                 try test_exec_args.appendSlice(arena, &.{ "-target", triple });
   3635             }
   3636             if (first_cli_mod.target_mcpu) |mcpu| {
   3637                 try test_exec_args.append(arena, try std.fmt.allocPrint(arena, "-mcpu={s}", .{mcpu}));
   3638             }
   3639             if (create_module.dynamic_linker) |dl| {
   3640                 try test_exec_args.appendSlice(arena, &.{ "--dynamic-linker", dl });
   3641             }
   3642             try test_exec_args.append(arena, null); // placeholder for the path of the emitted C source file
   3643         }
   3644 
   3645         try runOrTest(
   3646             comp,
   3647             gpa,
   3648             arena,
   3649             test_exec_args.items,
   3650             self_exe_path,
   3651             arg_mode,
   3652             target,
   3653             &comp_destroyed,
   3654             all_args,
   3655             runtime_args_start,
   3656             create_module.resolved_options.link_libc,
   3657         );
   3658     }
   3659 
   3660     // Skip resource deallocation in release builds; let the OS do it.
   3661     return cleanExit();
   3662 }
   3663 
   3664 const CreateModule = struct {
   3665     dirs: Compilation.Directories,
   3666     modules: std.StringArrayHashMapUnmanaged(CliModule),
   3667     opts: Compilation.Config.Options,
   3668     dynamic_linker: ?[]const u8,
   3669     object_format: ?[]const u8,
   3670     /// undefined until createModule() for the root module is called.
   3671     resolved_options: Compilation.Config,
   3672 
   3673     /// This one is used while collecting CLI options. The set of libs is used
   3674     /// directly after computing the target and used to compute link_libc,
   3675     /// link_libcpp, and then the libraries are filtered into
   3676     /// `unresolved_link_inputs` and `windows_libs`.
   3677     cli_link_inputs: std.ArrayListUnmanaged(link.UnresolvedInput),
   3678     windows_libs: std.StringArrayHashMapUnmanaged(void),
   3679     /// The local variable `unresolved_link_inputs` is fed into library
   3680     /// resolution, mutating the input array, and producing this data as
   3681     /// output. Allocated with gpa.
   3682     link_inputs: std.ArrayListUnmanaged(link.Input),
   3683 
   3684     c_source_files: std.ArrayListUnmanaged(Compilation.CSourceFile),
   3685     rc_source_files: std.ArrayListUnmanaged(Compilation.RcSourceFile),
   3686 
   3687     /// e.g. -m3dnow or -mno-outline-atomics. They correspond to std.Target llvm cpu feature names.
   3688     /// This array is populated by zig cc frontend and then has to be converted to zig-style
   3689     /// CPU features.
   3690     llvm_m_args: std.ArrayListUnmanaged([]const u8),
   3691     sysroot: ?[]const u8,
   3692     lib_directories: std.ArrayListUnmanaged(Directory),
   3693     lib_dir_args: std.ArrayListUnmanaged([]const u8),
   3694     libc_installation: ?LibCInstallation,
   3695     want_native_include_dirs: bool,
   3696     frameworks: std.StringArrayHashMapUnmanaged(Framework),
   3697     native_system_include_paths: []const []const u8,
   3698     framework_dirs: std.ArrayListUnmanaged([]const u8),
   3699     rpath_list: std.ArrayListUnmanaged([]const u8),
   3700     each_lib_rpath: ?bool,
   3701     libc_paths_file: ?[]const u8,
   3702 };
   3703 
   3704 fn createModule(
   3705     gpa: Allocator,
   3706     arena: Allocator,
   3707     create_module: *CreateModule,
   3708     index: usize,
   3709     parent: ?*Package.Module,
   3710     color: std.zig.Color,
   3711 ) Allocator.Error!*Package.Module {
   3712     const cli_mod = &create_module.modules.values()[index];
   3713     if (cli_mod.resolved) |m| return m;
   3714 
   3715     const name = create_module.modules.keys()[index];
   3716 
   3717     cli_mod.inherited.resolved_target = t: {
   3718         // If the target is not overridden, use the parent's target. Of course,
   3719         // if this is the root module then we need to proceed to resolve the
   3720         // target.
   3721         if (cli_mod.target_arch_os_abi == null and cli_mod.target_mcpu == null) {
   3722             if (parent) |p| break :t p.resolved_target;
   3723         }
   3724 
   3725         var target_parse_options: std.Target.Query.ParseOptions = .{
   3726             .arch_os_abi = cli_mod.target_arch_os_abi orelse "native",
   3727             .cpu_features = cli_mod.target_mcpu,
   3728             .dynamic_linker = create_module.dynamic_linker,
   3729             .object_format = create_module.object_format,
   3730         };
   3731 
   3732         // Before passing the mcpu string in for parsing, we convert any -m flags that were
   3733         // passed in via zig cc to zig-style.
   3734         if (create_module.llvm_m_args.items.len != 0) {
   3735             // If this returns null, we let it fall through to the case below which will
   3736             // run the full parse function and do proper error handling.
   3737             if (std.Target.Query.parseCpuArch(target_parse_options)) |cpu_arch| {
   3738                 var llvm_to_zig_name = std.StringHashMap([]const u8).init(gpa);
   3739                 defer llvm_to_zig_name.deinit();
   3740 
   3741                 for (cpu_arch.allFeaturesList()) |feature| {
   3742                     const llvm_name = feature.llvm_name orelse continue;
   3743                     try llvm_to_zig_name.put(llvm_name, feature.name);
   3744                 }
   3745 
   3746                 var mcpu_buffer = std.array_list.Managed(u8).init(gpa);
   3747                 defer mcpu_buffer.deinit();
   3748 
   3749                 try mcpu_buffer.appendSlice(cli_mod.target_mcpu orelse "baseline");
   3750 
   3751                 for (create_module.llvm_m_args.items) |llvm_m_arg| {
   3752                     if (mem.cutPrefix(u8, llvm_m_arg, "mno-")) |llvm_name| {
   3753                         const zig_name = llvm_to_zig_name.get(llvm_name) orelse {
   3754                             fatal("target architecture {s} has no LLVM CPU feature named '{s}'", .{
   3755                                 @tagName(cpu_arch), llvm_name,
   3756                             });
   3757                         };
   3758                         try mcpu_buffer.append('-');
   3759                         try mcpu_buffer.appendSlice(zig_name);
   3760                     } else if (mem.cutPrefix(u8, llvm_m_arg, "m")) |llvm_name| {
   3761                         const zig_name = llvm_to_zig_name.get(llvm_name) orelse {
   3762                             fatal("target architecture {s} has no LLVM CPU feature named '{s}'", .{
   3763                                 @tagName(cpu_arch), llvm_name,
   3764                             });
   3765                         };
   3766                         try mcpu_buffer.append('+');
   3767                         try mcpu_buffer.appendSlice(zig_name);
   3768                     } else {
   3769                         unreachable;
   3770                     }
   3771                 }
   3772 
   3773                 const adjusted_target_mcpu = try arena.dupe(u8, mcpu_buffer.items);
   3774                 std.log.debug("adjusted target_mcpu: {s}", .{adjusted_target_mcpu});
   3775                 target_parse_options.cpu_features = adjusted_target_mcpu;
   3776             }
   3777         }
   3778 
   3779         const target_query = std.zig.parseTargetQueryOrReportFatalError(arena, target_parse_options);
   3780         const target = std.zig.resolveTargetQueryOrFatal(target_query);
   3781         break :t .{
   3782             .result = target,
   3783             .is_native_os = target_query.isNativeOs(),
   3784             .is_native_abi = target_query.isNativeAbi(),
   3785             .is_explicit_dynamic_linker = !target_query.dynamic_linker.eql(.none),
   3786         };
   3787     };
   3788 
   3789     if (parent == null) {
   3790         // This block is for initializing the fields of
   3791         // `Compilation.Config.Options` that require knowledge of the
   3792         // target (which was just now resolved for the root module above).
   3793         const resolved_target = &cli_mod.inherited.resolved_target.?;
   3794         create_module.opts.resolved_target = resolved_target.*;
   3795         create_module.opts.root_optimize_mode = cli_mod.inherited.optimize_mode;
   3796         create_module.opts.root_strip = cli_mod.inherited.strip;
   3797         create_module.opts.root_error_tracing = cli_mod.inherited.error_tracing;
   3798         const target = &resolved_target.result;
   3799 
   3800         // First, remove libc, libc++, and compiler_rt libraries from the system libraries list.
   3801         // We need to know whether the set of system libraries contains anything besides these
   3802         // to decide whether to trigger native path detection logic.
   3803         // Preserves linker input order.
   3804         var unresolved_link_inputs: std.ArrayListUnmanaged(link.UnresolvedInput) = .empty;
   3805         defer unresolved_link_inputs.deinit(gpa);
   3806         try unresolved_link_inputs.ensureUnusedCapacity(gpa, create_module.cli_link_inputs.items.len);
   3807         var any_name_queries_remaining = false;
   3808         for (create_module.cli_link_inputs.items) |cli_link_input| switch (cli_link_input) {
   3809             .name_query => |nq| {
   3810                 const lib_name = nq.name;
   3811 
   3812                 if (std.zig.target.isLibCLibName(target, lib_name)) {
   3813                     create_module.opts.link_libc = true;
   3814                     continue;
   3815                 }
   3816                 if (std.zig.target.isLibCxxLibName(target, lib_name)) {
   3817                     create_module.opts.link_libcpp = true;
   3818                     continue;
   3819                 }
   3820 
   3821                 switch (target_util.classifyCompilerRtLibName(lib_name)) {
   3822                     .none => {},
   3823                     .only_libunwind, .both => {
   3824                         create_module.opts.link_libunwind = true;
   3825                         continue;
   3826                     },
   3827                     .only_compiler_rt => continue,
   3828                 }
   3829 
   3830                 if (target.isMinGW()) {
   3831                     const exists = mingw.libExists(arena, target, create_module.dirs.zig_lib, lib_name) catch |err| {
   3832                         fatal("failed to check zig installation for DLL import libs: {s}", .{
   3833                             @errorName(err),
   3834                         });
   3835                     };
   3836                     if (exists) {
   3837                         try create_module.windows_libs.put(arena, lib_name, {});
   3838                         continue;
   3839                     }
   3840                 }
   3841 
   3842                 if (fs.path.isAbsolute(lib_name)) {
   3843                     fatal("cannot use absolute path as a system library: {s}", .{lib_name});
   3844                 }
   3845 
   3846                 unresolved_link_inputs.appendAssumeCapacity(cli_link_input);
   3847                 any_name_queries_remaining = true;
   3848             },
   3849             else => {
   3850                 unresolved_link_inputs.appendAssumeCapacity(cli_link_input);
   3851             },
   3852         }; // After this point, unresolved_link_inputs is used instead of cli_link_inputs.
   3853 
   3854         if (any_name_queries_remaining) create_module.want_native_include_dirs = true;
   3855 
   3856         // Resolve the library path arguments with respect to sysroot.
   3857         try create_module.lib_directories.ensureUnusedCapacity(arena, create_module.lib_dir_args.items.len);
   3858         if (create_module.sysroot) |root| {
   3859             for (create_module.lib_dir_args.items) |lib_dir_arg| {
   3860                 if (fs.path.isAbsolute(lib_dir_arg)) {
   3861                     const stripped_dir = lib_dir_arg[fs.path.diskDesignator(lib_dir_arg).len..];
   3862                     const full_path = try fs.path.join(arena, &[_][]const u8{ root, stripped_dir });
   3863                     addLibDirectoryWarn(&create_module.lib_directories, full_path);
   3864                 } else {
   3865                     addLibDirectoryWarn(&create_module.lib_directories, lib_dir_arg);
   3866                 }
   3867             }
   3868         } else {
   3869             for (create_module.lib_dir_args.items) |lib_dir_arg| {
   3870                 addLibDirectoryWarn(&create_module.lib_directories, lib_dir_arg);
   3871             }
   3872         }
   3873         create_module.lib_dir_args = undefined; // From here we use lib_directories instead.
   3874 
   3875         if (resolved_target.is_native_os and target.os.tag.isDarwin()) {
   3876             // If we want to link against frameworks, we need system headers.
   3877             if (create_module.frameworks.count() > 0)
   3878                 create_module.want_native_include_dirs = true;
   3879         }
   3880 
   3881         if (create_module.each_lib_rpath orelse resolved_target.is_native_os) {
   3882             try create_module.rpath_list.ensureUnusedCapacity(arena, create_module.lib_directories.items.len);
   3883             for (create_module.lib_directories.items) |lib_directory| {
   3884                 create_module.rpath_list.appendAssumeCapacity(lib_directory.path.?);
   3885             }
   3886         }
   3887 
   3888         // Trigger native system library path detection if necessary.
   3889         if (create_module.sysroot == null and
   3890             resolved_target.is_native_os and resolved_target.is_native_abi and
   3891             create_module.want_native_include_dirs)
   3892         {
   3893             var paths = std.zig.system.NativePaths.detect(arena, target) catch |err| {
   3894                 fatal("unable to detect native system paths: {s}", .{@errorName(err)});
   3895             };
   3896             for (paths.warnings.items) |warning| {
   3897                 warn("{s}", .{warning});
   3898             }
   3899 
   3900             create_module.native_system_include_paths = try paths.include_dirs.toOwnedSlice(arena);
   3901 
   3902             try create_module.framework_dirs.appendSlice(arena, paths.framework_dirs.items);
   3903             try create_module.rpath_list.appendSlice(arena, paths.rpaths.items);
   3904 
   3905             try create_module.lib_directories.ensureUnusedCapacity(arena, paths.lib_dirs.items.len);
   3906             for (paths.lib_dirs.items) |path| addLibDirectoryWarn2(&create_module.lib_directories, path, true);
   3907         }
   3908 
   3909         if (create_module.libc_paths_file) |paths_file| {
   3910             create_module.libc_installation = LibCInstallation.parse(arena, paths_file, target) catch |err| {
   3911                 fatal("unable to parse libc paths file at path {s}: {s}", .{
   3912                     paths_file, @errorName(err),
   3913                 });
   3914             };
   3915         }
   3916 
   3917         if (target.os.tag == .windows and (target.abi == .msvc or target.abi == .itanium) and
   3918             any_name_queries_remaining)
   3919         {
   3920             if (create_module.libc_installation == null) {
   3921                 create_module.libc_installation = LibCInstallation.findNative(.{
   3922                     .allocator = arena,
   3923                     .verbose = true,
   3924                     .target = target,
   3925                 }) catch |err| {
   3926                     fatal("unable to find native libc installation: {s}", .{@errorName(err)});
   3927                 };
   3928             }
   3929             try create_module.lib_directories.ensureUnusedCapacity(arena, 2);
   3930             addLibDirectoryWarn(&create_module.lib_directories, create_module.libc_installation.?.msvc_lib_dir.?);
   3931             addLibDirectoryWarn(&create_module.lib_directories, create_module.libc_installation.?.kernel32_lib_dir.?);
   3932         }
   3933 
   3934         // Destructively mutates but does not transfer ownership of `unresolved_link_inputs`.
   3935         link.resolveInputs(
   3936             gpa,
   3937             arena,
   3938             target,
   3939             &unresolved_link_inputs,
   3940             &create_module.link_inputs,
   3941             create_module.lib_directories.items,
   3942             color,
   3943         ) catch |err| fatal("failed to resolve link inputs: {s}", .{@errorName(err)});
   3944 
   3945         if (!create_module.opts.any_dyn_libs) for (create_module.link_inputs.items) |item| switch (item) {
   3946             .dso, .dso_exact => {
   3947                 create_module.opts.any_dyn_libs = true;
   3948                 break;
   3949             },
   3950             else => {},
   3951         };
   3952 
   3953         create_module.resolved_options = Compilation.Config.resolve(create_module.opts) catch |err| switch (err) {
   3954             error.WasiExecModelRequiresWasi => fatal("only WASI OS targets support execution model", .{}),
   3955             error.SharedMemoryIsWasmOnly => fatal("only WebAssembly CPU targets support shared memory", .{}),
   3956             error.ObjectFilesCannotShareMemory => fatal("object files cannot share memory", .{}),
   3957             error.SharedMemoryRequiresAtomicsAndBulkMemory => fatal("shared memory requires atomics and bulk_memory CPU features", .{}),
   3958             error.ThreadsRequireSharedMemory => fatal("threads require shared memory", .{}),
   3959             error.EmittingLlvmModuleRequiresLlvmBackend => fatal("emitting an LLVM module requires using the LLVM backend", .{}),
   3960             error.LlvmLacksTargetSupport => fatal("LLVM lacks support for the specified target", .{}),
   3961             error.ZigLacksTargetSupport => fatal("compiler backend unavailable for the specified target", .{}),
   3962             error.EmittingBinaryRequiresLlvmLibrary => fatal("producing machine code via LLVM requires using the LLVM library", .{}),
   3963             error.LldIncompatibleObjectFormat => fatal("using LLD to link {s} files is unsupported", .{@tagName(target.ofmt)}),
   3964             error.LldCannotIncrementallyLink => fatal("self-hosted backends do not support linking with LLD", .{}),
   3965             error.LtoRequiresLld => fatal("LTO requires using LLD", .{}),
   3966             error.SanitizeThreadRequiresLibCpp => fatal("thread sanitization is (for now) implemented in C++, so it requires linking libc++", .{}),
   3967             error.LibCRequiresLibUnwind => fatal("libc of the specified target requires linking libunwind", .{}),
   3968             error.LibCppRequiresLibUnwind => fatal("libc++ requires linking libunwind", .{}),
   3969             error.OsRequiresLibC => fatal("the target OS requires using libc as the stable syscall interface", .{}),
   3970             error.LibCppRequiresLibC => fatal("libc++ requires linking libc", .{}),
   3971             error.LibUnwindRequiresLibC => fatal("libunwind requires linking libc", .{}),
   3972             error.TargetCannotDynamicLink => fatal("dynamic linking unavailable on the specified target", .{}),
   3973             error.TargetCannotStaticLinkExecutables => fatal("static linking of executables unavailable on the specified target", .{}),
   3974             error.LibCRequiresDynamicLinking => fatal("libc of the specified target requires dynamic linking", .{}),
   3975             error.SharedLibrariesRequireDynamicLinking => fatal("using shared libraries requires dynamic linking", .{}),
   3976             error.ExportMemoryAndDynamicIncompatible => fatal("exporting memory is incompatible with dynamic linking", .{}),
   3977             error.DynamicLibraryPrecludesPie => fatal("dynamic libraries cannot be position independent executables", .{}),
   3978             error.TargetRequiresPie => fatal("the specified target requires position independent executables", .{}),
   3979             error.SanitizeThreadRequiresPie => fatal("thread sanitization requires position independent executables", .{}),
   3980             error.BackendLacksErrorTracing => fatal("the selected backend has not yet implemented error return tracing", .{}),
   3981             error.LlvmLibraryUnavailable => fatal("zig was compiled without LLVM libraries", .{}),
   3982             error.LldUnavailable => fatal("zig was compiled without LLD libraries", .{}),
   3983             error.ClangUnavailable => fatal("zig was compiled without Clang libraries", .{}),
   3984             error.DllExportFnsRequiresWindows => fatal("only Windows OS targets support DLLs", .{}),
   3985             error.NewLinkerIncompatibleObjectFormat => fatal("using the new linker to link {s} files is unsupported", .{@tagName(target.ofmt)}),
   3986             error.NewLinkerIncompatibleWithLld => fatal("using the new linker is incompatible with using lld", .{}),
   3987         };
   3988     }
   3989 
   3990     const root: Compilation.Path = try .fromUnresolved(arena, create_module.dirs, &.{cli_mod.root_path});
   3991 
   3992     const mod = Package.Module.create(arena, .{
   3993         .paths = .{
   3994             .root = root,
   3995             .root_src_path = cli_mod.root_src_path,
   3996         },
   3997         .fully_qualified_name = name,
   3998 
   3999         .cc_argv = cli_mod.cc_argv,
   4000         .inherited = cli_mod.inherited,
   4001         .global = create_module.resolved_options,
   4002         .parent = parent,
   4003     }) catch |err| switch (err) {
   4004         error.ValgrindUnsupportedOnTarget => fatal("unable to create module '{s}': valgrind does not support the selected target CPU architecture", .{name}),
   4005         error.TargetRequiresSingleThreaded => fatal("unable to create module '{s}': the selected target does not support multithreading", .{name}),
   4006         error.BackendRequiresSingleThreaded => fatal("unable to create module '{s}': the selected machine code backend is limited to single-threaded applications", .{name}),
   4007         error.TargetRequiresPic => fatal("unable to create module '{s}': the selected target requires position independent code", .{name}),
   4008         error.PieRequiresPic => fatal("unable to create module '{s}': making a Position Independent Executable requires enabling Position Independent Code", .{name}),
   4009         error.DynamicLinkingRequiresPic => fatal("unable to create module '{s}': dynamic linking requires enabling Position Independent Code", .{name}),
   4010         error.TargetHasNoRedZone => fatal("unable to create module '{s}': the selected target does not have a red zone", .{name}),
   4011         error.StackCheckUnsupportedByTarget => fatal("unable to create module '{s}': the selected target does not support stack checking", .{name}),
   4012         error.StackProtectorUnsupportedByTarget => fatal("unable to create module '{s}': the selected target does not support stack protection", .{name}),
   4013         error.StackProtectorUnavailableWithoutLibC => fatal("unable to create module '{s}': enabling stack protection requires libc", .{name}),
   4014         error.OutOfMemory => return error.OutOfMemory,
   4015     };
   4016     cli_mod.resolved = mod;
   4017 
   4018     for (create_module.c_source_files.items[cli_mod.c_source_files_start..cli_mod.c_source_files_end]) |*item| item.owner = mod;
   4019 
   4020     for (create_module.rc_source_files.items[cli_mod.rc_source_files_start..cli_mod.rc_source_files_end]) |*item| item.owner = mod;
   4021 
   4022     for (cli_mod.deps) |dep| {
   4023         const dep_index = create_module.modules.getIndex(dep.value) orelse
   4024             fatal("module '{s}' depends on non-existent module '{s}'", .{ name, dep.key });
   4025         const dep_mod = try createModule(gpa, arena, create_module, dep_index, mod, color);
   4026         try mod.deps.put(arena, dep.key, dep_mod);
   4027     }
   4028 
   4029     return mod;
   4030 }
   4031 
   4032 fn saveState(comp: *Compilation, incremental: bool) void {
   4033     if (incremental) {
   4034         comp.saveState() catch |err| {
   4035             warn("unable to save incremental compilation state: {s}", .{@errorName(err)});
   4036         };
   4037     }
   4038 }
   4039 
   4040 fn serve(
   4041     comp: *Compilation,
   4042     in: *std.Io.Reader,
   4043     out: *std.Io.Writer,
   4044     test_exec_args: []const ?[]const u8,
   4045     self_exe_path: ?[]const u8,
   4046     arg_mode: ArgMode,
   4047     all_args: []const []const u8,
   4048     runtime_args_start: ?usize,
   4049 ) !void {
   4050     const gpa = comp.gpa;
   4051 
   4052     var server = try Server.init(.{
   4053         .in = in,
   4054         .out = out,
   4055         .zig_version = build_options.version,
   4056     });
   4057 
   4058     var child_pid: ?std.process.Child.Id = null;
   4059 
   4060     const main_progress_node = std.Progress.start(.{});
   4061     const file_system_inputs = comp.file_system_inputs.?;
   4062 
   4063     const IncrementalDebugServer = if (build_options.enable_debug_extensions and !builtin.single_threaded)
   4064         @import("IncrementalDebugServer.zig")
   4065     else
   4066         void;
   4067 
   4068     var ids: IncrementalDebugServer = if (comp.debugIncremental()) ids: {
   4069         break :ids .init(comp.zcu orelse @panic("--debug-incremental requires a ZCU"));
   4070     } else undefined;
   4071     defer if (comp.debugIncremental()) ids.deinit();
   4072 
   4073     if (comp.debugIncremental()) ids.spawn();
   4074 
   4075     while (true) {
   4076         const hdr = try server.receiveMessage();
   4077 
   4078         // Lock the debug server while handling the message.
   4079         if (comp.debugIncremental()) ids.mutex.lock();
   4080         defer if (comp.debugIncremental()) ids.mutex.unlock();
   4081 
   4082         switch (hdr.tag) {
   4083             .exit => return cleanExit(),
   4084             .update => {
   4085                 tracy.frameMark();
   4086                 file_system_inputs.clearRetainingCapacity();
   4087 
   4088                 if (arg_mode == .translate_c) {
   4089                     var arena_instance = std.heap.ArenaAllocator.init(gpa);
   4090                     defer arena_instance.deinit();
   4091                     const arena = arena_instance.allocator();
   4092                     var output: Compilation.CImportResult = undefined;
   4093                     try cmdTranslateC(comp, arena, &output, file_system_inputs, main_progress_node);
   4094                     defer output.deinit(gpa);
   4095 
   4096                     if (file_system_inputs.items.len != 0) {
   4097                         try server.serveStringMessage(.file_system_inputs, file_system_inputs.items);
   4098                     }
   4099 
   4100                     if (output.errors.errorMessageCount() != 0) {
   4101                         try server.serveErrorBundle(output.errors);
   4102                     } else {
   4103                         try server.serveEmitDigest(&output.digest, .{
   4104                             .flags = .{ .cache_hit = output.cache_hit },
   4105                         });
   4106                     }
   4107 
   4108                     continue;
   4109                 }
   4110 
   4111                 if (comp.config.output_mode == .Exe) {
   4112                     try comp.makeBinFileWritable();
   4113                 }
   4114 
   4115                 try comp.update(main_progress_node);
   4116 
   4117                 try comp.makeBinFileExecutable();
   4118                 try serveUpdateResults(&server, comp);
   4119             },
   4120             .run => {
   4121                 if (child_pid != null) {
   4122                     @panic("TODO block until the child exits");
   4123                 }
   4124                 @panic("TODO call runOrTest");
   4125                 //try runOrTest(
   4126                 //    comp,
   4127                 //    gpa,
   4128                 //    arena,
   4129                 //    test_exec_args,
   4130                 //    self_exe_path.?,
   4131                 //    arg_mode,
   4132                 //    target,
   4133                 //    true,
   4134                 //    &comp_destroyed,
   4135                 //    all_args,
   4136                 //    runtime_args_start,
   4137                 //    link_libc,
   4138                 //);
   4139             },
   4140             .hot_update => {
   4141                 tracy.frameMark();
   4142                 file_system_inputs.clearRetainingCapacity();
   4143                 if (child_pid) |pid| {
   4144                     try comp.hotCodeSwap(main_progress_node, pid);
   4145                     try serveUpdateResults(&server, comp);
   4146                 } else {
   4147                     if (comp.config.output_mode == .Exe) {
   4148                         try comp.makeBinFileWritable();
   4149                     }
   4150                     try comp.update(main_progress_node);
   4151                     try comp.makeBinFileExecutable();
   4152                     try serveUpdateResults(&server, comp);
   4153 
   4154                     child_pid = try runOrTestHotSwap(
   4155                         comp,
   4156                         gpa,
   4157                         test_exec_args,
   4158                         self_exe_path.?,
   4159                         arg_mode,
   4160                         all_args,
   4161                         runtime_args_start,
   4162                     );
   4163                 }
   4164             },
   4165             else => {
   4166                 fatal("unrecognized message from client: 0x{x}", .{@intFromEnum(hdr.tag)});
   4167             },
   4168         }
   4169     }
   4170 }
   4171 
   4172 fn serveUpdateResults(s: *Server, comp: *Compilation) !void {
   4173     const gpa = comp.gpa;
   4174 
   4175     var error_bundle = try comp.getAllErrorsAlloc();
   4176     defer error_bundle.deinit(gpa);
   4177 
   4178     if (comp.file_system_inputs) |file_system_inputs| {
   4179         if (file_system_inputs.items.len == 0) {
   4180             assert(error_bundle.errorMessageCount() > 0);
   4181         } else {
   4182             try s.serveStringMessage(.file_system_inputs, file_system_inputs.items);
   4183         }
   4184     }
   4185 
   4186     if (comp.time_report) |*tr| {
   4187         var decls_len: u32 = 0;
   4188 
   4189         var file_name_bytes: std.ArrayListUnmanaged(u8) = .empty;
   4190         defer file_name_bytes.deinit(gpa);
   4191         var files: std.AutoArrayHashMapUnmanaged(Zcu.File.Index, void) = .empty;
   4192         defer files.deinit(gpa);
   4193         var decl_data: std.ArrayListUnmanaged(u8) = .empty;
   4194         defer decl_data.deinit(gpa);
   4195 
   4196         // Each decl needs at least 34 bytes:
   4197         // * 2 for 1-byte name plus null terminator
   4198         // * 4 for `file`
   4199         // * 4 for `sema_count`
   4200         // * 8 for `sema_ns`
   4201         // * 8 for `codegen_ns`
   4202         // * 8 for `link_ns`
   4203         // Most, if not all, decls in `tr.decl_sema_ns` are valid, so we have a good size estimate.
   4204         try decl_data.ensureUnusedCapacity(gpa, tr.decl_sema_info.count() * 34);
   4205 
   4206         for (tr.decl_sema_info.keys(), tr.decl_sema_info.values()) |tracked_inst, sema_info| {
   4207             const resolved = tracked_inst.resolveFull(&comp.zcu.?.intern_pool) orelse continue;
   4208             const file = comp.zcu.?.fileByIndex(resolved.file);
   4209             const zir = file.zir orelse continue;
   4210             const decl_name = zir.nullTerminatedString(zir.getDeclaration(resolved.inst).name);
   4211 
   4212             const gop = try files.getOrPut(gpa, resolved.file);
   4213             if (!gop.found_existing) try file_name_bytes.print(gpa, "{f}\x00", .{file.path.fmt(comp)});
   4214 
   4215             const codegen_ns = tr.decl_codegen_ns.get(tracked_inst) orelse 0;
   4216             const link_ns = tr.decl_link_ns.get(tracked_inst) orelse 0;
   4217 
   4218             decls_len += 1;
   4219 
   4220             try decl_data.ensureUnusedCapacity(gpa, 33 + decl_name.len);
   4221             decl_data.appendSliceAssumeCapacity(decl_name);
   4222             decl_data.appendAssumeCapacity(0);
   4223 
   4224             const out_file = decl_data.addManyAsArrayAssumeCapacity(4);
   4225             const out_sema_count = decl_data.addManyAsArrayAssumeCapacity(4);
   4226             const out_sema_ns = decl_data.addManyAsArrayAssumeCapacity(8);
   4227             const out_codegen_ns = decl_data.addManyAsArrayAssumeCapacity(8);
   4228             const out_link_ns = decl_data.addManyAsArrayAssumeCapacity(8);
   4229             std.mem.writeInt(u32, out_file, @intCast(gop.index), .little);
   4230             std.mem.writeInt(u32, out_sema_count, sema_info.count, .little);
   4231             std.mem.writeInt(u64, out_sema_ns, sema_info.ns, .little);
   4232             std.mem.writeInt(u64, out_codegen_ns, codegen_ns, .little);
   4233             std.mem.writeInt(u64, out_link_ns, link_ns, .little);
   4234         }
   4235 
   4236         const header: std.zig.Server.Message.TimeReport = .{
   4237             .stats = tr.stats,
   4238             .llvm_pass_timings_len = @intCast(tr.llvm_pass_timings.len),
   4239             .files_len = @intCast(files.count()),
   4240             .decls_len = decls_len,
   4241             .flags = .{
   4242                 .use_llvm = comp.zcu != null and comp.zcu.?.llvm_object != null,
   4243             },
   4244         };
   4245 
   4246         var slices: [4][]const u8 = .{
   4247             @ptrCast(&header),
   4248             tr.llvm_pass_timings,
   4249             file_name_bytes.items,
   4250             decl_data.items,
   4251         };
   4252         try s.serveMessageHeader(.{
   4253             .tag = .time_report,
   4254             .bytes_len = len: {
   4255                 var len: u32 = 0;
   4256                 for (slices) |slice| len += @intCast(slice.len);
   4257                 break :len len;
   4258             },
   4259         });
   4260         try s.out.writeVecAll(&slices);
   4261         try s.out.flush();
   4262     }
   4263 
   4264     if (error_bundle.errorMessageCount() > 0) {
   4265         try s.serveErrorBundle(error_bundle);
   4266         return;
   4267     }
   4268 
   4269     if (comp.digest) |digest| {
   4270         try s.serveEmitDigest(&digest, .{
   4271             .flags = .{ .cache_hit = comp.last_update_was_cache_hit },
   4272         });
   4273     }
   4274 
   4275     // Serve empty error bundle to indicate the update is done.
   4276     try s.serveErrorBundle(std.zig.ErrorBundle.empty);
   4277 }
   4278 
   4279 fn runOrTest(
   4280     comp: *Compilation,
   4281     gpa: Allocator,
   4282     arena: Allocator,
   4283     test_exec_args: []const ?[]const u8,
   4284     self_exe_path: []const u8,
   4285     arg_mode: ArgMode,
   4286     target: *const std.Target,
   4287     comp_destroyed: *bool,
   4288     all_args: []const []const u8,
   4289     runtime_args_start: ?usize,
   4290     link_libc: bool,
   4291 ) !void {
   4292     const raw_emit_bin = comp.emit_bin orelse return;
   4293     const exe_path = switch (comp.cache_use) {
   4294         .none => p: {
   4295             if (fs.path.isAbsolute(raw_emit_bin)) break :p raw_emit_bin;
   4296             // Use `fs.path.join` to make a file in the cwd is still executed properly.
   4297             break :p try fs.path.join(arena, &.{
   4298                 ".",
   4299                 raw_emit_bin,
   4300             });
   4301         },
   4302         .whole, .incremental => try comp.dirs.local_cache.join(arena, &.{
   4303             "o",
   4304             &Cache.binToHex(comp.digest.?),
   4305             raw_emit_bin,
   4306         }),
   4307     };
   4308 
   4309     var argv = std.array_list.Managed([]const u8).init(gpa);
   4310     defer argv.deinit();
   4311 
   4312     if (test_exec_args.len == 0) {
   4313         try argv.append(exe_path);
   4314         if (arg_mode == .zig_test) {
   4315             try argv.append(
   4316                 try std.fmt.allocPrint(arena, "--seed=0x{x}", .{std.crypto.random.int(u32)}),
   4317             );
   4318         }
   4319     } else {
   4320         for (test_exec_args) |arg| {
   4321             try argv.append(arg orelse exe_path);
   4322         }
   4323     }
   4324     if (runtime_args_start) |i| {
   4325         try argv.appendSlice(all_args[i..]);
   4326     }
   4327     var env_map = try process.getEnvMap(arena);
   4328     try env_map.put("ZIG_EXE", self_exe_path);
   4329 
   4330     // We do not execve for tests because if the test fails we want to print
   4331     // the error message and invocation below.
   4332     if (process.can_execv and arg_mode == .run) {
   4333         // execv releases the locks; no need to destroy the Compilation here.
   4334         std.debug.lockStdErr();
   4335         const err = process.execve(gpa, argv.items, &env_map);
   4336         std.debug.unlockStdErr();
   4337         try warnAboutForeignBinaries(arena, arg_mode, target, link_libc);
   4338         const cmd = try std.mem.join(arena, " ", argv.items);
   4339         fatal("the following command failed to execve with '{s}':\n{s}", .{ @errorName(err), cmd });
   4340     } else if (process.can_spawn) {
   4341         var child = std.process.Child.init(argv.items, gpa);
   4342         child.env_map = &env_map;
   4343         child.stdin_behavior = .Inherit;
   4344         child.stdout_behavior = .Inherit;
   4345         child.stderr_behavior = .Inherit;
   4346 
   4347         // Here we release all the locks associated with the Compilation so
   4348         // that whatever this child process wants to do won't deadlock.
   4349         comp.destroy();
   4350         comp_destroyed.* = true;
   4351 
   4352         const term_result = t: {
   4353             std.debug.lockStdErr();
   4354             defer std.debug.unlockStdErr();
   4355             break :t child.spawnAndWait();
   4356         };
   4357         const term = term_result catch |err| {
   4358             try warnAboutForeignBinaries(arena, arg_mode, target, link_libc);
   4359             const cmd = try std.mem.join(arena, " ", argv.items);
   4360             fatal("the following command failed with '{s}':\n{s}", .{ @errorName(err), cmd });
   4361         };
   4362         switch (arg_mode) {
   4363             .run, .build => {
   4364                 switch (term) {
   4365                     .Exited => |code| {
   4366                         if (code == 0) {
   4367                             return cleanExit();
   4368                         } else {
   4369                             process.exit(code);
   4370                         }
   4371                     },
   4372                     else => {
   4373                         process.exit(1);
   4374                     },
   4375                 }
   4376             },
   4377             .zig_test => {
   4378                 switch (term) {
   4379                     .Exited => |code| {
   4380                         if (code == 0) {
   4381                             return cleanExit();
   4382                         } else {
   4383                             const cmd = try std.mem.join(arena, " ", argv.items);
   4384                             fatal("the following test command failed with exit code {d}:\n{s}", .{ code, cmd });
   4385                         }
   4386                     },
   4387                     else => {
   4388                         const cmd = try std.mem.join(arena, " ", argv.items);
   4389                         fatal("the following test command crashed:\n{s}", .{cmd});
   4390                     },
   4391                 }
   4392             },
   4393             else => unreachable,
   4394         }
   4395     } else {
   4396         const cmd = try std.mem.join(arena, " ", argv.items);
   4397         fatal("the following command cannot be executed ({s} does not support spawning a child process):\n{s}", .{ @tagName(native_os), cmd });
   4398     }
   4399 }
   4400 
   4401 fn runOrTestHotSwap(
   4402     comp: *Compilation,
   4403     gpa: Allocator,
   4404     test_exec_args: []const ?[]const u8,
   4405     self_exe_path: []const u8,
   4406     arg_mode: ArgMode,
   4407     all_args: []const []const u8,
   4408     runtime_args_start: ?usize,
   4409 ) !std.process.Child.Id {
   4410     const lf = comp.bin_file.?;
   4411 
   4412     const exe_path = switch (builtin.target.os.tag) {
   4413         // On Windows it seems impossible to perform an atomic rename of a file that is currently
   4414         // running in a process. Therefore, we do the opposite. We create a copy of the file in
   4415         // tmp zig-cache and use it to spawn the child process. This way we are free to update
   4416         // the binary with each requested hot update.
   4417         .windows => blk: {
   4418             try lf.emit.root_dir.handle.copyFile(lf.emit.sub_path, comp.dirs.local_cache.handle, lf.emit.sub_path, .{});
   4419             break :blk try fs.path.join(gpa, &.{ comp.dirs.local_cache.path orelse ".", lf.emit.sub_path });
   4420         },
   4421 
   4422         // A naive `directory.join` here will indeed get the correct path to the binary,
   4423         // however, in the case of cwd, we actually want `./foo` so that the path can be executed.
   4424         else => try fs.path.join(gpa, &.{
   4425             lf.emit.root_dir.path orelse ".", lf.emit.sub_path,
   4426         }),
   4427     };
   4428     defer gpa.free(exe_path);
   4429 
   4430     var argv = std.array_list.Managed([]const u8).init(gpa);
   4431     defer argv.deinit();
   4432 
   4433     if (test_exec_args.len == 0) {
   4434         // when testing pass the zig_exe_path to argv
   4435         if (arg_mode == .zig_test)
   4436             try argv.appendSlice(&[_][]const u8{
   4437                 exe_path, self_exe_path,
   4438             })
   4439             // when running just pass the current exe
   4440         else
   4441             try argv.appendSlice(&[_][]const u8{
   4442                 exe_path,
   4443             });
   4444     } else {
   4445         for (test_exec_args) |arg| {
   4446             if (arg) |a| {
   4447                 try argv.append(a);
   4448             } else {
   4449                 try argv.appendSlice(&[_][]const u8{
   4450                     exe_path, self_exe_path,
   4451                 });
   4452             }
   4453         }
   4454     }
   4455     if (runtime_args_start) |i| {
   4456         try argv.appendSlice(all_args[i..]);
   4457     }
   4458 
   4459     switch (builtin.target.os.tag) {
   4460         .macos, .ios, .tvos, .watchos, .visionos => {
   4461             const PosixSpawn = @import("DarwinPosixSpawn.zig");
   4462 
   4463             var attr = try PosixSpawn.Attr.init();
   4464             defer attr.deinit();
   4465 
   4466             // ASLR is probably a good default for better debugging experience/programming
   4467             // with hot-code updates in mind. However, we can also make it work with ASLR on.
   4468             try attr.set(.{
   4469                 .SETSIGDEF = true,
   4470                 .SETSIGMASK = true,
   4471                 .DISABLE_ASLR = true,
   4472             });
   4473 
   4474             var arena_allocator = std.heap.ArenaAllocator.init(gpa);
   4475             defer arena_allocator.deinit();
   4476             const arena = arena_allocator.allocator();
   4477 
   4478             const argv_buf = try arena.allocSentinel(?[*:0]u8, argv.items.len, null);
   4479             for (argv.items, 0..) |arg, i| argv_buf[i] = (try arena.dupeZ(u8, arg)).ptr;
   4480 
   4481             const pid = try PosixSpawn.spawn(argv.items[0], null, attr, argv_buf, std.c.environ);
   4482             return pid;
   4483         },
   4484         else => {
   4485             var child = std.process.Child.init(argv.items, gpa);
   4486 
   4487             child.stdin_behavior = .Inherit;
   4488             child.stdout_behavior = .Inherit;
   4489             child.stderr_behavior = .Inherit;
   4490 
   4491             try child.spawn();
   4492 
   4493             return child.id;
   4494         },
   4495     }
   4496 }
   4497 
   4498 const UpdateModuleError = Compilation.UpdateError || error{
   4499     /// The update caused compile errors. The error bundle has already been
   4500     /// reported to the user by being rendered to stderr.
   4501     CompileErrorsReported,
   4502 };
   4503 fn updateModule(comp: *Compilation, color: Color, prog_node: std.Progress.Node) UpdateModuleError!void {
   4504     try comp.update(prog_node);
   4505 
   4506     var errors = try comp.getAllErrorsAlloc();
   4507     defer errors.deinit(comp.gpa);
   4508 
   4509     if (errors.errorMessageCount() > 0) {
   4510         errors.renderToStdErr(color.renderOptions());
   4511         return error.CompileErrorsReported;
   4512     }
   4513 }
   4514 
   4515 fn cmdTranslateC(
   4516     comp: *Compilation,
   4517     arena: Allocator,
   4518     fancy_output: ?*Compilation.CImportResult,
   4519     file_system_inputs: ?*std.ArrayListUnmanaged(u8),
   4520     prog_node: std.Progress.Node,
   4521 ) !void {
   4522     dev.check(.translate_c_command);
   4523 
   4524     assert(comp.c_source_files.len == 1);
   4525     const c_source_file = comp.c_source_files[0];
   4526 
   4527     const translated_basename = try std.fmt.allocPrint(arena, "{s}.zig", .{comp.root_name});
   4528 
   4529     var man: Cache.Manifest = comp.obtainCObjectCacheManifest(comp.root_mod);
   4530     man.want_shared_lock = false;
   4531     defer man.deinit();
   4532 
   4533     man.hash.add(@as(u16, 0xb945)); // Random number to distinguish translate-c from compiling C objects
   4534     man.hash.add(comp.config.c_frontend);
   4535     Compilation.cache_helpers.hashCSource(&man, c_source_file) catch |err| {
   4536         fatal("unable to process '{s}': {s}", .{ c_source_file.src_path, @errorName(err) });
   4537     };
   4538 
   4539     const result: Compilation.CImportResult = if (try man.hit()) .{
   4540         .digest = man.finalBin(),
   4541         .cache_hit = true,
   4542         .errors = std.zig.ErrorBundle.empty,
   4543     } else result: {
   4544         const result = try comp.translateC(
   4545             arena,
   4546             &man,
   4547             Compilation.classifyFileExt(c_source_file.src_path),
   4548             .{ .path = c_source_file.src_path },
   4549             translated_basename,
   4550             comp.root_mod,
   4551             prog_node,
   4552         );
   4553 
   4554         if (result.errors.errorMessageCount() != 0) {
   4555             if (fancy_output) |p| {
   4556                 if (file_system_inputs) |buf| try man.populateFileSystemInputs(buf);
   4557                 p.* = result;
   4558                 return;
   4559             } else {
   4560                 const color: Color = .auto;
   4561                 result.errors.renderToStdErr(color.renderOptions());
   4562                 process.exit(1);
   4563             }
   4564         }
   4565 
   4566         man.writeManifest() catch |err| warn("failed to write cache manifest: {t}", .{err});
   4567         break :result result;
   4568     };
   4569 
   4570     if (file_system_inputs) |buf| try man.populateFileSystemInputs(buf);
   4571     if (fancy_output) |p| {
   4572         p.* = result;
   4573     } else {
   4574         const hex_digest = Cache.binToHex(result.digest);
   4575         const out_zig_path = try fs.path.join(arena, &.{ "o", &hex_digest, translated_basename });
   4576         const zig_file = comp.dirs.local_cache.handle.openFile(out_zig_path, .{}) catch |err| {
   4577             const path = comp.dirs.local_cache.path orelse ".";
   4578             fatal("unable to open cached translated zig file '{s}{s}{s}': {s}", .{
   4579                 path,
   4580                 fs.path.sep_str,
   4581                 out_zig_path,
   4582                 @errorName(err),
   4583             });
   4584         };
   4585         defer zig_file.close();
   4586         var stdout_writer = fs.File.stdout().writer(&stdout_buffer);
   4587         var file_reader = zig_file.reader(&.{});
   4588         _ = try stdout_writer.interface.sendFileAll(&file_reader, .unlimited);
   4589         try stdout_writer.interface.flush();
   4590         return cleanExit();
   4591     }
   4592 }
   4593 
   4594 pub fn translateC(
   4595     gpa: Allocator,
   4596     arena: Allocator,
   4597     argv: []const []const u8,
   4598     prog_node: std.Progress.Node,
   4599     capture: ?*[]u8,
   4600 ) !void {
   4601     try jitCmd(gpa, arena, argv, .{
   4602         .cmd_name = "translate-c",
   4603         .root_src_path = "translate-c/main.zig",
   4604         .depend_on_aro = true,
   4605         .progress_node = prog_node,
   4606         .capture = capture,
   4607     });
   4608 }
   4609 
   4610 const usage_init =
   4611     \\Usage: zig init
   4612     \\
   4613     \\   Initializes a `zig build` project in the current working
   4614     \\   directory.
   4615     \\
   4616     \\Options:
   4617     \\  -m, --minimal          Use minimal init template
   4618     \\  -h, --help             Print this help and exit
   4619     \\
   4620     \\
   4621 ;
   4622 
   4623 fn cmdInit(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
   4624     dev.check(.init_command);
   4625 
   4626     var template: enum { example, minimal } = .example;
   4627     {
   4628         var i: usize = 0;
   4629         while (i < args.len) : (i += 1) {
   4630             const arg = args[i];
   4631             if (mem.startsWith(u8, arg, "-")) {
   4632                 if (mem.eql(u8, arg, "-m") or mem.eql(u8, arg, "--minimal")) {
   4633                     template = .minimal;
   4634                 } else if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
   4635                     try fs.File.stdout().writeAll(usage_init);
   4636                     return cleanExit();
   4637                 } else {
   4638                     fatal("unrecognized parameter: '{s}'", .{arg});
   4639                 }
   4640             } else {
   4641                 fatal("unexpected extra parameter: '{s}'", .{arg});
   4642             }
   4643         }
   4644     }
   4645 
   4646     const cwd_path = try introspect.getResolvedCwd(arena);
   4647     const cwd_basename = fs.path.basename(cwd_path);
   4648     const sanitized_root_name = try sanitizeExampleName(arena, cwd_basename);
   4649 
   4650     const fingerprint: Package.Fingerprint = .generate(sanitized_root_name);
   4651 
   4652     switch (template) {
   4653         .example => {
   4654             var templates = findTemplates(gpa, arena);
   4655             defer templates.deinit();
   4656 
   4657             const s = fs.path.sep_str;
   4658             const template_paths = [_][]const u8{
   4659                 Package.build_zig_basename,
   4660                 Package.Manifest.basename,
   4661                 "src" ++ s ++ "main.zig",
   4662                 "src" ++ s ++ "root.zig",
   4663             };
   4664             var ok_count: usize = 0;
   4665 
   4666             for (template_paths) |template_path| {
   4667                 if (templates.write(arena, fs.cwd(), sanitized_root_name, template_path, fingerprint)) |_| {
   4668                     std.log.info("created {s}", .{template_path});
   4669                     ok_count += 1;
   4670                 } else |err| switch (err) {
   4671                     error.PathAlreadyExists => std.log.info("preserving already existing file: {s}", .{
   4672                         template_path,
   4673                     }),
   4674                     else => std.log.err("unable to write {s}: {s}\n", .{ template_path, @errorName(err) }),
   4675                 }
   4676             }
   4677 
   4678             if (ok_count == template_paths.len) {
   4679                 std.log.info("see `zig build --help` for a menu of options", .{});
   4680             }
   4681             return cleanExit();
   4682         },
   4683         .minimal => {
   4684             writeSimpleTemplateFile(Package.Manifest.basename,
   4685                 \\.{{
   4686                 \\    .name = .{s},
   4687                 \\    .version = "0.0.1",
   4688                 \\    .minimum_zig_version = "{s}",
   4689                 \\    .paths = .{{""}},
   4690                 \\    .fingerprint = 0x{x},
   4691                 \\}}
   4692                 \\
   4693             , .{
   4694                 sanitized_root_name,
   4695                 build_options.version,
   4696                 fingerprint.int(),
   4697             }) catch |err| switch (err) {
   4698                 else => fatal("failed to create '{s}': {s}", .{ Package.Manifest.basename, @errorName(err) }),
   4699                 error.PathAlreadyExists => fatal("refusing to overwrite '{s}'", .{Package.Manifest.basename}),
   4700             };
   4701             writeSimpleTemplateFile(Package.build_zig_basename,
   4702                 \\const std = @import("std");
   4703                 \\
   4704                 \\pub fn build(b: *std.Build) void {{
   4705                 \\    _ = b; // stub
   4706                 \\}}
   4707                 \\
   4708             , .{}) catch |err| switch (err) {
   4709                 else => fatal("failed to create '{s}': {s}", .{ Package.build_zig_basename, @errorName(err) }),
   4710                 // `build.zig` already existing is okay: the user has just used `zig init` to set up
   4711                 // their `build.zig.zon` *after* writing their `build.zig`. So this one isn't fatal.
   4712                 error.PathAlreadyExists => {
   4713                     std.log.info("successfully populated '{s}', preserving existing '{s}'", .{ Package.Manifest.basename, Package.build_zig_basename });
   4714                     return cleanExit();
   4715                 },
   4716             };
   4717             std.log.info("successfully populated '{s}' and '{s}'", .{ Package.Manifest.basename, Package.build_zig_basename });
   4718             return cleanExit();
   4719         },
   4720     }
   4721 }
   4722 
   4723 fn sanitizeExampleName(arena: Allocator, bytes: []const u8) error{OutOfMemory}![]const u8 {
   4724     var result: std.ArrayListUnmanaged(u8) = .empty;
   4725     for (bytes, 0..) |byte, i| switch (byte) {
   4726         '0'...'9' => {
   4727             if (i == 0) try result.append(arena, '_');
   4728             try result.append(arena, byte);
   4729         },
   4730         '_', 'a'...'z', 'A'...'Z' => try result.append(arena, byte),
   4731         '-', '.', ' ' => try result.append(arena, '_'),
   4732         else => continue,
   4733     };
   4734     if (!std.zig.isValidId(result.items)) return "foo";
   4735     if (result.items.len > Package.Manifest.max_name_len)
   4736         result.shrinkRetainingCapacity(Package.Manifest.max_name_len);
   4737 
   4738     return result.toOwnedSlice(arena);
   4739 }
   4740 
   4741 test sanitizeExampleName {
   4742     var arena_instance = std.heap.ArenaAllocator.init(std.testing.allocator);
   4743     defer arena_instance.deinit();
   4744     const arena = arena_instance.allocator();
   4745 
   4746     try std.testing.expectEqualStrings("foo_bar", try sanitizeExampleName(arena, "foo bar+"));
   4747     try std.testing.expectEqualStrings("foo", try sanitizeExampleName(arena, ""));
   4748     try std.testing.expectEqualStrings("foo", try sanitizeExampleName(arena, "!"));
   4749     try std.testing.expectEqualStrings("a", try sanitizeExampleName(arena, "!a"));
   4750     try std.testing.expectEqualStrings("a_b", try sanitizeExampleName(arena, "a.b!"));
   4751     try std.testing.expectEqualStrings("_01234", try sanitizeExampleName(arena, "01234"));
   4752     try std.testing.expectEqualStrings("foo", try sanitizeExampleName(arena, "error"));
   4753     try std.testing.expectEqualStrings("foo", try sanitizeExampleName(arena, "test"));
   4754     try std.testing.expectEqualStrings("tests", try sanitizeExampleName(arena, "tests"));
   4755     try std.testing.expectEqualStrings("test_project", try sanitizeExampleName(arena, "test project"));
   4756 }
   4757 
   4758 fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
   4759     dev.check(.build_command);
   4760 
   4761     var build_file: ?[]const u8 = null;
   4762     var override_lib_dir: ?[]const u8 = try EnvVar.ZIG_LIB_DIR.get(arena);
   4763     var override_global_cache_dir: ?[]const u8 = try EnvVar.ZIG_GLOBAL_CACHE_DIR.get(arena);
   4764     var override_local_cache_dir: ?[]const u8 = try EnvVar.ZIG_LOCAL_CACHE_DIR.get(arena);
   4765     var override_build_runner: ?[]const u8 = try EnvVar.ZIG_BUILD_RUNNER.get(arena);
   4766     var child_argv = std.array_list.Managed([]const u8).init(arena);
   4767     var reference_trace: ?u32 = null;
   4768     var debug_compile_errors = false;
   4769     var verbose_link = (native_os != .wasi or builtin.link_libc) and
   4770         EnvVar.ZIG_VERBOSE_LINK.isSet();
   4771     var verbose_cc = (native_os != .wasi or builtin.link_libc) and
   4772         EnvVar.ZIG_VERBOSE_CC.isSet();
   4773     var verbose_air = false;
   4774     var verbose_intern_pool = false;
   4775     var verbose_generic_instances = false;
   4776     var verbose_llvm_ir: ?[]const u8 = null;
   4777     var verbose_llvm_bc: ?[]const u8 = null;
   4778     var verbose_cimport = false;
   4779     var verbose_llvm_cpu_features = false;
   4780     var fetch_only = false;
   4781     var fetch_mode: Package.Fetch.JobQueue.Mode = .needed;
   4782     var system_pkg_dir_path: ?[]const u8 = null;
   4783     var debug_target: ?[]const u8 = null;
   4784     var debug_libc_paths_file: ?[]const u8 = null;
   4785 
   4786     const argv_index_exe = child_argv.items.len;
   4787     _ = try child_argv.addOne();
   4788 
   4789     const self_exe_path = try fs.selfExePathAlloc(arena);
   4790     try child_argv.append(self_exe_path);
   4791 
   4792     const argv_index_zig_lib_dir = child_argv.items.len;
   4793     _ = try child_argv.addOne();
   4794 
   4795     const argv_index_build_file = child_argv.items.len;
   4796     _ = try child_argv.addOne();
   4797 
   4798     const argv_index_cache_dir = child_argv.items.len;
   4799     _ = try child_argv.addOne();
   4800 
   4801     const argv_index_global_cache_dir = child_argv.items.len;
   4802     _ = try child_argv.addOne();
   4803 
   4804     try child_argv.appendSlice(&.{
   4805         "--seed",
   4806         try std.fmt.allocPrint(arena, "0x{x}", .{std.crypto.random.int(u32)}),
   4807     });
   4808     const argv_index_seed = child_argv.items.len - 1;
   4809 
   4810     // This parent process needs a way to obtain results from the configuration
   4811     // phase of the child process. In the future, the make phase will be
   4812     // executed in a separate process than the configure phase, and we can then
   4813     // use stdout from the configuration phase for this purpose.
   4814     //
   4815     // However, currently, both phases are in the same process, and Run Step
   4816     // provides API for making the runned subprocesses inherit stdout and stderr
   4817     // which means these streams are not available for passing metadata back
   4818     // to the parent.
   4819     //
   4820     // Until make and configure phases are separated into different processes,
   4821     // the strategy is to choose a temporary file name ahead of time, and then
   4822     // read this file in the parent to obtain the results, in the case the child
   4823     // exits with code 3.
   4824     const results_tmp_file_nonce = std.fmt.hex(std.crypto.random.int(u64));
   4825     try child_argv.append("-Z" ++ results_tmp_file_nonce);
   4826 
   4827     var color: Color = .auto;
   4828     var n_jobs: ?u32 = null;
   4829 
   4830     {
   4831         var i: usize = 0;
   4832         while (i < args.len) : (i += 1) {
   4833             const arg = args[i];
   4834             if (mem.startsWith(u8, arg, "-")) {
   4835                 if (mem.eql(u8, arg, "--build-file")) {
   4836                     if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});
   4837                     i += 1;
   4838                     build_file = args[i];
   4839                     continue;
   4840                 } else if (mem.eql(u8, arg, "--zig-lib-dir")) {
   4841                     if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});
   4842                     i += 1;
   4843                     override_lib_dir = args[i];
   4844                     continue;
   4845                 } else if (mem.eql(u8, arg, "--build-runner")) {
   4846                     if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});
   4847                     i += 1;
   4848                     override_build_runner = args[i];
   4849                     continue;
   4850                 } else if (mem.eql(u8, arg, "--cache-dir")) {
   4851                     if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});
   4852                     i += 1;
   4853                     override_local_cache_dir = args[i];
   4854                     continue;
   4855                 } else if (mem.eql(u8, arg, "--global-cache-dir")) {
   4856                     if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});
   4857                     i += 1;
   4858                     override_global_cache_dir = args[i];
   4859                     continue;
   4860                 } else if (mem.eql(u8, arg, "-freference-trace")) {
   4861                     reference_trace = 256;
   4862                 } else if (mem.eql(u8, arg, "--fetch")) {
   4863                     fetch_only = true;
   4864                 } else if (mem.cutPrefix(u8, arg, "--fetch=")) |sub_arg| {
   4865                     fetch_only = true;
   4866                     fetch_mode = std.meta.stringToEnum(Package.Fetch.JobQueue.Mode, sub_arg) orelse
   4867                         fatal("expected [needed|all] after '--fetch=', found '{s}'", .{
   4868                             sub_arg,
   4869                         });
   4870                 } else if (mem.eql(u8, arg, "--system")) {
   4871                     if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});
   4872                     i += 1;
   4873                     system_pkg_dir_path = args[i];
   4874                     try child_argv.append("--system");
   4875                     continue;
   4876                 } else if (mem.cutPrefix(u8, arg, "-freference-trace=")) |num| {
   4877                     reference_trace = std.fmt.parseUnsigned(u32, num, 10) catch |err| {
   4878                         fatal("unable to parse reference_trace count '{s}': {s}", .{ num, @errorName(err) });
   4879                     };
   4880                 } else if (mem.eql(u8, arg, "-fno-reference-trace")) {
   4881                     reference_trace = null;
   4882                 } else if (mem.eql(u8, arg, "--debug-log")) {
   4883                     if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});
   4884                     try child_argv.appendSlice(args[i .. i + 2]);
   4885                     i += 1;
   4886                     if (!build_options.enable_logging) {
   4887                         warn("Zig was compiled without logging enabled (-Dlog). --debug-log has no effect.", .{});
   4888                     } else {
   4889                         try log_scopes.append(arena, args[i]);
   4890                     }
   4891                     continue;
   4892                 } else if (mem.eql(u8, arg, "--debug-compile-errors")) {
   4893                     if (build_options.enable_debug_extensions) {
   4894                         debug_compile_errors = true;
   4895                     } else {
   4896                         warn("Zig was compiled without debug extensions. --debug-compile-errors has no effect.", .{});
   4897                     }
   4898                 } else if (mem.eql(u8, arg, "--debug-target")) {
   4899                     if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});
   4900                     i += 1;
   4901                     if (build_options.enable_debug_extensions) {
   4902                         debug_target = args[i];
   4903                     } else {
   4904                         warn("Zig was compiled without debug extensions. --debug-target has no effect.", .{});
   4905                     }
   4906                 } else if (mem.eql(u8, arg, "--debug-libc")) {
   4907                     if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});
   4908                     i += 1;
   4909                     if (build_options.enable_debug_extensions) {
   4910                         debug_libc_paths_file = args[i];
   4911                     } else {
   4912                         warn("Zig was compiled without debug extensions. --debug-libc has no effect.", .{});
   4913                     }
   4914                 } else if (mem.eql(u8, arg, "--verbose-link")) {
   4915                     verbose_link = true;
   4916                 } else if (mem.eql(u8, arg, "--verbose-cc")) {
   4917                     verbose_cc = true;
   4918                 } else if (mem.eql(u8, arg, "--verbose-air")) {
   4919                     verbose_air = true;
   4920                 } else if (mem.eql(u8, arg, "--verbose-intern-pool")) {
   4921                     verbose_intern_pool = true;
   4922                 } else if (mem.eql(u8, arg, "--verbose-generic-instances")) {
   4923                     verbose_generic_instances = true;
   4924                 } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) {
   4925                     verbose_llvm_ir = "-";
   4926                 } else if (mem.cutPrefix(u8, arg, "--verbose-llvm-ir=")) |rest| {
   4927                     verbose_llvm_ir = rest;
   4928                 } else if (mem.cutPrefix(u8, arg, "--verbose-llvm-bc=")) |rest| {
   4929                     verbose_llvm_bc = rest;
   4930                 } else if (mem.eql(u8, arg, "--verbose-cimport")) {
   4931                     verbose_cimport = true;
   4932                 } else if (mem.eql(u8, arg, "--verbose-llvm-cpu-features")) {
   4933                     verbose_llvm_cpu_features = true;
   4934                 } else if (mem.eql(u8, arg, "--color")) {
   4935                     if (i + 1 >= args.len) fatal("expected [auto|on|off] after {s}", .{arg});
   4936                     i += 1;
   4937                     color = std.meta.stringToEnum(Color, args[i]) orelse {
   4938                         fatal("expected [auto|on|off] after {s}, found '{s}'", .{ arg, args[i] });
   4939                     };
   4940                     try child_argv.appendSlice(&.{ arg, args[i] });
   4941                     continue;
   4942                 } else if (mem.cutPrefix(u8, arg, "-j")) |str| {
   4943                     const num = std.fmt.parseUnsigned(u32, str, 10) catch |err| {
   4944                         fatal("unable to parse jobs count '{s}': {s}", .{
   4945                             str, @errorName(err),
   4946                         });
   4947                     };
   4948                     if (num < 1) {
   4949                         fatal("number of jobs must be at least 1\n", .{});
   4950                     }
   4951                     n_jobs = num;
   4952                 } else if (mem.eql(u8, arg, "--seed")) {
   4953                     if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});
   4954                     i += 1;
   4955                     child_argv.items[argv_index_seed] = args[i];
   4956                     continue;
   4957                 } else if (mem.eql(u8, arg, "--")) {
   4958                     // The rest of the args are supposed to get passed onto
   4959                     // build runner's `build.args`
   4960                     try child_argv.appendSlice(args[i..]);
   4961                     break;
   4962                 }
   4963             }
   4964             try child_argv.append(arg);
   4965         }
   4966     }
   4967 
   4968     const work_around_btrfs_bug = native_os == .linux and
   4969         EnvVar.ZIG_BTRFS_WORKAROUND.isSet();
   4970     const root_prog_node = std.Progress.start(.{
   4971         .disable_printing = (color == .off),
   4972         .root_name = "Compile Build Script",
   4973     });
   4974     defer root_prog_node.end();
   4975 
   4976     // Normally the build runner is compiled for the host target but here is
   4977     // some code to help when debugging edits to the build runner so that you
   4978     // can make sure it compiles successfully on other targets.
   4979     const resolved_target: Package.Module.ResolvedTarget = t: {
   4980         if (build_options.enable_debug_extensions) {
   4981             if (debug_target) |triple| {
   4982                 const target_query = try std.Target.Query.parse(.{
   4983                     .arch_os_abi = triple,
   4984                 });
   4985                 break :t .{
   4986                     .result = std.zig.resolveTargetQueryOrFatal(target_query),
   4987                     .is_native_os = false,
   4988                     .is_native_abi = false,
   4989                     .is_explicit_dynamic_linker = false,
   4990                 };
   4991             }
   4992         }
   4993         break :t .{
   4994             .result = std.zig.resolveTargetQueryOrFatal(.{}),
   4995             .is_native_os = true,
   4996             .is_native_abi = true,
   4997             .is_explicit_dynamic_linker = false,
   4998         };
   4999     };
   5000     // Likewise, `--debug-libc` allows overriding the libc installation.
   5001     const libc_installation: ?*const LibCInstallation = lci: {
   5002         const paths_file = debug_libc_paths_file orelse break :lci null;
   5003         if (!build_options.enable_debug_extensions) unreachable;
   5004         const lci = try arena.create(LibCInstallation);
   5005         lci.* = try .parse(arena, paths_file, &resolved_target.result);
   5006         break :lci lci;
   5007     };
   5008 
   5009     process.raiseFileDescriptorLimit();
   5010 
   5011     const cwd_path = try introspect.getResolvedCwd(arena);
   5012     const build_root = try findBuildRoot(arena, .{
   5013         .cwd_path = cwd_path,
   5014         .build_file = build_file,
   5015     });
   5016 
   5017     // This `init` calls `fatal` on error.
   5018     var dirs: Compilation.Directories = .init(
   5019         arena,
   5020         override_lib_dir,
   5021         override_global_cache_dir,
   5022         .{ .override = path: {
   5023             if (override_local_cache_dir) |d| break :path d;
   5024             break :path try build_root.directory.join(arena, &.{introspect.default_local_zig_cache_basename});
   5025         } },
   5026         {},
   5027         self_exe_path,
   5028     );
   5029     defer dirs.deinit();
   5030 
   5031     child_argv.items[argv_index_zig_lib_dir] = dirs.zig_lib.path orelse cwd_path;
   5032     child_argv.items[argv_index_build_file] = build_root.directory.path orelse cwd_path;
   5033     child_argv.items[argv_index_global_cache_dir] = dirs.global_cache.path orelse cwd_path;
   5034     child_argv.items[argv_index_cache_dir] = dirs.local_cache.path orelse cwd_path;
   5035 
   5036     var thread_pool: ThreadPool = undefined;
   5037     try thread_pool.init(.{
   5038         .allocator = gpa,
   5039         .n_jobs = @min(@max(n_jobs orelse std.Thread.getCpuCount() catch 1, 1), std.math.maxInt(Zcu.PerThread.IdBacking)),
   5040         .track_ids = true,
   5041         .stack_size = thread_stack_size,
   5042     });
   5043     defer thread_pool.deinit();
   5044 
   5045     // Dummy http client that is not actually used when fetch_command is unsupported.
   5046     // Prevents bootstrap from depending on a bunch of unnecessary stuff.
   5047     var http_client: if (dev.env.supports(.fetch_command)) std.http.Client else struct {
   5048         allocator: Allocator,
   5049         fn deinit(_: @This()) void {}
   5050     } = .{ .allocator = gpa };
   5051     defer http_client.deinit();
   5052 
   5053     var unlazy_set: Package.Fetch.JobQueue.UnlazySet = .{};
   5054 
   5055     // This loop is re-evaluated when the build script exits with an indication that it
   5056     // could not continue due to missing lazy dependencies.
   5057     while (true) {
   5058         // We want to release all the locks before executing the child process, so we make a nice
   5059         // big block here to ensure the cleanup gets run when we extract out our argv.
   5060         {
   5061             const main_mod_paths: Package.Module.CreateOptions.Paths = if (override_build_runner) |runner| .{
   5062                 .root = try .fromUnresolved(arena, dirs, &.{fs.path.dirname(runner) orelse "."}),
   5063                 .root_src_path = fs.path.basename(runner),
   5064             } else .{
   5065                 .root = try .fromRoot(arena, dirs, .zig_lib, "compiler"),
   5066                 .root_src_path = "build_runner.zig",
   5067             };
   5068 
   5069             const config = try Compilation.Config.resolve(.{
   5070                 .output_mode = .Exe,
   5071                 .resolved_target = resolved_target,
   5072                 .have_zcu = true,
   5073                 .emit_bin = true,
   5074                 .is_test = false,
   5075             });
   5076 
   5077             const root_mod = try Package.Module.create(arena, .{
   5078                 .paths = main_mod_paths,
   5079                 .fully_qualified_name = "root",
   5080                 .cc_argv = &.{},
   5081                 .inherited = .{
   5082                     .resolved_target = resolved_target,
   5083                 },
   5084                 .global = config,
   5085                 .parent = null,
   5086             });
   5087 
   5088             const build_mod = try Package.Module.create(arena, .{
   5089                 .paths = .{
   5090                     .root = try .fromUnresolved(arena, dirs, &.{build_root.directory.path orelse "."}),
   5091                     .root_src_path = build_root.build_zig_basename,
   5092                 },
   5093                 .fully_qualified_name = "root.@build",
   5094                 .cc_argv = &.{},
   5095                 .inherited = .{},
   5096                 .global = config,
   5097                 .parent = root_mod,
   5098             });
   5099 
   5100             var cleanup_build_dir: ?fs.Dir = null;
   5101             defer if (cleanup_build_dir) |*dir| dir.close();
   5102 
   5103             if (dev.env.supports(.fetch_command)) {
   5104                 const fetch_prog_node = root_prog_node.start("Fetch Packages", 0);
   5105                 defer fetch_prog_node.end();
   5106 
   5107                 var job_queue: Package.Fetch.JobQueue = .{
   5108                     .http_client = &http_client,
   5109                     .thread_pool = &thread_pool,
   5110                     .global_cache = dirs.global_cache,
   5111                     .read_only = false,
   5112                     .recursive = true,
   5113                     .debug_hash = false,
   5114                     .work_around_btrfs_bug = work_around_btrfs_bug,
   5115                     .unlazy_set = unlazy_set,
   5116                     .mode = fetch_mode,
   5117                 };
   5118                 defer job_queue.deinit();
   5119 
   5120                 if (system_pkg_dir_path) |p| {
   5121                     job_queue.global_cache = .{
   5122                         .path = p,
   5123                         .handle = fs.cwd().openDir(p, .{}) catch |err| {
   5124                             fatal("unable to open system package directory '{s}': {s}", .{
   5125                                 p, @errorName(err),
   5126                             });
   5127                         },
   5128                     };
   5129                     job_queue.read_only = true;
   5130                     cleanup_build_dir = job_queue.global_cache.handle;
   5131                 } else {
   5132                     try http_client.initDefaultProxies(arena);
   5133                 }
   5134 
   5135                 try job_queue.all_fetches.ensureUnusedCapacity(gpa, 1);
   5136                 try job_queue.table.ensureUnusedCapacity(gpa, 1);
   5137 
   5138                 const phantom_package_root: Cache.Path = .{ .root_dir = build_root.directory };
   5139 
   5140                 var fetch: Package.Fetch = .{
   5141                     .arena = std.heap.ArenaAllocator.init(gpa),
   5142                     .location = .{ .relative_path = phantom_package_root },
   5143                     .location_tok = 0,
   5144                     .hash_tok = .none,
   5145                     .name_tok = 0,
   5146                     .lazy_status = .eager,
   5147                     .parent_package_root = phantom_package_root,
   5148                     .parent_manifest_ast = null,
   5149                     .prog_node = fetch_prog_node,
   5150                     .job_queue = &job_queue,
   5151                     .omit_missing_hash_error = true,
   5152                     .allow_missing_paths_field = false,
   5153                     .allow_missing_fingerprint = false,
   5154                     .allow_name_string = false,
   5155                     .use_latest_commit = false,
   5156 
   5157                     .package_root = undefined,
   5158                     .error_bundle = undefined,
   5159                     .manifest = null,
   5160                     .manifest_ast = undefined,
   5161                     .computed_hash = undefined,
   5162                     .has_build_zig = true,
   5163                     .oom_flag = false,
   5164                     .latest_commit = null,
   5165 
   5166                     .module = build_mod,
   5167                 };
   5168                 job_queue.all_fetches.appendAssumeCapacity(&fetch);
   5169 
   5170                 job_queue.table.putAssumeCapacityNoClobber(
   5171                     Package.Fetch.relativePathDigest(phantom_package_root, dirs.global_cache),
   5172                     &fetch,
   5173                 );
   5174 
   5175                 job_queue.thread_pool.spawnWg(&job_queue.wait_group, Package.Fetch.workerRun, .{
   5176                     &fetch, "root",
   5177                 });
   5178                 job_queue.wait_group.wait();
   5179 
   5180                 try job_queue.consolidateErrors();
   5181 
   5182                 if (fetch.error_bundle.root_list.items.len > 0) {
   5183                     var errors = try fetch.error_bundle.toOwnedBundle("");
   5184                     errors.renderToStdErr(color.renderOptions());
   5185                     process.exit(1);
   5186                 }
   5187 
   5188                 if (fetch_only) return cleanExit();
   5189 
   5190                 var source_buf = std.array_list.Managed(u8).init(gpa);
   5191                 defer source_buf.deinit();
   5192                 try job_queue.createDependenciesSource(&source_buf);
   5193                 const deps_mod = try createDependenciesModule(
   5194                     arena,
   5195                     source_buf.items,
   5196                     root_mod,
   5197                     dirs,
   5198                     config,
   5199                 );
   5200 
   5201                 {
   5202                     // We need a Module for each package's build.zig.
   5203                     const hashes = job_queue.table.keys();
   5204                     const fetches = job_queue.table.values();
   5205                     try deps_mod.deps.ensureUnusedCapacity(arena, @intCast(hashes.len));
   5206                     for (hashes, fetches) |*hash, f| {
   5207                         if (f == &fetch) {
   5208                             // The first one is a dummy package for the current project.
   5209                             continue;
   5210                         }
   5211                         if (!f.has_build_zig)
   5212                             continue;
   5213                         const hash_slice = hash.toSlice();
   5214                         const mod_root_path = try f.package_root.toString(arena);
   5215                         const m = try Package.Module.create(arena, .{
   5216                             .paths = .{
   5217                                 .root = try .fromUnresolved(arena, dirs, &.{mod_root_path}),
   5218                                 .root_src_path = Package.build_zig_basename,
   5219                             },
   5220                             .fully_qualified_name = try std.fmt.allocPrint(
   5221                                 arena,
   5222                                 "root.@dependencies.{s}",
   5223                                 .{hash_slice},
   5224                             ),
   5225                             .cc_argv = &.{},
   5226                             .inherited = .{},
   5227                             .global = config,
   5228                             .parent = root_mod,
   5229                         });
   5230                         const hash_cloned = try arena.dupe(u8, hash_slice);
   5231                         deps_mod.deps.putAssumeCapacityNoClobber(hash_cloned, m);
   5232                         f.module = m;
   5233                     }
   5234 
   5235                     // Each build.zig module needs access to each of its
   5236                     // dependencies' build.zig modules by name.
   5237                     for (fetches) |f| {
   5238                         const mod = f.module orelse continue;
   5239                         const man = f.manifest orelse continue;
   5240                         const dep_names = man.dependencies.keys();
   5241                         try mod.deps.ensureUnusedCapacity(arena, @intCast(dep_names.len));
   5242                         for (dep_names, man.dependencies.values()) |name, dep| {
   5243                             const dep_digest = Package.Fetch.depDigest(
   5244                                 f.package_root,
   5245                                 dirs.global_cache,
   5246                                 dep,
   5247                             ) orelse continue;
   5248                             const dep_mod = job_queue.table.get(dep_digest).?.module orelse continue;
   5249                             const name_cloned = try arena.dupe(u8, name);
   5250                             mod.deps.putAssumeCapacityNoClobber(name_cloned, dep_mod);
   5251                         }
   5252                     }
   5253                 }
   5254             } else try createEmptyDependenciesModule(
   5255                 arena,
   5256                 root_mod,
   5257                 dirs,
   5258                 config,
   5259             );
   5260 
   5261             try root_mod.deps.put(arena, "@build", build_mod);
   5262 
   5263             var create_diag: Compilation.CreateDiagnostic = undefined;
   5264             const comp = Compilation.create(gpa, arena, &create_diag, .{
   5265                 .libc_installation = libc_installation,
   5266                 .dirs = dirs,
   5267                 .root_name = "build",
   5268                 .config = config,
   5269                 .root_mod = root_mod,
   5270                 .main_mod = build_mod,
   5271                 .emit_bin = .yes_cache,
   5272                 .self_exe_path = self_exe_path,
   5273                 .thread_pool = &thread_pool,
   5274                 .verbose_cc = verbose_cc,
   5275                 .verbose_link = verbose_link,
   5276                 .verbose_air = verbose_air,
   5277                 .verbose_intern_pool = verbose_intern_pool,
   5278                 .verbose_generic_instances = verbose_generic_instances,
   5279                 .verbose_llvm_ir = verbose_llvm_ir,
   5280                 .verbose_llvm_bc = verbose_llvm_bc,
   5281                 .verbose_cimport = verbose_cimport,
   5282                 .verbose_llvm_cpu_features = verbose_llvm_cpu_features,
   5283                 .cache_mode = .whole,
   5284                 .reference_trace = reference_trace,
   5285                 .debug_compile_errors = debug_compile_errors,
   5286             }) catch |err| switch (err) {
   5287                 error.CreateFail => fatal("failed to create compilation: {f}", .{create_diag}),
   5288                 else => fatal("failed to create compilation: {s}", .{@errorName(err)}),
   5289             };
   5290             defer comp.destroy();
   5291 
   5292             updateModule(comp, color, root_prog_node) catch |err| switch (err) {
   5293                 error.CompileErrorsReported => process.exit(2),
   5294                 else => |e| return e,
   5295             };
   5296 
   5297             // Since incremental compilation isn't done yet, we use cache_mode = whole
   5298             // above, and thus the output file is already closed.
   5299             //try comp.makeBinFileExecutable();
   5300             child_argv.items[argv_index_exe] = try dirs.local_cache.join(arena, &.{
   5301                 "o",
   5302                 &Cache.binToHex(comp.digest.?),
   5303                 comp.emit_bin.?,
   5304             });
   5305         }
   5306 
   5307         if (process.can_spawn) {
   5308             var child = std.process.Child.init(child_argv.items, gpa);
   5309             child.stdin_behavior = .Inherit;
   5310             child.stdout_behavior = .Inherit;
   5311             child.stderr_behavior = .Inherit;
   5312 
   5313             const term = t: {
   5314                 std.debug.lockStdErr();
   5315                 defer std.debug.unlockStdErr();
   5316                 break :t child.spawnAndWait() catch |err| {
   5317                     fatal("failed to spawn build runner {s}: {s}", .{ child_argv.items[0], @errorName(err) });
   5318                 };
   5319             };
   5320 
   5321             switch (term) {
   5322                 .Exited => |code| {
   5323                     if (code == 0) return cleanExit();
   5324                     // Indicates that the build runner has reported compile errors
   5325                     // and this parent process does not need to report any further
   5326                     // diagnostics.
   5327                     if (code == 2) process.exit(2);
   5328 
   5329                     if (code == 3) {
   5330                         if (!dev.env.supports(.fetch_command)) process.exit(3);
   5331                         // Indicates the configure phase failed due to missing lazy
   5332                         // dependencies and stdout contains the hashes of the ones
   5333                         // that are missing.
   5334                         const s = fs.path.sep_str;
   5335                         const tmp_sub_path = "tmp" ++ s ++ results_tmp_file_nonce;
   5336                         const stdout = dirs.local_cache.handle.readFileAlloc(tmp_sub_path, arena, .limited(50 * 1024 * 1024)) catch |err| {
   5337                             fatal("unable to read results of configure phase from '{f}{s}': {s}", .{
   5338                                 dirs.local_cache, tmp_sub_path, @errorName(err),
   5339                             });
   5340                         };
   5341                         dirs.local_cache.handle.deleteFile(tmp_sub_path) catch {};
   5342 
   5343                         var it = mem.splitScalar(u8, stdout, '\n');
   5344                         var any_errors = false;
   5345                         while (it.next()) |hash| {
   5346                             if (hash.len == 0) continue;
   5347                             if (hash.len > Package.Hash.max_len) {
   5348                                 std.log.err("invalid digest (length {d} exceeds maximum): '{s}'", .{
   5349                                     hash.len, hash,
   5350                                 });
   5351                                 any_errors = true;
   5352                                 continue;
   5353                             }
   5354                             try unlazy_set.put(arena, .fromSlice(hash), {});
   5355                         }
   5356                         if (any_errors) process.exit(3);
   5357                         if (system_pkg_dir_path) |p| {
   5358                             // In this mode, the system needs to provide these packages; they
   5359                             // cannot be fetched by Zig.
   5360                             for (unlazy_set.keys()) |*hash| {
   5361                                 std.log.err("lazy dependency package not found: {s}" ++ s ++ "{s}", .{
   5362                                     p, hash.toSlice(),
   5363                                 });
   5364                             }
   5365                             std.log.info("remote package fetching disabled due to --system mode", .{});
   5366                             std.log.info("dependencies might be avoidable depending on build configuration", .{});
   5367                             process.exit(3);
   5368                         }
   5369                         continue;
   5370                     }
   5371 
   5372                     const cmd = try std.mem.join(arena, " ", child_argv.items);
   5373                     fatal("the following build command failed with exit code {d}:\n{s}", .{ code, cmd });
   5374                 },
   5375                 else => {
   5376                     const cmd = try std.mem.join(arena, " ", child_argv.items);
   5377                     fatal("the following build command crashed:\n{s}", .{cmd});
   5378                 },
   5379             }
   5380         } else {
   5381             const cmd = try std.mem.join(arena, " ", child_argv.items);
   5382             fatal("the following command cannot be executed ({s} does not support spawning a child process):\n{s}", .{ @tagName(native_os), cmd });
   5383         }
   5384     }
   5385 }
   5386 
   5387 const JitCmdOptions = struct {
   5388     cmd_name: []const u8,
   5389     root_src_path: []const u8,
   5390     prepend_zig_lib_dir_path: bool = false,
   5391     prepend_global_cache_path: bool = false,
   5392     prepend_zig_exe_path: bool = false,
   5393     depend_on_aro: bool = false,
   5394     capture: ?*[]u8 = null,
   5395     /// Send error bundles via std.zig.Server over stdout
   5396     server: bool = false,
   5397     progress_node: ?std.Progress.Node = null,
   5398 };
   5399 
   5400 fn jitCmd(
   5401     gpa: Allocator,
   5402     arena: Allocator,
   5403     args: []const []const u8,
   5404     options: JitCmdOptions,
   5405 ) !void {
   5406     dev.check(.jit_command);
   5407 
   5408     const color: Color = .auto;
   5409     const root_prog_node = if (options.progress_node) |node| node else std.Progress.start(.{
   5410         .disable_printing = (color == .off),
   5411     });
   5412 
   5413     const target_query: std.Target.Query = .{};
   5414     const resolved_target: Package.Module.ResolvedTarget = .{
   5415         .result = std.zig.resolveTargetQueryOrFatal(target_query),
   5416         .is_native_os = true,
   5417         .is_native_abi = true,
   5418         .is_explicit_dynamic_linker = false,
   5419     };
   5420 
   5421     const self_exe_path = fs.selfExePathAlloc(arena) catch |err| {
   5422         fatal("unable to find self exe path: {s}", .{@errorName(err)});
   5423     };
   5424 
   5425     const optimize_mode: std.builtin.OptimizeMode = if (EnvVar.ZIG_DEBUG_CMD.isSet())
   5426         .Debug
   5427     else
   5428         .ReleaseFast;
   5429     const strip = optimize_mode != .Debug;
   5430     const override_lib_dir: ?[]const u8 = try EnvVar.ZIG_LIB_DIR.get(arena);
   5431     const override_global_cache_dir: ?[]const u8 = try EnvVar.ZIG_GLOBAL_CACHE_DIR.get(arena);
   5432 
   5433     // This `init` calls `fatal` on error.
   5434     var dirs: Compilation.Directories = .init(
   5435         arena,
   5436         override_lib_dir,
   5437         override_global_cache_dir,
   5438         .global,
   5439         if (native_os == .wasi) wasi_preopens,
   5440         self_exe_path,
   5441     );
   5442     defer dirs.deinit();
   5443 
   5444     var thread_pool: ThreadPool = undefined;
   5445     try thread_pool.init(.{
   5446         .allocator = gpa,
   5447         .n_jobs = @min(@max(std.Thread.getCpuCount() catch 1, 1), std.math.maxInt(Zcu.PerThread.IdBacking)),
   5448         .track_ids = true,
   5449         .stack_size = thread_stack_size,
   5450     });
   5451     defer thread_pool.deinit();
   5452 
   5453     var child_argv: std.ArrayListUnmanaged([]const u8) = .empty;
   5454     try child_argv.ensureUnusedCapacity(arena, args.len + 4);
   5455 
   5456     // We want to release all the locks before executing the child process, so we make a nice
   5457     // big block here to ensure the cleanup gets run when we extract out our argv.
   5458     {
   5459         const main_mod_paths: Package.Module.CreateOptions.Paths = .{
   5460             .root = try .fromRoot(arena, dirs, .zig_lib, "compiler"),
   5461             .root_src_path = options.root_src_path,
   5462         };
   5463 
   5464         const config = try Compilation.Config.resolve(.{
   5465             .output_mode = .Exe,
   5466             .root_strip = strip,
   5467             .root_optimize_mode = optimize_mode,
   5468             .resolved_target = resolved_target,
   5469             .have_zcu = true,
   5470             .emit_bin = true,
   5471             .is_test = false,
   5472         });
   5473 
   5474         const root_mod = try Package.Module.create(arena, .{
   5475             .paths = main_mod_paths,
   5476             .fully_qualified_name = "root",
   5477             .cc_argv = &.{},
   5478             .inherited = .{
   5479                 .resolved_target = resolved_target,
   5480                 .optimize_mode = optimize_mode,
   5481                 .strip = strip,
   5482             },
   5483             .global = config,
   5484             .parent = null,
   5485         });
   5486 
   5487         if (options.depend_on_aro) {
   5488             const aro_mod = try Package.Module.create(arena, .{
   5489                 .paths = .{
   5490                     .root = try .fromRoot(arena, dirs, .zig_lib, "compiler/aro"),
   5491                     .root_src_path = "aro.zig",
   5492                 },
   5493                 .fully_qualified_name = "aro",
   5494                 .cc_argv = &.{},
   5495                 .inherited = .{
   5496                     .resolved_target = resolved_target,
   5497                     .optimize_mode = optimize_mode,
   5498                     .strip = strip,
   5499                 },
   5500                 .global = config,
   5501                 .parent = null,
   5502             });
   5503             try root_mod.deps.put(arena, "aro", aro_mod);
   5504         }
   5505 
   5506         var create_diag: Compilation.CreateDiagnostic = undefined;
   5507         const comp = Compilation.create(gpa, arena, &create_diag, .{
   5508             .dirs = dirs,
   5509             .root_name = options.cmd_name,
   5510             .config = config,
   5511             .root_mod = root_mod,
   5512             .main_mod = root_mod,
   5513             .emit_bin = .yes_cache,
   5514             .self_exe_path = self_exe_path,
   5515             .thread_pool = &thread_pool,
   5516             .cache_mode = .whole,
   5517         }) catch |err| switch (err) {
   5518             error.CreateFail => fatal("failed to create compilation: {f}", .{create_diag}),
   5519             else => fatal("failed to create compilation: {s}", .{@errorName(err)}),
   5520         };
   5521         defer comp.destroy();
   5522 
   5523         if (options.server) {
   5524             var stdout_writer = fs.File.stdout().writer(&stdout_buffer);
   5525             var server: std.zig.Server = .{
   5526                 .out = &stdout_writer.interface,
   5527                 .in = undefined, // won't be receiving messages
   5528             };
   5529 
   5530             try comp.update(root_prog_node);
   5531 
   5532             var error_bundle = try comp.getAllErrorsAlloc();
   5533             defer error_bundle.deinit(comp.gpa);
   5534             if (error_bundle.errorMessageCount() > 0) {
   5535                 try server.serveErrorBundle(error_bundle);
   5536                 process.exit(2);
   5537             }
   5538         } else {
   5539             updateModule(comp, color, root_prog_node) catch |err| switch (err) {
   5540                 error.CompileErrorsReported => process.exit(2),
   5541                 else => |e| return e,
   5542             };
   5543         }
   5544 
   5545         const exe_path = try dirs.global_cache.join(arena, &.{
   5546             "o",
   5547             &Cache.binToHex(comp.digest.?),
   5548             comp.emit_bin.?,
   5549         });
   5550         child_argv.appendAssumeCapacity(exe_path);
   5551     }
   5552 
   5553     if (options.prepend_zig_lib_dir_path)
   5554         child_argv.appendAssumeCapacity(dirs.zig_lib.path.?);
   5555     if (options.prepend_zig_exe_path)
   5556         child_argv.appendAssumeCapacity(self_exe_path);
   5557     if (options.prepend_global_cache_path)
   5558         child_argv.appendAssumeCapacity(dirs.global_cache.path.?);
   5559 
   5560     child_argv.appendSliceAssumeCapacity(args);
   5561 
   5562     if (process.can_execv and options.capture == null) {
   5563         if (EnvVar.ZIG_DEBUG_CMD.isSet()) {
   5564             const cmd = try std.mem.join(arena, " ", child_argv.items);
   5565             std.debug.print("{s}\n", .{cmd});
   5566         }
   5567         const err = process.execv(gpa, child_argv.items);
   5568         const cmd = try std.mem.join(arena, " ", child_argv.items);
   5569         fatal("the following command failed to execve with '{t}':\n{s}", .{ err, cmd });
   5570     }
   5571 
   5572     if (!process.can_spawn) {
   5573         const cmd = try std.mem.join(arena, " ", child_argv.items);
   5574         fatal("the following command cannot be executed ({s} does not support spawning a child process):\n{s}", .{
   5575             @tagName(native_os), cmd,
   5576         });
   5577     }
   5578 
   5579     var child = std.process.Child.init(child_argv.items, gpa);
   5580     child.stdin_behavior = .Inherit;
   5581     child.stdout_behavior = if (options.capture == null) .Inherit else .Pipe;
   5582     child.stderr_behavior = .Inherit;
   5583 
   5584     try child.spawn();
   5585 
   5586     if (options.capture) |ptr| {
   5587         var stdout_reader = child.stdout.?.readerStreaming(&.{});
   5588         ptr.* = try stdout_reader.interface.allocRemaining(arena, .limited(std.math.maxInt(u32)));
   5589     }
   5590 
   5591     const term = try child.wait();
   5592     switch (term) {
   5593         .Exited => |code| {
   5594             if (code == 0) {
   5595                 if (options.capture != null) return;
   5596                 return cleanExit();
   5597             }
   5598             const cmd = try std.mem.join(arena, " ", child_argv.items);
   5599             fatal("the following build command failed with exit code {d}:\n{s}", .{ code, cmd });
   5600         },
   5601         else => {
   5602             const cmd = try std.mem.join(arena, " ", child_argv.items);
   5603             fatal("the following build command crashed:\n{s}", .{cmd});
   5604         },
   5605     }
   5606 }
   5607 
   5608 const info_zen =
   5609     \\
   5610     \\ * Communicate intent precisely.
   5611     \\ * Edge cases matter.
   5612     \\ * Favor reading code over writing code.
   5613     \\ * Only one obvious way to do things.
   5614     \\ * Runtime crashes are better than bugs.
   5615     \\ * Compile errors are better than runtime crashes.
   5616     \\ * Incremental improvements.
   5617     \\ * Avoid local maximums.
   5618     \\ * Reduce the amount one must remember.
   5619     \\ * Focus on code rather than style.
   5620     \\ * Resource allocation may fail; resource deallocation must succeed.
   5621     \\ * Memory is a resource.
   5622     \\ * Together we serve the users.
   5623     \\
   5624     \\
   5625 ;
   5626 
   5627 extern fn ZigClangIsLLVMUsingSeparateLibcxx() bool;
   5628 
   5629 extern "c" fn ZigClang_main(argc: c_int, argv: [*:null]?[*:0]u8) c_int;
   5630 extern "c" fn ZigLlvmAr_main(argc: c_int, argv: [*:null]?[*:0]u8) c_int;
   5631 
   5632 fn argsCopyZ(alloc: Allocator, args: []const []const u8) ![:null]?[*:0]u8 {
   5633     var argv = try alloc.allocSentinel(?[*:0]u8, args.len, null);
   5634     for (args, 0..) |arg, i| {
   5635         argv[i] = try alloc.dupeZ(u8, arg); // TODO If there was an argsAllocZ we could avoid this allocation.
   5636     }
   5637     return argv;
   5638 }
   5639 
   5640 pub fn clangMain(alloc: Allocator, args: []const []const u8) error{OutOfMemory}!u8 {
   5641     if (!build_options.have_llvm)
   5642         fatal("`zig cc` and `zig c++` unavailable: compiler built without LLVM extensions", .{});
   5643 
   5644     var arena_instance = std.heap.ArenaAllocator.init(alloc);
   5645     defer arena_instance.deinit();
   5646     const arena = arena_instance.allocator();
   5647 
   5648     // Convert the args to the null-terminated format Clang expects.
   5649     const argv = try argsCopyZ(arena, args);
   5650     const exit_code = ZigClang_main(@as(c_int, @intCast(argv.len)), argv.ptr);
   5651     return @as(u8, @bitCast(@as(i8, @truncate(exit_code))));
   5652 }
   5653 
   5654 pub fn llvmArMain(alloc: Allocator, args: []const []const u8) error{OutOfMemory}!u8 {
   5655     if (!build_options.have_llvm)
   5656         fatal("`zig ar`, `zig dlltool`, `zig ranlib', and `zig lib` unavailable: compiler built without LLVM extensions", .{});
   5657 
   5658     var arena_instance = std.heap.ArenaAllocator.init(alloc);
   5659     defer arena_instance.deinit();
   5660     const arena = arena_instance.allocator();
   5661 
   5662     // Convert the args to the format llvm-ar expects.
   5663     // We intentionally shave off the zig binary at args[0].
   5664     const argv = try argsCopyZ(arena, args[1..]);
   5665     const exit_code = ZigLlvmAr_main(@as(c_int, @intCast(argv.len)), argv.ptr);
   5666     return @as(u8, @bitCast(@as(i8, @truncate(exit_code))));
   5667 }
   5668 
   5669 /// The first argument determines which backend is invoked. The options are:
   5670 /// * `ld.lld` - ELF
   5671 /// * `lld-link` - COFF
   5672 /// * `wasm-ld` - WebAssembly
   5673 pub fn lldMain(
   5674     alloc: Allocator,
   5675     args: []const []const u8,
   5676     can_exit_early: bool,
   5677 ) error{OutOfMemory}!u8 {
   5678     if (!build_options.have_llvm)
   5679         fatal("`zig {s}` unavailable: compiler built without LLVM extensions", .{args[0]});
   5680 
   5681     // Print a warning if lld is called multiple times in the same process,
   5682     // since it may misbehave
   5683     // https://github.com/ziglang/zig/issues/3825
   5684     const CallCounter = struct {
   5685         var count: usize = 0;
   5686     };
   5687     if (CallCounter.count == 1) { // Issue the warning on the first repeat call
   5688         warn("invoking LLD for the second time within the same process because the host OS ({s}) does not support spawning child processes. This sometimes activates LLD bugs", .{@tagName(native_os)});
   5689     }
   5690     CallCounter.count += 1;
   5691 
   5692     var arena_instance = std.heap.ArenaAllocator.init(alloc);
   5693     defer arena_instance.deinit();
   5694     const arena = arena_instance.allocator();
   5695 
   5696     // Convert the args to the format LLD expects.
   5697     // We intentionally shave off the zig binary at args[0].
   5698     const argv = try argsCopyZ(arena, args[1..]);
   5699     // "If an error occurs, false will be returned."
   5700     const ok = rc: {
   5701         const llvm = @import("codegen/llvm/bindings.zig");
   5702         const argc = @as(c_int, @intCast(argv.len));
   5703         if (mem.eql(u8, args[1], "ld.lld")) {
   5704             break :rc llvm.LinkELF(argc, argv.ptr, can_exit_early, false);
   5705         } else if (mem.eql(u8, args[1], "lld-link")) {
   5706             break :rc llvm.LinkCOFF(argc, argv.ptr, can_exit_early, false);
   5707         } else if (mem.eql(u8, args[1], "wasm-ld")) {
   5708             break :rc llvm.LinkWasm(argc, argv.ptr, can_exit_early, false);
   5709         } else {
   5710             unreachable;
   5711         }
   5712     };
   5713     return @intFromBool(!ok);
   5714 }
   5715 
   5716 const ArgIteratorResponseFile = process.ArgIteratorGeneral(.{ .comments = true, .single_quotes = true });
   5717 
   5718 /// Initialize the arguments from a Response File. "*.rsp"
   5719 fn initArgIteratorResponseFile(allocator: Allocator, resp_file_path: []const u8) !ArgIteratorResponseFile {
   5720     const max_bytes = 10 * 1024 * 1024; // 10 MiB of command line arguments is a reasonable limit
   5721     const cmd_line = try fs.cwd().readFileAlloc(resp_file_path, allocator, .limited(max_bytes));
   5722     errdefer allocator.free(cmd_line);
   5723 
   5724     return ArgIteratorResponseFile.initTakeOwnership(allocator, cmd_line);
   5725 }
   5726 
   5727 const clang_args = @import("clang_options.zig").list;
   5728 
   5729 pub const ClangArgIterator = struct {
   5730     has_next: bool,
   5731     zig_equivalent: ZigEquivalent,
   5732     only_arg: []const u8,
   5733     second_arg: []const u8,
   5734     other_args: []const []const u8,
   5735     argv: []const []const u8,
   5736     next_index: usize,
   5737     root_args: ?*Args,
   5738     arg_iterator_response_file: ArgIteratorResponseFile,
   5739     arena: Allocator,
   5740 
   5741     pub const ZigEquivalent = enum {
   5742         target,
   5743         o,
   5744         c,
   5745         r,
   5746         m,
   5747         x,
   5748         other,
   5749         positional,
   5750         l,
   5751         ignore,
   5752         driver_punt,
   5753         pic,
   5754         no_pic,
   5755         pie,
   5756         no_pie,
   5757         lto,
   5758         no_lto,
   5759         unwind_tables,
   5760         no_unwind_tables,
   5761         asynchronous_unwind_tables,
   5762         no_asynchronous_unwind_tables,
   5763         nostdlib,
   5764         nostdlib_cpp,
   5765         shared,
   5766         rdynamic,
   5767         wl,
   5768         wp,
   5769         preprocess_only,
   5770         asm_only,
   5771         optimize,
   5772         debug,
   5773         gdwarf32,
   5774         gdwarf64,
   5775         sanitize,
   5776         no_sanitize,
   5777         sanitize_trap,
   5778         no_sanitize_trap,
   5779         linker_script,
   5780         dry_run,
   5781         verbose,
   5782         for_linker,
   5783         linker_input_z,
   5784         lib_dir,
   5785         mcpu,
   5786         dep_file,
   5787         dep_file_to_stdout,
   5788         framework_dir,
   5789         framework,
   5790         nostdlibinc,
   5791         red_zone,
   5792         no_red_zone,
   5793         omit_frame_pointer,
   5794         no_omit_frame_pointer,
   5795         function_sections,
   5796         no_function_sections,
   5797         data_sections,
   5798         no_data_sections,
   5799         builtin,
   5800         no_builtin,
   5801         color_diagnostics,
   5802         no_color_diagnostics,
   5803         stack_check,
   5804         no_stack_check,
   5805         stack_protector,
   5806         no_stack_protector,
   5807         strip,
   5808         exec_model,
   5809         emit_llvm,
   5810         sysroot,
   5811         entry,
   5812         force_undefined_symbol,
   5813         weak_library,
   5814         weak_framework,
   5815         headerpad_max_install_names,
   5816         compress_debug_sections,
   5817         install_name,
   5818         undefined,
   5819         force_load_objc,
   5820         mingw_unicode_entry_point,
   5821         san_cov_trace_pc_guard,
   5822         san_cov,
   5823         no_san_cov,
   5824         rtlib,
   5825         static,
   5826         dynamic,
   5827     };
   5828 
   5829     const Args = struct {
   5830         next_index: usize,
   5831         argv: []const []const u8,
   5832     };
   5833 
   5834     fn init(arena: Allocator, argv: []const []const u8) ClangArgIterator {
   5835         return .{
   5836             .next_index = 2, // `zig cc foo` this points to `foo`
   5837             .has_next = argv.len > 2,
   5838             .zig_equivalent = undefined,
   5839             .only_arg = undefined,
   5840             .second_arg = undefined,
   5841             .other_args = undefined,
   5842             .argv = argv,
   5843             .root_args = null,
   5844             .arg_iterator_response_file = undefined,
   5845             .arena = arena,
   5846         };
   5847     }
   5848 
   5849     fn next(self: *ClangArgIterator) !void {
   5850         assert(self.has_next);
   5851         assert(self.next_index < self.argv.len);
   5852         // In this state we know that the parameter we are looking at is a root parameter
   5853         // rather than an argument to a parameter.
   5854         // We adjust the len below when necessary.
   5855         self.other_args = (self.argv.ptr + self.next_index)[0..1];
   5856         var arg = self.argv[self.next_index];
   5857         self.incrementArgIndex();
   5858 
   5859         if (mem.startsWith(u8, arg, "@")) {
   5860             if (self.root_args != null) return error.NestedResponseFile;
   5861 
   5862             // This is a "compiler response file". We must parse the file and treat its
   5863             // contents as command line parameters.
   5864             const arena = self.arena;
   5865             const resp_file_path = arg[1..];
   5866 
   5867             self.arg_iterator_response_file =
   5868                 initArgIteratorResponseFile(arena, resp_file_path) catch |err| {
   5869                     fatal("unable to read response file '{s}': {s}", .{ resp_file_path, @errorName(err) });
   5870                 };
   5871             // NOTE: The ArgIteratorResponseFile returns tokens from next() that are slices of an
   5872             // internal buffer. This internal buffer is arena allocated, so it is not cleaned up here.
   5873 
   5874             var resp_arg_list = std.array_list.Managed([]const u8).init(arena);
   5875             defer resp_arg_list.deinit();
   5876             {
   5877                 while (self.arg_iterator_response_file.next()) |token| {
   5878                     try resp_arg_list.append(token);
   5879                 }
   5880 
   5881                 const args = try arena.create(Args);
   5882                 errdefer arena.destroy(args);
   5883                 args.* = .{
   5884                     .next_index = self.next_index,
   5885                     .argv = self.argv,
   5886                 };
   5887                 self.root_args = args;
   5888             }
   5889             const resp_arg_slice = try resp_arg_list.toOwnedSlice();
   5890             self.next_index = 0;
   5891             self.argv = resp_arg_slice;
   5892 
   5893             if (resp_arg_slice.len == 0) {
   5894                 self.resolveRespFileArgs();
   5895                 return;
   5896             }
   5897 
   5898             self.has_next = true;
   5899             self.other_args = (self.argv.ptr + self.next_index)[0..1]; // We adjust len below when necessary.
   5900             arg = self.argv[self.next_index];
   5901             self.incrementArgIndex();
   5902         }
   5903 
   5904         if (mem.eql(u8, arg, "-") or !mem.startsWith(u8, arg, "-")) {
   5905             self.zig_equivalent = .positional;
   5906             self.only_arg = arg;
   5907             return;
   5908         }
   5909 
   5910         find_clang_arg: for (clang_args) |clang_arg| switch (clang_arg.syntax) {
   5911             .flag => {
   5912                 const prefix_len = clang_arg.matchEql(arg);
   5913                 if (prefix_len > 0) {
   5914                     self.zig_equivalent = clang_arg.zig_equivalent;
   5915                     self.only_arg = arg[prefix_len..];
   5916 
   5917                     break :find_clang_arg;
   5918                 }
   5919             },
   5920             .joined, .comma_joined => {
   5921                 // joined example: --target=foo
   5922                 // comma_joined example: -Wl,-soname,libsoundio.so.2
   5923                 const prefix_len = clang_arg.matchStartsWith(arg);
   5924                 if (prefix_len != 0) {
   5925                     self.zig_equivalent = clang_arg.zig_equivalent;
   5926                     self.only_arg = arg[prefix_len..]; // This will skip over the "--target=" part.
   5927 
   5928                     break :find_clang_arg;
   5929                 }
   5930             },
   5931             .joined_or_separate => {
   5932                 // Examples: `-lfoo`, `-l foo`
   5933                 const prefix_len = clang_arg.matchStartsWith(arg);
   5934                 if (prefix_len == arg.len) {
   5935                     if (self.next_index >= self.argv.len) {
   5936                         fatal("Expected parameter after '{s}'", .{arg});
   5937                     }
   5938                     self.only_arg = self.argv[self.next_index];
   5939                     self.incrementArgIndex();
   5940                     self.other_args.len += 1;
   5941                     self.zig_equivalent = clang_arg.zig_equivalent;
   5942 
   5943                     break :find_clang_arg;
   5944                 } else if (prefix_len != 0) {
   5945                     self.zig_equivalent = clang_arg.zig_equivalent;
   5946                     self.only_arg = arg[prefix_len..];
   5947 
   5948                     break :find_clang_arg;
   5949                 }
   5950             },
   5951             .joined_and_separate => {
   5952                 // Example: `-Xopenmp-target=riscv64-linux-unknown foo`
   5953                 const prefix_len = clang_arg.matchStartsWith(arg);
   5954                 if (prefix_len != 0) {
   5955                     self.only_arg = arg[prefix_len..];
   5956                     if (self.next_index >= self.argv.len) {
   5957                         fatal("Expected parameter after '{s}'", .{arg});
   5958                     }
   5959                     self.second_arg = self.argv[self.next_index];
   5960                     self.incrementArgIndex();
   5961                     self.other_args.len += 1;
   5962                     self.zig_equivalent = clang_arg.zig_equivalent;
   5963                     break :find_clang_arg;
   5964                 }
   5965             },
   5966             .separate => if (clang_arg.matchEql(arg) > 0) {
   5967                 if (self.next_index >= self.argv.len) {
   5968                     fatal("Expected parameter after '{s}'", .{arg});
   5969                 }
   5970                 self.only_arg = self.argv[self.next_index];
   5971                 self.incrementArgIndex();
   5972                 self.other_args.len += 1;
   5973                 self.zig_equivalent = clang_arg.zig_equivalent;
   5974                 break :find_clang_arg;
   5975             },
   5976             .remaining_args_joined => {
   5977                 const prefix_len = clang_arg.matchStartsWith(arg);
   5978                 if (prefix_len != 0) {
   5979                     @panic("TODO");
   5980                 }
   5981             },
   5982             .multi_arg => |num_args| if (clang_arg.matchEql(arg) > 0) {
   5983                 // Example `-sectcreate <arg1> <arg2> <arg3>`.
   5984                 var i: usize = 0;
   5985                 while (i < num_args) : (i += 1) {
   5986                     self.incrementArgIndex();
   5987                     self.other_args.len += 1;
   5988                 }
   5989                 self.zig_equivalent = clang_arg.zig_equivalent;
   5990                 break :find_clang_arg;
   5991             },
   5992         } else {
   5993             fatal("Unknown Clang option: '{s}'", .{arg});
   5994         }
   5995     }
   5996 
   5997     fn incrementArgIndex(self: *ClangArgIterator) void {
   5998         self.next_index += 1;
   5999         self.resolveRespFileArgs();
   6000     }
   6001 
   6002     fn resolveRespFileArgs(self: *ClangArgIterator) void {
   6003         const arena = self.arena;
   6004         if (self.next_index >= self.argv.len) {
   6005             if (self.root_args) |root_args| {
   6006                 self.next_index = root_args.next_index;
   6007                 self.argv = root_args.argv;
   6008 
   6009                 arena.destroy(root_args);
   6010                 self.root_args = null;
   6011             }
   6012             if (self.next_index >= self.argv.len) {
   6013                 self.has_next = false;
   6014             }
   6015         }
   6016     }
   6017 };
   6018 
   6019 fn parseCodeModel(arg: []const u8) std.builtin.CodeModel {
   6020     return std.meta.stringToEnum(std.builtin.CodeModel, arg) orelse
   6021         fatal("unsupported machine code model: '{s}'", .{arg});
   6022 }
   6023 
   6024 const usage_ast_check =
   6025     \\Usage: zig ast-check [file]
   6026     \\
   6027     \\    Given a .zig source file or .zon file, reports any compile errors
   6028     \\    that can be ascertained on the basis of the source code alone,
   6029     \\    without target information or type checking.
   6030     \\
   6031     \\    If [file] is omitted, stdin is used.
   6032     \\
   6033     \\Options:
   6034     \\  -h, --help            Print this help and exit
   6035     \\  --color [auto|off|on] Enable or disable colored error messages
   6036     \\  --zon                 Treat the input file as ZON, regardless of file extension
   6037     \\  -t                    (debug option) Output ZIR in text form to stdout
   6038     \\
   6039     \\
   6040 ;
   6041 
   6042 fn cmdAstCheck(
   6043     arena: Allocator,
   6044     args: []const []const u8,
   6045 ) !void {
   6046     dev.check(.ast_check_command);
   6047 
   6048     const Zir = std.zig.Zir;
   6049 
   6050     var color: Color = .auto;
   6051     var want_output_text = false;
   6052     var force_zon = false;
   6053     var zig_source_path: ?[]const u8 = null;
   6054 
   6055     var i: usize = 0;
   6056     while (i < args.len) : (i += 1) {
   6057         const arg = args[i];
   6058         if (mem.startsWith(u8, arg, "-")) {
   6059             if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
   6060                 try fs.File.stdout().writeAll(usage_ast_check);
   6061                 return cleanExit();
   6062             } else if (mem.eql(u8, arg, "-t")) {
   6063                 want_output_text = true;
   6064             } else if (mem.eql(u8, arg, "--zon")) {
   6065                 force_zon = true;
   6066             } else if (mem.eql(u8, arg, "--color")) {
   6067                 if (i + 1 >= args.len) {
   6068                     fatal("expected [auto|on|off] after --color", .{});
   6069                 }
   6070                 i += 1;
   6071                 const next_arg = args[i];
   6072                 color = std.meta.stringToEnum(Color, next_arg) orelse {
   6073                     fatal("expected [auto|on|off] after --color, found '{s}'", .{next_arg});
   6074                 };
   6075             } else {
   6076                 fatal("unrecognized parameter: '{s}'", .{arg});
   6077             }
   6078         } else if (zig_source_path == null) {
   6079             zig_source_path = arg;
   6080         } else {
   6081             fatal("extra positional parameter: '{s}'", .{arg});
   6082         }
   6083     }
   6084 
   6085     const display_path = zig_source_path orelse "<stdin>";
   6086     const source: [:0]const u8 = s: {
   6087         var f = if (zig_source_path) |p| file: {
   6088             break :file fs.cwd().openFile(p, .{}) catch |err| {
   6089                 fatal("unable to open file '{s}' for ast-check: {s}", .{ display_path, @errorName(err) });
   6090             };
   6091         } else fs.File.stdin();
   6092         defer if (zig_source_path != null) f.close();
   6093         var file_reader: fs.File.Reader = f.reader(&stdin_buffer);
   6094         break :s std.zig.readSourceFileToEndAlloc(arena, &file_reader) catch |err| {
   6095             fatal("unable to load file '{s}' for ast-check: {s}", .{ display_path, @errorName(err) });
   6096         };
   6097     };
   6098 
   6099     const mode: Ast.Mode = mode: {
   6100         if (force_zon) break :mode .zon;
   6101         if (zig_source_path) |path| {
   6102             if (mem.endsWith(u8, path, ".zon")) {
   6103                 break :mode .zon;
   6104             }
   6105         }
   6106         break :mode .zig;
   6107     };
   6108 
   6109     const tree = try Ast.parse(arena, source, mode);
   6110 
   6111     var stdout_writer = fs.File.stdout().writerStreaming(&stdout_buffer);
   6112     const stdout_bw = &stdout_writer.interface;
   6113     switch (mode) {
   6114         .zig => {
   6115             const zir = try AstGen.generate(arena, tree);
   6116 
   6117             if (zir.hasCompileErrors()) {
   6118                 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
   6119                 try wip_errors.init(arena);
   6120                 try wip_errors.addZirErrorMessages(zir, tree, source, display_path);
   6121                 var error_bundle = try wip_errors.toOwnedBundle("");
   6122                 error_bundle.renderToStdErr(color.renderOptions());
   6123                 if (zir.loweringFailed()) {
   6124                     process.exit(1);
   6125                 }
   6126             }
   6127 
   6128             if (!want_output_text) {
   6129                 if (zir.hasCompileErrors()) {
   6130                     process.exit(1);
   6131                 } else {
   6132                     return cleanExit();
   6133                 }
   6134             }
   6135             if (!build_options.enable_debug_extensions) {
   6136                 fatal("-t option only available in builds of zig with debug extensions", .{});
   6137             }
   6138 
   6139             {
   6140                 const token_bytes = @sizeOf(Ast.TokenList) +
   6141                     tree.tokens.len * (@sizeOf(std.zig.Token.Tag) + @sizeOf(Ast.ByteOffset));
   6142                 const tree_bytes = @sizeOf(Ast) + tree.nodes.len *
   6143                     (@sizeOf(Ast.Node.Tag) +
   6144                         @sizeOf(Ast.TokenIndex) +
   6145                         // Here we don't use @sizeOf(Ast.Node.Data) because it would include
   6146                         // the debug safety tag but we want to measure release size.
   6147                         8);
   6148                 const instruction_bytes = zir.instructions.len *
   6149                     // Here we don't use @sizeOf(Zir.Inst.Data) because it would include
   6150                     // the debug safety tag but we want to measure release size.
   6151                     (@sizeOf(Zir.Inst.Tag) + 8);
   6152                 const extra_bytes = zir.extra.len * @sizeOf(u32);
   6153                 const total_bytes = @sizeOf(Zir) + instruction_bytes + extra_bytes +
   6154                     zir.string_bytes.len * @sizeOf(u8);
   6155                 // zig fmt: off
   6156                 try stdout_bw.print(
   6157                     \\# Source bytes:       {Bi}
   6158                     \\# Tokens:             {} ({Bi})
   6159                     \\# AST Nodes:          {} ({Bi})
   6160                     \\# Total ZIR bytes:    {Bi}
   6161                     \\# Instructions:       {d} ({Bi})
   6162                     \\# String Table Bytes: {}
   6163                     \\# Extra Data Items:   {d} ({Bi})
   6164                     \\
   6165                 , .{
   6166                     source.len,
   6167                     tree.tokens.len, token_bytes,
   6168                     tree.nodes.len, tree_bytes,
   6169                     total_bytes,
   6170                     zir.instructions.len, instruction_bytes,
   6171                     zir.string_bytes.len,
   6172                     zir.extra.len, extra_bytes,
   6173                 });
   6174                 // zig fmt: on
   6175             }
   6176 
   6177             try @import("print_zir.zig").renderAsText(arena, tree, zir, stdout_bw);
   6178             try stdout_bw.flush();
   6179 
   6180             if (zir.hasCompileErrors()) {
   6181                 process.exit(1);
   6182             } else {
   6183                 return cleanExit();
   6184             }
   6185         },
   6186         .zon => {
   6187             const zoir = try ZonGen.generate(arena, tree, .{});
   6188             if (zoir.hasCompileErrors()) {
   6189                 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
   6190                 try wip_errors.init(arena);
   6191                 try wip_errors.addZoirErrorMessages(zoir, tree, source, display_path);
   6192                 var error_bundle = try wip_errors.toOwnedBundle("");
   6193                 error_bundle.renderToStdErr(color.renderOptions());
   6194                 process.exit(1);
   6195             }
   6196 
   6197             if (!want_output_text) {
   6198                 return cleanExit();
   6199             }
   6200 
   6201             if (!build_options.enable_debug_extensions) {
   6202                 fatal("-t option only available in builds of zig with debug extensions", .{});
   6203             }
   6204 
   6205             try @import("print_zoir.zig").renderToWriter(zoir, arena, stdout_bw);
   6206             try stdout_bw.flush();
   6207             return cleanExit();
   6208         },
   6209     }
   6210 }
   6211 
   6212 fn cmdDetectCpu(args: []const []const u8) !void {
   6213     dev.check(.detect_cpu_command);
   6214 
   6215     const detect_cpu_usage =
   6216         \\Usage: zig detect-cpu [--llvm]
   6217         \\
   6218         \\    Print the host CPU name and feature set to stdout.
   6219         \\
   6220         \\Options:
   6221         \\  -h, --help                    Print this help and exit
   6222         \\  --llvm                        Detect using LLVM API
   6223         \\
   6224     ;
   6225 
   6226     var use_llvm = false;
   6227 
   6228     {
   6229         var i: usize = 0;
   6230         while (i < args.len) : (i += 1) {
   6231             const arg = args[i];
   6232             if (mem.startsWith(u8, arg, "-")) {
   6233                 if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
   6234                     try fs.File.stdout().writeAll(detect_cpu_usage);
   6235                     return cleanExit();
   6236                 } else if (mem.eql(u8, arg, "--llvm")) {
   6237                     use_llvm = true;
   6238                 } else {
   6239                     fatal("unrecognized parameter: '{s}'", .{arg});
   6240                 }
   6241             } else {
   6242                 fatal("unexpected extra parameter: '{s}'", .{arg});
   6243             }
   6244         }
   6245     }
   6246 
   6247     if (use_llvm) {
   6248         if (!build_options.have_llvm)
   6249             fatal("compiler does not use LLVM; cannot compare CPU features with LLVM", .{});
   6250 
   6251         const llvm = @import("codegen/llvm/bindings.zig");
   6252         const name = llvm.GetHostCPUName() orelse fatal("LLVM could not figure out the host cpu name", .{});
   6253         const features = llvm.GetHostCPUFeatures() orelse fatal("LLVM could not figure out the host cpu feature set", .{});
   6254         const cpu = try detectNativeCpuWithLLVM(builtin.cpu.arch, name, features);
   6255         try printCpu(cpu);
   6256     } else {
   6257         const host_target = std.zig.resolveTargetQueryOrFatal(.{});
   6258         try printCpu(host_target.cpu);
   6259     }
   6260 }
   6261 
   6262 fn detectNativeCpuWithLLVM(
   6263     arch: std.Target.Cpu.Arch,
   6264     llvm_cpu_name_z: ?[*:0]const u8,
   6265     llvm_cpu_features_opt: ?[*:0]const u8,
   6266 ) !std.Target.Cpu {
   6267     var result = std.Target.Cpu.baseline(arch, builtin.os);
   6268 
   6269     if (llvm_cpu_name_z) |cpu_name_z| {
   6270         const llvm_cpu_name = mem.span(cpu_name_z);
   6271 
   6272         for (arch.allCpuModels()) |model| {
   6273             const this_llvm_name = model.llvm_name orelse continue;
   6274             if (mem.eql(u8, this_llvm_name, llvm_cpu_name)) {
   6275                 // Here we use the non-dependencies-populated set,
   6276                 // so that subtracting features later in this function
   6277                 // affect the prepopulated set.
   6278                 result = std.Target.Cpu{
   6279                     .arch = arch,
   6280                     .model = model,
   6281                     .features = model.features,
   6282                 };
   6283                 break;
   6284             }
   6285         }
   6286     }
   6287 
   6288     const all_features = arch.allFeaturesList();
   6289 
   6290     if (llvm_cpu_features_opt) |llvm_cpu_features| {
   6291         var it = mem.tokenizeScalar(u8, mem.span(llvm_cpu_features), ',');
   6292         while (it.next()) |decorated_llvm_feat| {
   6293             var op: enum {
   6294                 add,
   6295                 sub,
   6296             } = undefined;
   6297             var llvm_feat: []const u8 = undefined;
   6298             if (mem.startsWith(u8, decorated_llvm_feat, "+")) {
   6299                 op = .add;
   6300                 llvm_feat = decorated_llvm_feat[1..];
   6301             } else if (mem.startsWith(u8, decorated_llvm_feat, "-")) {
   6302                 op = .sub;
   6303                 llvm_feat = decorated_llvm_feat[1..];
   6304             } else {
   6305                 return error.InvalidLlvmCpuFeaturesFormat;
   6306             }
   6307             for (all_features, 0..) |feature, index_usize| {
   6308                 const this_llvm_name = feature.llvm_name orelse continue;
   6309                 if (mem.eql(u8, llvm_feat, this_llvm_name)) {
   6310                     const index: std.Target.Cpu.Feature.Set.Index = @intCast(index_usize);
   6311                     switch (op) {
   6312                         .add => result.features.addFeature(index),
   6313                         .sub => result.features.removeFeature(index),
   6314                     }
   6315                     break;
   6316                 }
   6317             }
   6318         }
   6319     }
   6320 
   6321     result.features.populateDependencies(all_features);
   6322     return result;
   6323 }
   6324 
   6325 fn printCpu(cpu: std.Target.Cpu) !void {
   6326     var stdout_writer = fs.File.stdout().writerStreaming(&stdout_buffer);
   6327     const stdout_bw = &stdout_writer.interface;
   6328 
   6329     if (cpu.model.llvm_name) |llvm_name| {
   6330         try stdout_bw.print("{s}\n", .{llvm_name});
   6331     }
   6332 
   6333     const all_features = cpu.arch.allFeaturesList();
   6334     for (all_features, 0..) |feature, index_usize| {
   6335         const llvm_name = feature.llvm_name orelse continue;
   6336         const index: std.Target.Cpu.Feature.Set.Index = @intCast(index_usize);
   6337         const is_enabled = cpu.features.isEnabled(index);
   6338         const plus_or_minus = "-+"[@intFromBool(is_enabled)];
   6339         try stdout_bw.print("{c}{s}\n", .{ plus_or_minus, llvm_name });
   6340     }
   6341 
   6342     try stdout_bw.flush();
   6343 }
   6344 
   6345 fn cmdDumpLlvmInts(
   6346     gpa: Allocator,
   6347     arena: Allocator,
   6348     args: []const []const u8,
   6349 ) !void {
   6350     dev.check(.llvm_ints_command);
   6351 
   6352     _ = gpa;
   6353 
   6354     if (!build_options.have_llvm)
   6355         fatal("compiler does not use LLVM; cannot dump LLVM integer sizes", .{});
   6356 
   6357     const triple = try arena.dupeZ(u8, args[0]);
   6358 
   6359     const llvm = @import("codegen/llvm/bindings.zig");
   6360 
   6361     for ([_]std.Target.Cpu.Arch{ .aarch64, .x86 }) |arch| {
   6362         @import("codegen/llvm.zig").initializeLLVMTarget(arch);
   6363     }
   6364 
   6365     const target: *llvm.Target = t: {
   6366         var target: *llvm.Target = undefined;
   6367         var error_message: [*:0]const u8 = undefined;
   6368         if (llvm.Target.getFromTriple(triple, &target, &error_message) != .False) @panic("bad");
   6369         break :t target;
   6370     };
   6371     const tm = llvm.TargetMachine.create(target, triple, null, null, .None, .Default, .Default, false, false, .Default, null, false);
   6372     const dl = tm.createTargetDataLayout();
   6373     const context = llvm.Context.create();
   6374 
   6375     var stdout_writer = fs.File.stdout().writerStreaming(&stdout_buffer);
   6376     const stdout_bw = &stdout_writer.interface;
   6377     for ([_]u16{ 1, 8, 16, 32, 64, 128, 256 }) |bits| {
   6378         const int_type = context.intType(bits);
   6379         const alignment = dl.abiAlignmentOfType(int_type);
   6380         try stdout_bw.print("LLVMABIAlignmentOfType(i{d}) == {d}\n", .{ bits, alignment });
   6381     }
   6382     try stdout_bw.flush();
   6383 
   6384     return cleanExit();
   6385 }
   6386 
   6387 /// This is only enabled for debug builds.
   6388 fn cmdDumpZir(
   6389     arena: Allocator,
   6390     args: []const []const u8,
   6391 ) !void {
   6392     dev.check(.dump_zir_command);
   6393 
   6394     const Zir = std.zig.Zir;
   6395 
   6396     const cache_file = args[0];
   6397 
   6398     var f = fs.cwd().openFile(cache_file, .{}) catch |err| {
   6399         fatal("unable to open zir cache file for dumping '{s}': {s}", .{ cache_file, @errorName(err) });
   6400     };
   6401     defer f.close();
   6402 
   6403     const zir = try Zcu.loadZirCache(arena, f);
   6404     var stdout_writer = fs.File.stdout().writerStreaming(&stdout_buffer);
   6405     const stdout_bw = &stdout_writer.interface;
   6406     {
   6407         const instruction_bytes = zir.instructions.len *
   6408             // Here we don't use @sizeOf(Zir.Inst.Data) because it would include
   6409             // the debug safety tag but we want to measure release size.
   6410             (@sizeOf(Zir.Inst.Tag) + 8);
   6411         const extra_bytes = zir.extra.len * @sizeOf(u32);
   6412         const total_bytes = @sizeOf(Zir) + instruction_bytes + extra_bytes +
   6413             zir.string_bytes.len * @sizeOf(u8);
   6414         // zig fmt: off
   6415         try stdout_bw.print(
   6416             \\# Total ZIR bytes:    {Bi}
   6417             \\# Instructions:       {d} ({Bi})
   6418             \\# String Table Bytes: {Bi}
   6419             \\# Extra Data Items:   {d} ({Bi})
   6420             \\
   6421         , .{
   6422             total_bytes,
   6423             zir.instructions.len, instruction_bytes,
   6424             zir.string_bytes.len,
   6425             zir.extra.len, extra_bytes,
   6426         });
   6427         // zig fmt: on
   6428     }
   6429 
   6430     try @import("print_zir.zig").renderAsText(arena, null, zir, stdout_bw);
   6431     try stdout_bw.flush();
   6432 }
   6433 
   6434 /// This is only enabled for debug builds.
   6435 fn cmdChangelist(
   6436     arena: Allocator,
   6437     args: []const []const u8,
   6438 ) !void {
   6439     dev.check(.changelist_command);
   6440 
   6441     const color: Color = .auto;
   6442     const Zir = std.zig.Zir;
   6443 
   6444     const old_source_path = args[0];
   6445     const new_source_path = args[1];
   6446 
   6447     const old_source = source: {
   6448         var f = fs.cwd().openFile(old_source_path, .{}) catch |err|
   6449             fatal("unable to open old source file '{s}': {s}", .{ old_source_path, @errorName(err) });
   6450         defer f.close();
   6451         var file_reader: fs.File.Reader = f.reader(&stdin_buffer);
   6452         break :source std.zig.readSourceFileToEndAlloc(arena, &file_reader) catch |err|
   6453             fatal("unable to read old source file '{s}': {s}", .{ old_source_path, @errorName(err) });
   6454     };
   6455     const new_source = source: {
   6456         var f = fs.cwd().openFile(new_source_path, .{}) catch |err|
   6457             fatal("unable to open new source file '{s}': {s}", .{ new_source_path, @errorName(err) });
   6458         defer f.close();
   6459         var file_reader: fs.File.Reader = f.reader(&stdin_buffer);
   6460         break :source std.zig.readSourceFileToEndAlloc(arena, &file_reader) catch |err|
   6461             fatal("unable to read new source file '{s}': {s}", .{ new_source_path, @errorName(err) });
   6462     };
   6463 
   6464     const old_tree = try Ast.parse(arena, old_source, .zig);
   6465     const old_zir = try AstGen.generate(arena, old_tree);
   6466 
   6467     if (old_zir.loweringFailed()) {
   6468         var wip_errors: std.zig.ErrorBundle.Wip = undefined;
   6469         try wip_errors.init(arena);
   6470         try wip_errors.addZirErrorMessages(old_zir, old_tree, old_source, old_source_path);
   6471         var error_bundle = try wip_errors.toOwnedBundle("");
   6472         error_bundle.renderToStdErr(color.renderOptions());
   6473         process.exit(1);
   6474     }
   6475 
   6476     const new_tree = try Ast.parse(arena, new_source, .zig);
   6477     const new_zir = try AstGen.generate(arena, new_tree);
   6478 
   6479     if (new_zir.loweringFailed()) {
   6480         var wip_errors: std.zig.ErrorBundle.Wip = undefined;
   6481         try wip_errors.init(arena);
   6482         try wip_errors.addZirErrorMessages(new_zir, new_tree, new_source, new_source_path);
   6483         var error_bundle = try wip_errors.toOwnedBundle("");
   6484         error_bundle.renderToStdErr(color.renderOptions());
   6485         process.exit(1);
   6486     }
   6487 
   6488     var inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .empty;
   6489     try Zcu.mapOldZirToNew(arena, old_zir, new_zir, &inst_map);
   6490 
   6491     var stdout_writer = fs.File.stdout().writerStreaming(&stdout_buffer);
   6492     const stdout_bw = &stdout_writer.interface;
   6493     {
   6494         try stdout_bw.print("Instruction mappings:\n", .{});
   6495         var it = inst_map.iterator();
   6496         while (it.next()) |entry| {
   6497             try stdout_bw.print(" %{d} => %{d}\n", .{
   6498                 @intFromEnum(entry.key_ptr.*),
   6499                 @intFromEnum(entry.value_ptr.*),
   6500             });
   6501         }
   6502     }
   6503     try stdout_bw.flush();
   6504 }
   6505 
   6506 fn eatIntPrefix(arg: []const u8, base: u8) []const u8 {
   6507     if (arg.len > 2 and arg[0] == '0') {
   6508         switch (std.ascii.toLower(arg[1])) {
   6509             'b' => if (base == 2) return arg[2..],
   6510             'o' => if (base == 8) return arg[2..],
   6511             'x' => if (base == 16) return arg[2..],
   6512             else => {},
   6513         }
   6514     }
   6515     return arg;
   6516 }
   6517 
   6518 fn prefixedIntArg(arg: []const u8, prefix: []const u8) ?u64 {
   6519     const number = mem.cutPrefix(u8, arg, prefix) orelse return null;
   6520     return std.fmt.parseUnsigned(u64, number, 0) catch |err| fatal("unable to parse '{s}': {t}", .{ arg, err });
   6521 }
   6522 
   6523 fn warnAboutForeignBinaries(
   6524     arena: Allocator,
   6525     arg_mode: ArgMode,
   6526     target: *const std.Target,
   6527     link_libc: bool,
   6528 ) !void {
   6529     const host_query: std.Target.Query = .{};
   6530     const host_target = std.zig.resolveTargetQueryOrFatal(host_query);
   6531 
   6532     switch (std.zig.system.getExternalExecutor(&host_target, target, .{ .link_libc = link_libc })) {
   6533         .native => return,
   6534         .rosetta => {
   6535             const host_name = try host_target.zigTriple(arena);
   6536             const foreign_name = try target.zigTriple(arena);
   6537             warn("the host system ({s}) does not appear to be capable of executing binaries from the target ({s}). Consider installing Rosetta.", .{
   6538                 host_name, foreign_name,
   6539             });
   6540         },
   6541         .qemu => |qemu| {
   6542             const host_name = try host_target.zigTriple(arena);
   6543             const foreign_name = try target.zigTriple(arena);
   6544             switch (arg_mode) {
   6545                 .zig_test => warn(
   6546                     "the host system ({s}) does not appear to be capable of executing binaries " ++
   6547                         "from the target ({s}). Consider using '--test-cmd {s} --test-cmd-bin' " ++
   6548                         "to run the tests",
   6549                     .{ host_name, foreign_name, qemu },
   6550                 ),
   6551                 else => warn(
   6552                     "the host system ({s}) does not appear to be capable of executing binaries " ++
   6553                         "from the target ({s}). Consider using '{s}' to run the binary",
   6554                     .{ host_name, foreign_name, qemu },
   6555                 ),
   6556             }
   6557         },
   6558         .wine => |wine| {
   6559             const host_name = try host_target.zigTriple(arena);
   6560             const foreign_name = try target.zigTriple(arena);
   6561             switch (arg_mode) {
   6562                 .zig_test => warn(
   6563                     "the host system ({s}) does not appear to be capable of executing binaries " ++
   6564                         "from the target ({s}). Consider using '--test-cmd {s} --test-cmd-bin' " ++
   6565                         "to run the tests",
   6566                     .{ host_name, foreign_name, wine },
   6567                 ),
   6568                 else => warn(
   6569                     "the host system ({s}) does not appear to be capable of executing binaries " ++
   6570                         "from the target ({s}). Consider using '{s}' to run the binary",
   6571                     .{ host_name, foreign_name, wine },
   6572                 ),
   6573             }
   6574         },
   6575         .wasmtime => |wasmtime| {
   6576             const host_name = try host_target.zigTriple(arena);
   6577             const foreign_name = try target.zigTriple(arena);
   6578             switch (arg_mode) {
   6579                 .zig_test => warn(
   6580                     "the host system ({s}) does not appear to be capable of executing binaries " ++
   6581                         "from the target ({s}). Consider using '--test-cmd {s} --test-cmd-bin' " ++
   6582                         "to run the tests",
   6583                     .{ host_name, foreign_name, wasmtime },
   6584                 ),
   6585                 else => warn(
   6586                     "the host system ({s}) does not appear to be capable of executing binaries " ++
   6587                         "from the target ({s}). Consider using '{s}' to run the binary",
   6588                     .{ host_name, foreign_name, wasmtime },
   6589                 ),
   6590             }
   6591         },
   6592         .darling => |darling| {
   6593             const host_name = try host_target.zigTriple(arena);
   6594             const foreign_name = try target.zigTriple(arena);
   6595             switch (arg_mode) {
   6596                 .zig_test => warn(
   6597                     "the host system ({s}) does not appear to be capable of executing binaries " ++
   6598                         "from the target ({s}). Consider using '--test-cmd {s} --test-cmd-bin' " ++
   6599                         "to run the tests",
   6600                     .{ host_name, foreign_name, darling },
   6601                 ),
   6602                 else => warn(
   6603                     "the host system ({s}) does not appear to be capable of executing binaries " ++
   6604                         "from the target ({s}). Consider using '{s}' to run the binary",
   6605                     .{ host_name, foreign_name, darling },
   6606                 ),
   6607             }
   6608         },
   6609         .bad_dl => |foreign_dl| {
   6610             const host_dl = host_target.dynamic_linker.get() orelse "(none)";
   6611             const tip_suffix = switch (arg_mode) {
   6612                 .zig_test => ", '--test-no-exec', or '--test-cmd'",
   6613                 else => "",
   6614             };
   6615             warn("the host system does not appear to be capable of executing binaries from the target because the host dynamic linker is '{s}', while the target dynamic linker is '{s}'. Consider using '--dynamic-linker'{s}", .{
   6616                 host_dl, foreign_dl, tip_suffix,
   6617             });
   6618         },
   6619         .bad_os_or_cpu => {
   6620             const host_name = try host_target.zigTriple(arena);
   6621             const foreign_name = try target.zigTriple(arena);
   6622             const tip_suffix = switch (arg_mode) {
   6623                 .zig_test => ". Consider using '--test-no-exec' or '--test-cmd'",
   6624                 else => "",
   6625             };
   6626             warn("the host system ({s}) does not appear to be capable of executing binaries from the target ({s}){s}", .{
   6627                 host_name, foreign_name, tip_suffix,
   6628             });
   6629         },
   6630     }
   6631 }
   6632 
   6633 fn parseSubSystem(next_arg: []const u8) !std.Target.SubSystem {
   6634     if (mem.eql(u8, next_arg, "console")) {
   6635         return .Console;
   6636     } else if (mem.eql(u8, next_arg, "windows")) {
   6637         return .Windows;
   6638     } else if (mem.eql(u8, next_arg, "posix")) {
   6639         return .Posix;
   6640     } else if (mem.eql(u8, next_arg, "native")) {
   6641         return .Native;
   6642     } else if (mem.eql(u8, next_arg, "efi_application")) {
   6643         return .EfiApplication;
   6644     } else if (mem.eql(u8, next_arg, "efi_boot_service_driver")) {
   6645         return .EfiBootServiceDriver;
   6646     } else if (mem.eql(u8, next_arg, "efi_rom")) {
   6647         return .EfiRom;
   6648     } else if (mem.eql(u8, next_arg, "efi_runtime_driver")) {
   6649         return .EfiRuntimeDriver;
   6650     } else {
   6651         fatal("invalid: --subsystem: '{s}'. Options are:\n{s}", .{
   6652             next_arg,
   6653             \\  console
   6654             \\  windows
   6655             \\  posix
   6656             \\  native
   6657             \\  efi_application
   6658             \\  efi_boot_service_driver
   6659             \\  efi_rom
   6660             \\  efi_runtime_driver
   6661             \\
   6662         });
   6663     }
   6664 }
   6665 
   6666 /// Model a header searchlist as a group.
   6667 /// Silently ignore superfluous search dirs.
   6668 /// Warn when a dir is added to multiple searchlists.
   6669 const ClangSearchSanitizer = struct {
   6670     map: std.StringHashMapUnmanaged(Membership) = .empty,
   6671 
   6672     fn reset(self: *@This()) void {
   6673         self.map.clearRetainingCapacity();
   6674     }
   6675 
   6676     fn addIncludePath(
   6677         self: *@This(),
   6678         ally: Allocator,
   6679         argv: *std.ArrayListUnmanaged([]const u8),
   6680         group: Group,
   6681         arg: []const u8,
   6682         dir: []const u8,
   6683         joined: bool,
   6684     ) !void {
   6685         const gopr = try self.map.getOrPut(ally, dir);
   6686         const m = gopr.value_ptr;
   6687         if (!gopr.found_existing) {
   6688             // init empty membership
   6689             m.* = .{};
   6690         }
   6691         const wtxt = "add '{s}' to header searchlist '-{s}' conflicts with '-{s}'";
   6692         switch (group) {
   6693             .I => {
   6694                 if (m.I) return;
   6695                 m.I = true;
   6696                 if (m.isystem) warn(wtxt, .{ dir, "I", "isystem" });
   6697                 if (m.idirafter) warn(wtxt, .{ dir, "I", "idirafter" });
   6698                 if (m.iframework) warn(wtxt, .{ dir, "I", "iframework" });
   6699             },
   6700             .isystem => {
   6701                 if (m.isystem) return;
   6702                 m.isystem = true;
   6703                 if (m.I) warn(wtxt, .{ dir, "isystem", "I" });
   6704                 if (m.idirafter) warn(wtxt, .{ dir, "isystem", "idirafter" });
   6705                 if (m.iframework) warn(wtxt, .{ dir, "isystem", "iframework" });
   6706             },
   6707             .iwithsysroot => {
   6708                 if (m.iwithsysroot) return;
   6709                 m.iwithsysroot = true;
   6710                 if (m.iframeworkwithsysroot) warn(wtxt, .{ dir, "iwithsysroot", "iframeworkwithsysroot" });
   6711             },
   6712             .idirafter => {
   6713                 if (m.idirafter) return;
   6714                 m.idirafter = true;
   6715                 if (m.I) warn(wtxt, .{ dir, "idirafter", "I" });
   6716                 if (m.isystem) warn(wtxt, .{ dir, "idirafter", "isystem" });
   6717                 if (m.iframework) warn(wtxt, .{ dir, "idirafter", "iframework" });
   6718             },
   6719             .iframework => {
   6720                 if (m.iframework) return;
   6721                 m.iframework = true;
   6722                 if (m.I) warn(wtxt, .{ dir, "iframework", "I" });
   6723                 if (m.isystem) warn(wtxt, .{ dir, "iframework", "isystem" });
   6724                 if (m.idirafter) warn(wtxt, .{ dir, "iframework", "idirafter" });
   6725             },
   6726             .iframeworkwithsysroot => {
   6727                 if (m.iframeworkwithsysroot) return;
   6728                 m.iframeworkwithsysroot = true;
   6729                 if (m.iwithsysroot) warn(wtxt, .{ dir, "iframeworkwithsysroot", "iwithsysroot" });
   6730             },
   6731             .embed_dir => {
   6732                 if (m.embed_dir) return;
   6733                 m.embed_dir = true;
   6734             },
   6735         }
   6736         try argv.ensureUnusedCapacity(ally, 2);
   6737         argv.appendAssumeCapacity(arg);
   6738         if (!joined) argv.appendAssumeCapacity(dir);
   6739     }
   6740 
   6741     const Group = enum { I, isystem, iwithsysroot, idirafter, iframework, iframeworkwithsysroot, embed_dir };
   6742 
   6743     const Membership = packed struct {
   6744         I: bool = false,
   6745         isystem: bool = false,
   6746         iwithsysroot: bool = false,
   6747         idirafter: bool = false,
   6748         iframework: bool = false,
   6749         iframeworkwithsysroot: bool = false,
   6750         embed_dir: bool = false,
   6751     };
   6752 };
   6753 
   6754 fn accessFrameworkPath(
   6755     test_path: *std.array_list.Managed(u8),
   6756     checked_paths: *std.array_list.Managed(u8),
   6757     framework_dir_path: []const u8,
   6758     framework_name: []const u8,
   6759 ) !bool {
   6760     const sep = fs.path.sep_str;
   6761 
   6762     for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
   6763         test_path.clearRetainingCapacity();
   6764         try test_path.print("{s}" ++ sep ++ "{s}.framework" ++ sep ++ "{s}{s}", .{
   6765             framework_dir_path, framework_name, framework_name, ext,
   6766         });
   6767         try checked_paths.print("\n {s}", .{test_path.items});
   6768         fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {
   6769             error.FileNotFound => continue,
   6770             else => |e| fatal("unable to search for {s} framework '{s}': {s}", .{
   6771                 ext, test_path.items, @errorName(e),
   6772             }),
   6773         };
   6774         return true;
   6775     }
   6776 
   6777     return false;
   6778 }
   6779 
   6780 fn parseRcIncludes(arg: []const u8) Compilation.RcIncludes {
   6781     return std.meta.stringToEnum(Compilation.RcIncludes, arg) orelse
   6782         fatal("unsupported rc includes type: '{s}'", .{arg});
   6783 }
   6784 
   6785 const usage_fetch =
   6786     \\Usage: zig fetch [options] <url>
   6787     \\Usage: zig fetch [options] <path>
   6788     \\
   6789     \\    Copy a package into the global cache and print its hash.
   6790     \\    <url> must point to one of the following:
   6791     \\      - A git+http / git+https server for the package
   6792     \\      - A tarball file (with or without compression) containing
   6793     \\        package source
   6794     \\      - A git bundle file containing package source
   6795     \\
   6796     \\Examples:
   6797     \\
   6798     \\  zig fetch --save git+https://example.com/andrewrk/fun-example-tool.git
   6799     \\  zig fetch --save https://example.com/andrewrk/fun-example-tool/archive/refs/heads/master.tar.gz
   6800     \\
   6801     \\Options:
   6802     \\  -h, --help                    Print this help and exit
   6803     \\  --global-cache-dir [path]     Override path to global Zig cache directory
   6804     \\  --debug-hash                  Print verbose hash information to stdout
   6805     \\  --save                        Add the fetched package to build.zig.zon
   6806     \\  --save=[name]                 Add the fetched package to build.zig.zon as name
   6807     \\  --save-exact                  Add the fetched package to build.zig.zon, storing the URL verbatim
   6808     \\  --save-exact=[name]           Add the fetched package to build.zig.zon as name, storing the URL verbatim
   6809     \\
   6810 ;
   6811 
   6812 fn cmdFetch(
   6813     gpa: Allocator,
   6814     arena: Allocator,
   6815     args: []const []const u8,
   6816 ) !void {
   6817     dev.check(.fetch_command);
   6818 
   6819     const color: Color = .auto;
   6820     const work_around_btrfs_bug = native_os == .linux and
   6821         EnvVar.ZIG_BTRFS_WORKAROUND.isSet();
   6822     var opt_path_or_url: ?[]const u8 = null;
   6823     var override_global_cache_dir: ?[]const u8 = try EnvVar.ZIG_GLOBAL_CACHE_DIR.get(arena);
   6824     var debug_hash: bool = false;
   6825     var save: union(enum) {
   6826         no,
   6827         yes: ?[]const u8,
   6828         exact: ?[]const u8,
   6829     } = .no;
   6830 
   6831     {
   6832         var i: usize = 0;
   6833         while (i < args.len) : (i += 1) {
   6834             const arg = args[i];
   6835             if (mem.startsWith(u8, arg, "-")) {
   6836                 if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
   6837                     try fs.File.stdout().writeAll(usage_fetch);
   6838                     return cleanExit();
   6839                 } else if (mem.eql(u8, arg, "--global-cache-dir")) {
   6840                     if (i + 1 >= args.len) fatal("expected argument after '{s}'", .{arg});
   6841                     i += 1;
   6842                     override_global_cache_dir = args[i];
   6843                 } else if (mem.eql(u8, arg, "--debug-hash")) {
   6844                     debug_hash = true;
   6845                 } else if (mem.eql(u8, arg, "--save")) {
   6846                     save = .{ .yes = null };
   6847                 } else if (mem.cutPrefix(u8, arg, "--save=")) |rest| {
   6848                     save = .{ .yes = rest };
   6849                 } else if (mem.eql(u8, arg, "--save-exact")) {
   6850                     save = .{ .exact = null };
   6851                 } else if (mem.cutPrefix(u8, arg, "--save-exact=")) |rest| {
   6852                     save = .{ .exact = rest };
   6853                 } else {
   6854                     fatal("unrecognized parameter: '{s}'", .{arg});
   6855                 }
   6856             } else if (opt_path_or_url != null) {
   6857                 fatal("unexpected extra parameter: '{s}'", .{arg});
   6858             } else {
   6859                 opt_path_or_url = arg;
   6860             }
   6861         }
   6862     }
   6863 
   6864     const path_or_url = opt_path_or_url orelse fatal("missing url or path parameter", .{});
   6865 
   6866     var thread_pool: ThreadPool = undefined;
   6867     try thread_pool.init(.{ .allocator = gpa });
   6868     defer thread_pool.deinit();
   6869 
   6870     var http_client: std.http.Client = .{ .allocator = gpa };
   6871     defer http_client.deinit();
   6872 
   6873     try http_client.initDefaultProxies(arena);
   6874 
   6875     var root_prog_node = std.Progress.start(.{
   6876         .root_name = "Fetch",
   6877     });
   6878     defer root_prog_node.end();
   6879 
   6880     var global_cache_directory: Directory = l: {
   6881         const p = override_global_cache_dir orelse try introspect.resolveGlobalCacheDir(arena);
   6882         break :l .{
   6883             .handle = try fs.cwd().makeOpenPath(p, .{}),
   6884             .path = p,
   6885         };
   6886     };
   6887     defer global_cache_directory.handle.close();
   6888 
   6889     var job_queue: Package.Fetch.JobQueue = .{
   6890         .http_client = &http_client,
   6891         .thread_pool = &thread_pool,
   6892         .global_cache = global_cache_directory,
   6893         .recursive = false,
   6894         .read_only = false,
   6895         .debug_hash = debug_hash,
   6896         .work_around_btrfs_bug = work_around_btrfs_bug,
   6897         .mode = .all,
   6898     };
   6899     defer job_queue.deinit();
   6900 
   6901     var fetch: Package.Fetch = .{
   6902         .arena = std.heap.ArenaAllocator.init(gpa),
   6903         .location = .{ .path_or_url = path_or_url },
   6904         .location_tok = 0,
   6905         .hash_tok = .none,
   6906         .name_tok = 0,
   6907         .lazy_status = .eager,
   6908         .parent_package_root = undefined,
   6909         .parent_manifest_ast = null,
   6910         .prog_node = root_prog_node,
   6911         .job_queue = &job_queue,
   6912         .omit_missing_hash_error = true,
   6913         .allow_missing_paths_field = false,
   6914         .allow_missing_fingerprint = true,
   6915         .allow_name_string = true,
   6916         .use_latest_commit = true,
   6917 
   6918         .package_root = undefined,
   6919         .error_bundle = undefined,
   6920         .manifest = null,
   6921         .manifest_ast = undefined,
   6922         .computed_hash = undefined,
   6923         .has_build_zig = false,
   6924         .oom_flag = false,
   6925         .latest_commit = null,
   6926 
   6927         .module = null,
   6928     };
   6929     defer fetch.deinit();
   6930 
   6931     fetch.run() catch |err| switch (err) {
   6932         error.OutOfMemory => fatal("out of memory", .{}),
   6933         error.FetchFailed => {}, // error bundle checked below
   6934     };
   6935 
   6936     if (fetch.error_bundle.root_list.items.len > 0) {
   6937         var errors = try fetch.error_bundle.toOwnedBundle("");
   6938         errors.renderToStdErr(color.renderOptions());
   6939         process.exit(1);
   6940     }
   6941 
   6942     const package_hash = fetch.computedPackageHash();
   6943     const package_hash_slice = package_hash.toSlice();
   6944 
   6945     root_prog_node.end();
   6946     root_prog_node = .{ .index = .none };
   6947 
   6948     const name = switch (save) {
   6949         .no => {
   6950             var stdout = fs.File.stdout().writerStreaming(&stdout_buffer);
   6951             try stdout.interface.print("{s}\n", .{package_hash_slice});
   6952             try stdout.interface.flush();
   6953             return cleanExit();
   6954         },
   6955         .yes, .exact => |name| name: {
   6956             if (name) |n| break :name n;
   6957             const fetched_manifest = fetch.manifest orelse
   6958                 fatal("unable to determine name; fetched package has no build.zig.zon file", .{});
   6959             break :name fetched_manifest.name;
   6960         },
   6961     };
   6962 
   6963     const cwd_path = try introspect.getResolvedCwd(arena);
   6964 
   6965     var build_root = try findBuildRoot(arena, .{
   6966         .cwd_path = cwd_path,
   6967     });
   6968     defer build_root.deinit();
   6969 
   6970     // The name to use in case the manifest file needs to be created now.
   6971     const init_root_name = fs.path.basename(build_root.directory.path orelse cwd_path);
   6972     var manifest, var ast = try loadManifest(gpa, arena, .{
   6973         .root_name = try sanitizeExampleName(arena, init_root_name),
   6974         .dir = build_root.directory.handle,
   6975         .color = color,
   6976     });
   6977     defer {
   6978         manifest.deinit(gpa);
   6979         ast.deinit(gpa);
   6980     }
   6981 
   6982     var fixups: Ast.Render.Fixups = .{};
   6983     defer fixups.deinit(gpa);
   6984 
   6985     var saved_path_or_url = path_or_url;
   6986 
   6987     if (fetch.latest_commit) |latest_commit| resolved: {
   6988         const latest_commit_hex = try std.fmt.allocPrint(arena, "{f}", .{latest_commit});
   6989 
   6990         var uri = try std.Uri.parse(path_or_url);
   6991 
   6992         if (uri.fragment) |fragment| {
   6993             const target_ref = try fragment.toRawMaybeAlloc(arena);
   6994 
   6995             // the refspec may already be fully resolved
   6996             if (std.mem.eql(u8, target_ref, latest_commit_hex)) break :resolved;
   6997 
   6998             std.log.info("resolved ref '{s}' to commit {s}", .{ target_ref, latest_commit_hex });
   6999 
   7000             // include the original refspec in a query parameter, could be used to check for updates
   7001             uri.query = .{ .percent_encoded = try std.fmt.allocPrint(arena, "ref={f}", .{
   7002                 std.fmt.alt(fragment, .formatEscaped),
   7003             }) };
   7004         } else {
   7005             std.log.info("resolved to commit {s}", .{latest_commit_hex});
   7006         }
   7007 
   7008         // replace the refspec with the resolved commit SHA
   7009         uri.fragment = .{ .raw = latest_commit_hex };
   7010 
   7011         switch (save) {
   7012             .yes => saved_path_or_url = try std.fmt.allocPrint(arena, "{f}", .{uri}),
   7013             .no, .exact => {}, // keep the original URL
   7014         }
   7015     }
   7016 
   7017     const new_node_init = try std.fmt.allocPrint(arena,
   7018         \\.{{
   7019         \\            .url = "{f}",
   7020         \\            .hash = "{f}",
   7021         \\        }}
   7022     , .{
   7023         std.zig.fmtString(saved_path_or_url),
   7024         std.zig.fmtString(package_hash_slice),
   7025     });
   7026 
   7027     const new_node_text = try std.fmt.allocPrint(arena, ".{f} = {s},\n", .{
   7028         std.zig.fmtIdPU(name), new_node_init,
   7029     });
   7030 
   7031     const dependencies_init = try std.fmt.allocPrint(arena, ".{{\n        {s}    }}", .{
   7032         new_node_text,
   7033     });
   7034 
   7035     const dependencies_text = try std.fmt.allocPrint(arena, ".dependencies = {s},\n", .{
   7036         dependencies_init,
   7037     });
   7038 
   7039     if (manifest.dependencies.get(name)) |dep| {
   7040         if (dep.hash) |h| {
   7041             switch (dep.location) {
   7042                 .url => |u| {
   7043                     if (mem.eql(u8, h, package_hash_slice) and mem.eql(u8, u, saved_path_or_url)) {
   7044                         std.log.info("existing dependency named '{s}' is up-to-date", .{name});
   7045                         process.exit(0);
   7046                     }
   7047                 },
   7048                 .path => {},
   7049             }
   7050         }
   7051 
   7052         const location_replace = try std.fmt.allocPrint(
   7053             arena,
   7054             "\"{f}\"",
   7055             .{std.zig.fmtString(saved_path_or_url)},
   7056         );
   7057         const hash_replace = try std.fmt.allocPrint(
   7058             arena,
   7059             "\"{f}\"",
   7060             .{std.zig.fmtString(package_hash_slice)},
   7061         );
   7062 
   7063         warn("overwriting existing dependency named '{s}'", .{name});
   7064         try fixups.replace_nodes_with_string.put(gpa, dep.location_node, location_replace);
   7065         if (dep.hash_node.unwrap()) |hash_node| {
   7066             try fixups.replace_nodes_with_string.put(gpa, hash_node, hash_replace);
   7067         } else {
   7068             // https://github.com/ziglang/zig/issues/21690
   7069         }
   7070     } else if (manifest.dependencies.count() > 0) {
   7071         // Add fixup for adding another dependency.
   7072         const deps = manifest.dependencies.values();
   7073         const last_dep_node = deps[deps.len - 1].node;
   7074         try fixups.append_string_after_node.put(gpa, last_dep_node, new_node_text);
   7075     } else if (manifest.dependencies_node.unwrap()) |dependencies_node| {
   7076         // Add fixup for replacing the entire dependencies struct.
   7077         try fixups.replace_nodes_with_string.put(gpa, dependencies_node, dependencies_init);
   7078     } else {
   7079         // Add fixup for adding dependencies struct.
   7080         try fixups.append_string_after_node.put(gpa, manifest.version_node, dependencies_text);
   7081     }
   7082 
   7083     var aw: std.Io.Writer.Allocating = .init(gpa);
   7084     defer aw.deinit();
   7085     try ast.render(gpa, &aw.writer, fixups);
   7086     const rendered = aw.written();
   7087 
   7088     build_root.directory.handle.writeFile(.{ .sub_path = Package.Manifest.basename, .data = rendered }) catch |err| {
   7089         fatal("unable to write {s} file: {t}", .{ Package.Manifest.basename, err });
   7090     };
   7091 
   7092     return cleanExit();
   7093 }
   7094 
   7095 fn createEmptyDependenciesModule(
   7096     arena: Allocator,
   7097     main_mod: *Package.Module,
   7098     dirs: Compilation.Directories,
   7099     global_options: Compilation.Config,
   7100 ) !void {
   7101     var source = std.array_list.Managed(u8).init(arena);
   7102     try Package.Fetch.JobQueue.createEmptyDependenciesSource(&source);
   7103     _ = try createDependenciesModule(
   7104         arena,
   7105         source.items,
   7106         main_mod,
   7107         dirs,
   7108         global_options,
   7109     );
   7110 }
   7111 
   7112 /// Creates the dependencies.zig file and corresponding `Package.Module` for the
   7113 /// build runner to obtain via `@import("@dependencies")`.
   7114 fn createDependenciesModule(
   7115     arena: Allocator,
   7116     source: []const u8,
   7117     main_mod: *Package.Module,
   7118     dirs: Compilation.Directories,
   7119     global_options: Compilation.Config,
   7120 ) !*Package.Module {
   7121     // Atomically create the file in a directory named after the hash of its contents.
   7122     const basename = "dependencies.zig";
   7123     const rand_int = std.crypto.random.int(u64);
   7124     const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(rand_int);
   7125     {
   7126         var tmp_dir = try dirs.local_cache.handle.makeOpenPath(tmp_dir_sub_path, .{});
   7127         defer tmp_dir.close();
   7128         try tmp_dir.writeFile(.{ .sub_path = basename, .data = source });
   7129     }
   7130 
   7131     var hh: Cache.HashHelper = .{};
   7132     hh.addBytes(build_options.version);
   7133     hh.addBytes(source);
   7134     const hex_digest = hh.final();
   7135 
   7136     const o_dir_sub_path = try arena.dupe(u8, "o" ++ fs.path.sep_str ++ hex_digest);
   7137     try Package.Fetch.renameTmpIntoCache(
   7138         dirs.local_cache.handle,
   7139         tmp_dir_sub_path,
   7140         o_dir_sub_path,
   7141     );
   7142 
   7143     const deps_mod = try Package.Module.create(arena, .{
   7144         .paths = .{
   7145             .root = try .fromRoot(arena, dirs, .local_cache, o_dir_sub_path),
   7146             .root_src_path = basename,
   7147         },
   7148         .fully_qualified_name = "root.@dependencies",
   7149         .parent = main_mod,
   7150         .cc_argv = &.{},
   7151         .inherited = .{},
   7152         .global = global_options,
   7153     });
   7154     try main_mod.deps.put(arena, "@dependencies", deps_mod);
   7155     return deps_mod;
   7156 }
   7157 
   7158 const BuildRoot = struct {
   7159     directory: Cache.Directory,
   7160     build_zig_basename: []const u8,
   7161     cleanup_build_dir: ?fs.Dir,
   7162 
   7163     fn deinit(br: *BuildRoot) void {
   7164         if (br.cleanup_build_dir) |*dir| dir.close();
   7165         br.* = undefined;
   7166     }
   7167 };
   7168 
   7169 const FindBuildRootOptions = struct {
   7170     build_file: ?[]const u8 = null,
   7171     cwd_path: ?[]const u8 = null,
   7172 };
   7173 
   7174 fn findBuildRoot(arena: Allocator, options: FindBuildRootOptions) !BuildRoot {
   7175     const cwd_path = options.cwd_path orelse try introspect.getResolvedCwd(arena);
   7176     const build_zig_basename = if (options.build_file) |bf|
   7177         fs.path.basename(bf)
   7178     else
   7179         Package.build_zig_basename;
   7180 
   7181     if (options.build_file) |bf| {
   7182         if (fs.path.dirname(bf)) |dirname| {
   7183             const dir = fs.cwd().openDir(dirname, .{}) catch |err| {
   7184                 fatal("unable to open directory to build file from argument 'build-file', '{s}': {s}", .{ dirname, @errorName(err) });
   7185             };
   7186             return .{
   7187                 .build_zig_basename = build_zig_basename,
   7188                 .directory = .{ .path = dirname, .handle = dir },
   7189                 .cleanup_build_dir = dir,
   7190             };
   7191         }
   7192 
   7193         return .{
   7194             .build_zig_basename = build_zig_basename,
   7195             .directory = .{ .path = null, .handle = fs.cwd() },
   7196             .cleanup_build_dir = null,
   7197         };
   7198     }
   7199     // Search up parent directories until we find build.zig.
   7200     var dirname: []const u8 = cwd_path;
   7201     while (true) {
   7202         const joined_path = try fs.path.join(arena, &[_][]const u8{ dirname, build_zig_basename });
   7203         if (fs.cwd().access(joined_path, .{})) |_| {
   7204             const dir = fs.cwd().openDir(dirname, .{}) catch |err| {
   7205                 fatal("unable to open directory while searching for build.zig file, '{s}': {s}", .{ dirname, @errorName(err) });
   7206             };
   7207             return .{
   7208                 .build_zig_basename = build_zig_basename,
   7209                 .directory = .{
   7210                     .path = dirname,
   7211                     .handle = dir,
   7212                 },
   7213                 .cleanup_build_dir = dir,
   7214             };
   7215         } else |err| switch (err) {
   7216             error.FileNotFound => {
   7217                 dirname = fs.path.dirname(dirname) orelse {
   7218                     std.log.info("initialize {s} template file with 'zig init'", .{
   7219                         Package.build_zig_basename,
   7220                     });
   7221                     std.log.info("see 'zig --help' for more options", .{});
   7222                     fatal("no build.zig file found, in the current directory or any parent directories", .{});
   7223                 };
   7224                 continue;
   7225             },
   7226             else => |e| return e,
   7227         }
   7228     }
   7229 }
   7230 
   7231 const LoadManifestOptions = struct {
   7232     root_name: []const u8,
   7233     dir: fs.Dir,
   7234     color: Color,
   7235 };
   7236 
   7237 fn loadManifest(
   7238     gpa: Allocator,
   7239     arena: Allocator,
   7240     options: LoadManifestOptions,
   7241 ) !struct { Package.Manifest, Ast } {
   7242     const manifest_bytes = while (true) {
   7243         break options.dir.readFileAllocOptions(
   7244             Package.Manifest.basename,
   7245             arena,
   7246             .limited(Package.Manifest.max_bytes),
   7247             .@"1",
   7248             0,
   7249         ) catch |err| switch (err) {
   7250             error.FileNotFound => {
   7251                 writeSimpleTemplateFile(Package.Manifest.basename,
   7252                     \\.{{
   7253                     \\    .name = .{s},
   7254                     \\    .version = "{s}",
   7255                     \\    .paths = .{{""}},
   7256                     \\    .fingerprint = 0x{x},
   7257                     \\}}
   7258                     \\
   7259                 , .{
   7260                     options.root_name,
   7261                     build_options.version,
   7262                     Package.Fingerprint.generate(options.root_name).int(),
   7263                 }) catch |e| {
   7264                     fatal("unable to write {s}: {s}", .{ Package.Manifest.basename, @errorName(e) });
   7265                 };
   7266                 continue;
   7267             },
   7268             else => |e| fatal("unable to load {s}: {s}", .{
   7269                 Package.Manifest.basename, @errorName(e),
   7270             }),
   7271         };
   7272     };
   7273     var ast = try Ast.parse(gpa, manifest_bytes, .zon);
   7274     errdefer ast.deinit(gpa);
   7275 
   7276     if (ast.errors.len > 0) {
   7277         try std.zig.printAstErrorsToStderr(gpa, ast, Package.Manifest.basename, options.color);
   7278         process.exit(2);
   7279     }
   7280 
   7281     var manifest = try Package.Manifest.parse(gpa, ast, .{});
   7282     errdefer manifest.deinit(gpa);
   7283 
   7284     if (manifest.errors.len > 0) {
   7285         var wip_errors: std.zig.ErrorBundle.Wip = undefined;
   7286         try wip_errors.init(gpa);
   7287         defer wip_errors.deinit();
   7288 
   7289         const src_path = try wip_errors.addString(Package.Manifest.basename);
   7290         try manifest.copyErrorsIntoBundle(ast, src_path, &wip_errors);
   7291 
   7292         var error_bundle = try wip_errors.toOwnedBundle("");
   7293         defer error_bundle.deinit(gpa);
   7294         error_bundle.renderToStdErr(options.color.renderOptions());
   7295 
   7296         process.exit(2);
   7297     }
   7298     return .{ manifest, ast };
   7299 }
   7300 
   7301 const Templates = struct {
   7302     zig_lib_directory: Cache.Directory,
   7303     dir: fs.Dir,
   7304     buffer: std.array_list.Managed(u8),
   7305 
   7306     fn deinit(templates: *Templates) void {
   7307         templates.zig_lib_directory.handle.close();
   7308         templates.dir.close();
   7309         templates.buffer.deinit();
   7310         templates.* = undefined;
   7311     }
   7312 
   7313     fn write(
   7314         templates: *Templates,
   7315         arena: Allocator,
   7316         out_dir: fs.Dir,
   7317         root_name: []const u8,
   7318         template_path: []const u8,
   7319         fingerprint: Package.Fingerprint,
   7320     ) !void {
   7321         if (fs.path.dirname(template_path)) |dirname| {
   7322             out_dir.makePath(dirname) catch |err| {
   7323                 fatal("unable to make path '{s}': {s}", .{ dirname, @errorName(err) });
   7324             };
   7325         }
   7326 
   7327         const max_bytes = 10 * 1024 * 1024;
   7328         const contents = templates.dir.readFileAlloc(template_path, arena, .limited(max_bytes)) catch |err| {
   7329             fatal("unable to read template file '{s}': {s}", .{ template_path, @errorName(err) });
   7330         };
   7331         templates.buffer.clearRetainingCapacity();
   7332         try templates.buffer.ensureUnusedCapacity(contents.len);
   7333         var i: usize = 0;
   7334         while (i < contents.len) {
   7335             if (contents[i] == '_' or contents[i] == '.') {
   7336                 // Both '_' and '.' are allowed because depending on the context
   7337                 // one prefix will be valid, while the other might not.
   7338                 if (std.mem.startsWith(u8, contents[i + 1 ..], "NAME")) {
   7339                     try templates.buffer.appendSlice(root_name);
   7340                     i += "_NAME".len;
   7341                     continue;
   7342                 } else if (std.mem.startsWith(u8, contents[i + 1 ..], "FINGERPRINT")) {
   7343                     try templates.buffer.print("0x{x}", .{fingerprint.int()});
   7344                     i += "_FINGERPRINT".len;
   7345                     continue;
   7346                 } else if (std.mem.startsWith(u8, contents[i + 1 ..], "ZIGVER")) {
   7347                     try templates.buffer.appendSlice(build_options.version);
   7348                     i += "_ZIGVER".len;
   7349                     continue;
   7350                 }
   7351             }
   7352 
   7353             try templates.buffer.append(contents[i]);
   7354             i += 1;
   7355         }
   7356 
   7357         return out_dir.writeFile(.{
   7358             .sub_path = template_path,
   7359             .data = templates.buffer.items,
   7360             .flags = .{ .exclusive = true },
   7361         });
   7362     }
   7363 };
   7364 fn writeSimpleTemplateFile(file_name: []const u8, comptime fmt: []const u8, args: anytype) !void {
   7365     const f = try fs.cwd().createFile(file_name, .{ .exclusive = true });
   7366     defer f.close();
   7367     var buf: [4096]u8 = undefined;
   7368     var fw = f.writer(&buf);
   7369     try fw.interface.print(fmt, args);
   7370     try fw.interface.flush();
   7371 }
   7372 
   7373 fn findTemplates(gpa: Allocator, arena: Allocator) Templates {
   7374     const cwd_path = introspect.getResolvedCwd(arena) catch |err| {
   7375         fatal("unable to get cwd: {s}", .{@errorName(err)});
   7376     };
   7377     const self_exe_path = fs.selfExePathAlloc(arena) catch |err| {
   7378         fatal("unable to find self exe path: {s}", .{@errorName(err)});
   7379     };
   7380     var zig_lib_directory = introspect.findZigLibDirFromSelfExe(arena, cwd_path, self_exe_path) catch |err| {
   7381         fatal("unable to find zig installation directory '{s}': {s}", .{ self_exe_path, @errorName(err) });
   7382     };
   7383 
   7384     const s = fs.path.sep_str;
   7385     const template_sub_path = "init";
   7386     const template_dir = zig_lib_directory.handle.openDir(template_sub_path, .{}) catch |err| {
   7387         const path = zig_lib_directory.path orelse ".";
   7388         fatal("unable to open zig project template directory '{s}{s}{s}': {s}", .{
   7389             path, s, template_sub_path, @errorName(err),
   7390         });
   7391     };
   7392 
   7393     return .{
   7394         .zig_lib_directory = zig_lib_directory,
   7395         .dir = template_dir,
   7396         .buffer = std.array_list.Managed(u8).init(gpa),
   7397     };
   7398 }
   7399 
   7400 fn parseOptimizeMode(s: []const u8) std.builtin.OptimizeMode {
   7401     return std.meta.stringToEnum(std.builtin.OptimizeMode, s) orelse
   7402         fatal("unrecognized optimization mode: '{s}'", .{s});
   7403 }
   7404 
   7405 fn parseWasiExecModel(s: []const u8) std.builtin.WasiExecModel {
   7406     return std.meta.stringToEnum(std.builtin.WasiExecModel, s) orelse
   7407         fatal("expected [command|reactor] for -mexec-mode=[value], found '{s}'", .{s});
   7408 }
   7409 
   7410 fn parseStackSize(s: []const u8) u64 {
   7411     return std.fmt.parseUnsigned(u64, s, 0) catch |err|
   7412         fatal("unable to parse stack size '{s}': {s}", .{ s, @errorName(err) });
   7413 }
   7414 
   7415 fn parseImageBase(s: []const u8) u64 {
   7416     return std.fmt.parseUnsigned(u64, s, 0) catch |err|
   7417         fatal("unable to parse image base '{s}': {s}", .{ s, @errorName(err) });
   7418 }
   7419 
   7420 fn handleModArg(
   7421     arena: Allocator,
   7422     mod_name: []const u8,
   7423     opt_root_src_orig: ?[]const u8,
   7424     create_module: *CreateModule,
   7425     mod_opts: *Package.Module.CreateOptions.Inherited,
   7426     cc_argv: *std.ArrayListUnmanaged([]const u8),
   7427     target_arch_os_abi: *?[]const u8,
   7428     target_mcpu: *?[]const u8,
   7429     deps: *std.ArrayListUnmanaged(CliModule.Dep),
   7430     c_source_files_owner_index: *usize,
   7431     rc_source_files_owner_index: *usize,
   7432     cssan: *ClangSearchSanitizer,
   7433 ) !void {
   7434     const gop = try create_module.modules.getOrPut(arena, mod_name);
   7435 
   7436     if (gop.found_existing) {
   7437         fatal("unable to add module '{s}': already exists as '{s}{c}{s}'", .{
   7438             mod_name, gop.value_ptr.root_path, fs.path.sep, gop.value_ptr.root_src_path,
   7439         });
   7440     }
   7441 
   7442     // See duplicate logic: ModCreationGlobalFlags
   7443     if (mod_opts.single_threaded == false)
   7444         create_module.opts.any_non_single_threaded = true;
   7445     if (mod_opts.sanitize_thread == true)
   7446         create_module.opts.any_sanitize_thread = true;
   7447     if (mod_opts.sanitize_c) |sc| switch (sc) {
   7448         .off => {},
   7449         .trap => if (create_module.opts.any_sanitize_c == .off) {
   7450             create_module.opts.any_sanitize_c = .trap;
   7451         },
   7452         .full => create_module.opts.any_sanitize_c = .full,
   7453     };
   7454     if (mod_opts.fuzz == true)
   7455         create_module.opts.any_fuzz = true;
   7456     if (mod_opts.unwind_tables) |uwt| switch (uwt) {
   7457         .none => {},
   7458         .sync, .async => create_module.opts.any_unwind_tables = true,
   7459     };
   7460     if (mod_opts.strip == false)
   7461         create_module.opts.any_non_stripped = true;
   7462     if (mod_opts.error_tracing == true)
   7463         create_module.opts.any_error_tracing = true;
   7464 
   7465     const root_path: []const u8, const root_src_path: []const u8 = if (opt_root_src_orig) |path| root: {
   7466         create_module.opts.have_zcu = true;
   7467         break :root .{ fs.path.dirname(path) orelse ".", fs.path.basename(path) };
   7468     } else .{ ".", "" };
   7469 
   7470     gop.value_ptr.* = .{
   7471         .root_path = root_path,
   7472         .root_src_path = root_src_path,
   7473         .cc_argv = try cc_argv.toOwnedSlice(arena),
   7474         .inherited = mod_opts.*,
   7475         .target_arch_os_abi = target_arch_os_abi.*,
   7476         .target_mcpu = target_mcpu.*,
   7477         .deps = try deps.toOwnedSlice(arena),
   7478         .resolved = null,
   7479         .c_source_files_start = c_source_files_owner_index.*,
   7480         .c_source_files_end = create_module.c_source_files.items.len,
   7481         .rc_source_files_start = rc_source_files_owner_index.*,
   7482         .rc_source_files_end = create_module.rc_source_files.items.len,
   7483     };
   7484     cssan.reset();
   7485     mod_opts.* = .{};
   7486     target_arch_os_abi.* = null;
   7487     target_mcpu.* = null;
   7488     c_source_files_owner_index.* = create_module.c_source_files.items.len;
   7489     rc_source_files_owner_index.* = create_module.rc_source_files.items.len;
   7490 }
   7491 
   7492 fn anyObjectLinkInputs(link_inputs: []const link.UnresolvedInput) bool {
   7493     for (link_inputs) |link_input| switch (link_input) {
   7494         .path_query => |pq| switch (Compilation.classifyFileExt(pq.path.sub_path)) {
   7495             .object, .static_library, .res => return true,
   7496             else => continue,
   7497         },
   7498         else => continue,
   7499     };
   7500     return false;
   7501 }
   7502 
   7503 fn addLibDirectoryWarn(lib_directories: *std.ArrayListUnmanaged(Directory), path: []const u8) void {
   7504     return addLibDirectoryWarn2(lib_directories, path, false);
   7505 }
   7506 
   7507 fn addLibDirectoryWarn2(
   7508     lib_directories: *std.ArrayListUnmanaged(Directory),
   7509     path: []const u8,
   7510     ignore_not_found: bool,
   7511 ) void {
   7512     lib_directories.appendAssumeCapacity(.{
   7513         .handle = fs.cwd().openDir(path, .{}) catch |err| {
   7514             if (err == error.FileNotFound and ignore_not_found) return;
   7515             warn("unable to open library directory '{s}': {s}", .{ path, @errorName(err) });
   7516             return;
   7517         },
   7518         .path = path,
   7519     });
   7520 }