diff --git a/src/Builtin.zig b/src/Builtin.zig index 7224a6fd24..4c8038019c 100644 --- a/src/Builtin.zig +++ b/src/Builtin.zig @@ -20,8 +20,11 @@ wasi_exec_model: std.builtin.WasiExecModel, pub fn generate(opts: @This(), allocator: Allocator) Allocator.Error![:0]u8 { var buffer = std.ArrayList(u8).init(allocator); - defer buffer.deinit(); + try append(opts, &buffer); + return buffer.toOwnedSliceSentinel(0); +} +pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void { const target = opts.target; const generic_arch_name = target.cpu.arch.genericName(); const zig_backend = opts.zig_backend; @@ -231,10 +234,65 @@ pub fn generate(opts: @This(), allocator: Allocator) Allocator.Error![:0]u8 { ); } } +} - return buffer.toOwnedSliceSentinel(0); +pub fn populateFile(comp: *Compilation, mod: *Module, file: *File) !void { + assert(file.source_loaded == true); + + if (mod.root.statFile(mod.root_src_path)) |stat| { + if (stat.size != file.source.len) { + std.log.warn( + "the cached file '{}{s}' had the wrong size. Expected {d}, found {d}. " ++ + "Overwriting with correct file contents now", + .{ mod.root, mod.root_src_path, file.source.len, stat.size }, + ); + + try writeFile(file, mod); + } else { + file.stat = .{ + .size = stat.size, + .inode = stat.inode, + .mtime = stat.mtime, + }; + } + } else |err| switch (err) { + error.BadPathName => unreachable, // it's always "builtin.zig" + error.NameTooLong => unreachable, // it's always "builtin.zig" + error.PipeBusy => unreachable, // it's not a pipe + error.WouldBlock => unreachable, // not asking for non-blocking I/O + + error.FileNotFound => try writeFile(file, mod), + + else => |e| return e, + } + + file.tree = try std.zig.Ast.parse(comp.gpa, file.source, .zig); + file.tree_loaded = true; + assert(file.tree.errors.len == 0); // builtin.zig must parse + + file.zir = try AstGen.generate(comp.gpa, file.tree); + file.zir_loaded = true; + file.status = .success_zir; +} + +fn writeFile(file: *File, mod: *Module) !void { + var af = try mod.root.atomicFile(mod.root_src_path, .{}); + defer af.deinit(); + try af.file.writeAll(file.source); + try af.finish(); + + file.stat = .{ + .size = file.source.len, + .inode = 0, // dummy value + .mtime = 0, // dummy value + }; } const std = @import("std"); const Allocator = std.mem.Allocator; const build_options = @import("build_options"); +const Module = @import("Package/Module.zig"); +const assert = std.debug.assert; +const AstGen = @import("AstGen.zig"); +const File = @import("Module.zig").File; +const Compilation = @import("Compilation.zig"); diff --git a/src/Compilation.zig b/src/Compilation.zig index 8cf7a66fbc..35ee243617 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -37,6 +37,7 @@ const Zir = @import("Zir.zig"); const Autodoc = @import("Autodoc.zig"); const Color = @import("main.zig").Color; const resinator = @import("resinator.zig"); +const Builtin = @import("Builtin.zig"); pub const Config = @import("Compilation/Config.zig"); @@ -59,7 +60,10 @@ root_mod: *Package.Module, /// User-specified settings that have all the defaults resolved into concrete values. config: Config, -/// This is `null` when `-fno-emit-bin` is used. +/// The main output file. +/// In whole cache mode, this is null except for during the body of the update +/// function. In incremental cache mode, this is a long-lived object. +/// In both cases, this is `null` when `-fno-emit-bin` is used. bin_file: ?*link.File, /// The root path for the dynamic linker and system libraries (as well as frameworks on Darwin) @@ -80,6 +84,8 @@ version: ?std.SemanticVersion, libc_installation: ?*const LibCInstallation, skip_linker_dependencies: bool, no_builtin: bool, +function_sections: bool, +data_sections: bool, c_object_table: std.AutoArrayHashMapUnmanaged(*CObject, void) = .{}, win32_resource_table: if (build_options.only_core_functionality) void else std.AutoArrayHashMapUnmanaged(*Win32Resource, void) = @@ -120,7 +126,6 @@ failed_win32_resources: if (build_options.only_core_functionality) void else std /// Miscellaneous things that can fail. misc_failures: std.AutoArrayHashMapUnmanaged(MiscTask, MiscError) = .{}, -keep_source_files_loaded: bool, /// When this is `true` it means invoking clang as a sub-process is expected to inherit /// stdin, stdout, stderr, and if it returns non success, to forward the exit code. /// Otherwise we attempt to parse the error messages and expose them via the Compilation API. @@ -144,6 +149,7 @@ debug_compiler_runtime_libs: bool, debug_compile_errors: bool, job_queued_compiler_rt_lib: bool = false, job_queued_compiler_rt_obj: bool = false, +job_queued_update_builtin_zig: bool, alloc_failure_occurred: bool = false, formatted_panics: bool = false, last_update_was_cache_hit: bool = false, @@ -814,13 +820,13 @@ pub const cache_helpers = struct { addEmitLoc(hh, optional_emit_loc orelse return); } - pub fn addOptionalDebugFormat(hh: *Cache.HashHelper, x: ?link.File.DebugFormat) void { + pub fn addOptionalDebugFormat(hh: *Cache.HashHelper, x: ?Config.DebugFormat) void { hh.add(x != null); addDebugFormat(hh, x orelse return); } - pub fn addDebugFormat(hh: *Cache.HashHelper, x: link.File.DebugFormat) void { - const tag: @typeInfo(link.File.DebugFormat).Union.tag_type.? = x; + pub fn addDebugFormat(hh: *Cache.HashHelper, x: Config.DebugFormat) void { + const tag: @typeInfo(Config.DebugFormat).Union.tag_type.? = x; hh.add(tag); switch (x) { .strip, .code_view => {}, @@ -860,11 +866,11 @@ pub const SystemLib = link.SystemLib; pub const CacheMode = enum { incremental, whole }; -pub const CacheUse = union(CacheMode) { +const CacheUse = union(CacheMode) { incremental: *Incremental, whole: *Whole, - pub const Whole = struct { + const Whole = struct { /// This is a pointer to a local variable inside `update()`. cache_manifest: ?*Cache.Manifest = null, cache_manifest_mutex: std.Thread.Mutex = .{}, @@ -873,12 +879,14 @@ pub const CacheUse = union(CacheMode) { /// of exactly the correct size for "o/[digest]/[basename]". /// The basename is of the outputted binary file in case we don't know the directory yet. bin_sub_path: ?[]u8, - /// Same as `whole_bin_sub_path` but for implibs. + /// Same as `bin_sub_path` but for implibs. implib_sub_path: ?[]u8, docs_sub_path: ?[]u8, + lf_open_opts: link.File.OpenOptions, + tmp_artifact_directory: ?Cache.Directory, }; - pub const Incremental = struct { + const Incremental = struct { /// Where build artifacts and incremental compilation metadata serialization go. artifact_directory: Compilation.Directory, }; @@ -937,7 +945,6 @@ pub const InitOptions = struct { /// this flag would be set to disable this machinery to avoid false positives. disable_lld_caching: bool = false, cache_mode: CacheMode = .incremental, - keep_source_files_loaded: bool = false, lib_dirs: []const []const u8 = &[0][]const u8{}, rpath_list: []const []const u8 = &[0][]const u8{}, symbol_wrap_set: std.StringArrayHashMapUnmanaged(void) = .{}, @@ -1040,7 +1047,6 @@ pub const InitOptions = struct { test_name_prefix: ?[]const u8 = null, test_runner_path: ?[]const u8 = null, subsystem: ?std.Target.SubSystem = null, - debug_format: ?link.File.DebugFormat = null, /// (Zig compiler development) Enable dumping linker's state as JSON. enable_link_snapshots: bool = false, /// (Darwin) Install name of the dylib @@ -1327,7 +1333,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { cache.hash.add(options.config.link_libcpp); cache.hash.add(options.config.link_libunwind); cache.hash.add(output_mode); - cache_helpers.addOptionalDebugFormat(&cache.hash, options.debug_format); + cache_helpers.addDebugFormat(&cache.hash, comp.config.debug_format); cache_helpers.addOptionalEmitLoc(&cache.hash, options.emit_bin); cache_helpers.addOptionalEmitLoc(&cache.hash, options.emit_implib); cache_helpers.addOptionalEmitLoc(&cache.hash, options.emit_docs); @@ -1380,7 +1386,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { }; errdefer if (opt_zcu) |zcu| zcu.deinit(); - const system_libs = try std.StringArrayHashMapUnmanaged(SystemLib).init( + var system_libs = try std.StringArrayHashMapUnmanaged(SystemLib).init( gpa, options.system_lib_names, options.system_lib_infos, @@ -1409,7 +1415,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .win32_resource_work_queue = if (build_options.only_core_functionality) {} else std.fifo.LinearFifo(*Win32Resource, .Dynamic).init(gpa), .astgen_work_queue = std.fifo.LinearFifo(*Module.File, .Dynamic).init(gpa), .embed_file_work_queue = std.fifo.LinearFifo(*Module.EmbedFile, .Dynamic).init(gpa), - .keep_source_files_loaded = options.keep_source_files_loaded, .c_source_files = options.c_source_files, .rc_source_files = options.rc_source_files, .cache_parent = cache, @@ -1451,10 +1456,12 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .llvm_opt_bisect_limit = options.llvm_opt_bisect_limit, .skip_linker_dependencies = options.skip_linker_dependencies, .no_builtin = options.no_builtin, + .job_queued_update_builtin_zig = have_zcu, + .function_sections = options.function_sections, + .data_sections = options.data_sections, }; const lf_open_opts: link.File.OpenOptions = .{ - .comp = comp, .linker_script = options.linker_script, .z_nodelete = options.linker_z_nodelete, .z_notext = options.linker_z_notext, @@ -1471,8 +1478,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .lib_dirs = options.lib_dirs, .rpath_list = options.rpath_list, .symbol_wrap_set = options.symbol_wrap_set, - .function_sections = options.function_sections, - .data_sections = options.data_sections, .allow_shlib_undefined = options.linker_allow_shlib_undefined, .bind_global_refs_locally = options.linker_bind_global_refs_locally orelse false, .compress_debug_sections = options.linker_compress_debug_sections orelse .none, @@ -1507,7 +1512,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .build_id = build_id, .disable_lld_caching = options.disable_lld_caching or cache_mode == .whole, .subsystem = options.subsystem, - .debug_format = options.debug_format, .hash_style = options.hash_style, .enable_link_snapshots = options.enable_link_snapshots, .install_name = options.install_name, @@ -1572,17 +1576,17 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .directory = emit_bin.directory orelse artifact_directory, .sub_path = emit_bin.basename, }; - comp.bin_file = try link.File.open(arena, emit, lf_open_opts); + comp.bin_file = try link.File.open(arena, comp, emit, lf_open_opts); } - if (options.implib_emit) |emit_implib| { + if (options.emit_implib) |emit_implib| { comp.implib_emit = .{ .directory = emit_implib.directory orelse artifact_directory, .sub_path = emit_implib.basename, }; } - if (options.docs_emit) |emit_docs| { + if (options.emit_docs) |emit_docs| { comp.docs_emit = .{ .directory = emit_docs.directory orelse artifact_directory, .sub_path = emit_docs.basename, @@ -1610,6 +1614,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .bin_sub_path = try prepareWholeEmitSubPath(arena, options.emit_bin), .implib_sub_path = try prepareWholeEmitSubPath(arena, options.emit_implib), .docs_sub_path = try prepareWholeEmitSubPath(arena, options.emit_docs), + .tmp_artifact_directory = null, }; comp.cache_use = .{ .whole = whole }; }, @@ -1662,7 +1667,10 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { } } - const have_bin_emit = comp.bin_file != null or comp.whole_bin_sub_path != null; + const have_bin_emit = switch (comp.cache_use) { + .whole => |whole| whole.bin_sub_path != null, + .incremental => comp.bin_file != null, + }; if (have_bin_emit and !comp.skip_linker_dependencies and target.ofmt != .c) { if (target.isDarwin()) { @@ -1814,8 +1822,13 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { pub fn destroy(self: *Compilation) void { if (self.bin_file) |lf| lf.destroy(); if (self.module) |zcu| zcu.deinit(); + switch (self.cache_use) { + .incremental => |incremental| { + incremental.artifact_directory.handle.close(); + }, + .whole => {}, + } - const gpa = self.gpa; self.work_queue.deinit(); self.anon_work_queue.deinit(); self.c_object_work_queue.deinit(); @@ -1825,6 +1838,9 @@ pub fn destroy(self: *Compilation) void { self.astgen_work_queue.deinit(); self.embed_file_work_queue.deinit(); + const gpa = self.gpa; + self.system_libs.deinit(gpa); + { var it = self.crt_files.iterator(); while (it.next()) |entry| { @@ -1914,7 +1930,7 @@ pub fn hotCodeSwap(comp: *Compilation, prog_node: *std.Progress.Node, pid: std.C } fn cleanupAfterUpdate(comp: *Compilation) void { - switch (comp) { + switch (comp.cache_use) { .incremental => return, .whole => |whole| { if (whole.cache_manifest) |man| { @@ -1971,7 +1987,7 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void log.debug("CacheMode.whole cache hit for {s}", .{comp.root_name}); const digest = man.final(); - comp.wholeCacheModeSetBinFilePath(&digest); + comp.wholeCacheModeSetBinFilePath(whole, &digest); assert(comp.bin_file.lock == null); comp.bin_file.lock = man.toOwnedLock(); @@ -2001,21 +2017,21 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void // Now that the directory is known, it is time to create the Emit // objects and call link.File.open. - if (comp.whole_implib_sub_path) |sub_path| { + if (whole.implib_sub_path) |sub_path| { comp.implib_emit = .{ .directory = tmp_artifact_directory, .sub_path = std.fs.path.basename(sub_path), }; } - if (comp.whole_docs_sub_path) |sub_path| { + if (whole.docs_sub_path) |sub_path| { comp.docs_emit = .{ .directory = tmp_artifact_directory, .sub_path = std.fs.path.basename(sub_path), }; } - if (comp.whole_bin_sub_path) |sub_path| { + if (whole.bin_sub_path) |sub_path| { const emit: Emit = .{ .directory = tmp_artifact_directory, .sub_path = std.fs.path.basename(sub_path), @@ -2024,7 +2040,7 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void // but in practice it won't leak much and usually whole cache mode // will be combined with exactly one call to update(). const arena = comp.arena.allocator(); - comp.bin_file = try link.File.open(arena, emit, whole.lf_open_opts); + comp.bin_file = try link.File.createEmpty(arena, comp, emit, whole.lf_open_opts); } }, .incremental => {}, @@ -2158,7 +2174,7 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void const o_sub_path = "o" ++ s ++ digest; try renameTmpIntoCache(comp.local_cache_directory, tmp_dir_sub_path, o_sub_path); - comp.wholeCacheModeSetBinFilePath(&digest); + comp.wholeCacheModeSetBinFilePath(whole, &digest); // Failure here only means an unnecessary cache miss. man.writeManifest() catch |err| { @@ -2170,19 +2186,6 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void }, .incremental => {}, } - - // Unload all source files to save memory. - // The ZIR needs to stay loaded in memory because (1) Decl objects contain references - // to it, and (2) generic instantiations, comptime calls, inline calls will need - // to reference the ZIR. - if (!comp.keep_source_files_loaded) { - if (comp.module) |module| { - for (module.import_table.values()) |file| { - file.unloadTree(comp.gpa); - file.unloadSource(comp.gpa); - } - } - } } /// This function is called by the frontend before flush(). It communicates that @@ -2274,10 +2277,14 @@ fn flush(comp: *Compilation, prog_node: *std.Progress.Node) !void { } /// Communicate the output binary location to parent Compilations. -fn wholeCacheModeSetBinFilePath(comp: *Compilation, digest: *const [Cache.hex_digest_len]u8) void { +fn wholeCacheModeSetBinFilePath( + comp: *Compilation, + whole: *CacheUse.Whole, + digest: *const [Cache.hex_digest_len]u8, +) void { const digest_start = 2; // "o/[digest]/[basename]" - if (comp.whole_bin_sub_path) |sub_path| { + if (whole.bin_sub_path) |sub_path| { @memcpy(sub_path[digest_start..][0..digest.len], digest); comp.bin_file.?.emit = .{ @@ -2286,7 +2293,7 @@ fn wholeCacheModeSetBinFilePath(comp: *Compilation, digest: *const [Cache.hex_di }; } - if (comp.whole_implib_sub_path) |sub_path| { + if (whole.implib_sub_path) |sub_path| { @memcpy(sub_path[digest_start..][0..digest.len], digest); comp.implib_emit = .{ @@ -2295,7 +2302,7 @@ fn wholeCacheModeSetBinFilePath(comp: *Compilation, digest: *const [Cache.hex_di }; } - if (comp.whole_docs_sub_path) |sub_path| { + if (whole.docs_sub_path) |sub_path| { @memcpy(sub_path[digest_start..][0..digest.len], digest); comp.docs_emit = .{ @@ -3232,13 +3239,25 @@ pub fn performAllTheWork( // 1. to avoid race condition of zig processes truncating each other's builtin.zig files // 2. optimization; in the hot path it only incurs a stat() syscall, which happens // in the `astgen_wait_group`. - if (comp.module) |mod| { - if (mod.job_queued_update_builtin_zig) { - mod.job_queued_update_builtin_zig = false; + if (comp.job_queued_update_builtin_zig) b: { + comp.job_queued_update_builtin_zig = false; + const zcu = comp.module orelse break :b; + _ = zcu; + // TODO put all the modules in a flat array to make them easy to iterate. + var seen: std.AutoArrayHashMapUnmanaged(*Package.Module, void) = .{}; + defer seen.deinit(comp.gpa); + try seen.put(comp.gpa, comp.root_mod); + var i: usize = 0; + while (i < seen.count()) : (i += 1) { + const mod = seen.keys()[i]; + for (mod.deps.values()) |dep| + try seen.put(comp.gpa, dep); + + const file = mod.builtin_file orelse continue; comp.astgen_wait_group.start(); try comp.thread_pool.spawn(workerUpdateBuiltinZigFile, .{ - comp, mod, &comp.astgen_wait_group, + comp, mod, file, &comp.astgen_wait_group, }); } } @@ -3702,19 +3721,17 @@ fn workerAstGenFile( fn workerUpdateBuiltinZigFile( comp: *Compilation, - mod: *Module, + mod: *Package.Module, + file: *Module.File, wg: *WaitGroup, ) void { defer wg.finish(); - - mod.populateBuiltinFile() catch |err| { - const dir_path: []const u8 = mod.zig_cache_artifact_directory.path orelse "."; - + Builtin.populateFile(comp, mod, file) catch |err| { comp.mutex.lock(); defer comp.mutex.unlock(); - comp.setMiscFailure(.write_builtin_zig, "unable to write builtin.zig to {s}: {s}", .{ - dir_path, @errorName(err), + comp.setMiscFailure(.write_builtin_zig, "unable to write '{}{s}': {s}", .{ + mod.root, mod.root_src_path, @errorName(err), }); }; } @@ -3755,14 +3772,17 @@ fn detectEmbedFileUpdate(comp: *Compilation, embed_file: *Module.EmbedFile) !voi @panic("TODO: handle embed file incremental update"); } -pub fn obtainCObjectCacheManifest(comp: *const Compilation) Cache.Manifest { +pub fn obtainCObjectCacheManifest( + comp: *const Compilation, + owner_mod: *Package.Module, +) Cache.Manifest { var man = comp.cache_parent.obtain(); // Only things that need to be added on top of the base hash, and only things // that apply both to @cImport and compiling C objects. No linking stuff here! // Also nothing that applies only to compiling .zig code. - man.hash.add(comp.sanitize_c); - man.hash.addListOfBytes(comp.clang_argv); + man.hash.add(owner_mod.sanitize_c); + man.hash.addListOfBytes(owner_mod.clang_argv); man.hash.add(comp.config.link_libcpp); // When libc_installation is null it means that Zig generated this dir list @@ -3797,19 +3817,19 @@ pub const CImportResult = struct { /// Caller owns returned memory. /// This API is currently coupled pretty tightly to stage1's needs; it will need to be reworked /// a bit when we want to start using it from self-hosted. -pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult { +pub fn cImport(comp: *Compilation, c_src: []const u8, owner_mod: *Package.Module) !CImportResult { if (build_options.only_core_functionality) @panic("@cImport is not available in a zig2.c build"); const tracy_trace = trace(@src()); defer tracy_trace.end(); const cimport_zig_basename = "cimport.zig"; - var man = comp.obtainCObjectCacheManifest(); + var man = comp.obtainCObjectCacheManifest(owner_mod); defer man.deinit(); man.hash.add(@as(u16, 0xb945)); // Random number to distinguish translate-c from compiling C objects man.hash.addBytes(c_src); - man.hash.add(comp.c_frontend); + man.hash.add(comp.config.c_frontend); // If the previous invocation resulted in clang errors, we will see a hit // here with 0 files in the manifest, in which case it is actually a miss. @@ -3846,15 +3866,15 @@ pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult { var argv = std.ArrayList([]const u8).init(comp.gpa); defer argv.deinit(); - try argv.append(@tagName(comp.c_frontend)); // argv[0] is program name, actual args start at [1] - try comp.addTranslateCCArgs(arena, &argv, .c, out_dep_path); + try argv.append(@tagName(comp.config.c_frontend)); // argv[0] is program name, actual args start at [1] + try comp.addTranslateCCArgs(arena, &argv, .c, out_dep_path, owner_mod); try argv.append(out_h_path); if (comp.verbose_cc) { dump_argv(argv.items); } - var tree = switch (comp.c_frontend) { + var tree = switch (comp.config.c_frontend) { .aro => tree: { const translate_c = @import("aro_translate_c.zig"); _ = translate_c; @@ -4119,7 +4139,7 @@ fn reportRetryableEmbedFileError( } fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.Progress.Node) !void { - if (comp.c_frontend == .aro) { + if (comp.config.c_frontend == .aro) { return comp.failCObj(c_object, "aro does not support compiling C objects yet", .{}); } if (!build_options.have_llvm) { @@ -4142,7 +4162,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P _ = comp.failed_c_objects.swapRemove(c_object); } - var man = comp.obtainCObjectCacheManifest(); + var man = comp.obtainCObjectCacheManifest(c_object.src.owner); defer man.deinit(); man.hash.add(comp.clang_preprocessor_mode); @@ -4219,7 +4239,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P if (std.process.can_execv and direct_o and comp.disable_c_depfile and comp.clang_passthrough_mode) { - try comp.addCCArgs(arena, &argv, ext, null); + try comp.addCCArgs(arena, &argv, ext, null, c_object.src.owner); try argv.appendSlice(c_object.src.extra_flags); try argv.appendSlice(c_object.src.cache_exempt_flags); @@ -4262,7 +4282,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P null else try std.fmt.allocPrint(arena, "{s}.d", .{out_obj_path}); - try comp.addCCArgs(arena, &argv, ext, out_dep_path); + try comp.addCCArgs(arena, &argv, ext, out_dep_path, c_object.src.owner); try argv.appendSlice(c_object.src.extra_flags); try argv.appendSlice(c_object.src.cache_exempt_flags); @@ -4610,7 +4630,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32 // mode. While these defines are not normally present when calling rc.exe directly, // them being defined matches the behavior of how MSVC calls rc.exe which is the more // relevant behavior in this case. - try comp.addCCArgs(arena, &argv, .rc, out_dep_path); + try comp.addCCArgs(arena, &argv, .rc, out_dep_path, rc_src.owner); if (comp.verbose_cc) { dump_argv(argv.items); @@ -4788,11 +4808,12 @@ pub fn addTranslateCCArgs( argv: *std.ArrayList([]const u8), ext: FileExt, out_dep_path: ?[]const u8, + owner_mod: *Package.Module, ) !void { - try argv.appendSlice(&[_][]const u8{ "-x", "c" }); - try comp.addCCArgs(arena, argv, ext, out_dep_path); + try argv.appendSlice(&.{ "-x", "c" }); + try comp.addCCArgs(arena, argv, ext, out_dep_path, owner_mod); // This gives us access to preprocessing entities, presumably at the cost of performance. - try argv.appendSlice(&[_][]const u8{ "-Xclang", "-detailed-preprocessing-record" }); + try argv.appendSlice(&.{ "-Xclang", "-detailed-preprocessing-record" }); } /// Add common C compiler args between translate-c and C object compilation. @@ -4825,11 +4846,11 @@ pub fn addCCArgs( try argv.append("-fno-caret-diagnostics"); } - if (comp.bin_file.function_sections) { + if (comp.function_sections) { try argv.append("-ffunction-sections"); } - if (comp.bin_file.data_sections) { + if (comp.data_sections) { try argv.append("-fdata-sections"); } @@ -5088,7 +5109,7 @@ pub fn addCCArgs( try argv.append("-fPIC"); } - if (comp.unwind_tables) { + if (mod.unwind_tables) { try argv.append("-funwind-tables"); } else { try argv.append("-fno-unwind-tables"); @@ -5174,7 +5195,7 @@ pub fn addCCArgs( } try argv.ensureUnusedCapacity(2); - switch (comp.bin_file.debug_format) { + switch (comp.config.debug_format) { .strip => {}, .code_view => { // -g is required here because -gcodeview doesn't trigger debug info @@ -5210,7 +5231,7 @@ pub fn addCCArgs( try argv.append("-ffreestanding"); } - try argv.appendSlice(comp.clang_argv); + try argv.appendSlice(mod.cc_argv); } fn failCObj( @@ -6094,6 +6115,7 @@ fn buildOutputFromZig( .have_zcu = true, .emit_bin = true, .root_optimize_mode = comp.compilerRtOptMode(), + .root_strip = comp.compilerRtStrip(), .link_libc = comp.config.link_libc, .any_unwind_tables = unwind_tables, }); @@ -6198,6 +6220,7 @@ pub fn build_crt_file( .have_zcu = false, .emit_bin = true, .root_optimize_mode = comp.compilerRtOptMode(), + .root_strip = comp.compilerRtStrip(), .link_libc = false, .lto = switch (output_mode) { .Lib => comp.config.lto, diff --git a/src/Compilation/Config.zig b/src/Compilation/Config.zig index aba21e4bfe..0afb633c86 100644 --- a/src/Compilation/Config.zig +++ b/src/Compilation/Config.zig @@ -33,9 +33,16 @@ shared_memory: bool, is_test: bool, test_evented_io: bool, entry: ?[]const u8, +debug_format: DebugFormat, pub const CFrontend = enum { clang, aro }; +pub const DebugFormat = union(enum) { + strip, + dwarf: std.dwarf.Format, + code_view, +}; + pub const Options = struct { output_mode: std.builtin.OutputMode, resolved_target: Module.ResolvedTarget, @@ -43,6 +50,7 @@ pub const Options = struct { have_zcu: bool, emit_bin: bool, root_optimize_mode: ?std.builtin.OptimizeMode = null, + root_strip: ?bool = null, link_mode: ?std.builtin.LinkMode = null, ensure_libc_on_non_freestanding: bool = false, ensure_libcpp_on_non_freestanding: bool = false, @@ -51,6 +59,7 @@ pub const Options = struct { any_unwind_tables: bool = false, any_dyn_libs: bool = false, any_c_source_files: bool = false, + any_non_stripped: bool = false, emit_llvm_ir: bool = false, emit_llvm_bc: bool = false, link_libc: ?bool = null, @@ -74,6 +83,7 @@ pub const Options = struct { export_memory: ?bool = null, shared_memory: ?bool = null, test_evented_io: bool = false, + debug_format: ?Config.DebugFormat = null, }; pub fn resolve(options: Options) !Config { @@ -365,6 +375,26 @@ pub fn resolve(options: Options) !Config { break :b false; }; + const root_strip = b: { + if (options.root_strip) |x| break :b x; + if (root_optimize_mode == .ReleaseSmall) break :b true; + if (!target_util.hasDebugInfo(target)) break :b true; + break :b false; + }; + + const debug_format: DebugFormat = b: { + if (root_strip and !options.any_non_stripped) break :b .strip; + break :b switch (target.ofmt) { + .elf, .macho, .wasm => .{ .dwarf = .@"32" }, + .coff => .code_view, + .c => switch (target.os.tag) { + .windows, .uefi => .code_view, + else => .{ .dwarf = .@"32" }, + }, + .spirv, .nvptx, .dxcontainer, .hex, .raw, .plan9 => .strip, + }; + }; + return .{ .output_mode = options.output_mode, .have_zcu = options.have_zcu, @@ -388,6 +418,7 @@ pub fn resolve(options: Options) !Config { .use_lld = use_lld, .entry = entry, .wasi_exec_model = wasi_exec_model, + .debug_format = debug_format, }; } diff --git a/src/Module.zig b/src/Module.zig index e32bad7295..121f639f6b 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -152,8 +152,6 @@ stage1_flags: packed struct { reserved: u2 = 0, } = .{}, -job_queued_update_builtin_zig: bool = true, - compile_log_text: ArrayListUnmanaged(u8) = .{}, emit_h: ?*GlobalEmitH, @@ -2490,7 +2488,6 @@ pub fn deinit(mod: *Module) void { mod.compile_log_text.deinit(gpa); - mod.zig_cache_artifact_directory.handle.close(); mod.local_zir_cache.handle.close(); mod.global_zir_cache.handle.close(); @@ -3075,72 +3072,6 @@ fn updateZirRefs(mod: *Module, file: *File, old_zir: Zir) !void { } } -pub fn populateBuiltinFile(mod: *Module) !void { - const tracy = trace(@src()); - defer tracy.end(); - - const comp = mod.comp; - const builtin_mod, const file = blk: { - comp.mutex.lock(); - defer comp.mutex.unlock(); - - const builtin_mod = mod.main_mod.deps.get("builtin").?; - const result = try mod.importPkg(builtin_mod); - break :blk .{ builtin_mod, result.file }; - }; - const gpa = mod.gpa; - file.source = try comp.generateBuiltinZigSource(gpa); - file.source_loaded = true; - - if (builtin_mod.root.statFile(builtin_mod.root_src_path)) |stat| { - if (stat.size != file.source.len) { - log.warn( - "the cached file '{}{s}' had the wrong size. Expected {d}, found {d}. " ++ - "Overwriting with correct file contents now", - .{ builtin_mod.root, builtin_mod.root_src_path, file.source.len, stat.size }, - ); - - try writeBuiltinFile(file, builtin_mod); - } else { - file.stat = .{ - .size = stat.size, - .inode = stat.inode, - .mtime = stat.mtime, - }; - } - } else |err| switch (err) { - error.BadPathName => unreachable, // it's always "builtin.zig" - error.NameTooLong => unreachable, // it's always "builtin.zig" - error.PipeBusy => unreachable, // it's not a pipe - error.WouldBlock => unreachable, // not asking for non-blocking I/O - - error.FileNotFound => try writeBuiltinFile(file, builtin_mod), - - else => |e| return e, - } - - file.tree = try Ast.parse(gpa, file.source, .zig); - file.tree_loaded = true; - assert(file.tree.errors.len == 0); // builtin.zig must parse - - file.zir = try AstGen.generate(gpa, file.tree); - file.zir_loaded = true; - file.status = .success_zir; -} - -fn writeBuiltinFile(file: *File, builtin_mod: *Package.Module) !void { - var af = try builtin_mod.root.atomicFile(builtin_mod.root_src_path, .{}); - defer af.deinit(); - try af.file.writeAll(file.source); - try af.finish(); - - file.stat = .{ - .size = file.source.len, - .inode = 0, // dummy value - .mtime = 0, // dummy value - }; -} - pub fn mapOldZirToNew( gpa: Allocator, old_zir: Zir, diff --git a/src/Package/Module.zig b/src/Package/Module.zig index 0916742876..051303ca26 100644 --- a/src/Package/Module.zig +++ b/src/Package/Module.zig @@ -33,11 +33,16 @@ cc_argv: []const []const u8, /// (SPIR-V) whether to generate a structured control flow graph or not structured_cfg: bool, -/// The contents of `@import("builtin")` for this module. -generated_builtin_source: []const u8, +/// If the module is an `@import("builtin")` module, this is the `File` that +/// is preallocated for it. Otherwise this field is null. +builtin_file: ?*File, pub const Deps = std.StringArrayHashMapUnmanaged(*Module); +pub fn isBuiltin(m: Module) bool { + return m.file != null; +} + pub const Tree = struct { /// Each `Package` exposes a `Module` with build.zig as its root source file. build_module_table: std.AutoArrayHashMapUnmanaged(MultiHashHexDigest, *Module), @@ -329,6 +334,8 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module { .wasi_exec_model = options.global.wasi_exec_model, }, arena); + const new_file = try arena.create(File); + const digest = Cache.HashHelper.oneShot(generated_builtin_source); const builtin_sub_path = try arena.dupe(u8, "b" ++ std.fs.path.sep_str ++ digest); const new = try arena.create(Module); @@ -359,12 +366,25 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module { .stack_protector = stack_protector, .code_model = code_model, .red_zone = red_zone, - .generated_builtin_source = generated_builtin_source, .sanitize_c = sanitize_c, .sanitize_thread = sanitize_thread, .unwind_tables = unwind_tables, .cc_argv = &.{}, .structured_cfg = structured_cfg, + .builtin_file = new_file, + }; + new_file.* = .{ + .sub_file_path = "builtin.zig", + .source = generated_builtin_source, + .source_loaded = true, + .tree_loaded = false, + .zir_loaded = false, + .stat = undefined, + .tree = undefined, + .zir = undefined, + .status = .never_loaded, + .mod = new, + .root_decl = .none, }; break :b new; }; @@ -391,12 +411,12 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module { .stack_protector = stack_protector, .code_model = code_model, .red_zone = red_zone, - .generated_builtin_source = builtin_mod.generated_builtin_source, .sanitize_c = sanitize_c, .sanitize_thread = sanitize_thread, .unwind_tables = unwind_tables, .cc_argv = options.cc_argv, .structured_cfg = structured_cfg, + .builtin_file = null, }; try mod.deps.ensureUnusedCapacity(arena, 1); @@ -437,8 +457,8 @@ pub fn createLimited(gpa: Allocator, options: LimitedOptions) Allocator.Error!*P .sanitize_thread = undefined, .unwind_tables = undefined, .cc_argv = undefined, - .generated_builtin_source = undefined, .structured_cfg = undefined, + .builtin_file = null, }; return mod; } @@ -457,3 +477,4 @@ const Cache = std.Build.Cache; const Builtin = @import("../Builtin.zig"); const assert = std.debug.assert; const Compilation = @import("../Compilation.zig"); +const File = @import("../Module.zig").File; diff --git a/src/Sema.zig b/src/Sema.zig index 910b1cca47..2d46faf435 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -784,6 +784,11 @@ pub const Block = struct { } } + pub fn ownerModule(block: Block) *Package.Module { + const zcu = block.sema.mod; + return zcu.namespacePtr(block.namespace).file_scope.mod; + } + pub fn startAnonDecl(block: *Block) !WipAnonDecl { return WipAnonDecl{ .block = block, @@ -5733,7 +5738,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr // Ignore the result, all the relevant operations have written to c_import_buf already. _ = try sema.analyzeBodyBreak(&child_block, body); - var c_import_res = comp.cImport(c_import_buf.items) catch |err| + var c_import_res = comp.cImport(c_import_buf.items, parent_block.ownerModule()) catch |err| return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)}); defer c_import_res.deinit(gpa); diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index ee9e3de086..709b2bf6a9 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -854,9 +854,8 @@ pub const Object = struct { /// want to iterate over it while adding entries to it. pub const DITypeMap = std.AutoArrayHashMapUnmanaged(InternPool.Index, AnnotatedDITypePtr); - pub fn create(arena: Allocator, options: link.File.OpenOptions) !*Object { + pub fn create(arena: Allocator, comp: *Compilation) !*Object { if (build_options.only_c) unreachable; - const comp = options.comp; const gpa = comp.gpa; const target = comp.root_mod.resolved_target.result; const llvm_target_triple = try targetTriple(arena, target); @@ -878,14 +877,7 @@ pub const Object = struct { var target_data: if (build_options.have_llvm) *llvm.TargetData else void = undefined; if (builder.useLibLlvm()) { debug_info: { - const debug_format = options.debug_format orelse b: { - if (strip) break :b .strip; - break :b switch (target.ofmt) { - .coff => .code_view, - else => .{ .dwarf = .@"32" }, - }; - }; - switch (debug_format) { + switch (comp.config.debug_format) { .strip => break :debug_info, .code_view => builder.llvm.module.?.addModuleCodeViewFlag(), .dwarf => |f| builder.llvm.module.?.addModuleDebugInfoFlag(f == .@"64"), @@ -961,8 +953,8 @@ pub const Object = struct { opt_level, reloc_mode, code_model, - options.function_sections orelse false, - options.data_sections orelse false, + comp.function_sections, + comp.data_sections, float_abi, if (target_util.llvmMachineAbi(target)) |s| s.ptr else null, ); diff --git a/src/libunwind.zig b/src/libunwind.zig index 9215e24f7c..bc1c0d0343 100644 --- a/src/libunwind.zig +++ b/src/libunwind.zig @@ -28,6 +28,7 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: *std.Progress.Node) !void { .have_zcu = false, .emit_bin = true, .root_optimize_mode = comp.compilerRtOptMode(), + .root_strip = comp.compilerRtStrip(), .link_libc = true, // Disable LTO to avoid https://github.com/llvm/llvm-project/issues/56825 .lto = false, @@ -131,7 +132,7 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: *std.Progress.Node) !void { .libc_installation = comp.libc_installation, .emit_bin = emit_bin, .link_mode = link_mode, - .function_sections = comp.bin_file.function_sections, + .function_sections = comp.function_sections, .c_source_files = &c_source_files, .verbose_cc = comp.verbose_cc, .verbose_link = comp.verbose_link, diff --git a/src/link.zig b/src/link.zig index 2a61e46969..91def2a134 100644 --- a/src/link.zig +++ b/src/link.zig @@ -68,9 +68,6 @@ pub const File = struct { force_undefined_symbols: std.StringArrayHashMapUnmanaged(void), allow_shlib_undefined: bool, stack_size: u64, - debug_format: DebugFormat, - function_sections: bool, - data_sections: bool, /// Prevents other processes from clobbering files in the output directory /// of this linking operation. @@ -78,16 +75,7 @@ pub const File = struct { child_pid: ?std.ChildProcess.Id = null, - pub const DebugFormat = union(enum) { - strip, - dwarf: std.dwarf.Format, - code_view, - }; - pub const OpenOptions = struct { - comp: *Compilation, - emit: Compilation.Emit, - symbol_count_hint: u64 = 32, program_code_size_hint: u64 = 256 * 1024, @@ -95,8 +83,6 @@ pub const File = struct { entry_addr: ?u64, stack_size: ?u64, image_base: ?u64, - function_sections: bool, - data_sections: bool, eh_frame_hdr: bool, emit_relocs: bool, rdynamic: bool, @@ -150,8 +136,6 @@ pub const File = struct { compatibility_version: ?std.SemanticVersion, - debug_format: ?DebugFormat, - // TODO: remove this. libraries are resolved by the frontend. lib_dirs: []const []const u8, rpath_list: []const []const u8, @@ -190,10 +174,29 @@ pub const File = struct { /// rewriting it. A malicious file is detected as incremental link failure /// and does not cause Illegal Behavior. This operation is not atomic. /// `arena` is used for allocations with the same lifetime as the created File. - pub fn open(arena: Allocator, options: OpenOptions) !*File { - switch (Tag.fromObjectFormat(options.comp.root_mod.resolved_target.result.ofmt)) { + pub fn open( + arena: Allocator, + comp: *Compilation, + emit: Compilation.Emit, + options: OpenOptions, + ) !*File { + switch (Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt)) { inline else => |tag| { - const ptr = try tag.Type().open(arena, options); + const ptr = try tag.Type().open(arena, comp, emit, options); + return &ptr.base; + }, + } + } + + pub fn createEmpty( + arena: Allocator, + comp: *Compilation, + emit: Compilation.Emit, + options: OpenOptions, + ) !*File { + switch (Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt)) { + inline else => |tag| { + const ptr = try tag.Type().createEmpty(arena, comp, emit, options); return &ptr.base; }, } diff --git a/src/link/C.zig b/src/link/C.zig index 043ca0ce6f..ce44cc4c06 100644 --- a/src/link/C.zig +++ b/src/link/C.zig @@ -92,21 +92,24 @@ pub fn addString(this: *C, s: []const u8) Allocator.Error!String { }; } -pub fn open(arena: Allocator, options: link.File.OpenOptions) !*C { - const target = options.comp.root_mod.resolved_target.result; +pub fn open( + arena: Allocator, + comp: *Compilation, + emit: Compilation.Emit, + options: link.File.OpenOptions, +) !*C { + const target = comp.root_mod.resolved_target.result; assert(target.ofmt == .c); - const optimize_mode = options.comp.root_mod.optimize_mode; - const use_lld = build_options.have_llvm and options.comp.config.use_lld; - const use_llvm = options.comp.config.use_llvm; - const output_mode = options.comp.config.output_mode; - const link_mode = options.comp.config.link_mode; + const optimize_mode = comp.root_mod.optimize_mode; + const use_lld = build_options.have_llvm and comp.config.use_lld; + const use_llvm = comp.config.use_llvm; + const output_mode = comp.config.output_mode; + const link_mode = comp.config.link_mode; // These are caught by `Compilation.Config.resolve`. assert(!use_lld); assert(!use_llvm); - const emit = options.emit; - const file = try emit.directory.handle.createFile(emit.sub_path, .{ // Truncation is done on `flush`. .truncate = false, @@ -119,7 +122,7 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*C { c_file.* = .{ .base = .{ .tag = .c, - .comp = options.comp, + .comp = comp, .emit = emit, .gc_sections = options.gc_sections orelse (optimize_mode != .Debug and output_mode != .Obj), .stack_size = options.stack_size orelse 16777216, @@ -129,9 +132,6 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*C { .build_id = options.build_id, .rpath_list = options.rpath_list, .force_undefined_symbols = options.force_undefined_symbols, - .debug_format = options.debug_format orelse .{ .dwarf = .@"32" }, - .function_sections = options.function_sections, - .data_sections = options.data_sections, }, }; diff --git a/src/link/Coff.zig b/src/link/Coff.zig index db99ba189c..eba24f0d17 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -234,44 +234,49 @@ const ideal_factor = 3; const minimum_text_block_size = 64; pub const min_text_capacity = padToIdeal(minimum_text_block_size); -pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Coff { +pub fn open( + arena: Allocator, + comp: *Compilation, + emit: Compilation.Emit, + options: link.File.OpenOptions, +) !*Coff { if (build_options.only_c) unreachable; - const target = options.comp.root_mod.resolved_target.result; + const target = comp.root_mod.resolved_target.result; assert(target.ofmt == .coff); - const self = try createEmpty(arena, options); + const self = try createEmpty(arena, comp, emit, options); errdefer self.base.destroy(); - const use_lld = build_options.have_llvm and options.comp.config.use_lld; - const use_llvm = options.comp.config.use_llvm; + const use_lld = build_options.have_llvm and comp.config.use_lld; + const use_llvm = comp.config.use_llvm; if (use_lld and use_llvm) { // LLVM emits the object file; LLD links it into the final product. return self; } - const sub_path = if (!use_lld) options.emit.sub_path else p: { + const sub_path = if (!use_lld) emit.sub_path else p: { // Open a temporary object file, not the final output file because we // want to link with LLD. const o_file_path = try std.fmt.allocPrint(arena, "{s}{s}", .{ - options.emit.sub_path, target.ofmt.fileExt(target.cpu.arch), + emit.sub_path, target.ofmt.fileExt(target.cpu.arch), }); self.base.intermediary_basename = o_file_path; break :p o_file_path; }; - self.base.file = try options.emit.directory.handle.createFile(sub_path, .{ + self.base.file = try emit.directory.handle.createFile(sub_path, .{ .truncate = false, .read = true, .mode = link.File.determineMode( use_lld, - options.comp.config.output_mode, - options.comp.config.link_mode, + comp.config.output_mode, + comp.config.link_mode, ), }); assert(self.llvm_object == null); - const gpa = self.base.comp.gpa; + const gpa = comp.gpa; try self.strtab.buffer.ensureUnusedCapacity(gpa, @sizeOf(u32)); self.strtab.buffer.appendNTimesAssumeCapacity(0, @sizeOf(u32)); @@ -362,8 +367,12 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Coff { return self; } -pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Coff { - const comp = options.comp; +pub fn createEmpty( + arena: Allocator, + comp: *Compilation, + emit: Compilation.Emit, + options: link.File.OpenOptions, +) !*Coff { const target = comp.root_mod.resolved_target.result; const optimize_mode = comp.root_mod.optimize_mode; const output_mode = comp.config.output_mode; @@ -380,7 +389,7 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Coff { .base = .{ .tag = .coff, .comp = comp, - .emit = options.emit, + .emit = emit, .stack_size = options.stack_size orelse 16777216, .gc_sections = options.gc_sections orelse (optimize_mode != .Debug), .allow_shlib_undefined = options.allow_shlib_undefined orelse false, @@ -389,9 +398,6 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Coff { .build_id = options.build_id, .rpath_list = options.rpath_list, .force_undefined_symbols = options.force_undefined_symbols, - .debug_format = options.debug_format orelse .code_view, - .function_sections = options.function_sections, - .data_sections = options.data_sections, }, .ptr_width = ptr_width, .page_size = page_size, @@ -423,7 +429,7 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Coff { const use_llvm = comp.config.use_llvm; if (use_llvm and comp.config.have_zcu) { - self.llvm_object = try LlvmObject.create(arena, options); + self.llvm_object = try LlvmObject.create(arena, comp); } return self; } diff --git a/src/link/Coff/lld.zig b/src/link/Coff/lld.zig index 1719d5fa67..ad9e18fa22 100644 --- a/src/link/Coff/lld.zig +++ b/src/link/Coff/lld.zig @@ -171,7 +171,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod try argv.append("-ERRORLIMIT:0"); try argv.append("-NOLOGO"); - if (self.base.debug_format != .strip) { + if (comp.config.debug_format != .strip) { try argv.append("-DEBUG"); const out_ext = std.fs.path.extension(full_out_path); diff --git a/src/link/Elf.zig b/src/link/Elf.zig index b54bde325f..5f96e195ab 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -228,18 +228,23 @@ pub const HashStyle = enum { sysv, gnu, both }; pub const CompressDebugSections = enum { none, zlib, zstd }; pub const SortSection = enum { name, alignment }; -pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Elf { +pub fn open( + arena: Allocator, + comp: *Compilation, + emit: Compilation.Emit, + options: link.File.OpenOptions, +) !*Elf { if (build_options.only_c) unreachable; - const target = options.comp.root_mod.resolved_target.result; + const target = comp.root_mod.resolved_target.result; assert(target.ofmt == .elf); - const use_lld = build_options.have_llvm and options.comp.config.use_lld; - const use_llvm = options.comp.config.use_llvm; - const opt_zcu = options.comp.module; - const output_mode = options.comp.config.output_mode; - const link_mode = options.comp.config.link_mode; + const use_lld = build_options.have_llvm and comp.config.use_lld; + const use_llvm = comp.config.use_llvm; + const opt_zcu = comp.module; + const output_mode = comp.config.output_mode; + const link_mode = comp.config.link_mode; - const self = try createEmpty(arena, options); + const self = try createEmpty(arena, comp, emit, options); errdefer self.base.destroy(); if (use_lld and use_llvm) { @@ -250,23 +255,23 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Elf { const is_obj = output_mode == .Obj; const is_obj_or_ar = is_obj or (output_mode == .Lib and link_mode == .Static); - const sub_path = if (!use_lld) options.emit.sub_path else p: { + const sub_path = if (!use_lld) emit.sub_path else p: { // Open a temporary object file, not the final output file because we // want to link with LLD. const o_file_path = try std.fmt.allocPrint(arena, "{s}{s}", .{ - options.emit.sub_path, target.ofmt.fileExt(target.cpu.arch), + emit.sub_path, target.ofmt.fileExt(target.cpu.arch), }); self.base.intermediary_basename = o_file_path; break :p o_file_path; }; - self.base.file = try options.emit.directory.handle.createFile(sub_path, .{ + self.base.file = try emit.directory.handle.createFile(sub_path, .{ .truncate = false, .read = true, .mode = link.File.determineMode(use_lld, output_mode, link_mode), }); - const gpa = options.comp.gpa; + const gpa = comp.gpa; // Index 0 is always a null symbol. try self.symbols.append(gpa, .{}); @@ -343,8 +348,12 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Elf { return self; } -pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Elf { - const comp = options.comp; +pub fn createEmpty( + arena: Allocator, + comp: *Compilation, + emit: Compilation.Emit, + options: link.File.OpenOptions, +) !*Elf { const use_llvm = comp.config.use_llvm; const optimize_mode = comp.root_mod.optimize_mode; const target = comp.root_mod.resolved_target.result; @@ -373,7 +382,7 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Elf { .base = .{ .tag = .elf, .comp = comp, - .emit = options.emit, + .emit = emit, .gc_sections = options.gc_sections orelse (optimize_mode != .Debug and output_mode != .Obj), .stack_size = options.stack_size orelse 16777216, .allow_shlib_undefined = options.allow_shlib_undefined orelse !is_native_os, @@ -382,9 +391,6 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Elf { .build_id = options.build_id, .rpath_list = options.rpath_list, .force_undefined_symbols = options.force_undefined_symbols, - .debug_format = options.debug_format orelse .{ .dwarf = .@"32" }, - .function_sections = options.function_sections, - .data_sections = options.data_sections, }, .ptr_width = ptr_width, .page_size = page_size, @@ -423,7 +429,7 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Elf { .version_script = options.version_script, }; if (use_llvm and comp.config.have_zcu) { - self.llvm_object = try LlvmObject.create(arena, options); + self.llvm_object = try LlvmObject.create(arena, comp); } return self; @@ -1753,7 +1759,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void { try argv.append("-pie"); } - if (self.base.debug_format == .strip) { + if (comp.config.debug_format == .strip) { try argv.append("-s"); } @@ -2640,7 +2646,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v try argv.append("--export-dynamic"); } - if (self.base.debug_format == .strip) { + if (comp.config.debug_format == .strip) { try argv.append("-s"); } diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index 5fa31711e6..0bf1e837e3 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -293,13 +293,14 @@ fn initOutputSection(self: Object, elf_file: *Elf, shdr: ElfShdr) error{OutOfMem } fn skipShdr(self: *Object, index: u16, elf_file: *Elf) bool { + const comp = elf_file.base.comp; const shdr = self.shdrs.items[index]; const name = self.getString(shdr.sh_name); const ignore = blk: { if (mem.startsWith(u8, name, ".note")) break :blk true; if (mem.startsWith(u8, name, ".comment")) break :blk true; if (mem.startsWith(u8, name, ".llvm_addrsig")) break :blk true; - if (elf_file.base.debug_format == .strip and shdr.sh_flags & elf.SHF_ALLOC == 0 and + if (comp.config.debug_format == .strip and shdr.sh_flags & elf.SHF_ALLOC == 0 and mem.startsWith(u8, name, ".debug")) break :blk true; break :blk false; }; diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 05ff55dd18..75bc53bb48 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -76,7 +76,8 @@ pub const symbol_mask: u32 = 0x7fffffff; pub const SHN_ATOM: u16 = 0x100; pub fn init(self: *ZigObject, elf_file: *Elf) !void { - const gpa = elf_file.base.comp.gpa; + const comp = elf_file.base.comp; + const gpa = comp.gpa; try self.atoms.append(gpa, 0); // null input section try self.relocs.append(gpa, .{}); // null relocs section @@ -96,8 +97,13 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void { esym.st_shndx = elf.SHN_ABS; symbol_ptr.esym_index = esym_index; - if (elf_file.base.debug_format != .strip) { - self.dwarf = Dwarf.init(&elf_file.base, .dwarf32); + switch (comp.config.debug_format) { + .strip => {}, + .dwarf => |v| { + assert(v == .@"32"); + self.dwarf = Dwarf.init(&elf_file.base, .dwarf32); + }, + .code_view => unreachable, } } diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 87faec6537..25d59f3de3 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -182,18 +182,21 @@ pub const SdkLayout = enum { vendored, }; -pub fn open(arena: Allocator, options: link.File.OpenOptions) !*MachO { +pub fn open( + arena: Allocator, + comp: *Compilation, + emit: Compilation.Emit, + options: link.File.OpenOptions, +) !*MachO { if (build_options.only_c) unreachable; - const comp = options.comp; const target = comp.root_mod.resolved_target.result; const use_lld = build_options.have_llvm and comp.config.use_lld; const use_llvm = comp.config.use_llvm; assert(target.ofmt == .macho); const gpa = comp.gpa; - const emit = options.emit; const mode: Mode = mode: { - if (use_llvm or comp.module == null or comp.cache_mode == .whole) + if (use_llvm or comp.module == null or comp.cache_use == .whole) break :mode .zld; break :mode .incremental; }; @@ -201,7 +204,7 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*MachO { if (comp.module == null) { // No point in opening a file, we would not write anything to it. // Initialize with empty. - return createEmpty(arena, options); + return createEmpty(arena, comp, emit, options); } // Open a temporary object file, not the final output file because we // want to link with LLD. @@ -210,7 +213,7 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*MachO { }); } else emit.sub_path; - const self = try createEmpty(arena, options); + const self = try createEmpty(arena, comp, emit, options); errdefer self.base.destroy(); if (mode == .zld) { @@ -232,7 +235,7 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*MachO { }); self.base.file = file; - if (self.base.debug_format != .strip and comp.module != null) { + if (comp.config.debug_format != .strip and comp.module != null) { // Create dSYM bundle. log.debug("creating {s}.dSYM bundle", .{sub_path}); @@ -279,8 +282,12 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*MachO { return self; } -pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*MachO { - const comp = options.comp; +pub fn createEmpty( + arena: Allocator, + comp: *Compilation, + emit: Compilation.Emit, + options: link.File.OpenOptions, +) !*MachO { const optimize_mode = comp.root_mod.optimize_mode; const use_llvm = comp.config.use_llvm; @@ -289,7 +296,7 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*MachO { .base = .{ .tag = .macho, .comp = comp, - .emit = options.emit, + .emit = emit, .gc_sections = options.gc_sections orelse (optimize_mode != .Debug), .stack_size = options.stack_size orelse 16777216, .allow_shlib_undefined = options.allow_shlib_undefined orelse false, @@ -298,11 +305,8 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*MachO { .build_id = options.build_id, .rpath_list = options.rpath_list, .force_undefined_symbols = options.force_undefined_symbols, - .debug_format = options.debug_format orelse .{ .dwarf = .@"32" }, - .function_sections = options.function_sections, - .data_sections = options.data_sections, }, - .mode = if (use_llvm or comp.module == null or comp.cache_mode == .whole) + .mode = if (use_llvm or comp.module == null or comp.cache_use == .whole) .zld else .incremental, @@ -317,7 +321,7 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*MachO { }; if (use_llvm and comp.module != null) { - self.llvm_object = try LlvmObject.create(arena, options); + self.llvm_object = try LlvmObject.create(arena, comp); } log.debug("selected linker mode '{s}'", .{@tagName(self.mode)}); @@ -4313,7 +4317,8 @@ fn addLocalToSymtab(self: *MachO, sym_loc: SymbolWithLoc, locals: *std.ArrayList } fn writeSymtab(self: *MachO) !SymtabCtx { - const gpa = self.base.comp.gpa; + const comp = self.base.comp; + const gpa = comp.gpa; var locals = std.ArrayList(macho.nlist_64).init(gpa); defer locals.deinit(); @@ -4368,7 +4373,7 @@ fn writeSymtab(self: *MachO) !SymtabCtx { // We generate stabs last in order to ensure that the strtab always has debug info // strings trailing - if (self.base.debug_format != .strip) { + if (comp.config.debug_format != .strip) { for (self.objects.items) |object| { assert(self.d_sym == null); // TODO try self.generateSymbolStabs(object, &locals); diff --git a/src/link/NvPtx.zig b/src/link/NvPtx.zig index 846e496ec1..57a8352898 100644 --- a/src/link/NvPtx.zig +++ b/src/link/NvPtx.zig @@ -25,12 +25,17 @@ const LlvmObject = @import("../codegen/llvm.zig").Object; base: link.File, llvm_object: *LlvmObject, -pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*NvPtx { +pub fn createEmpty( + arena: Allocator, + comp: *Compilation, + emit: Compilation.Emit, + options: link.File.OpenOptions, +) !*NvPtx { if (build_options.only_c) unreachable; - const target = options.comp.root_mod.resolved_target.result; - const use_lld = build_options.have_llvm and options.comp.config.use_lld; - const use_llvm = options.comp.config.use_llvm; + const target = comp.root_mod.resolved_target.result; + const use_lld = build_options.have_llvm and comp.config.use_lld; + const use_llvm = comp.config.use_llvm; assert(use_llvm); // Caught by Compilation.Config.resolve. assert(!use_lld); // Caught by Compilation.Config.resolve. @@ -42,13 +47,13 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*NvPtx { else => return error.PtxArchNotSupported, } - const llvm_object = try LlvmObject.create(arena, options); + const llvm_object = try LlvmObject.create(arena, comp); const nvptx = try arena.create(NvPtx); nvptx.* = .{ .base = .{ .tag = .nvptx, - .comp = options.comp, - .emit = options.emit, + .comp = comp, + .emit = emit, .gc_sections = options.gc_sections orelse false, .stack_size = options.stack_size orelse 0, .allow_shlib_undefined = options.allow_shlib_undefined orelse false, @@ -57,9 +62,6 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*NvPtx { .build_id = options.build_id, .rpath_list = options.rpath_list, .force_undefined_symbols = options.force_undefined_symbols, - .debug_format = options.debug_format orelse .{ .dwarf = .@"32" }, - .function_sections = options.function_sections, - .data_sections = options.data_sections, }, .llvm_object = llvm_object, }; @@ -67,10 +69,15 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*NvPtx { return nvptx; } -pub fn open(arena: Allocator, options: link.File.OpenOptions) !*NvPtx { - const target = options.comp.root_mod.resolved_target.result; +pub fn open( + arena: Allocator, + comp: *Compilation, + emit: Compilation.Emit, + options: link.File.OpenOptions, +) !*NvPtx { + const target = comp.root_mod.resolved_target.result; assert(target.ofmt == .nvptx); - return createEmpty(arena, options); + return createEmpty(arena, comp, emit, options); } pub fn deinit(self: *NvPtx) void { diff --git a/src/link/Plan9.zig b/src/link/Plan9.zig index b3c08fb66b..c970e72e51 100644 --- a/src/link/Plan9.zig +++ b/src/link/Plan9.zig @@ -294,8 +294,12 @@ pub fn defaultBaseAddrs(arch: std.Target.Cpu.Arch) Bases { }; } -pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Plan9 { - const comp = options.comp; +pub fn createEmpty( + arena: Allocator, + comp: *Compilation, + emit: Compilation.Emit, + options: link.File.OpenOptions, +) !*Plan9 { const target = comp.root_mod.resolved_target.result; const gpa = comp.gpa; const optimize_mode = comp.root_mod.optimize_mode; @@ -313,7 +317,7 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Plan9 { .base = .{ .tag = .plan9, .comp = comp, - .emit = options.emit, + .emit = emit, .gc_sections = options.gc_sections orelse (optimize_mode != .Debug and output_mode != .Obj), .stack_size = options.stack_size orelse 16777216, .allow_shlib_undefined = options.allow_shlib_undefined orelse false, @@ -322,9 +326,6 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Plan9 { .build_id = options.build_id, .rpath_list = options.rpath_list, .force_undefined_symbols = options.force_undefined_symbols, - .debug_format = options.debug_format orelse .{ .dwarf = .@"32" }, - .function_sections = options.function_sections, - .data_sections = options.data_sections, }, .sixtyfour_bit = sixtyfour_bit, .bases = undefined, @@ -1308,26 +1309,31 @@ pub fn deinit(self: *Plan9) void { } } -pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Plan9 { +pub fn open( + arena: Allocator, + comp: *Compilation, + emit: Compilation.Emit, + options: link.File.OpenOptions, +) !*Plan9 { if (build_options.only_c) unreachable; - const target = options.comp.root_mod.resolved_target.result; - const use_lld = build_options.have_llvm and options.comp.config.use_lld; - const use_llvm = options.comp.config.use_llvm; + const target = comp.root_mod.resolved_target.result; + const use_lld = build_options.have_llvm and comp.config.use_lld; + const use_llvm = comp.config.use_llvm; assert(!use_llvm); // Caught by Compilation.Config.resolve. assert(!use_lld); // Caught by Compilation.Config.resolve. assert(target.ofmt == .plan9); - const self = try createEmpty(arena, options); + const self = try createEmpty(arena, comp, emit, options); errdefer self.base.destroy(); - const file = try options.emit.directory.handle.createFile(options.emit.sub_path, .{ + const file = try emit.directory.handle.createFile(emit.sub_path, .{ .read = true, .mode = link.File.determineMode( use_lld, - options.comp.config.output_mode, - options.comp.config.link_mode, + comp.config.output_mode, + comp.config.link_mode, ), }); errdefer file.close(); @@ -1335,7 +1341,7 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Plan9 { self.bases = defaultBaseAddrs(target.cpu.arch); - const gpa = options.comp.gpa; + const gpa = comp.gpa; try self.syms.appendSlice(gpa, &.{ // we include the global offset table to make it easier for debugging diff --git a/src/link/SpirV.zig b/src/link/SpirV.zig index bb278a8e4a..853d97b014 100644 --- a/src/link/SpirV.zig +++ b/src/link/SpirV.zig @@ -49,16 +49,21 @@ object: codegen.Object, pub const base_tag: link.File.Tag = .spirv; -pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*SpirV { - const gpa = options.comp.gpa; - const target = options.comp.root_mod.resolved_target.result; +pub fn createEmpty( + arena: Allocator, + comp: *Compilation, + emit: Compilation.Emit, + options: link.File.OpenOptions, +) !*SpirV { + const gpa = comp.gpa; + const target = comp.root_mod.resolved_target.result; const self = try arena.create(SpirV); self.* = .{ .base = .{ .tag = .spirv, - .comp = options.comp, - .emit = options.emit, + .comp = comp, + .emit = emit, .gc_sections = options.gc_sections orelse false, .stack_size = options.stack_size orelse 0, .allow_shlib_undefined = options.allow_shlib_undefined orelse false, @@ -67,9 +72,6 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*SpirV { .build_id = options.build_id, .rpath_list = options.rpath_list, .force_undefined_symbols = options.force_undefined_symbols, - .function_sections = options.function_sections, - .data_sections = options.data_sections, - .debug_format = options.debug_format orelse .{ .dwarf = .@"32" }, }, .object = codegen.Object.init(gpa), }; @@ -90,22 +92,27 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*SpirV { return self; } -pub fn open(arena: Allocator, options: link.File.OpenOptions) !*SpirV { +pub fn open( + arena: Allocator, + comp: *Compilation, + emit: Compilation.Emit, + options: link.File.OpenOptions, +) !*SpirV { if (build_options.only_c) unreachable; - const target = options.comp.root_mod.resolved_target.result; - const use_lld = build_options.have_llvm and options.comp.config.use_lld; - const use_llvm = options.comp.config.use_llvm; + const target = comp.root_mod.resolved_target.result; + const use_lld = build_options.have_llvm and comp.config.use_lld; + const use_llvm = comp.config.use_llvm; assert(!use_llvm); // Caught by Compilation.Config.resolve. assert(!use_lld); // Caught by Compilation.Config.resolve. assert(target.ofmt == .spirv); // Caught by Compilation.Config.resolve. - const spirv = try createEmpty(arena, options); + const spirv = try createEmpty(arena, comp, emit, options); errdefer spirv.base.destroy(); // TODO: read the file and keep valid parts instead of truncating - const file = try options.emit.directory.handle.createFile(options.emit.sub_path, .{ + const file = try emit.directory.handle.createFile(emit.sub_path, .{ .truncate = true, .read = true, }); diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 74d83e6c3c..8f63e7c6fd 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -373,9 +373,13 @@ pub const StringTable = struct { } }; -pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Wasm { +pub fn open( + arena: Allocator, + comp: *Compilation, + emit: Compilation.Emit, + options: link.File.OpenOptions, +) !*Wasm { if (build_options.only_c) unreachable; - const comp = options.comp; const gpa = comp.gpa; const target = comp.root_mod.resolved_target.result; assert(target.ofmt == .wasm); @@ -385,7 +389,7 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Wasm { const output_mode = comp.config.output_mode; const shared_memory = comp.config.shared_memory; - const wasm = try createEmpty(arena, options); + const wasm = try createEmpty(arena, comp, emit, options); errdefer wasm.base.destroy(); if (use_lld and use_llvm) { @@ -393,18 +397,18 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Wasm { return wasm; } - const sub_path = if (!use_lld) options.emit.sub_path else p: { + const sub_path = if (!use_lld) emit.sub_path else p: { // Open a temporary object file, not the final output file because we // want to link with LLD. const o_file_path = try std.fmt.allocPrint(arena, "{s}{s}", .{ - options.emit.sub_path, target.ofmt.fileExt(target.cpu.arch), + emit.sub_path, target.ofmt.fileExt(target.cpu.arch), }); wasm.base.intermediary_basename = o_file_path; break :p o_file_path; }; // TODO: read the file and keep valid parts instead of truncating - const file = try options.emit.directory.handle.createFile(sub_path, .{ + const file = try emit.directory.handle.createFile(sub_path, .{ .truncate = true, .read = true, .mode = if (fs.has_executable_bit) @@ -530,8 +534,12 @@ pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Wasm { return wasm; } -pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Wasm { - const comp = options.comp; +pub fn createEmpty( + arena: Allocator, + comp: *Compilation, + emit: Compilation.Emit, + options: link.File.OpenOptions, +) !*Wasm { const use_llvm = comp.config.use_llvm; const output_mode = comp.config.output_mode; @@ -540,7 +548,7 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Wasm { .base = .{ .tag = .wasm, .comp = comp, - .emit = options.emit, + .emit = emit, .gc_sections = options.gc_sections orelse (output_mode != .Obj), .stack_size = options.stack_size orelse std.wasm.page_size * 16, // 1MB .allow_shlib_undefined = options.allow_shlib_undefined orelse false, @@ -549,9 +557,6 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Wasm { .build_id = options.build_id, .rpath_list = options.rpath_list, .force_undefined_symbols = options.force_undefined_symbols, - .debug_format = options.debug_format orelse .{ .dwarf = .@"32" }, - .function_sections = options.function_sections, - .data_sections = options.data_sections, }, .name = undefined, .import_table = options.import_table, @@ -566,7 +571,7 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Wasm { }; if (use_llvm) { - wasm.llvm_object = try LlvmObject.create(arena, options); + wasm.llvm_object = try LlvmObject.create(arena, comp); } return wasm; } @@ -4205,11 +4210,11 @@ fn writeToFile( if (data_section_index) |data_index| { try wasm.emitDataRelocations(&binary_bytes, data_index, symbol_table); } - } else if (wasm.base.debug_format != .strip) { + } else if (comp.config.debug_format != .strip) { try wasm.emitNameSection(&binary_bytes, arena); } - if (wasm.base.debug_format != .strip) { + if (comp.config.debug_format != .strip) { // The build id must be computed on the main sections only, // so we have to do it now, before the debug sections. switch (wasm.base.build_id) { @@ -4748,7 +4753,7 @@ fn linkWithLLD(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) ! try argv.append("--no-gc-sections"); } - if (wasm.base.debug_format == .strip) { + if (comp.config.debug_format == .strip) { try argv.append("-s"); } @@ -5276,7 +5281,9 @@ pub fn storeDeclType(wasm: *Wasm, decl_index: InternPool.DeclIndex, func_type: s fn markReferences(wasm: *Wasm) !void { const tracy = trace(@src()); defer tracy.end(); + const do_garbage_collect = wasm.base.gc_sections; + const comp = wasm.base.comp; for (wasm.resolved_symbols.keys()) |sym_loc| { const sym = sym_loc.getSymbol(wasm); @@ -5287,7 +5294,7 @@ fn markReferences(wasm: *Wasm) !void { // Debug sections may require to be parsed and marked when it contains // relocations to alive symbols. - if (sym.tag == .section and wasm.base.debug_format != .strip) { + if (sym.tag == .section and comp.config.debug_format != .strip) { const file = sym_loc.file orelse continue; // Incremental debug info is done independently const object = &wasm.objects.items[file]; const atom_index = try Object.parseSymbolIntoAtom(object, file, sym_loc.index, wasm); diff --git a/src/main.zig b/src/main.zig index 9acad1a0ca..dbd9759015 100644 --- a/src/main.zig +++ b/src/main.zig @@ -892,7 +892,6 @@ fn buildOutputType( var contains_res_file: bool = false; var reference_trace: ?u32 = null; var pdb_out_path: ?[]const u8 = null; - var debug_format: ?link.File.DebugFormat = null; var error_limit: ?Module.ErrorInt = null; // These are before resolving sysroot. var lib_dir_args: std.ArrayListUnmanaged([]const u8) = .{}; @@ -1054,6 +1053,8 @@ fn buildOutputType( create_module.opts.any_sanitize_thread = true; if (mod_opts.unwind_tables == true) create_module.opts.any_unwind_tables = true; + if (mod_opts.strip == false) + create_module.opts.any_non_stripped = true; const root_src = try introspect.resolvePath(arena, root_src_orig); try create_module.modules.put(arena, mod_name, .{ @@ -1480,9 +1481,9 @@ fn buildOutputType( } else if (mem.eql(u8, arg, "-fno-strip")) { mod_opts.strip = false; } else if (mem.eql(u8, arg, "-gdwarf32")) { - debug_format = .{ .dwarf = .@"32" }; + create_module.opts.debug_format = .{ .dwarf = .@"32" }; } else if (mem.eql(u8, arg, "-gdwarf64")) { - debug_format = .{ .dwarf = .@"64" }; + create_module.opts.debug_format = .{ .dwarf = .@"64" }; } else if (mem.eql(u8, arg, "-fformatted-panics")) { formatted_panics = true; } else if (mem.eql(u8, arg, "-fno-formatted-panics")) { @@ -1989,11 +1990,11 @@ fn buildOutputType( }, .gdwarf32 => { mod_opts.strip = false; - debug_format = .{ .dwarf = .@"32" }; + create_module.opts.debug_format = .{ .dwarf = .@"32" }; }, .gdwarf64 => { mod_opts.strip = false; - debug_format = .{ .dwarf = .@"64" }; + create_module.opts.debug_format = .{ .dwarf = .@"64" }; }, .sanitize => { if (mem.eql(u8, it.only_arg, "undefined")) { @@ -2532,6 +2533,8 @@ fn buildOutputType( create_module.opts.any_sanitize_thread = true; if (mod_opts.unwind_tables == true) create_module.opts.any_unwind_tables = true; + if (mod_opts.strip == false) + create_module.opts.any_non_stripped = true; const src_path = try introspect.resolvePath(arena, unresolved_src_path); try create_module.modules.put(arena, "main", .{ @@ -3359,7 +3362,6 @@ fn buildOutputType( .emit_docs = emit_docs_resolved.data, .emit_implib = emit_implib_resolved.data, .dll_export_fns = dll_export_fns, - .keep_source_files_loaded = false, .lib_dirs = lib_dirs.items, .rpath_list = rpath_list.items, .symbol_wrap_set = symbol_wrap_set, @@ -3443,7 +3445,6 @@ fn buildOutputType( .test_runner_path = test_runner_path, .disable_lld_caching = !output_to_cache, .subsystem = subsystem, - .debug_format = debug_format, .debug_compile_errors = debug_compile_errors, .enable_link_snapshots = enable_link_snapshots, .install_name = install_name, @@ -3484,7 +3485,9 @@ fn buildOutputType( defer if (!comp_destroyed) comp.destroy(); if (show_builtin) { - return std.io.getStdOut().writeAll(try comp.generateBuiltinZigSource(arena)); + const builtin_mod = comp.root_mod.deps.get("builtin").?; + const source = builtin_mod.builtin_file.?.source; + return std.io.getStdOut().writeAll(source); } switch (listen) { .none => {}, @@ -3737,6 +3740,7 @@ fn createModule( const resolved_target = cli_mod.inherited.resolved_target.?; create_module.opts.resolved_target = resolved_target; create_module.opts.root_optimize_mode = cli_mod.inherited.optimize_mode; + create_module.opts.root_strip = cli_mod.inherited.strip; const target = resolved_target.result; // First, remove libc, libc++, and compiler_rt libraries from the system libraries list. @@ -4366,12 +4370,12 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, fancy_output: ?*Compilati const translated_zig_basename = try std.fmt.allocPrint(arena, "{s}.zig", .{comp.root_name}); - var man: Cache.Manifest = comp.obtainCObjectCacheManifest(); + var man: Cache.Manifest = comp.obtainCObjectCacheManifest(comp.root_mod); man.want_shared_lock = false; defer man.deinit(); man.hash.add(@as(u16, 0xb945)); // Random number to distinguish translate-c from compiling C objects - man.hash.add(comp.c_frontend); + man.hash.add(comp.config.c_frontend); Compilation.cache_helpers.hashCSource(&man, c_source_file) catch |err| { fatal("unable to process '{s}': {s}", .{ c_source_file.src_path, @errorName(err) }); }; @@ -4380,14 +4384,14 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, fancy_output: ?*Compilati const digest = if (try man.hit()) man.final() else digest: { if (fancy_output) |p| p.cache_hit = false; var argv = std.ArrayList([]const u8).init(arena); - try argv.append(@tagName(comp.c_frontend)); // argv[0] is program name, actual args start at [1] + try argv.append(@tagName(comp.config.c_frontend)); // argv[0] is program name, actual args start at [1] var zig_cache_tmp_dir = try comp.local_cache_directory.handle.makeOpenPath("tmp", .{}); defer zig_cache_tmp_dir.close(); const ext = Compilation.classifyFileExt(c_source_file.src_path); const out_dep_path: ?[]const u8 = blk: { - if (comp.c_frontend == .aro or comp.disable_c_depfile or !ext.clangSupportsDepFile()) + if (comp.config.c_frontend == .aro or comp.disable_c_depfile or !ext.clangSupportsDepFile()) break :blk null; const c_src_basename = fs.path.basename(c_source_file.src_path); @@ -4397,14 +4401,15 @@ fn cmdTranslateC(comp: *Compilation, arena: Allocator, fancy_output: ?*Compilati }; // TODO - if (comp.c_frontend != .aro) try comp.addTranslateCCArgs(arena, &argv, ext, out_dep_path); + if (comp.config.c_frontend != .aro) + try comp.addTranslateCCArgs(arena, &argv, ext, out_dep_path, comp.root_mod); try argv.append(c_source_file.src_path); if (comp.verbose_cc) { Compilation.dump_argv(argv.items); } - var tree = switch (comp.c_frontend) { + var tree = switch (comp.config.c_frontend) { .aro => tree: { const aro = @import("aro"); const translate_c = @import("aro_translate_c.zig");