Commit b8861a94dd

Andrew Kelley <andrew@ziglang.org>
2020-09-22 01:33:29
stage2: building compiler_rt and libc static archive with stage1
* add CLI support for verbose debugging options * implement building compiler_rt and libc static archive using stage1 C++ backend * add function_sections and link_libcpp to root cache hash. * cleanups to use the new Directory.join method. * Package supports being initialized directly and cleaned up create() method. * fix classifyFileExt incorrectly saying .zir is .zig. Thanks @Rocknest! * unify updateSubCompilation implementations
1 parent bd1465a
src-self-hosted/link/Elf.zig
@@ -1253,8 +1253,9 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
 
     const is_lib = self.base.options.output_mode == .Lib;
     const is_dyn_lib = self.base.options.link_mode == .Dynamic and is_lib;
+    const is_exe_or_dyn_lib = is_dyn_lib or self.base.options.output_mode == .Exe;
     const have_dynamic_linker = self.base.options.link_libc and
-        self.base.options.link_mode == .Dynamic and (is_dyn_lib or self.base.options.output_mode == .Exe);
+        self.base.options.link_mode == .Dynamic and is_exe_or_dyn_lib;
 
     try ch.addOptionalFile(self.base.options.linker_script);
     try ch.addOptionalFile(self.base.options.version_script);
@@ -1489,16 +1490,13 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
         try argv.append(p);
     }
 
-    // TODO compiler-rt and libc
-    //if (!g->is_dummy_so && (g->out_type == OutTypeExe || is_dyn_lib)) {
-    //    if (g->libc_link_lib == nullptr) {
-    //        Buf *libc_a_path = build_c(g, OutTypeLib, lj->build_dep_prog_node);
-    //        try argv.append(buf_ptr(libc_a_path));
-    //    }
-
-    //    Buf *compiler_rt_o_path = build_compiler_rt(g, OutTypeLib, lj->build_dep_prog_node);
-    //    try argv.append(buf_ptr(compiler_rt_o_path));
-    //}
+    // compiler-rt and libc
+    if (is_exe_or_dyn_lib) {
+        if (!self.base.options.link_libc) {
+            try argv.append(comp.libc_static_lib.?.full_object_path);
+        }
+        try argv.append(comp.compiler_rt_static_lib.?.full_object_path);
+    }
 
     // Shared libraries.
     try argv.ensureCapacity(argv.items.len + self.base.options.system_libs.len);
