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