@@ -1545,7 +1543,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
                 try argv.append(try comp.get_libc_crt_file(arena, "libc_nonshared.a"));
             } else if (target.isMusl()) {
                 try argv.append(comp.libunwind_static_lib.?.full_object_path);
-                try argv.append(comp.libc_static_lib.?);
+                try argv.append(comp.libc_static_lib.?.full_object_path);
             } else if (self.base.options.link_libcpp) {
                 try argv.append(comp.libunwind_static_lib.?.full_object_path);
             } else {
src-self-hosted/Compilation.zig
@@ -46,6 +46,12 @@ sanitize_c: bool,
 clang_passthrough_mode: bool,
 /// Whether to print clang argvs to stdout.
 verbose_cc: bool,
+verbose_tokenize: bool,
+verbose_ast: bool,
+verbose_ir: bool,
+verbose_llvm_ir: bool,
+verbose_cimport: bool,
+verbose_llvm_cpu_features: bool,
 disable_c_depfile: bool,
 is_test: bool,
 
@@ -59,18 +65,21 @@ zig_cache_directory: Directory,
 libc_include_dir_list: []const []const u8,
 rand: *std.rand.Random,
 
-/// Populated when we build libc++.a. A Job to build this is placed in the queue
+/// Populated when we build the libc++ static library. A Job to build this is placed in the queue
 /// and resolved before calling linker.flush().
 libcxx_static_lib: ?[]const u8 = null,
-/// Populated when we build libc++abi.a. A Job to build this is placed in the queue
+/// Populated when we build the libc++abi static library. A Job to build this is placed in the queue
 /// and resolved before calling linker.flush().
 libcxxabi_static_lib: ?[]const u8 = null,
-/// Populated when we build libunwind.a. A Job to build this is placed in the queue
+/// Populated when we build the libunwind static library. A Job to build this is placed in the queue
 /// and resolved before calling linker.flush().
 libunwind_static_lib: ?CRTFile = null,
-/// Populated when we build c.a. A Job to build this is placed in the queue
+/// Populated when we build the libc static library. A Job to build this is placed in the queue
 /// and resolved before calling linker.flush().
-libc_static_lib: ?[]const u8 = null,
+libc_static_lib: ?CRTFile = null,
+/// Populated when we build the libcompiler_rt static library. A Job to build this is placed in the queue
+/// and resolved before calling linker.flush().
+compiler_rt_static_lib: ?CRTFile = null,
 
 glibc_so_files: ?glibc.BuiltSharedObjects = null,
 
@@ -121,6 +130,11 @@ const Job = union(enum) {
     glibc_shared_objects,
     /// libunwind.a, usually needed when linking libc
     libunwind: void,
+    /// needed when producing a dynamic library or executable
+    libcompiler_rt: void,
+    /// needed when not linking libc and using LLVM for code generation because it generates
+    /// calls to, for example, memcpy and memset.
+    zig_libc: void,
 
     /// Generate builtin.zig source code and write it into the correct place.
     generate_builtin_zig: void,
@@ -310,6 +324,15 @@ pub const InitOptions = struct {
 };
 
 pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
+    const is_dyn_lib = switch (options.output_mode) {
+        .Obj, .Exe => false,
+        .Lib => (options.link_mode orelse .Static) == .Dynamic,
+    };
+    const is_exe_or_dyn_lib = switch (options.output_mode) {
+        .Obj => false,
+        .Lib => is_dyn_lib,
+        .Exe => true,
+    };
     const comp: *Compilation = comp: {
         // For allocations that have the same lifetime as Compilation. This arena is used only during this
         // initialization and then is freed in deinit().
@@ -375,15 +398,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
             return error.MachineCodeModelNotSupported;
         }
 
-        const is_dyn_lib = switch (options.output_mode) {
-            .Obj, .Exe => false,
-            .Lib => (options.link_mode orelse .Static) == .Dynamic,
-        };
-        const is_exe_or_dyn_lib = switch (options.output_mode) {
-            .Obj => false,
-            .Lib => is_dyn_lib,
-            .Exe => true,
-        };
         const must_dynamic_link = dl: {
             if (target_util.cannotDynamicLink(options.target))
                 break :dl false;
@@ -461,6 +475,27 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
         };
 
         const single_threaded = options.single_threaded or target_util.isSingleThreaded(options.target);
+        const function_sections = options.function_sections orelse false;
+
+        const llvm_cpu_features: ?[*:0]const u8 = if (build_options.have_llvm and use_llvm) blk: {
+            var buf = std.ArrayList(u8).init(arena);
+            for (options.target.cpu.arch.allFeaturesList()) |feature, index_usize| {
+                const index = @intCast(Target.Cpu.Feature.Set.Index, index_usize);
+                const is_enabled = options.target.cpu.features.isEnabled(index);
+
+                if (feature.llvm_name) |llvm_name| {
+                    const plus_or_minus = "-+"[@boolToInt(is_enabled)];
+                    try buf.ensureCapacity(buf.items.len + 2 + llvm_name.len);
+                    buf.appendAssumeCapacity(plus_or_minus);
+                    buf.appendSliceAssumeCapacity(llvm_name);
+                    buf.appendSliceAssumeCapacity(",");
+                }
+            }
+            assert(mem.endsWith(u8, buf.items, ","));
+            buf.items[buf.items.len - 1] = 0;
+            buf.shrink(buf.items.len);
+            break :blk buf.items[0 .. buf.items.len - 1 :0].ptr;
+        } else null;
 
         // We put everything into the cache hash that *cannot be modified during an incremental update*.
         // For example, one cannot change the target between updates, but one can change source files,
@@ -489,8 +524,10 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
         cache.hash.add(pic);
         cache.hash.add(stack_check);
         cache.hash.add(link_mode);
+        cache.hash.add(function_sections);
         cache.hash.add(options.strip);
         cache.hash.add(options.link_libc);
+        cache.hash.add(options.link_libcpp);
         cache.hash.add(options.output_mode);
         cache.hash.add(options.machine_code_model);
         // TODO audit this and make sure everything is in it
@@ -596,10 +633,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
             owned_link_dir = artifact_dir;
             const link_artifact_directory: Directory = .{
                 .handle = artifact_dir,
-                .path = if (options.zig_cache_directory.path) |p|
-                    try std.fs.path.join(arena, &[_][]const u8{ p, artifact_sub_dir })
-                else
-                    artifact_sub_dir,
+                .path = try options.zig_cache_directory.join(arena, &[_][]const u8{artifact_sub_dir}),
             };
             break :blk link_artifact_directory;
         };
@@ -609,26 +643,6 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
             .ReleaseFast, .ReleaseSmall => false,
         };
 
-        const llvm_cpu_features: ?[*:0]const u8 = if (build_options.have_llvm and use_llvm) blk: {
-            var buf = std.ArrayList(u8).init(arena);
-            for (options.target.cpu.arch.allFeaturesList()) |feature, index_usize| {
-                const index = @intCast(Target.Cpu.Feature.Set.Index, index_usize);
-                const is_enabled = options.target.cpu.features.isEnabled(index);
-
-                if (feature.llvm_name) |llvm_name| {
-                    const plus_or_minus = "-+"[@boolToInt(is_enabled)];
-                    try buf.ensureCapacity(buf.items.len + 2 + llvm_name.len);
-                    buf.appendAssumeCapacity(plus_or_minus);
-                    buf.appendSliceAssumeCapacity(llvm_name);
-                    buf.appendSliceAssumeCapacity(",");
-                }
-            }
-            assert(mem.endsWith(u8, buf.items, ","));
-            buf.items[buf.items.len - 1] = 0;
-            buf.shrink(buf.items.len);
-            break :blk buf.items[0 .. buf.items.len - 1 :0].ptr;
-        } else null;
-
         const stage1_module: ?*stage1.Module = if (build_options.is_stage1 and use_llvm) blk: {
             // Here we use the legacy stage1 C++ compiler to compile Zig code.
             const stage2_target = try arena.create(stage1.Stage2Target);
@@ -646,7 +660,9 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
             if (options.color == .Off) progress.terminal = null;
 
             const mod = module.?;
-            const main_zig_file = mod.root_pkg.root_src_path;
+            const main_zig_file = try mod.root_pkg.root_src_directory.join(arena, &[_][]const u8{
+                mod.root_pkg.root_src_path,
+            });
             const zig_lib_dir = options.zig_lib_directory.path.?;
             const builtin_sub = &[_][]const u8{"builtin.zig"};
             const builtin_zig_path = try mod.zig_cache_artifact_directory.join(arena, builtin_sub);
@@ -700,7 +716,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
                 .dll_export_fns = dll_export_fns,
                 .link_mode_dynamic = link_mode == .Dynamic,
                 .valgrind_enabled = valgrind,
-                .function_sections = options.function_sections orelse false,
+                .function_sections = function_sections,
                 .enable_stack_probing = stack_check,
                 .enable_time_report = options.time_report,
                 .enable_stack_report = false,
@@ -790,6 +806,12 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
             .rand = options.rand,
             .clang_passthrough_mode = options.clang_passthrough_mode,
             .verbose_cc = options.verbose_cc,
+            .verbose_tokenize = options.verbose_tokenize,
+            .verbose_ast = options.verbose_ast,
+            .verbose_ir = options.verbose_ir,
+            .verbose_llvm_ir = options.verbose_llvm_ir,
+            .verbose_cimport = options.verbose_cimport,
+            .verbose_llvm_cpu_features = options.verbose_llvm_cpu_features,
             .disable_c_depfile = options.disable_c_depfile,
             .owned_link_dir = owned_link_dir,
             .is_test = options.is_test,
@@ -823,10 +845,15 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
     if (comp.wantBuildLibUnwindFromSource()) {
         try comp.work_queue.writeItem(.{ .libunwind = {} });
     }
-
     if (comp.stage1_module) |module| {
         try comp.work_queue.writeItem(.{ .stage1_module = {} });
     }
+    if (is_exe_or_dyn_lib) {
+        try comp.work_queue.writeItem(.{ .libcompiler_rt = {} });
+        if (!comp.bin_file.options.link_libc) {
+            try comp.work_queue.writeItem(.{ .zig_libc = {} });
+        }
+    }
 
     return comp;
 }
@@ -852,8 +879,14 @@ pub fn destroy(self: *Compilation) void {
         self.crt_files.deinit(gpa);
     }
 
-    if (self.libunwind_static_lib) |*unwind_crt_file| {
-        unwind_crt_file.deinit(gpa);
+    if (self.libunwind_static_lib) |*crt_file| {
+        crt_file.deinit(gpa);
+    }
+    if (self.compiler_rt_static_lib) |*crt_file| {
+        crt_file.deinit(gpa);
+    }
+    if (self.libc_static_lib) |*crt_file| {
+        crt_file.deinit(gpa);
     }
 
     for (self.c_object_table.items()) |entry| {
@@ -889,41 +922,46 @@ pub fn update(self: *Compilation) !void {
         self.work_queue.writeItemAssumeCapacity(.{ .c_object = entry.key });
     }
 
-    if (self.bin_file.options.module) |module| {
-        module.generation += 1;
-
-        // TODO Detect which source files changed.
-        // Until then we simulate a full cache miss. Source files could have been loaded for any reason;
-        // to force a refresh we unload now.
-        if (module.root_scope.cast(Module.Scope.File)) |zig_file| {
-            zig_file.unload(module.gpa);
-            module.analyzeContainer(&zig_file.root_container) catch |err| switch (err) {
-                error.AnalysisFail => {
-                    assert(self.totalErrorCount() != 0);
-                },
-                else => |e| return e,
-            };
-        } else if (module.root_scope.cast(Module.Scope.ZIRModule)) |zir_module| {
-            zir_module.unload(module.gpa);
-            module.analyzeRootZIRModule(zir_module) catch |err| switch (err) {
-                error.AnalysisFail => {
-                    assert(self.totalErrorCount() != 0);
-                },
-                else => |e| return e,
-            };
+    const use_stage1 = build_options.is_stage1 and self.bin_file.options.use_llvm;
+    if (!use_stage1) {
+        if (self.bin_file.options.module) |module| {
+            module.generation += 1;
+
+            // TODO Detect which source files changed.
+            // Until then we simulate a full cache miss. Source files could have been loaded for any reason;
+            // to force a refresh we unload now.
+            if (module.root_scope.cast(Module.Scope.File)) |zig_file| {
+                zig_file.unload(module.gpa);
+                module.analyzeContainer(&zig_file.root_container) catch |err| switch (err) {
+                    error.AnalysisFail => {
+                        assert(self.totalErrorCount() != 0);
+                    },
+                    else => |e| return e,
+                };
+            } else if (module.root_scope.cast(Module.Scope.ZIRModule)) |zir_module| {
+                zir_module.unload(module.gpa);
+                module.analyzeRootZIRModule(zir_module) catch |err| switch (err) {
+                    error.AnalysisFail => {
+                        assert(self.totalErrorCount() != 0);
+                    },
+                    else => |e| return e,
+                };
+            }
         }
     }
 
     try self.performAllTheWork();
 
-    if (self.bin_file.options.module) |module| {
-        // Process the deletion set.
-        while (module.deletion_set.popOrNull()) |decl| {
-            if (decl.dependants.items().len != 0) {
-                decl.deletion_flag = false;
-                continue;
+    if (!use_stage1) {
+        if (self.bin_file.options.module) |module| {
+            // Process the deletion set.
+            while (module.deletion_set.popOrNull()) |decl| {
+                if (decl.dependants.items().len != 0) {
+                    decl.deletion_flag = false;
+                    continue;
+                }
+                try module.deleteDecl(decl);
             }
-            try module.deleteDecl(decl);
         }
     }
 
@@ -1142,6 +1180,18 @@ pub fn performAllTheWork(self: *Compilation) error{OutOfMemory}!void {
                 fatal("unable to build libunwind: {}", .{@errorName(err)});
             };
         },
+        .libcompiler_rt => {
+            self.buildStaticLibFromZig("compiler_rt.zig", &self.compiler_rt_static_lib) catch |err| {
+                // TODO Expose this as a normal compile error rather than crashing here.
+                fatal("unable to build compiler_rt: {}", .{@errorName(err)});
+            };
+        },
+        .zig_libc => {
+            self.buildStaticLibFromZig("c.zig", &self.libc_static_lib) catch |err| {
+                // TODO Expose this as a normal compile error rather than crashing here.
+                fatal("unable to build zig's multitarget libc: {}", .{@errorName(err)});
+            };
+        },
         .generate_builtin_zig => {
             // This Job is only queued up if there is a zig module.
             self.updateBuiltinZigFile(self.bin_file.options.module.?) catch |err| {
@@ -1691,7 +1741,7 @@ pub fn classifyFileExt(filename: []const u8) FileExt {
     } else if (mem.endsWith(u8, filename, ".zig")) {
         return .zig;
     } else if (mem.endsWith(u8, filename, ".zir")) {
-        return .zig;
+        return .zir;
     } else if (hasSharedLibraryExt(filename)) {
         return .shared_library;
     } else if (hasStaticLibraryExt(filename)) {
@@ -2030,3 +2080,97 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8
     });
     return buffer.toOwnedSlice();
 }
+
+pub fn updateSubCompilation(sub_compilation: *Compilation) !void {
+    try sub_compilation.update();
+
+    // Look for compilation errors in this sub_compilation
+    var errors = try sub_compilation.getAllErrorsAlloc();
+    defer errors.deinit(sub_compilation.gpa);
+
+    if (errors.list.len != 0) {
+        for (errors.list) |full_err_msg| {
+            std.log.err("{}:{}:{}: {}\n", .{
+                full_err_msg.src_path,
+                full_err_msg.line + 1,
+                full_err_msg.column + 1,
+                full_err_msg.msg,
+            });
+        }
+        return error.BuildingLibCObjectFailed;
+    }
+}
+
+fn buildStaticLibFromZig(comp: *Compilation, basename: []const u8, out: *?CRTFile) !void {
+    const tracy = trace(@src());
+    defer tracy.end();
+
+    const special_sub = "std" ++ std.fs.path.sep_str ++ "special";
+    const special_path = try comp.zig_lib_directory.join(comp.gpa, &[_][]const u8{special_sub});
+    defer comp.gpa.free(special_path);
+
+    var special_dir = try comp.zig_lib_directory.handle.openDir(special_sub, .{});
+    defer special_dir.close();
+
+    var root_pkg: Package = .{
+        .root_src_directory = .{
+            .path = special_path,
+            .handle = special_dir,
+        },
+        .root_src_path = basename,
+    };
+
+    const emit_bin = Compilation.EmitLoc{
+        .directory = null, // Put it in the cache directory.
+        .basename = basename,
+    };
+    const optimize_mode: std.builtin.Mode = blk: {
+        if (comp.is_test)
+            break :blk comp.bin_file.options.optimize_mode;
+        switch (comp.bin_file.options.optimize_mode) {
+            .Debug, .ReleaseFast, .ReleaseSafe => break :blk .ReleaseFast,
+            .ReleaseSmall => break :blk .ReleaseSmall,
+        }
+    };
+    const sub_compilation = try Compilation.create(comp.gpa, .{
+        // TODO use the global cache directory here
+        .zig_cache_directory = comp.zig_cache_directory,
+        .zig_lib_directory = comp.zig_lib_directory,
+        .target = comp.getTarget(),
+        .root_name = mem.split(basename, ".").next().?,
+        .root_pkg = &root_pkg,
+        .output_mode = .Lib,
+        .rand = comp.rand,
+        .libc_installation = comp.bin_file.options.libc_installation,
+        .emit_bin = emit_bin,
+        .optimize_mode = optimize_mode,
+        .link_mode = .Static,
+        .function_sections = true,
+        .want_sanitize_c = false,
+        .want_stack_check = false,
+        .want_valgrind = false,
+        .want_pic = comp.bin_file.options.pic,
+        .emit_h = null,
+        .strip = comp.bin_file.options.strip,
+        .is_native_os = comp.bin_file.options.is_native_os,
+        .self_exe_path = comp.self_exe_path,
+        .verbose_cc = comp.verbose_cc,
+        .verbose_link = comp.bin_file.options.verbose_link,
+        .verbose_tokenize = comp.verbose_tokenize,
+        .verbose_ast = comp.verbose_ast,
+        .verbose_ir = comp.verbose_ir,
+        .verbose_llvm_ir = comp.verbose_llvm_ir,
+        .verbose_cimport = comp.verbose_cimport,
+        .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
+        .clang_passthrough_mode = comp.clang_passthrough_mode,
+    });
+    defer sub_compilation.destroy();
+
+    try sub_compilation.updateSubCompilation();
+
+    assert(out.* == null);
+    out.* = Compilation.CRTFile{
+        .full_object_path = try sub_compilation.bin_file.options.directory.join(comp.gpa, &[_][]const u8{basename}),
+        .lock = sub_compilation.bin_file.toOwnedLock(),
+    };
+}
src-self-hosted/glibc.zig
@@ -713,11 +713,17 @@ fn build_crt_file(
         .c_source_files = c_source_files,
         .verbose_cc = comp.verbose_cc,
         .verbose_link = comp.bin_file.options.verbose_link,
+        .verbose_tokenize = comp.verbose_tokenize,
+        .verbose_ast = comp.verbose_ast,
+        .verbose_ir = comp.verbose_ir,
+        .verbose_llvm_ir = comp.verbose_llvm_ir,
+        .verbose_cimport = comp.verbose_cimport,
+        .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
         .clang_passthrough_mode = comp.clang_passthrough_mode,
     });
     defer sub_compilation.destroy();
 
-    try updateSubCompilation(sub_compilation);
+    try sub_compilation.updateSubCompilation();
 
     try comp.crt_files.ensureCapacity(comp.gpa, comp.crt_files.count() + 1);
     const artifact_path = if (sub_compilation.bin_file.options.directory.path) |p|
@@ -989,6 +995,12 @@ fn buildSharedLib(
         .self_exe_path = comp.self_exe_path,
         .verbose_cc = comp.verbose_cc,
         .verbose_link = comp.bin_file.options.verbose_link,
+        .verbose_tokenize = comp.verbose_tokenize,
+        .verbose_ast = comp.verbose_ast,
+        .verbose_ir = comp.verbose_ir,
+        .verbose_llvm_ir = comp.verbose_llvm_ir,
+        .verbose_cimport = comp.verbose_cimport,
+        .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
         .clang_passthrough_mode = comp.clang_passthrough_mode,
         .version = version,
         .version_script = map_file_path,
@@ -997,25 +1009,5 @@ fn buildSharedLib(
     });
     defer sub_compilation.destroy();
 
-    try updateSubCompilation(sub_compilation);
-}
-
-fn updateSubCompilation(sub_compilation: *Compilation) !void {
-    try sub_compilation.update();
-
-    // Look for compilation errors in this sub_compilation
-    var errors = try sub_compilation.getAllErrorsAlloc();
-    defer errors.deinit(sub_compilation.gpa);
-
-    if (errors.list.len != 0) {
-        for (errors.list) |full_err_msg| {
-            std.log.err("{}:{}:{}: {}\n", .{
-                full_err_msg.src_path,
-                full_err_msg.line + 1,
-                full_err_msg.column + 1,
-                full_err_msg.msg,
-            });
-        }
-        return error.BuildingLibCObjectFailed;
-    }
+    try sub_compilation.updateSubCompilation();
 }
src-self-hosted/libunwind.zig
@@ -109,12 +109,18 @@ pub fn buildStaticLib(comp: *Compilation) !void {
         .c_source_files = &c_source_files,
         .verbose_cc = comp.verbose_cc,
         .verbose_link = comp.bin_file.options.verbose_link,
+        .verbose_tokenize = comp.verbose_tokenize,
+        .verbose_ast = comp.verbose_ast,
+        .verbose_ir = comp.verbose_ir,
+        .verbose_llvm_ir = comp.verbose_llvm_ir,
+        .verbose_cimport = comp.verbose_cimport,
+        .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
         .clang_passthrough_mode = comp.clang_passthrough_mode,
         .link_libc = true,
     });
     defer sub_compilation.destroy();
 
-    try updateSubCompilation(sub_compilation);
+    try sub_compilation.updateSubCompilation();
 
     assert(comp.libunwind_static_lib == null);
     comp.libunwind_static_lib = Compilation.CRTFile{
@@ -122,23 +128,3 @@ pub fn buildStaticLib(comp: *Compilation) !void {
         .lock = sub_compilation.bin_file.toOwnedLock(),
     };
 }
-
-fn updateSubCompilation(sub_compilation: *Compilation) !void {
-    try sub_compilation.update();
-
-    // Look for compilation errors in this sub_compilation
-    var errors = try sub_compilation.getAllErrorsAlloc();
-    defer errors.deinit(sub_compilation.gpa);
-
-    if (errors.list.len != 0) {
-        for (errors.list) |full_err_msg| {
-            std.log.err("{}:{}:{}: {}\n", .{
-                full_err_msg.src_path,
-                full_err_msg.line + 1,
-                full_err_msg.column + 1,
-                full_err_msg.msg,
-            });
-        }
-        return error.BuildingLibCObjectFailed;
-    }
-}
src-self-hosted/link.zig
@@ -387,13 +387,15 @@ pub const File = struct {
         // If there is no Zig code to compile, then we should skip flushing the output file because it
         // will not be part of the linker line anyway.
         const module_obj_path: ?[]const u8 = if (base.options.module) |module| blk: {
+            const use_stage1 = build_options.is_stage1 and base.options.use_llvm;
+            if (use_stage1) {
+                const obj_basename = try std.fmt.allocPrint(arena, "{}.o", .{base.options.root_name});
+                const full_obj_path = try directory.join(arena, &[_][]const u8{obj_basename});
+                break :blk full_obj_path;
+            }
             try base.flushModule(comp);
-
             const obj_basename = base.intermediary_basename.?;
-            const full_obj_path = if (directory.path) |dir_path|
-                try std.fs.path.join(arena, &[_][]const u8{ dir_path, obj_basename })
-            else
-                obj_basename;
+            const full_obj_path = try directory.join(arena, &[_][]const u8{obj_basename});
             break :blk full_obj_path;
         } else null;
 
src-self-hosted/main.zig
@@ -1108,8 +1108,14 @@ pub fn buildOutputType(
         .yes => |p| p,
     };
 
-    const root_pkg = if (root_src_file) |src_path| try Package.create(gpa, fs.cwd(), ".", src_path) else null;
-    defer if (root_pkg) |pkg| pkg.destroy(gpa);
+    var root_pkg_memory: Package = undefined;
+    const root_pkg: ?*Package = if (root_src_file) |src_path| blk: {
+        root_pkg_memory = .{
+            .root_src_directory = .{ .path = null, .handle = fs.cwd() },
+            .root_src_path = src_path,
+        };
+        break :blk &root_pkg_memory;
+    } else null;
 
     const self_exe_path = try fs.selfExePathAlloc(arena);
     var zig_lib_directory = introspect.findZigLibDirFromSelfExe(arena, self_exe_path) catch |err| {
src-self-hosted/Package.zig
@@ -1,32 +1,41 @@
 pub const Table = std.StringHashMapUnmanaged(*Package);
 
 root_src_directory: Compilation.Directory,
-/// Relative to `root_src_directory`.
-root_src_path: []u8,
-table: Table,
+/// Relative to `root_src_directory`. May contain path separators.
+root_src_path: []const u8,
+table: Table = .{},
+
+const std = @import("std");
+const mem = std.mem;
+const Allocator = std.mem.Allocator;
+const assert = std.debug.assert;
+const Package = @This();
+const Compilation = @import("Compilation.zig");
 
 /// No references to `root_src_dir` and `root_src_path` are kept.
 pub fn create(
     gpa: *Allocator,
-    base_dir: std.fs.Dir,
-    /// Relative to `base_dir`.
+    base_directory: Compilation.Directory,
+    /// Relative to `base_directory`.
     root_src_dir: []const u8,
     /// Relative to `root_src_dir`.
     root_src_path: []const u8,
 ) !*Package {
     const ptr = try gpa.create(Package);
     errdefer gpa.destroy(ptr);
+
+    const root_src_dir_path = try base_directory.join(gpa, &[_][]const u8{root_src_dir});
+    errdefer gpa.free(root_src_dir_path);
+
     const root_src_path_dupe = try mem.dupe(gpa, u8, root_src_path);
     errdefer gpa.free(root_src_path_dupe);
-    const root_src_dir_path = try mem.dupe(gpa, u8, root_src_dir);
-    errdefer gpa.free(root_src_dir_path);
+
     ptr.* = .{
         .root_src_directory = .{
             .path = root_src_dir_path,
-            .handle = try base_dir.openDir(root_src_dir, .{}),
+            .handle = try base_directory.handle.openDir(root_src_dir, .{}),
         },
         .root_src_path = root_src_path_dupe,
-        .table = .{},
     };
     return ptr;
 }
@@ -50,10 +59,3 @@ pub fn add(pkg: *Package, gpa: *Allocator, name: []const u8, package: *Package)
     const name_dupe = try mem.dupe(gpa, u8, name);
     pkg.table.putAssumeCapacityNoClobber(name_dupe, package);
 }
-
-const std = @import("std");
-const mem = std.mem;
-const Allocator = std.mem.Allocator;
-const assert = std.debug.assert;
-const Package = @This();
-const Compilation = @import("Compilation.zig");
BRANCH_TODO
@@ -1,6 +1,8 @@
+ * Cache integration for stage1 zig code compilation
  * build & link against compiler-rt
  * build & link against freestanding libc
- * Cache integration for stage1 zig code compilation
+ * resolve builtin.zig not working on windows & macos; try os_path_real
+ * build & link against libcxx and libcxxabi
  * `zig test`
  * `zig build`
  * `-ftime-report`
@@ -16,32 +18,33 @@
  * make sure zig cc works
    - using it as a preprocessor (-E)
    - try building some software
+ * implement proper parsing of LLD stderr/stdout and exposing compile errors
+ * implement proper parsing of clang stderr/stdout and exposing compile errors
  * support rpaths in ELF linker code
  * repair @cImport
  * add CLI support for a way to pass extra flags to c source files
- * capture lld stdout/stderr better
  * musl
  * mingw-w64
  * use global zig-cache dir for crt files
  * MachO LLD linking
  * COFF LLD linking
  * WASM LLD linking
- * implement proper parsing of LLD stderr/stdout and exposing compile errors
- * implement proper parsing of clang stderr/stdout and exposing compile errors
- * implement proper compile errors for failing to build glibc crt files and shared libs
- * improve the stage2 tests to support testing with LLVM extensions enabled
- * multi-thread building C objects
  * support cross compiling stage2 with `zig build`
- * implement emit-h in stage2
- * implement -fno-emit-bin
- * audit the base cache hash
  * --main-pkg-path
  * audit the CLI options for stage2
  * `zig init-lib`
  * `zig init-exe`
  * `zig run`
  * restore error messages for stage2_add_link_lib
+ * audit the base cache hash
 
+ * implement proper compile errors for failing to build glibc crt files and shared libs
+ * implement -fno-emit-bin
+ * improve the stage2 tests to support testing with LLVM extensions enabled
+ * rename src/ to src/stage1/
+ * rename src-self-hosted/ to src/
+ * implement emit-h in stage2
+ * multi-thread building C objects
  * implement serialization/deserialization of incremental compilation metadata
  * incremental compilation - implement detection of which source files changed
  * improve the cache hash logic for c objects with respect to extra flags and file parameters
@@ -59,16 +62,13 @@
  * integrate target features into building assembly code
  * libc_installation.zig: make it look for msvc only if msvc abi is chosen
  * switch the default C ABI for windows to be mingw-w64
- * port windows_sdk.cpp to zig
  * change glibc log errors to normal exposed compile errors
  * update Package to use Compilation.Directory in create()
    - skip LLD caching when bin directory is not in the cache (so we don't put `id.txt` into the cwd)
      (maybe make it an explicit option and have main.zig disable it)
    - make it possible for Package to not openDir and reference already existing resources.
- * rename src/ to src/stage1/
- * rename src-self-hosted/ to src/
  * improve Directory.join to only use 1 allocation in a clean way.
  * tracy builds with lc++
  * some kind of "zig identifier escape" function rather than unconditionally using @"" syntax
    in builtin.zig
- * rename Mode to OptimizeMode
+ * rename std.builtin.Mode to std.builtin.OptimizeMode