From 12de7e3472cb2292e75578d33a8b8cc91f1ef0b0 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 10 Dec 2023 15:25:06 -0700 Subject: WIP: move many global settings to become per-Module Much of the logic from Compilation.create() is extracted into Compilation.Config.resolve() which accepts many optional settings and produces concrete settings. This separate step is needed by API users of Compilation so that they can pass the resolved global settings to the Module creation function, which itself needs to resolve per-Module settings. Since the target and other things are no longer global settings, I did not want them stored in link.File (in the `options` field). That options field was already a kludge; those options should be resolved into concrete settings. This commit also starts to work on that, deleting link.Options, moving the fields into Compilation and ObjectFormat-specific structs instead. Some fields were ephemeral and should not have been stored at all, such as symbol_size_hint. The link.File object of Compilation is now a `?*link.File` and `null` when -fno-emit-bin is passed. It is now arena-allocated along with Compilation itself, avoiding some messy cleanup code that was there before. On the command line, it is now possible to configure the standard library itself by using `--mod std` just like any other module. This meant that the CLI needed to create the standard library module rather than having Compilation create it. There are a lot of changes in this commit and it's still not done. I didn't realize how quickly this changeset was going to balloon out of control, and there are still many lines that need to be changed before it even compiles successfully. * introduce std.Build.Cache.HashHelper.oneShot * add error_tracing to std.Build.Module * extract build.zig file generation into src/Builtin.zig * each CSourceFile and RcSourceFile now has a Module owner, which determines some of the C compiler flags. --- src/Package/Module.zig | 409 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 403 insertions(+), 6 deletions(-) (limited to 'src/Package/Module.zig') diff --git a/src/Package/Module.zig b/src/Package/Module.zig index 0c8d40bffa..94431856ac 100644 --- a/src/Package/Module.zig +++ b/src/Package/Module.zig @@ -1,6 +1,6 @@ //! Corresponds to something that Zig source code can `@import`. -//! Not to be confused with src/Module.zig which should be renamed -//! to something else. https://github.com/ziglang/zig/issues/14307 +//! Not to be confused with src/Module.zig which will be renamed +//! to Zcu. https://github.com/ziglang/zig/issues/14307 /// Only files inside this directory can be imported. root: Package.Path, @@ -14,6 +14,26 @@ fully_qualified_name: []const u8, /// responsible for detecting these names and using the correct package. deps: Deps = .{}, +resolved_target: ResolvedTarget, +optimize_mode: std.builtin.OptimizeMode, +code_model: std.builtin.CodeModel, +single_threaded: bool, +error_tracing: bool, +valgrind: bool, +pic: bool, +strip: bool, +omit_frame_pointer: bool, +stack_check: bool, +stack_protector: u32, +red_zone: bool, +sanitize_c: bool, +sanitize_thread: bool, +unwind_tables: bool, +cc_argv: []const []const u8, + +/// The contents of `@import("builtin")` for this module. +generated_builtin_source: []const u8, + pub const Deps = std.StringArrayHashMapUnmanaged(*Module); pub const Tree = struct { @@ -21,10 +41,382 @@ pub const Tree = struct { build_module_table: std.AutoArrayHashMapUnmanaged(MultiHashHexDigest, *Module), }; -pub fn create(allocator: Allocator, m: Module) Allocator.Error!*Module { - const new = try allocator.create(Module); - new.* = m; - return new; +pub const CreateOptions = struct { + /// Where to store builtin.zig. The global cache directory is used because + /// it is a pure function based on CLI flags. + global_cache_directory: Cache.Directory, + paths: Paths, + fully_qualified_name: []const u8, + + cc_argv: []const []const u8, + inherited: Inherited, + global: Compilation.Config, + /// If this is null then `resolved_target` must be non-null. + parent: ?*Package.Module, + + builtin_mod: ?*Package.Module, + + pub const Paths = struct { + root: Package.Path, + /// Relative to `root`. May contain path separators. + root_src_path: []const u8, + }; + + pub const Inherited = struct { + /// If this is null then `parent` must be non-null. + resolved_target: ?ResolvedTarget = null, + optimize_mode: ?std.builtin.OptimizeMode = null, + code_model: ?std.builtin.CodeModel = null, + single_threaded: ?bool = null, + error_tracing: ?bool = null, + valgrind: ?bool = null, + pic: ?bool = null, + strip: ?bool = null, + omit_frame_pointer: ?bool = null, + stack_check: ?bool = null, + /// null means default. + /// 0 means no stack protector. + /// other number means stack protection with that buffer size. + stack_protector: ?u32 = null, + red_zone: ?bool = null, + unwind_tables: ?bool = null, + sanitize_c: ?bool = null, + sanitize_thread: ?bool = null, + }; +}; + +pub const ResolvedTarget = struct { + result: std.Target, + is_native_os: bool, + is_native_abi: bool, + llvm_cpu_features: ?[*:0]const u8 = null, +}; + +/// At least one of `parent` and `resolved_target` must be non-null. +pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module { + const resolved_target = options.inherited.resolved_target orelse options.parent.?.resolved_target; + const target = resolved_target.result; + + const optimize_mode = options.inherited.optimize_mode orelse + if (options.parent) |p| p.optimize_mode else .Debug; + + const unwind_tables = options.inherited.unwind_tables orelse + if (options.parent) |p| p.unwind_tables else options.global.any_unwind_tables; + + const strip = b: { + if (options.inherited.strip) |x| break :b x; + if (options.parent) |p| break :b p.strip; + if (optimize_mode == .ReleaseSmall) break :b true; + if (!target_util.hasDebugInfo(target)) break :b true; + break :b false; + }; + + const valgrind = b: { + if (!target_util.hasValgrindSupport(target)) { + if (options.inherited.valgrind == true) + return error.ValgrindUnsupportedOnTarget; + break :b false; + } + if (options.inherited.valgrind) |x| break :b x; + if (options.parent) |p| break :b p.valgrind; + if (strip) break :b false; + break :b optimize_mode == .Debug; + }; + + const zig_backend = target_util.zigBackend(target, options.global.use_llvm); + + const single_threaded = b: { + if (target_util.alwaysSingleThreaded(target)) { + if (options.inherited.single_threaded == false) + return error.TargetRequiresSingleThreaded; + break :b true; + } + + if (options.global.have_zcu) { + if (!target_util.supportsThreads(target, zig_backend)) { + if (options.inherited.single_threaded == false) + return error.BackendRequiresSingleThreaded; + break :b true; + } + } + + if (options.inherited.single_threaded) |x| break :b x; + if (options.parent) |p| break :b p.single_threaded; + break :b target_util.defaultSingleThreaded(target); + }; + + const error_tracing = b: { + if (options.inherited.error_tracing) |x| break :b x; + if (options.parent) |p| break :b p.error_tracing; + if (strip) break :b false; + break :b switch (optimize_mode) { + .Debug => true, + .ReleaseSafe, .ReleaseFast, .ReleaseSmall => false, + }; + }; + + const pic = b: { + if (target_util.requiresPIC(target, options.global.link_libc)) { + if (options.inherited.pic == false) + return error.TargetRequiresPic; + break :b true; + } + if (options.global.pie) { + if (options.inherited.pic == false) + return error.PieRequiresPic; + break :b true; + } + if (options.global.link_mode == .Dynamic) { + if (options.inherited.pic == false) + return error.DynamicLinkingRequiresPic; + break :b true; + } + if (options.inherited.pic) |x| break :b x; + if (options.parent) |p| break :b p.pic; + break :b false; + }; + + const red_zone = b: { + if (!target_util.hasRedZone(target)) { + if (options.inherited.red_zone == true) + return error.TargetHasNoRedZone; + break :b true; + } + if (options.inherited.red_zone) |x| break :b x; + if (options.parent) |p| break :b p.red_zone; + break :b true; + }; + + const omit_frame_pointer = b: { + if (options.inherited.omit_frame_pointer) |x| break :b x; + if (options.parent) |p| break :b p.omit_frame_pointer; + if (optimize_mode == .Debug) break :b false; + break :b true; + }; + + const sanitize_thread = b: { + if (options.inherited.sanitize_thread) |x| break :b x; + if (options.parent) |p| break :b p.sanitize_thread; + break :b false; + }; + + const code_model = b: { + if (options.inherited.code_model) |x| break :b x; + if (options.parent) |p| break :b p.code_model; + break :b .default; + }; + + const is_safe_mode = switch (optimize_mode) { + .Debug, .ReleaseSafe => true, + .ReleaseFast, .ReleaseSmall => false, + }; + + const sanitize_c = b: { + if (options.inherited.sanitize_c) |x| break :b x; + if (options.parent) |p| break :b p.sanitize_c; + break :b is_safe_mode; + }; + + const stack_check = b: { + if (!target_util.supportsStackProbing(target)) { + if (options.inherited.stack_check == true) + return error.StackCheckUnsupportedByTarget; + break :b false; + } + if (options.inherited.stack_check) |x| break :b x; + if (options.parent) |p| break :b p.stack_check; + break :b is_safe_mode; + }; + + const stack_protector: u32 = sp: { + if (!target_util.supportsStackProtector(target, zig_backend)) { + if (options.inherited.stack_protector) |x| { + if (x > 0) return error.StackProtectorUnsupportedByTarget; + } + break :sp 0; + } + + // This logic is checking for linking libc because otherwise our start code + // which is trying to set up TLS (i.e. the fs/gs registers) but the stack + // protection code depends on fs/gs registers being already set up. + // If we were able to annotate start code, or perhaps the entire std lib, + // as being exempt from stack protection checks, we could change this logic + // to supporting stack protection even when not linking libc. + // TODO file issue about this + if (!options.global.link_libc) { + if (options.inherited.stack_protector) |x| { + if (x > 0) return error.StackProtectorUnavailableWithoutLibC; + } + break :sp 0; + } + + if (options.inherited.stack_protector) |x| break :sp x; + if (options.parent) |p| break :sp p.stack_protector; + if (!is_safe_mode) break :sp 0; + + break :sp target_util.default_stack_protector_buffer_size; + }; + + const llvm_cpu_features: ?[*:0]const u8 = b: { + if (resolved_target.llvm_cpu_features) |x| break :b x; + if (!options.global.use_llvm) break :b null; + + var buf = std.ArrayList(u8).init(arena); + for (target.cpu.arch.allFeaturesList(), 0..) |feature, index_usize| { + const index = @as(std.Target.Cpu.Feature.Set.Index, @intCast(index_usize)); + const is_enabled = target.cpu.features.isEnabled(index); + + if (feature.llvm_name) |llvm_name| { + const plus_or_minus = "-+"[@intFromBool(is_enabled)]; + try buf.ensureUnusedCapacity(2 + llvm_name.len); + buf.appendAssumeCapacity(plus_or_minus); + buf.appendSliceAssumeCapacity(llvm_name); + buf.appendSliceAssumeCapacity(","); + } + } + if (buf.items.len == 0) break :b ""; + assert(std.mem.endsWith(u8, buf.items, ",")); + buf.items[buf.items.len - 1] = 0; + buf.shrinkAndFree(buf.items.len); + break :b buf.items[0 .. buf.items.len - 1 :0].ptr; + }; + + const builtin_mod = options.builtin_mod orelse b: { + const generated_builtin_source = try Builtin.generate(.{ + .target = target, + .zig_backend = zig_backend, + .output_mode = options.global.output_mode, + .link_mode = options.global.link_mode, + .is_test = options.global.is_test, + .test_evented_io = options.global.test_evented_io, + .single_threaded = single_threaded, + .link_libc = options.global.link_libc, + .link_libcpp = options.global.link_libcpp, + .optimize_mode = optimize_mode, + .error_tracing = error_tracing, + .valgrind = valgrind, + .sanitize_thread = sanitize_thread, + .pic = pic, + .pie = options.global.pie, + .strip = strip, + .code_model = code_model, + .omit_frame_pointer = omit_frame_pointer, + .wasi_exec_model = options.global.wasi_exec_model, + }, arena); + + 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); + new.* = .{ + .root = .{ + .root_dir = options.global_cache_directory, + .sub_path = builtin_sub_path, + }, + .root_src_path = "builtin.zig", + .fully_qualified_name = if (options.parent == null) + "builtin" + else + try std.fmt.allocPrint(arena, "{s}.builtin", .{options.fully_qualified_name}), + .resolved_target = .{ + .result = target, + .is_native_os = resolved_target.is_native_os, + .is_native_abi = resolved_target.is_native_abi, + .llvm_cpu_features = llvm_cpu_features, + }, + .optimize_mode = optimize_mode, + .single_threaded = single_threaded, + .error_tracing = error_tracing, + .valgrind = valgrind, + .pic = pic, + .strip = strip, + .omit_frame_pointer = omit_frame_pointer, + .stack_check = stack_check, + .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 = &.{}, + }; + break :b new; + }; + + const mod = try arena.create(Module); + mod.* = .{ + .root = options.paths.root, + .root_src_path = options.paths.root_src_path, + .fully_qualified_name = options.fully_qualified_name, + .resolved_target = .{ + .result = target, + .is_native_os = resolved_target.is_native_os, + .is_native_abi = resolved_target.is_native_abi, + .llvm_cpu_features = llvm_cpu_features, + }, + .optimize_mode = optimize_mode, + .single_threaded = single_threaded, + .error_tracing = error_tracing, + .valgrind = valgrind, + .pic = pic, + .strip = strip, + .omit_frame_pointer = omit_frame_pointer, + .stack_check = stack_check, + .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, + }; + + try mod.deps.ensureUnusedCapacity(arena, 1); + mod.deps.putAssumeCapacityNoClobber("builtin", builtin_mod); + + return mod; +} + +/// All fields correspond to `CreateOptions`. +pub const LimitedOptions = struct { + root: Package.Path, + root_src_path: []const u8, + fully_qualified_name: []const u8, +}; + +/// This one can only be used if the Module will only be used for AstGen and earlier in +/// the pipeline. Illegal behavior occurs if a limited module touches Sema. +pub fn createLimited(gpa: Allocator, options: LimitedOptions) Allocator.Error!*Package.Module { + const mod = try gpa.create(Module); + mod.* = .{ + .root = options.root, + .root_src_path = options.root_src_path, + .fully_qualified_name = options.fully_qualified_name, + + .resolved_target = undefined, + .optimize_mode = undefined, + .code_model = undefined, + .single_threaded = undefined, + .error_tracing = undefined, + .valgrind = undefined, + .pic = undefined, + .strip = undefined, + .omit_frame_pointer = undefined, + .stack_check = undefined, + .stack_protector = undefined, + .red_zone = undefined, + .sanitize_c = undefined, + .sanitize_thread = undefined, + .unwind_tables = undefined, + .cc_argv = undefined, + .generated_builtin_source = undefined, + }; + return mod; +} + +pub fn getBuiltinDependency(m: *Module) *Module { + return m.deps.values()[0]; } const Module = @This(); @@ -32,3 +424,8 @@ const Package = @import("../Package.zig"); const std = @import("std"); const Allocator = std.mem.Allocator; const MultiHashHexDigest = Package.Manifest.MultiHashHexDigest; +const target_util = @import("../target.zig"); +const Cache = std.Build.Cache; +const Builtin = @import("../Builtin.zig"); +const assert = std.debug.assert; +const Compilation = @import("../Compilation.zig"); -- cgit v1.2.3 From 43720be04af8ddb8334b210ff936a834fb8871a7 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 12 Dec 2023 13:00:13 -0700 Subject: frontend: fix stack protector option logic Commit 97e23896a9168132b6d36ca22ae1af10dd53d80d regressed this behavior because it made target_util.supportsStackProtector *correctly* notice which zig backend is being used to generate code, while the logic calling that function *incorrectly assumed* that .zig code is being compiled, when in reality it might be only C code being compiled. This commit adjusts the option resolution logic for stack protector so that it takes into account the zig backend only if there is a zig compilation unit. A separate piece of logic checks whether clang supports stack protector for a given target. closes #18009 closes #18114 closes #18254 --- src/Compilation/Config.zig | 6 ++++-- src/Package/Module.zig | 13 ++++++++++++- src/main.zig | 4 ++-- src/target.zig | 7 +++++++ 4 files changed, 25 insertions(+), 5 deletions(-) (limited to 'src/Package/Module.zig') diff --git a/src/Compilation/Config.zig b/src/Compilation/Config.zig index fe33a18c0a..33b9bab40b 100644 --- a/src/Compilation/Config.zig +++ b/src/Compilation/Config.zig @@ -31,6 +31,7 @@ shared_memory: bool, is_test: bool, test_evented_io: bool, entry: ?[]const u8, +any_c_source_files: bool, pub const CFrontend = enum { clang, aro }; @@ -48,7 +49,7 @@ pub const Options = struct { any_sanitize_thread: bool = false, any_unwind_tables: bool = false, any_dyn_libs: bool = false, - c_source_files_len: usize = 0, + any_c_source_files: bool = false, emit_llvm_ir: bool = false, emit_llvm_bc: bool = false, link_libc: ?bool = null, @@ -231,7 +232,7 @@ pub fn resolve(options: Options) !Config { } if (options.lto) |x| break :b x; - if (options.c_source_files_len == 0) break :b false; + if (!options.any_c_source_files) break :b false; if (target.cpu.arch.isRISCV()) { // Clang and LLVM currently don't support RISC-V target-abi for LTO. @@ -384,6 +385,7 @@ pub fn resolve(options: Options) !Config { .use_lld = use_lld, .entry = entry, .wasi_exec_model = wasi_exec_model, + .any_c_source_files = options.any_c_source_files, }; } diff --git a/src/Package/Module.zig b/src/Package/Module.zig index 94431856ac..f1e7091855 100644 --- a/src/Package/Module.zig +++ b/src/Package/Module.zig @@ -229,7 +229,18 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module { }; const stack_protector: u32 = sp: { - if (!target_util.supportsStackProtector(target, zig_backend)) { + const use_zig_backend = options.global.have_zcu or + (options.global.any_c_source_files and options.global.c_frontend == .aro); + if (use_zig_backend and !target_util.supportsStackProtector(target, zig_backend)) { + if (options.inherited.stack_protector) |x| { + if (x > 0) return error.StackProtectorUnsupportedByTarget; + } + break :sp 0; + } + + if (options.global.any_c_source_files and options.global.c_frontend == .clang and + !target_util.clangSupportsStackProtector(target)) + { if (options.inherited.stack_protector) |x| { if (x > 0) return error.StackProtectorUnsupportedByTarget; } diff --git a/src/main.zig b/src/main.zig index 4f701398ca..61b9b6ff56 100644 --- a/src/main.zig +++ b/src/main.zig @@ -949,7 +949,7 @@ fn buildOutputType( // Populated just before the call to `createModule`. .emit_bin = undefined, // Populated just before the call to `createModule`. - .c_source_files_len = undefined, + .any_c_source_files = undefined, }, // Populated in the call to `createModule` for the root module. .resolved_options = undefined, @@ -2635,7 +2635,7 @@ fn buildOutputType( create_module.opts.emit_llvm_ir = emit_llvm_ir != .no; create_module.opts.emit_llvm_bc = emit_llvm_bc != .no; create_module.opts.emit_bin = emit_bin != .no; - create_module.opts.c_source_files_len = create_module.c_source_files.items.len; + create_module.opts.any_c_source_files = create_module.c_source_files.items.len != 0; const main_mod = try createModule(gpa, arena, &create_module, 0, null, zig_lib_directory); for (create_module.modules.keys(), create_module.modules.values()) |key, cli_mod| { diff --git a/src/target.zig b/src/target.zig index 04c25a5f0c..68777945a9 100644 --- a/src/target.zig +++ b/src/target.zig @@ -360,6 +360,13 @@ pub fn supportsStackProtector(target: std.Target, backend: std.builtin.CompilerB }; } +pub fn clangSupportsStackProtector(target: std.Target) bool { + return switch (target.cpu.arch) { + .spirv32, .spirv64 => return false, + else => true, + }; +} + pub fn libcProvidesStackProtector(target: std.Target) bool { return !target.isMinGW() and target.os.tag != .wasi and !target.isSpirV(); } -- cgit v1.2.3 From 33cdf33b95676dca9f91216e0f8742f9cf7e84fb Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 13 Dec 2023 18:28:00 -0700 Subject: compiler: update many references to bin_file.options --- src/Compilation.zig | 370 +++++++++++++++++++++------------------ src/Package/Module.zig | 17 ++ src/codegen/llvm.zig | 2 +- src/codegen/spirv.zig | 12 +- src/link.zig | 19 +- src/link/Coff.zig | 24 ++- src/link/Elf.zig | 60 ++++++- src/link/MachO/load_commands.zig | 2 +- src/link/MachO/zld.zig | 2 +- src/link/SpirV.zig | 2 + src/main.zig | 40 ++--- 11 files changed, 319 insertions(+), 231 deletions(-) (limited to 'src/Package/Module.zig') diff --git a/src/Compilation.zig b/src/Compilation.zig index be9fb2a989..5f99c85ba0 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -77,6 +77,7 @@ system_libs: std.StringArrayHashMapUnmanaged(SystemLib), version: ?std.SemanticVersion, libc_installation: ?*const LibCInstallation, skip_linker_dependencies: bool, +no_builtin: bool, c_object_table: std.AutoArrayHashMapUnmanaged(*CObject, void) = .{}, win32_resource_table: if (build_options.only_core_functionality) void else std.AutoArrayHashMapUnmanaged(*Win32Resource, void) = @@ -988,10 +989,9 @@ pub const InitOptions = struct { linker_tsaware: bool = false, linker_nxcompat: bool = false, linker_dynamicbase: bool = true, - linker_optimization: ?u8 = null, - linker_compress_debug_sections: ?link.CompressDebugSections = null, + linker_compress_debug_sections: ?link.File.Elf.CompressDebugSections = null, linker_module_definition_file: ?[]const u8 = null, - linker_sort_section: ?link.SortSection = null, + linker_sort_section: ?link.File.Elf.SortSection = null, major_subsystem_version: ?u32 = null, minor_subsystem_version: ?u32 = null, clang_passthrough_mode: bool = false, @@ -1011,7 +1011,7 @@ pub const InitOptions = struct { /// building such dependencies themselves, this flag must be set to avoid /// infinite recursion. skip_linker_dependencies: bool = false, - hash_style: link.HashStyle = .both, + hash_style: link.File.Elf.HashStyle = .both, entry: ?[]const u8 = null, force_undefined_symbols: std.StringArrayHashMapUnmanaged(void) = .{}, stack_size: ?u64 = null, @@ -1049,8 +1049,6 @@ pub const InitOptions = struct { /// (Windows) PDB output path pdb_out_path: ?[]const u8 = null, error_limit: ?Compilation.Module.ErrorInt = null, - /// (SPIR-V) whether to generate a structured control flow graph or not - want_structured_cfg: ?bool = null, }; fn addModuleTableToCacheHash( @@ -1277,10 +1275,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { } } - const linker_optimization: u8 = options.linker_optimization orelse switch (options.root_mod.optimize_mode) { - .Debug => @as(u8, 0), - else => @as(u8, 3), - }; // TODO: https://github.com/ziglang/zig/issues/17969 const formatted_panics = options.formatted_panics orelse (options.root_mod.optimize_mode == .Debug); @@ -1359,7 +1353,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { hash.add(formatted_panics); hash.add(options.emit_h != null); hash.add(error_limit); - hash.addOptional(options.want_structured_cfg); // In the case of incremental cache mode, this `zig_cache_artifact_directory` // is computed based on a hash of non-linker inputs, and it is where all @@ -1641,13 +1634,13 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .framework_dirs = options.framework_dirs, .llvm_opt_bisect_limit = options.llvm_opt_bisect_limit, .skip_linker_dependencies = options.skip_linker_dependencies, + .no_builtin = options.no_builtin, }; if (bin_file_emit) |emit| { comp.bin_file = try link.File.open(arena, .{ .comp = comp, .emit = emit, - .optimization = linker_optimization, .linker_script = options.linker_script, .z_nodelete = options.linker_z_nodelete, .z_notext = options.linker_z_notext, @@ -1666,7 +1659,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .symbol_wrap_set = options.symbol_wrap_set, .function_sections = options.function_sections, .data_sections = options.data_sections, - .no_builtin = options.no_builtin, .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, @@ -1713,7 +1705,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .force_undefined_symbols = options.force_undefined_symbols, .pdb_source_path = options.pdb_source_path, .pdb_out_path = options.pdb_out_path, - .want_structured_cfg = options.want_structured_cfg, .entry_addr = null, // CLI does not expose this option (yet?) }); } @@ -2076,7 +2067,7 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void }; if (is_hit) { comp.last_update_was_cache_hit = true; - log.debug("CacheMode.whole cache hit for {s}", .{comp.bin_file.options.root_name}); + log.debug("CacheMode.whole cache hit for {s}", .{comp.root_name}); const digest = man.final(); comp.wholeCacheModeSetBinFilePath(&digest); @@ -2085,7 +2076,7 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void comp.bin_file.lock = man.toOwnedLock(); return; } - log.debug("CacheMode.whole cache miss for {s}", .{comp.bin_file.options.root_name}); + log.debug("CacheMode.whole cache miss for {s}", .{comp.root_name}); // Initialize `bin_file.emit` with a temporary Directory so that compilation can // continue on the same path as incremental, using the temporary Directory. @@ -2169,7 +2160,7 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void // import_table here. // Likewise, in the case of `zig test`, the test runner is the root source file, // and so there is nothing to import the main file. - if (comp.bin_file.options.is_test) { + if (comp.config.is_test) { _ = try module.importPkg(module.main_mod); } @@ -2194,7 +2185,7 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void } try comp.work_queue.writeItem(.{ .analyze_mod = std_mod }); - if (comp.bin_file.options.is_test) { + if (comp.config.is_test) { try comp.work_queue.writeItem(.{ .analyze_mod = module.main_mod }); } @@ -2208,20 +2199,20 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void if (comp.module) |module| { if (builtin.mode == .Debug and comp.verbose_intern_pool) { std.debug.print("intern pool stats for '{s}':\n", .{ - comp.bin_file.options.root_name, + comp.root_name, }); module.intern_pool.dump(); } if (builtin.mode == .Debug and comp.verbose_generic_instances) { std.debug.print("generic instances for '{s}:0x{x}':\n", .{ - comp.bin_file.options.root_name, + comp.root_name, @as(usize, @intFromPtr(module)), }); module.intern_pool.dumpGenericInstances(comp.gpa); } - if (comp.bin_file.options.is_test and comp.totalErrorCount() == 0) { + if (comp.config.is_test and comp.totalErrorCount() == 0) { // The `test_functions` decl has been intentionally postponed until now, // at which point we must populate it with the list of test functions that // have been discovered and not filtered out. @@ -2336,7 +2327,7 @@ fn maybeGenerateAutodocs(comp: *Compilation, prog_node: *std.Progress.Node) !voi // file copies at the end of generate() can also be extracted to // separate jobs if (!build_options.only_c and !build_options.only_core_functionality) { - if (comp.bin_file.options.docs_emit) |emit| { + if (comp.docs_emit) |emit| { var dir = try emit.directory.handle.makeOpenPath(emit.sub_path, .{}); defer dir.close(); @@ -2426,24 +2417,16 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes try addModuleTableToCacheHash(gpa, arena, &man.hash, mod.main_mod, .{ .files = man }); // Synchronize with other matching comments: ZigOnlyHashStuff - man.hash.add(comp.config.use_llvm); - man.hash.add(comp.config.use_lib_llvm); - man.hash.add(comp.bin_file.options.dll_export_fns); - man.hash.add(comp.bin_file.options.is_test); - man.hash.add(comp.test_evented_io); + man.hash.add(comp.config.test_evented_io); man.hash.addOptionalBytes(comp.test_filter); man.hash.addOptionalBytes(comp.test_name_prefix); man.hash.add(comp.skip_linker_dependencies); man.hash.add(comp.formatted_panics); man.hash.add(mod.emit_h != null); man.hash.add(mod.error_limit); - man.hash.add(comp.bin_file.options.want_structured_cfg); } - try man.addOptionalFile(comp.bin_file.options.linker_script); - try man.addOptionalFile(comp.bin_file.options.version_script); - - for (comp.bin_file.options.objects) |obj| { + for (comp.objects) |obj| { _ = try man.addFile(obj.path, null); man.hash.add(obj.must_link); man.hash.add(obj.loption); @@ -2469,39 +2452,19 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes } } + man.hash.addOptionalBytes(comp.sysroot); + man.hash.addOptional(comp.version); man.hash.addListOfBytes(comp.rc_include_dir_list); cache_helpers.addOptionalEmitLoc(&man.hash, comp.emit_asm); cache_helpers.addOptionalEmitLoc(&man.hash, comp.emit_llvm_ir); cache_helpers.addOptionalEmitLoc(&man.hash, comp.emit_llvm_bc); - man.hash.add(comp.bin_file.stack_size); - man.hash.add(comp.bin_file.options.gc_sections); - man.hash.add(comp.bin_file.options.eh_frame_hdr); - man.hash.add(comp.bin_file.options.emit_relocs); - man.hash.add(comp.bin_file.options.rdynamic); - man.hash.addListOfBytes(comp.bin_file.options.lib_dirs); - man.hash.addListOfBytes(comp.bin_file.options.rpath_list); - man.hash.addListOfBytes(comp.bin_file.options.symbol_wrap_set.keys()); - man.hash.add(comp.bin_file.options.each_lib_rpath); - man.hash.add(comp.bin_file.build_id); man.hash.add(comp.skip_linker_dependencies); - man.hash.add(comp.bin_file.options.z_nodelete); - man.hash.add(comp.bin_file.options.z_notext); - man.hash.add(comp.bin_file.options.z_defs); - man.hash.add(comp.bin_file.options.z_origin); - man.hash.add(comp.bin_file.options.z_nocopyreloc); - man.hash.add(comp.bin_file.options.z_now); - man.hash.add(comp.bin_file.options.z_relro); - man.hash.add(comp.bin_file.options.z_common_page_size orelse 0); - man.hash.add(comp.bin_file.options.z_max_page_size orelse 0); - man.hash.add(comp.bin_file.options.hash_style); - man.hash.add(comp.bin_file.options.compress_debug_sections); man.hash.add(comp.include_compiler_rt); - man.hash.add(comp.bin_file.options.sort_section); if (comp.config.link_libc) { - man.hash.add(comp.bin_file.options.libc_installation != null); - if (comp.bin_file.options.libc_installation) |libc_installation| { + man.hash.add(comp.libc_installation != null); + if (comp.libc_installation) |libc_installation| { man.hash.addOptionalBytes(libc_installation.crt_dir); if (target.abi == .msvc) { man.hash.addOptionalBytes(libc_installation.msvc_lib_dir); @@ -2510,55 +2473,93 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes } man.hash.addOptionalBytes(target.dynamic_linker.get()); } - man.hash.addOptionalBytes(comp.bin_file.options.soname); - man.hash.add(comp.bin_file.options.version); try link.hashAddSystemLibs(man, comp.system_libs); - man.hash.addListOfBytes(comp.bin_file.options.force_undefined_symbols.keys()); - man.hash.add(comp.bin_file.allow_shlib_undefined); - man.hash.add(comp.bin_file.options.bind_global_refs_locally); - man.hash.add(comp.bin_file.options.tsan); - man.hash.addOptionalBytes(comp.bin_file.options.sysroot); - man.hash.add(comp.bin_file.options.linker_optimization); - - switch (comp.bin_file.tag) { - .elf => { - const elf = comp.bin_file.cast(link.File.Elf).?; - man.hash.add(elf.image_base); - }, - .wasm => { - const wasm = comp.bin_file.cast(link.File.Wasm).?; - man.hash.add(comp.config.import_memory); - man.hash.add(comp.config.export_memory); - man.hash.add(comp.config.shared_memory); - man.hash.add(wasm.initial_memory); - man.hash.add(wasm.max_memory); - man.hash.add(wasm.global_base); - }, - .macho => { - const macho = comp.bin_file.cast(link.File.MachO).?; - man.hash.addListOfBytes(comp.framework_dirs); - try link.hashAddFrameworks(man, macho.frameworks); - try man.addOptionalFile(macho.entitlements); - man.hash.add(macho.pagezero_size); - man.hash.add(macho.headerpad_size); - man.hash.add(macho.headerpad_max_install_names); - man.hash.add(macho.dead_strip_dylibs); - }, - .coff => { - const coff = comp.bin_file.cast(link.File.Coff).?; - man.hash.add(coff.image_base); - man.hash.add(coff.subsystem); - man.hash.add(coff.tsaware); - man.hash.add(coff.nxcompat); - man.hash.add(coff.dynamicbase); - man.hash.add(coff.major_subsystem_version); - man.hash.add(coff.minor_subsystem_version); - }, + + man.hash.add(comp.config.use_llvm); + man.hash.add(comp.config.use_lib_llvm); + man.hash.add(comp.config.is_test); + man.hash.add(comp.config.import_memory); + man.hash.add(comp.config.export_memory); + man.hash.add(comp.config.shared_memory); + + if (comp.bin_file) |lf| { + man.hash.add(lf.stack_size); + man.hash.add(lf.gc_sections); + man.hash.addListOfBytes(lf.rpath_list); + man.hash.add(lf.build_id); + man.hash.addListOfBytes(lf.force_undefined_symbols.keys()); + man.hash.add(lf.allow_shlib_undefined); + + switch (lf.tag) { + .elf => { + const elf = lf.cast(link.File.Elf).?; + man.hash.add(elf.rdynamic); + man.hash.add(elf.eh_frame_hdr); + man.hash.add(elf.image_base); + man.hash.add(elf.emit_relocs); + man.hash.add(elf.z_nodelete); + man.hash.add(elf.z_notext); + man.hash.add(elf.z_defs); + man.hash.add(elf.z_origin); + man.hash.add(elf.z_nocopyreloc); + man.hash.add(elf.z_now); + man.hash.add(elf.z_relro); + man.hash.add(elf.z_common_page_size orelse 0); + man.hash.add(elf.z_max_page_size orelse 0); + man.hash.addListOfBytes(elf.lib_dirs); + man.hash.add(elf.hash_style); + man.hash.add(elf.compress_debug_sections); + man.hash.addListOfBytes(elf.symbol_wrap_set.keys()); + man.hash.add(elf.each_lib_rpath); + man.hash.addOptional(elf.sort_section); + man.hash.addOptionalBytes(elf.soname); + man.hash.add(elf.bind_global_refs_locally); + try man.addOptionalFile(elf.linker_script); + try man.addOptionalFile(elf.version_script); + }, + .wasm => { + const wasm = lf.cast(link.File.Wasm).?; + man.hash.add(wasm.rdynamic); + man.hash.add(wasm.initial_memory); + man.hash.add(wasm.max_memory); + man.hash.add(wasm.global_base); + }, + .macho => { + const macho = lf.cast(link.File.MachO).?; + man.hash.addListOfBytes(comp.framework_dirs); + try link.File.MachO.hashAddFrameworks(man, macho.frameworks); + try man.addOptionalFile(macho.entitlements); + man.hash.add(macho.pagezero_vmsize); + man.hash.add(macho.headerpad_size); + man.hash.add(macho.headerpad_max_install_names); + man.hash.add(macho.dead_strip_dylibs); + }, + .coff => { + const coff = lf.cast(link.File.Coff).?; + man.hash.add(coff.dll_export_fns); + man.hash.add(coff.image_base); + man.hash.addOptional(coff.subsystem); + man.hash.add(coff.tsaware); + man.hash.add(coff.nxcompat); + man.hash.add(coff.dynamicbase); + man.hash.add(coff.major_subsystem_version); + man.hash.add(coff.minor_subsystem_version); + man.hash.addListOfBytes(coff.lib_dirs); + }, + .spirv => { + const spirv = lf.cast(link.File.SpirV).?; + _ = spirv; + // TODO + }, + .c => {}, // TODO + .plan9 => {}, // TODO + .nvptx => {}, // TODO + } } } fn emitOthers(comp: *Compilation) void { - if (comp.bin_file.options.output_mode != .Obj or comp.module != null or + if (comp.config.output_mode != .Obj or comp.module != null or comp.c_object_table.count() == 0) { return; @@ -2724,10 +2725,10 @@ pub fn saveState(comp: *Compilation) !void { var bufs_list: [6]std.os.iovec_const = undefined; var bufs_len: usize = 0; - const emit = comp.bin_file.options.emit orelse return; + const lf = comp.bin_file orelse return; - if (comp.module) |mod| { - const ip = &mod.intern_pool; + if (comp.module) |zcu| { + const ip = &zcu.intern_pool; const header: Header = .{ .intern_pool = .{ .items_len = @intCast(ip.items.len), @@ -2751,7 +2752,7 @@ pub fn saveState(comp: *Compilation) !void { } var basename_buf: [255]u8 = undefined; const basename = std.fmt.bufPrint(&basename_buf, "{s}.zcs", .{ - comp.bin_file.options.root_name, + comp.root_name, }) catch o: { basename_buf[basename_buf.len - 4 ..].* = ".zcs".*; break :o &basename_buf; @@ -2759,7 +2760,7 @@ pub fn saveState(comp: *Compilation) !void { // Using an atomic file prevents a crash or power failure from corrupting // the previous incremental compilation state. - var af = try emit.directory.handle.atomicFile(basename, .{}); + var af = try lf.emit.directory.handle.atomicFile(basename, .{}); defer af.deinit(); try af.file.pwritevAll(bufs_list[0..bufs_len], 0); try af.finish(); @@ -3507,7 +3508,7 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v error.AnalysisFail => return, }; const decl = module.declPtr(decl_index); - if (decl.kind == .@"test" and comp.bin_file.options.is_test) { + if (decl.kind == .@"test" and comp.config.is_test) { // Tests are always emitted in test binaries. The decl_refs are created by // Module.populateTestFunctions, but this will not queue body analysis, so do // that now. @@ -3850,7 +3851,7 @@ pub fn obtainCObjectCacheManifest(comp: *const Compilation) Cache.Manifest { // based on the zig library directory alone. The zig lib directory file // path is purposefully either in the cache or not in the cache. The // decision should not be overridden here. - if (comp.bin_file.options.libc_installation != null) { + if (comp.libc_installation != null) { man.hash.addListOfBytes(comp.libc_include_dir_list); } @@ -4248,9 +4249,9 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P // file and building an object we need to link them together, but with just one it should go // directly to the output file. const direct_o = comp.c_source_files.len == 1 and comp.module == null and - comp.bin_file.options.output_mode == .Obj and comp.bin_file.options.objects.len == 0; + comp.config.output_mode == .Obj and comp.objects.len == 0; const o_basename_noext = if (direct_o) - comp.bin_file.options.root_name + comp.root_name else c_source_basename[0 .. c_source_basename.len - std.fs.path.extension(c_source_basename).len]; @@ -4304,8 +4305,8 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P try argv.appendSlice(c_object.src.extra_flags); try argv.appendSlice(c_object.src.cache_exempt_flags); - const out_obj_path = if (comp.bin_file.options.emit) |emit| - try emit.directory.join(arena, &.{emit.sub_path}) + const out_obj_path = if (comp.bin_file) |lf| + try lf.emit.directory.join(arena, &.{lf.emit.sub_path}) else "/dev/null"; @@ -4883,8 +4884,9 @@ pub fn addCCArgs( argv: *std.ArrayList([]const u8), ext: FileExt, out_dep_path: ?[]const u8, + mod: *Package.Module, ) !void { - const target = comp.getTarget(); + const target = mod.resolved_target.result; // As of Clang 16.x, it will by default read extra flags from /etc/clang. // I'm sure the person who implemented this means well, but they have a lot @@ -4905,15 +4907,15 @@ pub fn addCCArgs( try argv.append("-fno-caret-diagnostics"); } - if (comp.bin_file.options.function_sections) { + if (comp.bin_file.function_sections) { try argv.append("-ffunction-sections"); } - if (comp.bin_file.options.data_sections) { + if (comp.bin_file.data_sections) { try argv.append("-fdata-sections"); } - if (comp.bin_file.options.no_builtin) { + if (comp.no_builtin) { try argv.append("-fno-builtin"); } @@ -4953,7 +4955,7 @@ pub fn addCCArgs( })); } - if (comp.bin_file.options.link_libunwind) { + if (comp.config.link_libunwind) { const libunwind_include_path = try std.fs.path.join(arena, &[_][]const u8{ comp.zig_lib_directory.path.?, "libunwind", "include", }); @@ -4987,7 +4989,7 @@ pub fn addCCArgs( "-nostdinc", "-fno-spell-checking", }); - if (comp.bin_file.options.lto) { + if (comp.config.lto) { try argv.append("-flto"); } @@ -5042,9 +5044,8 @@ pub fn addCCArgs( argv.appendAssumeCapacity(arg); } } - const code_model = comp.bin_file.options.machine_code_model; - if (code_model != .default) { - try argv.append(try std.fmt.allocPrint(arena, "-mcmodel={s}", .{@tagName(code_model)})); + if (mod.code_model != .default) { + try argv.append(try std.fmt.allocPrint(arena, "-mcmodel={s}", .{@tagName(mod.code_model)})); } switch (target.os.tag) { @@ -5093,7 +5094,7 @@ pub fn addCCArgs( try argv.append("-mthumb"); } - if (comp.sanitize_c and !comp.bin_file.options.tsan) { + if (mod.sanitize_c and !mod.sanitize_thread) { try argv.append("-fsanitize=undefined"); try argv.append("-fsanitize-trap=undefined"); // It is very common, and well-defined, for a pointer on one side of a C ABI @@ -5104,27 +5105,27 @@ pub fn addCCArgs( // Without this flag, Clang would invoke UBSAN when such an extern // function was called. try argv.append("-fno-sanitize=function"); - } else if (comp.sanitize_c and comp.bin_file.options.tsan) { + } else if (mod.sanitize_c and mod.sanitize_thread) { try argv.append("-fsanitize=undefined,thread"); try argv.append("-fsanitize-trap=undefined"); try argv.append("-fno-sanitize=function"); - } else if (!comp.sanitize_c and comp.bin_file.options.tsan) { + } else if (!mod.sanitize_c and mod.sanitize_thread) { try argv.append("-fsanitize=thread"); } - if (comp.bin_file.options.red_zone) { + if (mod.red_zone) { try argv.append("-mred-zone"); } else if (target_util.hasRedZone(target)) { try argv.append("-mno-red-zone"); } - if (comp.bin_file.options.omit_frame_pointer) { + if (mod.omit_frame_pointer) { try argv.append("-fomit-frame-pointer"); } else { try argv.append("-fno-omit-frame-pointer"); } - const ssp_buf_size = comp.bin_file.options.stack_protector; + const ssp_buf_size = mod.stack_protector; if (ssp_buf_size != 0) { try argv.appendSlice(&[_][]const u8{ "-fstack-protector-strong", @@ -5135,7 +5136,7 @@ pub fn addCCArgs( try argv.append("-fno-stack-protector"); } - switch (comp.bin_file.options.optimize_mode) { + switch (mod.optimize_mode) { .Debug => { // windows c runtime requires -D_DEBUG if using debug libraries try argv.append("-D_DEBUG"); @@ -5165,7 +5166,7 @@ pub fn addCCArgs( }, } - if (target_util.supports_fpic(target) and comp.bin_file.options.pic) { + if (target_util.supports_fpic(target) and mod.pic) { try argv.append("-fPIC"); } @@ -5940,7 +5941,7 @@ pub fn get_libc_crt_file(comp: *Compilation, arena: Allocator, basename: []const { return comp.crt_files.get(basename).?.full_object_path; } - const lci = comp.bin_file.options.libc_installation orelse return error.LibCInstallationNotAvailable; + const lci = comp.libc_installation orelse return error.LibCInstallationNotAvailable; const crt_dir_path = lci.crt_dir orelse return error.LibCInstallationMissingCRTDir; const full_path = try std.fs.path.join(arena, &[_][]const u8{ crt_dir_path, basename }); return full_path; @@ -6112,7 +6113,7 @@ fn canBuildZigLibC(target: std.Target, use_llvm: bool) bool { pub fn getZigBackend(comp: Compilation) std.builtin.CompilerBackend { const target = comp.root_mod.resolved_target.result; - return target_util.zigBackend(target, comp.bin_file.options.use_llvm); + return target_util.zigBackend(target, comp.config.use_llvm); } pub fn updateSubCompilation( @@ -6165,6 +6166,9 @@ fn buildOutputFromZig( assert(output_mode != .Exe); + const lf = comp.bin_file.?; + const unwind_tables = if (lf.cast(link.File.Elf)) |elf| elf.eh_frame_hdr else false; + const config = try Config.resolve(.{ .output_mode = output_mode, .resolved_target = comp.root_mod.resolved_target, @@ -6173,6 +6177,7 @@ fn buildOutputFromZig( .emit_bin = true, .root_optimize_mode = comp.compilerRtOptMode(), .link_libc = comp.config.link_libc, + .any_unwind_tables = unwind_tables, }); const root_mod = Package.Module.create(.{ @@ -6187,9 +6192,10 @@ fn buildOutputFromZig( .stack_protector = 0, .red_zone = comp.root_mod.red_zone, .omit_frame_pointer = comp.root_mod.omit_frame_pointer, - .unwind_tables = comp.bin_file.options.eh_frame_hdr, + .unwind_tables = unwind_tables, .pic = comp.root_mod.pic, .optimize_mode = comp.compilerRtOptMode(), + .structured_cfg = comp.root_mod.structured_cfg, }, .global = config, .cc_argv = &.{}, @@ -6210,21 +6216,21 @@ fn buildOutputFromZig( .global_cache_directory = comp.global_cache_directory, .local_cache_directory = comp.global_cache_directory, .zig_lib_directory = comp.zig_lib_directory, + .self_exe_path = comp.self_exe_path, .resolved = config, .root_mod = root_mod, .cache_mode = .whole, .root_name = root_name, .thread_pool = comp.thread_pool, - .libc_installation = comp.bin_file.options.libc_installation, + .libc_installation = comp.libc_installation, .emit_bin = emit_bin, .link_mode = .Static, .function_sections = true, .data_sections = true, .no_builtin = true, .emit_h = null, - .self_exe_path = comp.self_exe_path, .verbose_cc = comp.verbose_cc, - .verbose_link = comp.bin_file.options.verbose_link, + .verbose_link = comp.verbose_link, .verbose_air = comp.verbose_air, .verbose_intern_pool = comp.verbose_intern_pool, .verbose_generic_instances = comp.verbose_intern_pool, @@ -6234,7 +6240,6 @@ fn buildOutputFromZig( .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, .clang_passthrough_mode = comp.clang_passthrough_mode, .skip_linker_dependencies = true, - .want_structured_cfg = comp.bin_file.options.want_structured_cfg, }); defer sub_compilation.destroy(); @@ -6242,8 +6247,8 @@ fn buildOutputFromZig( assert(out.* == null); out.* = Compilation.CRTFile{ - .full_object_path = try sub_compilation.bin_file.options.emit.?.directory.join(comp.gpa, &[_][]const u8{ - sub_compilation.bin_file.options.emit.?.sub_path, + .full_object_path = try sub_compilation.bin_file.?.emit.directory.join(comp.gpa, &[_][]const u8{ + sub_compilation.bin_file.?.emit.sub_path, }), .lock = sub_compilation.bin_file.toOwnedLock(), }; @@ -6260,51 +6265,70 @@ pub fn build_crt_file( const tracy_trace = trace(@src()); defer tracy_trace.end(); - const target = comp.getTarget(); - const basename = try std.zig.binNameAlloc(comp.gpa, .{ + const gpa = comp.gpa; + const basename = try std.zig.binNameAlloc(gpa, .{ .root_name = root_name, - .target = target, + .target = comp.root_mod.resolved_target.result, .output_mode = output_mode, }); - errdefer comp.gpa.free(basename); + errdefer gpa.free(basename); - const sub_compilation = try Compilation.create(comp.gpa, .{ + const config = try Config.resolve(.{ + .output_mode = output_mode, + .resolved_target = comp.root_mod.resolved_target, + .is_test = false, + .have_zcu = false, + .emit_bin = true, + .root_optimize_mode = comp.compilerRtOptMode(), + .link_libc = false, + .lto = switch (output_mode) { + .Lib => comp.config.lto, + .Obj, .Exe => false, + }, + }); + const root_mod = Package.Module.create(.{ + .paths = .{ + .root = .{ .root_dir = comp.zig_lib_directory }, + .root_src_path = "", + }, + .fully_qualified_name = "root", + .inherited = .{ + .strip = comp.compilerRtStrip(), + .stack_check = false, + .stack_protector = 0, + .sanitize_c = false, + .sanitize_thread = false, + .red_zone = comp.root_mod.red_zone, + .omit_frame_pointer = comp.root_mod.omit_frame_pointer, + .valgrind = false, + .unwind_tables = false, + .pic = comp.root_mod.pic, + .optimize_mode = comp.compilerRtOptMode(), + .structured_cfg = comp.root_mod.structured_cfg, + }, + .global = config, + .cc_argv = &.{}, + }); + + const sub_compilation = try Compilation.create(gpa, .{ .local_cache_directory = comp.global_cache_directory, .global_cache_directory = comp.global_cache_directory, .zig_lib_directory = comp.zig_lib_directory, + .self_exe_path = comp.self_exe_path, .cache_mode = .whole, - .target = target, + .resolved = config, + .root_mod = root_mod, .root_name = root_name, - .main_mod = null, - .output_mode = output_mode, .thread_pool = comp.thread_pool, - .libc_installation = comp.bin_file.options.libc_installation, + .libc_installation = comp.libc_installation, .emit_bin = .{ .directory = null, // Put it in the cache directory. .basename = basename, }, - .optimize_mode = comp.compilerRtOptMode(), - .want_sanitize_c = false, - .want_stack_check = false, - .want_stack_protector = 0, - .want_red_zone = comp.bin_file.options.red_zone, - .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer, - .want_valgrind = false, - .want_tsan = false, - .want_pic = comp.bin_file.options.pic, - .want_pie = null, - .want_lto = switch (output_mode) { - .Lib => comp.bin_file.options.lto, - .Obj, .Exe => false, - }, .emit_h = null, - .strip = comp.compilerRtStrip(), - .is_native_os = comp.bin_file.options.is_native_os, - .is_native_abi = comp.bin_file.options.is_native_abi, - .self_exe_path = comp.self_exe_path, .c_source_files = c_source_files, .verbose_cc = comp.verbose_cc, - .verbose_link = comp.bin_file.options.verbose_link, + .verbose_link = comp.verbose_link, .verbose_air = comp.verbose_air, .verbose_intern_pool = comp.verbose_intern_pool, .verbose_generic_instances = comp.verbose_generic_instances, @@ -6314,17 +6338,16 @@ pub fn build_crt_file( .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, .clang_passthrough_mode = comp.clang_passthrough_mode, .skip_linker_dependencies = true, - .want_structured_cfg = comp.bin_file.options.want_structured_cfg, }); defer sub_compilation.destroy(); try comp.updateSubCompilation(sub_compilation, misc_task_tag, prog_node); - try comp.crt_files.ensureUnusedCapacity(comp.gpa, 1); + try comp.crt_files.ensureUnusedCapacity(gpa, 1); comp.crt_files.putAssumeCapacityNoClobber(basename, .{ - .full_object_path = try sub_compilation.bin_file.options.emit.?.directory.join(comp.gpa, &[_][]const u8{ - sub_compilation.bin_file.options.emit.?.sub_path, + .full_object_path = try sub_compilation.bin_file.?.emit.directory.join(gpa, &[_][]const u8{ + sub_compilation.bin_file.?.emit.sub_path, }), .lock = sub_compilation.bin_file.toOwnedLock(), }); @@ -6357,10 +6380,11 @@ pub fn addLinkLib(comp: *Compilation, lib_name: []const u8) !void { /// compiler-rt, libcxx, libc, libunwind, etc. pub fn compilerRtOptMode(comp: Compilation) std.builtin.OptimizeMode { if (comp.debug_compiler_runtime_libs) { - return comp.bin_file.options.optimize_mode; + return comp.root_mod.optimize_mode; } - switch (comp.bin_file.options.optimize_mode) { - .Debug, .ReleaseSafe => return target_util.defaultCompilerRtOptimizeMode(comp.getTarget()), + const target = comp.root_mod.resolved_target.result; + switch (comp.root_mod.optimize_mode) { + .Debug, .ReleaseSafe => return target_util.defaultCompilerRtOptimizeMode(target), .ReleaseFast => return .ReleaseFast, .ReleaseSmall => return .ReleaseSmall, } @@ -6369,5 +6393,5 @@ pub fn compilerRtOptMode(comp: Compilation) std.builtin.OptimizeMode { /// This decides whether to strip debug info for all zig-provided libraries, including /// compiler-rt, libcxx, libc, libunwind, etc. pub fn compilerRtStrip(comp: Compilation) bool { - return comp.bin_file.options.strip; + return comp.root_mod.strip; } diff --git a/src/Package/Module.zig b/src/Package/Module.zig index f1e7091855..0916742876 100644 --- a/src/Package/Module.zig +++ b/src/Package/Module.zig @@ -30,6 +30,8 @@ sanitize_c: bool, sanitize_thread: bool, unwind_tables: bool, 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, @@ -82,6 +84,7 @@ pub const CreateOptions = struct { unwind_tables: ?bool = null, sanitize_c: ?bool = null, sanitize_thread: ?bool = null, + structured_cfg: ?bool = null, }; }; @@ -268,6 +271,17 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module { break :sp target_util.default_stack_protector_buffer_size; }; + const structured_cfg = b: { + if (options.inherited.structured_cfg) |x| break :b x; + if (options.parent) |p| break :b p.structured_cfg; + // We always want a structured control flow in shaders. This option is + // only relevant for OpenCL kernels. + break :b switch (target.os.tag) { + .opencl => false, + else => true, + }; + }; + const llvm_cpu_features: ?[*:0]const u8 = b: { if (resolved_target.llvm_cpu_features) |x| break :b x; if (!options.global.use_llvm) break :b null; @@ -350,6 +364,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module { .sanitize_thread = sanitize_thread, .unwind_tables = unwind_tables, .cc_argv = &.{}, + .structured_cfg = structured_cfg, }; break :b new; }; @@ -381,6 +396,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module { .sanitize_thread = sanitize_thread, .unwind_tables = unwind_tables, .cc_argv = options.cc_argv, + .structured_cfg = structured_cfg, }; try mod.deps.ensureUnusedCapacity(arena, 1); @@ -422,6 +438,7 @@ pub fn createLimited(gpa: Allocator, options: LimitedOptions) Allocator.Error!*P .unwind_tables = undefined, .cc_argv = undefined, .generated_builtin_source = undefined, + .structured_cfg = undefined, }; return mod; } diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index beb3e5e9f6..ee9e3de086 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -3084,7 +3084,7 @@ pub const Object = struct { if (comp.unwind_tables) { try attributes.addFnAttr(.{ .uwtable = Builder.Attribute.UwTable.default }, &o.builder); } - if (comp.skip_linker_dependencies or comp.bin_file.options.no_builtin) { + if (comp.skip_linker_dependencies or comp.no_builtin) { // The intent here is for compiler-rt and libc functions to not generate // infinite recursion. For example, if we are compiling the memcpy function, // and llvm detects that the body is equivalent to memcpy, it may replace the diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index fb1f2bb827..6b2587e3cb 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -191,13 +191,9 @@ pub const Object = struct { air: Air, liveness: Liveness, ) !void { - const target = mod.getTarget(); - // We always want a structured control flow in shaders. This option is only relevant - // for OpenCL kernels. - const want_structured_cfg = switch (target.os.tag) { - .opencl => mod.comp.bin_file.options.want_structured_cfg orelse false, - else => true, - }; + const decl = mod.declPtr(decl_index); + const namespace = mod.namespacePtr(decl.src_namespace); + const structured_cfg = namespace.file_scope.mod.structured_cfg; var decl_gen = DeclGen{ .gpa = self.gpa, @@ -208,7 +204,7 @@ pub const Object = struct { .air = air, .liveness = liveness, .type_map = &self.type_map, - .control_flow = switch (want_structured_cfg) { + .control_flow = switch (structured_cfg) { true => .{ .structured = .{} }, false => .{ .unstructured = .{} }, }, diff --git a/src/link.zig b/src/link.zig index 580b2d7daf..5908a07dec 100644 --- a/src/link.zig +++ b/src/link.zig @@ -32,8 +32,6 @@ pub const SystemLib = struct { path: ?[]const u8, }; -pub const SortSection = enum { name, alignment }; - pub const CacheMode = enum { incremental, whole }; pub fn hashAddSystemLibs( @@ -51,10 +49,6 @@ pub fn hashAddSystemLibs( pub const producer_string = if (builtin.is_test) "zig test" else "zig " ++ build_options.version; -pub const HashStyle = enum { sysv, gnu, both }; - -pub const CompressDebugSections = enum { none, zlib, zstd }; - pub const File = struct { tag: Tag, @@ -105,12 +99,9 @@ pub const File = struct { image_base: ?u64, function_sections: bool, data_sections: bool, - no_builtin: bool, eh_frame_hdr: bool, emit_relocs: bool, rdynamic: bool, - optimization: u8, - linker_script: ?[]const u8, z_nodelete: bool, z_notext: bool, z_defs: bool, @@ -123,7 +114,7 @@ pub const File = struct { tsaware: bool, nxcompat: bool, dynamicbase: bool, - compress_debug_sections: CompressDebugSections, + compress_debug_sections: Elf.CompressDebugSections, bind_global_refs_locally: bool, import_symbols: bool, import_table: bool, @@ -136,13 +127,14 @@ pub const File = struct { each_lib_rpath: bool, build_id: std.zig.BuildId, disable_lld_caching: bool, - hash_style: HashStyle, - sort_section: ?SortSection, + hash_style: Elf.HashStyle, + sort_section: ?Elf.SortSection, major_subsystem_version: ?u32, minor_subsystem_version: ?u32, gc_sections: ?bool, allow_shlib_undefined: ?bool, subsystem: ?std.Target.SubSystem, + linker_script: ?[]const u8, version_script: ?[]const u8, soname: ?[]const u8, print_gc_sections: bool, @@ -192,9 +184,6 @@ pub const File = struct { /// (Windows) .def file to specify when linking module_definition_file: ?[]const u8, - /// (SPIR-V) whether to generate a structured control flow graph or not - want_structured_cfg: ?bool, - wasi_emulated_libs: []const wasi_libc.CRTFile, }; diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 41cf524ec0..db99ba189c 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -10,6 +10,15 @@ base: link.File, image_base: u64, error_flags: link.File.ErrorFlags = .{}, dll_export_fns: bool, +subsystem: ?std.Target.SubSystem, +tsaware: bool, +nxcompat: bool, +dynamicbase: bool, +/// TODO this and minor_subsystem_version should be combined into one property and left as +/// default or populated together. They should not be separate fields. +major_subsystem_version: u32, +minor_subsystem_version: u32, +lib_dirs: []const []const u8, ptr_width: PtrWidth, page_size: u32, @@ -403,6 +412,13 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Coff { }, .dll_export_fns = options.dll_export_fns, + .subsystem = options.subsystem, + .tsaware = options.tsaware, + .nxcompat = options.nxcompat, + .dynamicbase = options.dynamicbase, + .major_subsystem_version = options.major_subsystem_version orelse 6, + .minor_subsystem_version = options.minor_subsystem_version orelse 0, + .lib_dirs = options.lib_dirs, }; const use_llvm = comp.config.use_llvm; @@ -2305,8 +2321,8 @@ fn writeHeader(self: *Coff) !void { .minor_operating_system_version = 0, .major_image_version = 0, .minor_image_version = 0, - .major_subsystem_version = 6, - .minor_subsystem_version = 0, + .major_subsystem_version = self.major_subsystem_version, + .minor_subsystem_version = self.minor_subsystem_version, .win32_version_value = 0, .size_of_image = size_of_image, .size_of_headers = size_of_headers, @@ -2339,8 +2355,8 @@ fn writeHeader(self: *Coff) !void { .minor_operating_system_version = 0, .major_image_version = 0, .minor_image_version = 0, - .major_subsystem_version = 6, - .minor_subsystem_version = 0, + .major_subsystem_version = self.major_subsystem_version, + .minor_subsystem_version = self.minor_subsystem_version, .win32_version_value = 0, .size_of_image = size_of_image, .size_of_headers = size_of_headers, diff --git a/src/link/Elf.zig b/src/link/Elf.zig index a116c46d2f..b54bde325f 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1,6 +1,29 @@ base: link.File, image_base: u64, rdynamic: bool, +eh_frame_hdr: bool, +emit_relocs: bool, +z_nodelete: bool, +z_notext: bool, +z_defs: bool, +z_origin: bool, +z_nocopyreloc: bool, +z_now: bool, +z_relro: bool, +/// TODO make this non optional and resolve the default in open() +z_common_page_size: ?u64, +/// TODO make this non optional and resolve the default in open() +z_max_page_size: ?u64, +lib_dirs: []const []const u8, +hash_style: HashStyle, +compress_debug_sections: CompressDebugSections, +symbol_wrap_set: std.StringArrayHashMapUnmanaged(void), +each_lib_rpath: bool, +sort_section: ?SortSection, +soname: ?[]const u8, +bind_global_refs_locally: bool, +linker_script: ?[]const u8, +version_script: ?[]const u8, ptr_width: PtrWidth, @@ -201,6 +224,9 @@ const minimum_atom_size = 64; pub const min_text_capacity = padToIdeal(minimum_atom_size); pub const PtrWidth = enum { p32, p64 }; +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 { if (build_options.only_c) unreachable; @@ -374,6 +400,27 @@ pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Elf { }, .rdynamic = options.rdynamic, + .eh_frame_hdr = options.eh_frame_hdr, + .emit_relocs = options.emit_relocs, + .z_nodelete = options.z_nodelete, + .z_notext = options.z_notext, + .z_defs = options.z_defs, + .z_origin = options.z_origin, + .z_nocopyreloc = options.z_nocopyreloc, + .z_now = options.z_now, + .z_relro = options.z_relro, + .z_common_page_size = options.z_common_page_size, + .z_max_page_size = options.z_max_page_size, + .lib_dirs = options.lib_dirs, + .hash_style = options.hash_style, + .compress_debug_sections = options.compress_debug_sections, + .symbol_wrap_set = options.symbol_wrap_set, + .each_lib_rpath = options.each_lib_rpath, + .sort_section = options.sort_section, + .soname = options.soname, + .bind_global_refs_locally = options.bind_global_refs_locally, + .linker_script = options.linker_script, + .version_script = options.version_script, }; if (use_llvm and comp.config.have_zcu) { self.llvm_object = try LlvmObject.create(arena, options); @@ -2424,8 +2471,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v man.hash.add(self.bind_global_refs_locally); man.hash.add(self.compress_debug_sections); man.hash.add(comp.config.any_sanitize_thread); - man.hash.addOptionalBytes(self.sysroot); - man.hash.add(self.optimization); + man.hash.addOptionalBytes(comp.sysroot); // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock. _ = try man.hit(); @@ -2500,7 +2546,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v try argv.append("--error-limit=0"); - if (self.sysroot) |sysroot| { + if (comp.sysroot) |sysroot| { try argv.append(try std.fmt.allocPrint(arena, "--sysroot={s}", .{sysroot})); } @@ -2511,9 +2557,11 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v .ReleaseFast, .ReleaseSafe => try argv.append("--lto-O3"), } } - try argv.append(try std.fmt.allocPrint(arena, "-O{d}", .{ - self.optimization, - })); + switch (comp.root_mod.optimize_mode) { + .Debug => {}, + .ReleaseSmall => try argv.append("-O2"), + .ReleaseFast, .ReleaseSafe => try argv.append("-O3"), + } if (comp.config.entry) |entry| { try argv.append("--entry"); diff --git a/src/link/MachO/load_commands.zig b/src/link/MachO/load_commands.zig index 3bffc7f73e..8bcf439354 100644 --- a/src/link/MachO/load_commands.zig +++ b/src/link/MachO/load_commands.zig @@ -476,7 +476,7 @@ pub fn inferSdkVersion(gpa: Allocator, comp: *const Compilation) ?std.SemanticVe const sdk_layout = macho_file.sdk_layout orelse return null; const sdk_dir = switch (sdk_layout) { - .sdk => macho_file.sysroot.?, + .sdk => comp.sysroot.?, .vendored => std.fs.path.join(arena, &.{ comp.zig_lib_directory.path.?, "libc", "darwin" }) catch return null, }; if (readSdkVersionFromSettings(arena, sdk_dir)) |ver| { diff --git a/src/link/MachO/zld.zig b/src/link/MachO/zld.zig index f40aaea4db..06fede6e1b 100644 --- a/src/link/MachO/zld.zig +++ b/src/link/MachO/zld.zig @@ -249,7 +249,7 @@ pub fn linkWithZld( } } - if (macho_file.sysroot) |syslibroot| { + if (comp.sysroot) |syslibroot| { try argv.append("-syslibroot"); try argv.append(syslibroot); } diff --git a/src/link/SpirV.zig b/src/link/SpirV.zig index d8f78c32f1..bb278a8e4a 100644 --- a/src/link/SpirV.zig +++ b/src/link/SpirV.zig @@ -47,6 +47,8 @@ base: link.File, 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; diff --git a/src/main.zig b/src/main.zig index 5f65908b5c..9acad1a0ca 100644 --- a/src/main.zig +++ b/src/main.zig @@ -828,9 +828,9 @@ fn buildOutputType( var linker_script: ?[]const u8 = null; var version_script: ?[]const u8 = null; var disable_c_depfile = false; - var linker_sort_section: ?link.SortSection = null; + var linker_sort_section: ?link.File.Elf.SortSection = null; var linker_gc_sections: ?bool = null; - var linker_compress_debug_sections: ?link.CompressDebugSections = null; + var linker_compress_debug_sections: ?link.File.Elf.CompressDebugSections = null; var linker_allow_shlib_undefined: ?bool = null; var linker_bind_global_refs_locally: ?bool = null; var linker_import_symbols: bool = false; @@ -855,7 +855,7 @@ fn buildOutputType( var linker_tsaware = false; var linker_nxcompat = false; var linker_dynamicbase = true; - var linker_optimization: ?u8 = null; + var linker_optimization: ?[]const u8 = null; var linker_module_definition_file: ?[]const u8 = null; var test_no_exec = false; var force_undefined_symbols: std.StringArrayHashMapUnmanaged(void) = .{}; @@ -881,7 +881,7 @@ fn buildOutputType( var enable_link_snapshots: bool = false; var debug_incremental: bool = false; var install_name: ?[]const u8 = null; - var hash_style: link.HashStyle = .both; + var hash_style: link.File.Elf.HashStyle = .both; var entitlements: ?[]const u8 = null; var pagezero_size: ?u64 = null; var lib_search_strategy: SystemLib.SearchStrategy = .paths_first; @@ -894,7 +894,6 @@ fn buildOutputType( var pdb_out_path: ?[]const u8 = null; var debug_format: ?link.File.DebugFormat = null; var error_limit: ?Module.ErrorInt = null; - var want_structured_cfg: ?bool = null; // These are before resolving sysroot. var lib_dir_args: std.ArrayListUnmanaged([]const u8) = .{}; var extra_cflags: std.ArrayListUnmanaged([]const u8) = .{}; @@ -1110,9 +1109,9 @@ fn buildOutputType( try extra_rcflags.append(arena, next_arg); } } else if (mem.startsWith(u8, arg, "-fstructured-cfg")) { - want_structured_cfg = true; + mod_opts.structured_cfg = true; } else if (mem.startsWith(u8, arg, "-fno-structured-cfg")) { - want_structured_cfg = false; + mod_opts.structured_cfg = false; } else if (mem.eql(u8, arg, "--color")) { const next_arg = args_iter.next() orelse { fatal("expected [auto|on|off] after --color", .{}); @@ -1152,11 +1151,11 @@ fn buildOutputType( install_name = args_iter.nextOrFatal(); } else if (mem.startsWith(u8, arg, "--compress-debug-sections=")) { const param = arg["--compress-debug-sections=".len..]; - linker_compress_debug_sections = std.meta.stringToEnum(link.CompressDebugSections, param) orelse { + linker_compress_debug_sections = std.meta.stringToEnum(link.File.Elf.CompressDebugSections, param) orelse { fatal("expected --compress-debug-sections=[none|zlib|zstd], found '{s}'", .{param}); }; } else if (mem.eql(u8, arg, "--compress-debug-sections")) { - linker_compress_debug_sections = link.CompressDebugSections.zlib; + linker_compress_debug_sections = link.File.Elf.CompressDebugSections.zlib; } else if (mem.eql(u8, arg, "-pagezero_size")) { const next_arg = args_iter.nextOrFatal(); pagezero_size = std.fmt.parseUnsigned(u64, eatIntPrefix(next_arg, 16), 16) catch |err| { @@ -2067,7 +2066,7 @@ fn buildOutputType( if (it.only_arg.len == 0) { linker_compress_debug_sections = .zlib; } else { - linker_compress_debug_sections = std.meta.stringToEnum(link.CompressDebugSections, it.only_arg) orelse { + linker_compress_debug_sections = std.meta.stringToEnum(link.File.Elf.CompressDebugSections, it.only_arg) orelse { fatal("expected [none|zlib|zstd] after --compress-debug-sections, found '{s}'", .{it.only_arg}); }; } @@ -2138,14 +2137,9 @@ fn buildOutputType( } else if (mem.eql(u8, arg, "-version-script") or mem.eql(u8, arg, "--version-script")) { version_script = linker_args_it.nextOrFatal(); } else if (mem.eql(u8, arg, "-O")) { - const opt = linker_args_it.nextOrFatal(); - linker_optimization = std.fmt.parseUnsigned(u8, opt, 10) catch |err| { - fatal("unable to parse optimization level '{s}': {s}", .{ opt, @errorName(err) }); - }; + linker_optimization = linker_args_it.nextOrFatal(); } else if (mem.startsWith(u8, arg, "-O")) { - linker_optimization = std.fmt.parseUnsigned(u8, arg["-O".len..], 10) catch |err| { - fatal("unable to parse optimization level '{s}': {s}", .{ arg, @errorName(err) }); - }; + linker_optimization = arg["-O".len..]; } else if (mem.eql(u8, arg, "-pagezero_size")) { const next_arg = linker_args_it.nextOrFatal(); pagezero_size = std.fmt.parseUnsigned(u64, eatIntPrefix(next_arg, 16), 16) catch |err| { @@ -2176,7 +2170,7 @@ fn buildOutputType( linker_print_map = true; } else if (mem.eql(u8, arg, "--sort-section")) { const arg1 = linker_args_it.nextOrFatal(); - linker_sort_section = std.meta.stringToEnum(link.SortSection, arg1) orelse { + linker_sort_section = std.meta.stringToEnum(link.File.Elf.SortSection, arg1) orelse { fatal("expected [name|alignment] after --sort-section, found '{s}'", .{arg1}); }; } else if (mem.eql(u8, arg, "--allow-shlib-undefined") or @@ -2222,7 +2216,7 @@ fn buildOutputType( try linker_export_symbol_names.append(arena, linker_args_it.nextOrFatal()); } else if (mem.eql(u8, arg, "--compress-debug-sections")) { const arg1 = linker_args_it.nextOrFatal(); - linker_compress_debug_sections = std.meta.stringToEnum(link.CompressDebugSections, arg1) orelse { + linker_compress_debug_sections = std.meta.stringToEnum(link.File.Elf.CompressDebugSections, arg1) orelse { fatal("expected [none|zlib|zstd] after --compress-debug-sections, found '{s}'", .{arg1}); }; } else if (mem.startsWith(u8, arg, "-z")) { @@ -2405,7 +2399,7 @@ fn buildOutputType( mem.eql(u8, arg, "--hash-style")) { const next_arg = linker_args_it.nextOrFatal(); - hash_style = std.meta.stringToEnum(link.HashStyle, next_arg) orelse { + hash_style = std.meta.stringToEnum(link.File.Elf.HashStyle, next_arg) orelse { fatal("expected [sysv|gnu|both] after --hash-style, found '{s}'", .{ next_arg, }); @@ -2625,6 +2619,10 @@ fn buildOutputType( }; defer global_cache_directory.handle.close(); + if (linker_optimization) |o| { + warn("ignoring deprecated linker optimization setting '{s}'", .{o}); + } + create_module.global_cache_directory = global_cache_directory; create_module.opts.emit_llvm_ir = emit_llvm_ir != .no; create_module.opts.emit_llvm_bc = emit_llvm_bc != .no; @@ -3409,7 +3407,6 @@ fn buildOutputType( .linker_tsaware = linker_tsaware, .linker_nxcompat = linker_nxcompat, .linker_dynamicbase = linker_dynamicbase, - .linker_optimization = linker_optimization, .linker_compress_debug_sections = linker_compress_debug_sections, .linker_module_definition_file = linker_module_definition_file, .major_subsystem_version = major_subsystem_version, @@ -3458,7 +3455,6 @@ fn buildOutputType( .reference_trace = reference_trace, .pdb_out_path = pdb_out_path, .error_limit = error_limit, - .want_structured_cfg = want_structured_cfg, }) catch |err| switch (err) { error.LibCUnavailable => { const triple_name = try target.zigTriple(arena); -- cgit v1.2.3 From f54471b54c471bb6f8e51a1383be09d01c24d0c3 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 14 Dec 2023 16:41:20 -0700 Subject: compiler: miscellaneous branch progress implement builtin.zig file population for all modules rather than assuming there is only one global builtin.zig module. move some fields from link.File to Compilation move some fields from Module to Compilation compute debug_format in global Compilation config resolution wire up C compilation to the concept of owner modules make whole cache mode call link.File.createEmpty() instead of link.File.open() --- src/Builtin.zig | 62 ++++++++++++++- src/Compilation.zig | 183 +++++++++++++++++++++++++-------------------- src/Compilation/Config.zig | 31 ++++++++ src/Module.zig | 69 ----------------- src/Package/Module.zig | 31 ++++++-- src/Sema.zig | 7 +- src/codegen/llvm.zig | 16 +--- src/libunwind.zig | 3 +- src/link.zig | 41 +++++----- src/link/C.zig | 26 +++---- src/link/Coff.zig | 42 ++++++----- src/link/Coff/lld.zig | 2 +- src/link/Elf.zig | 48 ++++++------ src/link/Elf/Object.zig | 3 +- src/link/Elf/ZigObject.zig | 12 ++- src/link/MachO.zig | 39 +++++----- src/link/NvPtx.zig | 33 ++++---- src/link/Plan9.zig | 36 +++++---- src/link/SpirV.zig | 35 +++++---- src/link/Wasm.zig | 41 +++++----- src/main.zig | 33 ++++---- 21 files changed, 457 insertions(+), 336 deletions(-) (limited to 'src/Package/Module.zig') 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, 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().open(arena, options); + 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"); -- cgit v1.2.3 From 2596f5d92593a5f7dad21d9a54f2d08f33639432 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 14 Dec 2023 19:49:53 -0700 Subject: update bin_file.options references in Sema mainly pertaining to error return tracing --- src/Compilation/Config.zig | 22 ++++++++++++++++ src/Package/Module.zig | 10 ++------ src/Sema.zig | 64 +++++++++++++++++++++++----------------------- src/codegen/llvm.zig | 10 ++++---- src/main.zig | 5 ++++ 5 files changed, 66 insertions(+), 45 deletions(-) (limited to 'src/Package/Module.zig') diff --git a/src/Compilation/Config.zig b/src/Compilation/Config.zig index 0afb633c86..efe314095c 100644 --- a/src/Compilation/Config.zig +++ b/src/Compilation/Config.zig @@ -9,6 +9,10 @@ link_libunwind: bool, any_unwind_tables: bool, any_c_source_files: bool, any_non_single_threaded: bool, +/// This is true if any Module has error_tracing set to true. Function types +/// and function calling convention depend on this global value, however, other +/// kinds of error tracing are omitted depending on the per-Module setting. +any_error_tracing: bool, pie: bool, /// If this is true then linker code is responsible for making an LLVM IR /// Module, outputting it to an object file, and then linking that together @@ -34,6 +38,8 @@ is_test: bool, test_evented_io: bool, entry: ?[]const u8, debug_format: DebugFormat, +root_strip: bool, +root_error_tracing: bool, pub const CFrontend = enum { clang, aro }; @@ -51,6 +57,7 @@ pub const Options = struct { emit_bin: bool, root_optimize_mode: ?std.builtin.OptimizeMode = null, root_strip: ?bool = null, + root_error_tracing: ?bool = null, link_mode: ?std.builtin.LinkMode = null, ensure_libc_on_non_freestanding: bool = false, ensure_libcpp_on_non_freestanding: bool = false, @@ -60,6 +67,7 @@ pub const Options = struct { any_dyn_libs: bool = false, any_c_source_files: bool = false, any_non_stripped: bool = false, + any_error_tracing: bool = false, emit_llvm_ir: bool = false, emit_llvm_bc: bool = false, link_libc: ?bool = null, @@ -395,6 +403,17 @@ pub fn resolve(options: Options) !Config { }; }; + const root_error_tracing = b: { + if (options.root_error_tracing) |x| break :b x; + if (root_strip) break :b false; + break :b switch (root_optimize_mode) { + .Debug => true, + .ReleaseSafe, .ReleaseFast, .ReleaseSmall => false, + }; + }; + + const any_error_tracing = root_error_tracing or options.any_error_tracing; + return .{ .output_mode = options.output_mode, .have_zcu = options.have_zcu, @@ -407,6 +426,8 @@ pub fn resolve(options: Options) !Config { .any_unwind_tables = any_unwind_tables, .any_c_source_files = options.any_c_source_files, .any_non_single_threaded = options.any_non_single_threaded, + .any_error_tracing = any_error_tracing, + .root_error_tracing = root_error_tracing, .pie = pie, .lto = lto, .import_memory = import_memory, @@ -419,6 +440,7 @@ pub fn resolve(options: Options) !Config { .entry = entry, .wasi_exec_model = wasi_exec_model, .debug_format = debug_format, + .root_strip = root_strip, }; } diff --git a/src/Package/Module.zig b/src/Package/Module.zig index 051303ca26..5e786a6fa2 100644 --- a/src/Package/Module.zig +++ b/src/Package/Module.zig @@ -114,9 +114,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module { const strip = b: { if (options.inherited.strip) |x| break :b x; if (options.parent) |p| break :b p.strip; - if (optimize_mode == .ReleaseSmall) break :b true; - if (!target_util.hasDebugInfo(target)) break :b true; - break :b false; + break :b options.global.root_strip; }; const valgrind = b: { @@ -156,11 +154,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module { const error_tracing = b: { if (options.inherited.error_tracing) |x| break :b x; if (options.parent) |p| break :b p.error_tracing; - if (strip) break :b false; - break :b switch (optimize_mode) { - .Debug => true, - .ReleaseSafe, .ReleaseFast, .ReleaseSmall => false, - }; + break :b options.global.root_error_tracing; }; const pic = b: { diff --git a/src/Sema.zig b/src/Sema.zig index 2d46faf435..6d14deb095 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -1329,13 +1329,13 @@ fn analyzeBodyInner( }, .dbg_block_begin => { dbg_block_begins += 1; - try sema.zirDbgBlockBegin(block); + try zirDbgBlockBegin(block); i += 1; continue; }, .dbg_block_end => { dbg_block_begins -= 1; - try sema.zirDbgBlockEnd(block); + try zirDbgBlockEnd(block); i += 1; continue; }, @@ -1830,17 +1830,17 @@ fn analyzeBodyInner( }; // balance out dbg_block_begins in case of early noreturn - const noreturn_inst = block.instructions.popOrNull(); - while (dbg_block_begins > 0) { - dbg_block_begins -= 1; - if (block.is_comptime or mod.comp.bin_file.options.strip) continue; - - _ = try block.addInst(.{ - .tag = .dbg_block_end, - .data = undefined, - }); + if (!block.is_comptime and !block.ownerModule().strip) { + const noreturn_inst = block.instructions.popOrNull(); + while (dbg_block_begins > 0) { + dbg_block_begins -= 1; + _ = try block.addInst(.{ + .tag = .dbg_block_end, + .data = undefined, + }); + } + if (noreturn_inst) |some| try block.instructions.append(sema.gpa, some); } - if (noreturn_inst) |some| try block.instructions.append(sema.gpa, some); // We may have overwritten the capture scope due to a `repeat` instruction where // the body had a capture; restore it now. @@ -6272,7 +6272,7 @@ fn zirDbgStmt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!voi // ZIR code that possibly will need to generate runtime code. So error messages // and other source locations must not rely on sema.src being set from dbg_stmt // instructions. - if (block.is_comptime or sema.mod.comp.bin_file.options.strip) return; + if (block.is_comptime or block.ownerModule().strip) return; const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt; @@ -6297,8 +6297,8 @@ fn zirDbgStmt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!voi }); } -fn zirDbgBlockBegin(sema: *Sema, block: *Block) CompileError!void { - if (block.is_comptime or sema.mod.comp.bin_file.options.strip) return; +fn zirDbgBlockBegin(block: *Block) CompileError!void { + if (block.is_comptime or block.ownerModule().strip) return; _ = try block.addInst(.{ .tag = .dbg_block_begin, @@ -6306,8 +6306,8 @@ fn zirDbgBlockBegin(sema: *Sema, block: *Block) CompileError!void { }); } -fn zirDbgBlockEnd(sema: *Sema, block: *Block) CompileError!void { - if (block.is_comptime or sema.mod.comp.bin_file.options.strip) return; +fn zirDbgBlockEnd(block: *Block) CompileError!void { + if (block.is_comptime or block.ownerModule().strip) return; _ = try block.addInst(.{ .tag = .dbg_block_end, @@ -6321,7 +6321,7 @@ fn zirDbgVar( inst: Zir.Inst.Index, air_tag: Air.Inst.Tag, ) CompileError!void { - if (block.is_comptime or sema.mod.comp.bin_file.options.strip) return; + if (block.is_comptime or block.ownerModule().strip) return; const str_op = sema.code.instructions.items(.data)[@intFromEnum(inst)].str_op; const operand = try sema.resolveInst(str_op.operand); @@ -6519,7 +6519,7 @@ pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref const src = sema.src; if (!mod.backendSupportsFeature(.error_return_trace)) return .none; - if (!mod.comp.bin_file.options.error_return_tracing) return .none; + if (!block.ownerModule().error_tracing) return .none; if (block.is_comptime) return .none; @@ -6703,7 +6703,7 @@ fn zirCall( input_is_error = false; } - if (mod.backendSupportsFeature(.error_return_trace) and mod.comp.bin_file.options.error_return_tracing and + if (mod.backendSupportsFeature(.error_return_trace) and block.ownerModule().error_tracing and !block.is_comptime and !block.is_typeof and (input_is_error or pop_error_return_trace)) { const return_ty = sema.typeOf(call_inst); @@ -7456,7 +7456,7 @@ fn analyzeCall( new_fn_info.return_type = sema.fn_ret_ty.toIntern(); const new_func_resolved_ty = try mod.funcType(new_fn_info); if (!is_comptime_call and !block.is_typeof) { - try sema.emitDbgInline(block, prev_fn_index, module_fn_index, new_func_resolved_ty, .dbg_inline_begin); + try emitDbgInline(block, prev_fn_index, module_fn_index, new_func_resolved_ty, .dbg_inline_begin); const zir_tags = sema.code.instructions.items(.tag); for (fn_info.param_body) |param| switch (zir_tags[@intFromEnum(param)]) { @@ -7494,7 +7494,7 @@ fn analyzeCall( if (!is_comptime_call and !block.is_typeof and sema.typeOf(result).zigTypeTag(mod) != .NoReturn) { - try sema.emitDbgInline( + try emitDbgInline( block, module_fn_index, prev_fn_index, @@ -8067,15 +8067,13 @@ fn resolveTupleLazyValues(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) } fn emitDbgInline( - sema: *Sema, block: *Block, old_func: InternPool.Index, new_func: InternPool.Index, new_func_ty: Type, tag: Air.Inst.Tag, ) CompileError!void { - const mod = sema.mod; - if (mod.comp.bin_file.options.strip) return; + if (block.ownerModule().strip) return; // Recursive inline call; no dbg_inline needed. if (old_func == new_func) return; @@ -9109,7 +9107,7 @@ fn handleExternLibName( ); break :blk; } - if (!target.isWasm() and !comp.bin_file.options.pic) { + if (!target.isWasm() and !block.ownerModule().pic) { return sema.fail( block, src_loc, @@ -18738,16 +18736,16 @@ fn wantErrorReturnTracing(sema: *Sema, fn_ret_ty: Type) bool { const mod = sema.mod; if (!mod.backendSupportsFeature(.error_return_trace)) return false; - return fn_ret_ty.isError(mod) and - mod.comp.bin_file.options.error_return_tracing; + return fn_ret_ty.isError(mod) and mod.comp.config.any_error_tracing; } fn zirSaveErrRetIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { const mod = sema.mod; const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].save_err_ret_index; + // TODO: replace all of these checks with logic in module creation if (!mod.backendSupportsFeature(.error_return_trace)) return; - if (!mod.comp.bin_file.options.error_return_tracing) return; + if (!block.ownerModule().error_tracing) return; // This is only relevant at runtime. if (block.is_comptime or block.is_typeof) return; @@ -18774,7 +18772,7 @@ fn zirRestoreErrRetIndex(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index) if (!mod.backendSupportsFeature(.error_return_trace)) return; if (!ip.funcAnalysis(sema.owner_func_index).calls_or_awaits_errorable_fn) return; - if (!mod.comp.bin_file.options.error_return_tracing) return; + if (!start_block.ownerModule().error_tracing) return; const tracy = trace(@src()); defer tracy.end(); @@ -20045,7 +20043,7 @@ fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref { if (sema.owner_func_index != .none and ip.funcAnalysis(sema.owner_func_index).calls_or_awaits_errorable_fn and - mod.comp.bin_file.options.error_return_tracing and + mod.ownerModule().error_tracing and mod.backendSupportsFeature(.error_return_trace)) { return block.addTy(.err_return_trace, opt_ptr_stack_trace_ty); @@ -34504,7 +34502,9 @@ pub fn resolveFnTypes(sema: *Sema, fn_ty: Type) CompileError!void { try sema.resolveTypeFully(Type.fromInterned(fn_ty_info.return_type)); - if (mod.comp.bin_file.options.error_return_tracing and Type.fromInterned(fn_ty_info.return_type).isError(mod)) { + if (mod.comp.config.any_error_tracing and + Type.fromInterned(fn_ty_info.return_type).isError(mod)) + { // Ensure the type exists so that backends can assume that. _ = try sema.getBuiltinType("StackTrace"); } diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 6545f84f9d..75fb373d9b 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -1398,7 +1398,7 @@ pub const Object = struct { }; const err_return_tracing = Type.fromInterned(fn_info.return_type).isError(mod) and - mod.comp.bin_file.options.error_return_tracing; + mod.comp.config.any_error_tracing; const err_ret_trace: Builder.Value = if (err_return_tracing) param: { const param = wip.arg(llvm_arg_i); @@ -2820,7 +2820,7 @@ pub const Object = struct { } if (Type.fromInterned(fn_info.return_type).isError(mod) and - o.module.comp.bin_file.options.error_return_tracing) + o.module.comp.config.any_error_tracing) { const ptr_ty = try mod.singleMutPtrType(try o.getStackTraceType()); try param_di_types.append(try o.lowerDebugType(ptr_ty, .full)); @@ -2988,7 +2988,7 @@ pub const Object = struct { } const err_return_tracing = Type.fromInterned(fn_info.return_type).isError(mod) and - mod.comp.bin_file.options.error_return_tracing; + mod.comp.config.any_error_tracing; if (err_return_tracing) { try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder); @@ -3677,7 +3677,7 @@ pub const Object = struct { } if (Type.fromInterned(fn_info.return_type).isError(mod) and - mod.comp.bin_file.options.error_return_tracing) + mod.comp.config.any_error_tracing) { const ptr_ty = try mod.singleMutPtrType(try o.getStackTraceType()); try llvm_params.append(o.gpa, try o.lowerType(ptr_ty)); @@ -5142,7 +5142,7 @@ pub const FuncGen = struct { }; const err_return_tracing = return_type.isError(mod) and - o.module.comp.bin_file.options.error_return_tracing; + o.module.comp.config.any_error_tracing; if (err_return_tracing) { assert(self.err_ret_trace != .none); try llvm_args.append(self.err_ret_trace); diff --git a/src/main.zig b/src/main.zig index dbd9759015..b73023e5b3 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1055,6 +1055,8 @@ fn buildOutputType( create_module.opts.any_unwind_tables = true; if (mod_opts.strip == false) create_module.opts.any_non_stripped = true; + if (mod_opts.error_tracing == true) + create_module.opts.any_error_tracing = true; const root_src = try introspect.resolvePath(arena, root_src_orig); try create_module.modules.put(arena, mod_name, .{ @@ -2535,6 +2537,8 @@ fn buildOutputType( create_module.opts.any_unwind_tables = true; if (mod_opts.strip == false) create_module.opts.any_non_stripped = true; + if (mod_opts.error_tracing == true) + create_module.opts.any_error_tracing = true; const src_path = try introspect.resolvePath(arena, unresolved_src_path); try create_module.modules.put(arena, "main", .{ @@ -3741,6 +3745,7 @@ fn createModule( 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; + create_module.opts.root_error_tracing = cli_mod.inherited.error_tracing; const target = resolved_target.result; // First, remove libc, libc++, and compiler_rt libraries from the system libraries list. -- cgit v1.2.3 From a1236b32f9a4114231312b1493dcbac308a2c055 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 15 Dec 2023 14:22:24 -0700 Subject: libcxx: update to new Compilation API --- src/Compilation/Config.zig | 2 + src/Module.zig | 6 +- src/Package/Module.zig | 5 ++ src/libcxx.zig | 157 ++++++++++++++++++++++++++++++--------------- src/musl.zig | 3 - 5 files changed, 114 insertions(+), 59 deletions(-) (limited to 'src/Package/Module.zig') diff --git a/src/Compilation/Config.zig b/src/Compilation/Config.zig index efe314095c..44ace55ae4 100644 --- a/src/Compilation/Config.zig +++ b/src/Compilation/Config.zig @@ -13,6 +13,7 @@ any_non_single_threaded: bool, /// and function calling convention depend on this global value, however, other /// kinds of error tracing are omitted depending on the per-Module setting. any_error_tracing: bool, +any_sanitize_thread: bool, pie: bool, /// If this is true then linker code is responsible for making an LLVM IR /// Module, outputting it to an object file, and then linking that together @@ -427,6 +428,7 @@ pub fn resolve(options: Options) !Config { .any_c_source_files = options.any_c_source_files, .any_non_single_threaded = options.any_non_single_threaded, .any_error_tracing = any_error_tracing, + .any_sanitize_thread = options.any_sanitize_thread, .root_error_tracing = root_error_tracing, .pie = pie, .lto = lto, diff --git a/src/Module.zig b/src/Module.zig index 0645b6f04f..571301c8e6 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -4566,7 +4566,7 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato // If we don't get an error return trace from a caller, create our own. if (func.analysis(ip).calls_or_awaits_errorable_fn and - mod.comp.config.error_tracing and + mod.comp.config.any_error_tracing and !sema.fn_ret_ty.isError(mod)) { sema.setupErrorReturnTrace(&inner_block, last_arg_index) catch |err| switch (err) { @@ -5567,8 +5567,8 @@ pub const Feature = enum { }; pub fn backendSupportsFeature(zcu: Module, feature: Feature) bool { - const cpu_arch = zcu.root_mod.resolved_target.cpu.arch; - const ofmt = zcu.root_mod.resolved_target.ofmt; + const cpu_arch = zcu.root_mod.resolved_target.result.cpu.arch; + const ofmt = zcu.root_mod.resolved_target.result.ofmt; const use_llvm = zcu.comp.config.use_llvm; return switch (feature) { .panic_fn => ofmt == .c or use_llvm or cpu_arch == .x86_64, diff --git a/src/Package/Module.zig b/src/Package/Module.zig index 5e786a6fa2..4ce0f0a856 100644 --- a/src/Package/Module.zig +++ b/src/Package/Module.zig @@ -102,6 +102,11 @@ pub const ResolvedTarget = struct { /// At least one of `parent` and `resolved_target` must be non-null. pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module { + if (options.inherited.sanitize_thread == true) assert(options.global.any_sanitize_thread); + if (options.inherited.single_threaded == false) assert(options.global.any_non_single_threaded); + if (options.inherited.unwind_tables == true) assert(options.global.any_unwind_tables); + if (options.inherited.error_tracing == true) assert(options.global.any_error_tracing); + const resolved_target = options.inherited.resolved_target orelse options.parent.?.resolved_target; const target = resolved_target.result; diff --git a/src/libcxx.zig b/src/libcxx.zig index 8ae7db80f1..1f78b867a3 100644 --- a/src/libcxx.zig +++ b/src/libcxx.zig @@ -6,6 +6,7 @@ const target_util = @import("target.zig"); const Compilation = @import("Compilation.zig"); const build_options = @import("build_options"); const trace = @import("tracy.zig").trace; +const Module = @import("Package/Module.zig"); pub const AbiVersion = enum(u2) { @"1" = 1, @@ -115,7 +116,7 @@ pub fn buildLibCXX(comp: *Compilation, prog_node: *std.Progress.Node) !void { const root_name = "c++"; const output_mode = .Lib; const link_mode = .Static; - const target = comp.getTarget(); + const target = comp.root_mod.resolved_target.result; const basename = try std.zig.binNameAlloc(arena, .{ .root_name = root_name, .target = target, @@ -226,46 +227,70 @@ pub fn buildLibCXX(comp: *Compilation, prog_node: *std.Progress.Node) !void { }); } + const optimize_mode = comp.compilerRtOptMode(); + const strip = comp.compilerRtStrip(); + + const config = try Compilation.Config.resolve(.{ + .output_mode = output_mode, + .link_mode = link_mode, + .resolved_target = comp.root_mod.resolved_target, + .is_test = false, + .have_zcu = false, + .emit_bin = true, + .root_optimize_mode = optimize_mode, + .root_strip = strip, + .link_libc = true, + .lto = comp.config.lto, + }); + + const root_mod = try Module.create(arena, .{ + .global_cache_directory = comp.global_cache_directory, + .paths = .{ + .root = .{ .root_dir = comp.zig_lib_directory }, + .root_src_path = "", + }, + .fully_qualified_name = "root", + .inherited = .{ + .strip = strip, + .stack_check = false, + .stack_protector = 0, + .sanitize_c = false, + .sanitize_thread = comp.config.any_sanitize_thread, + .red_zone = comp.root_mod.red_zone, + .omit_frame_pointer = comp.root_mod.omit_frame_pointer, + .valgrind = false, + .optimize_mode = optimize_mode, + .structured_cfg = comp.root_mod.structured_cfg, + .pic = comp.root_mod.pic, + }, + .global = config, + .cc_argv = &.{}, + .parent = null, + .builtin_mod = null, + }); + const sub_compilation = try Compilation.create(comp.gpa, .{ .local_cache_directory = comp.global_cache_directory, .global_cache_directory = comp.global_cache_directory, .zig_lib_directory = comp.zig_lib_directory, + .self_exe_path = comp.self_exe_path, .cache_mode = .whole, - .target = target, + .config = config, + .root_mod = root_mod, .root_name = root_name, - .main_mod = null, - .output_mode = output_mode, .thread_pool = comp.thread_pool, - .libc_installation = comp.bin_file.options.libc_installation, + .libc_installation = comp.libc_installation, .emit_bin = emit_bin, - .optimize_mode = comp.compilerRtOptMode(), - .link_mode = link_mode, - .want_sanitize_c = false, - .want_stack_check = false, - .want_stack_protector = 0, - .want_red_zone = comp.bin_file.options.red_zone, - .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer, - .want_valgrind = false, - .want_tsan = comp.bin_file.options.tsan, - .want_pic = comp.bin_file.options.pic, - .want_pie = null, - .want_lto = comp.bin_file.options.lto, - .function_sections = comp.bin_file.options.function_sections, .emit_h = null, - .strip = comp.compilerRtStrip(), - .is_native_os = comp.bin_file.options.is_native_os, - .is_native_abi = comp.bin_file.options.is_native_abi, - .self_exe_path = comp.self_exe_path, .c_source_files = c_source_files.items, .verbose_cc = comp.verbose_cc, - .verbose_link = comp.bin_file.options.verbose_link, + .verbose_link = comp.verbose_link, .verbose_air = comp.verbose_air, .verbose_llvm_ir = comp.verbose_llvm_ir, .verbose_llvm_bc = comp.verbose_llvm_bc, .verbose_cimport = comp.verbose_cimport, .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, .clang_passthrough_mode = comp.clang_passthrough_mode, - .link_libc = true, .skip_linker_dependencies = true, }); defer sub_compilation.destroy(); @@ -274,8 +299,8 @@ pub fn buildLibCXX(comp: *Compilation, prog_node: *std.Progress.Node) !void { assert(comp.libcxx_static_lib == null); comp.libcxx_static_lib = Compilation.CRTFile{ - .full_object_path = try sub_compilation.bin_file.options.emit.?.directory.join(comp.gpa, &[_][]const u8{ - sub_compilation.bin_file.options.emit.?.sub_path, + .full_object_path = try sub_compilation.bin_file.?.emit.directory.join(comp.gpa, &.{ + sub_compilation.bin_file.?.emit.sub_path, }), .lock = sub_compilation.bin_file.toOwnedLock(), }; @@ -296,7 +321,7 @@ pub fn buildLibCXXABI(comp: *Compilation, prog_node: *std.Progress.Node) !void { const root_name = "c++abi"; const output_mode = .Lib; const link_mode = .Static; - const target = comp.getTarget(); + const target = comp.root_mod.resolved_target.result; const basename = try std.zig.binNameAlloc(arena, .{ .root_name = root_name, .target = target, @@ -365,7 +390,6 @@ pub fn buildLibCXXABI(comp: *Compilation, prog_node: *std.Progress.Node) !void { } try cflags.append("-nostdinc++"); try cflags.append("-fstrict-aliasing"); - try cflags.append("-funwind-tables"); try cflags.append("-std=c++20"); // These depend on only the zig lib directory file path, which is @@ -389,46 +413,73 @@ pub fn buildLibCXXABI(comp: *Compilation, prog_node: *std.Progress.Node) !void { }); } + const optimize_mode = comp.compilerRtOptMode(); + const strip = comp.compilerRtStrip(); + const unwind_tables = true; + + const config = try Compilation.Config.resolve(.{ + .output_mode = output_mode, + .link_mode = link_mode, + .resolved_target = comp.root_mod.resolved_target, + .is_test = false, + .have_zcu = false, + .emit_bin = true, + .root_optimize_mode = optimize_mode, + .root_strip = strip, + .link_libc = true, + .any_unwind_tables = unwind_tables, + .lto = comp.config.lto, + }); + + const root_mod = try Module.create(arena, .{ + .global_cache_directory = comp.global_cache_directory, + .paths = .{ + .root = .{ .root_dir = comp.zig_lib_directory }, + .root_src_path = "", + }, + .fully_qualified_name = "root", + .inherited = .{ + .strip = strip, + .stack_check = false, + .stack_protector = 0, + .sanitize_c = false, + .sanitize_thread = comp.config.any_sanitize_thread, + .red_zone = comp.root_mod.red_zone, + .omit_frame_pointer = comp.root_mod.omit_frame_pointer, + .valgrind = false, + .optimize_mode = optimize_mode, + .structured_cfg = comp.root_mod.structured_cfg, + .unwind_tables = unwind_tables, + .pic = comp.root_mod.pic, + }, + .global = config, + .cc_argv = &.{}, + .parent = null, + .builtin_mod = null, + }); + const sub_compilation = try Compilation.create(comp.gpa, .{ .local_cache_directory = comp.global_cache_directory, .global_cache_directory = comp.global_cache_directory, .zig_lib_directory = comp.zig_lib_directory, + .self_exe_path = comp.self_exe_path, .cache_mode = .whole, - .target = target, + .config = config, + .root_mod = root_mod, .root_name = root_name, - .main_mod = null, - .output_mode = output_mode, .thread_pool = comp.thread_pool, - .libc_installation = comp.bin_file.options.libc_installation, + .libc_installation = comp.libc_installation, .emit_bin = emit_bin, - .optimize_mode = comp.compilerRtOptMode(), - .link_mode = link_mode, - .want_sanitize_c = false, - .want_stack_check = false, - .want_stack_protector = 0, - .want_red_zone = comp.bin_file.options.red_zone, - .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer, - .want_valgrind = false, - .want_tsan = comp.bin_file.options.tsan, - .want_pic = comp.bin_file.options.pic, - .want_pie = null, - .want_lto = comp.bin_file.options.lto, - .function_sections = comp.bin_file.options.function_sections, .emit_h = null, - .strip = comp.compilerRtStrip(), - .is_native_os = comp.bin_file.options.is_native_os, - .is_native_abi = comp.bin_file.options.is_native_abi, - .self_exe_path = comp.self_exe_path, .c_source_files = c_source_files.items, .verbose_cc = comp.verbose_cc, - .verbose_link = comp.bin_file.options.verbose_link, + .verbose_link = comp.verbose_link, .verbose_air = comp.verbose_air, .verbose_llvm_ir = comp.verbose_llvm_ir, .verbose_llvm_bc = comp.verbose_llvm_bc, .verbose_cimport = comp.verbose_cimport, .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, .clang_passthrough_mode = comp.clang_passthrough_mode, - .link_libc = true, .skip_linker_dependencies = true, }); defer sub_compilation.destroy(); @@ -437,8 +488,8 @@ pub fn buildLibCXXABI(comp: *Compilation, prog_node: *std.Progress.Node) !void { assert(comp.libcxxabi_static_lib == null); comp.libcxxabi_static_lib = Compilation.CRTFile{ - .full_object_path = try sub_compilation.bin_file.options.emit.?.directory.join(comp.gpa, &[_][]const u8{ - sub_compilation.bin_file.options.emit.?.sub_path, + .full_object_path = try sub_compilation.bin_file.?.emit.directory.join(comp.gpa, &[_][]const u8{ + sub_compilation.bin_file.?.emit.sub_path, }), .lock = sub_compilation.bin_file.toOwnedLock(), }; diff --git a/src/musl.zig b/src/musl.zig index e29d348d1f..249753d415 100644 --- a/src/musl.zig +++ b/src/musl.zig @@ -191,7 +191,6 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr return comp.build_crt_file("c", .Lib, .@"musl libc.a", prog_node, c_source_files.items); }, .libc_so => { - const unwind_tables = false; const optimize_mode = comp.compilerRtOptMode(); const strip = comp.compilerRtStrip(); const config = try Compilation.Config.resolve(.{ @@ -204,7 +203,6 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr .root_optimize_mode = optimize_mode, .root_strip = strip, .link_libc = false, - .any_unwind_tables = unwind_tables, }); const target = comp.root_mod.resolved_target.result; @@ -232,7 +230,6 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr .red_zone = comp.root_mod.red_zone, .omit_frame_pointer = comp.root_mod.omit_frame_pointer, .valgrind = false, - .unwind_tables = unwind_tables, .optimize_mode = optimize_mode, .structured_cfg = comp.root_mod.structured_cfg, }, -- cgit v1.2.3 From 0be97b5ae3d32ca9cd7fbb68d5972538b48d8c76 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 16 Dec 2023 01:49:57 -0700 Subject: fix population of builtin.zig not making the parent dir --- src/Builtin.zig | 2 +- src/Compilation.zig | 9 ++++++++- src/Package.zig | 10 ++++++++++ src/Package/Module.zig | 2 +- src/codegen/llvm.zig | 12 ++++++++++-- 5 files changed, 30 insertions(+), 5 deletions(-) (limited to 'src/Package/Module.zig') diff --git a/src/Builtin.zig b/src/Builtin.zig index 4c8038019c..f80f466302 100644 --- a/src/Builtin.zig +++ b/src/Builtin.zig @@ -276,7 +276,7 @@ pub fn populateFile(comp: *Compilation, mod: *Module, file: *File) !void { } fn writeFile(file: *File, mod: *Module) !void { - var af = try mod.root.atomicFile(mod.root_src_path, .{}); + var af = try mod.root.atomicFile(mod.root_src_path, .{ .make_path = true }); defer af.deinit(); try af.file.writeAll(file.source); try af.finish(); diff --git a/src/Compilation.zig b/src/Compilation.zig index fb6e5a44b0..20e2d1ce53 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -1119,6 +1119,11 @@ fn addModuleTableToCacheHash( var i: usize = 0; while (i < seen_table.count()) : (i += 1) { const mod = seen_table.keys()[i]; + if (mod.isBuiltin()) { + // Skip builtin.zig; it is useless as an input, and we don't want to + // have to write it before checking for a cache hit. + continue; + } cache_helpers.addResolvedTarget(hash, mod.resolved_target); hash.add(mod.optimize_mode); @@ -1133,6 +1138,8 @@ fn addModuleTableToCacheHash( hash.add(mod.red_zone); hash.add(mod.sanitize_c); hash.add(mod.sanitize_thread); + hash.add(mod.unwind_tables); + hash.add(mod.structured_cfg); switch (hash_type) { .path_bytes => { @@ -2371,7 +2378,6 @@ pub const link_hash_implementation_version = 10; fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifest) !void { const gpa = comp.gpa; - const target = comp.getTarget(); var arena_allocator = std.heap.ArenaAllocator.init(gpa); defer arena_allocator.deinit(); @@ -2432,6 +2438,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes man.hash.add(comp.include_compiler_rt); if (comp.config.link_libc) { man.hash.add(comp.libc_installation != null); + const target = comp.root_mod.resolved_target.result; if (comp.libc_installation) |libc_installation| { man.hash.addOptionalBytes(libc_installation.crt_dir); if (target.abi == .msvc) { diff --git a/src/Package.zig b/src/Package.zig index ab06ca9852..373b46e495 100644 --- a/src/Package.zig +++ b/src/Package.zig @@ -108,6 +108,16 @@ pub const Path = struct { return p.root_dir.handle.access(joined_path, flags); } + pub fn makePath(p: Path, sub_path: []const u8) !void { + var buf: [fs.MAX_PATH_BYTES]u8 = undefined; + const joined_path = if (p.sub_path.len == 0) sub_path else p: { + break :p std.fmt.bufPrint(&buf, "{s}" ++ fs.path.sep_str ++ "{s}", .{ + p.sub_path, sub_path, + }) catch return error.NameTooLong; + }; + return p.root_dir.handle.makePath(joined_path); + } + pub fn format( self: Path, comptime fmt_string: []const u8, diff --git a/src/Package/Module.zig b/src/Package/Module.zig index 4ce0f0a856..2d54c9296c 100644 --- a/src/Package/Module.zig +++ b/src/Package/Module.zig @@ -40,7 +40,7 @@ builtin_file: ?*File, pub const Deps = std.StringArrayHashMapUnmanaged(*Module); pub fn isBuiltin(m: Module) bool { - return m.file != null; + return m.builtin_file != null; } pub const Tree = struct { diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 3a53bddcb8..91c4faffcc 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -898,14 +898,22 @@ pub const Object = struct { // very location dependent. // TODO: the only concern I have with this is WASI as either host or target, should // we leave the paths as relative then? + // TODO: This is totally wrong. In dwarf, paths are encoded as relative to + // a particular directory, and then the directory path is specified elsewhere. + // In the compiler frontend we have it stored correctly in this + // way already, but here we throw all that sweet information + // into the garbage can by converting into absolute paths. What + // a terrible tragedy. const compile_unit_dir_z = blk: { if (comp.module) |zcu| m: { const d = try zcu.root_mod.root.joinStringZ(arena, ""); if (d.len == 0) break :m; if (std.fs.path.isAbsolute(d)) break :blk d; - break :blk std.fs.realpathAlloc(arena, d) catch d; + const realpath = std.fs.realpathAlloc(arena, d) catch break :blk d; + break :blk try arena.dupeZ(u8, realpath); } - break :blk try std.process.getCwdAlloc(arena); + const cwd = try std.process.getCwdAlloc(arena); + break :blk try arena.dupeZ(u8, cwd); }; builder.llvm.di_compile_unit = builder.llvm.di_builder.?.createCompileUnit( -- cgit v1.2.3 From f2564318385ea90b08af044ae32ddef26e6346bd Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 16 Dec 2023 15:22:31 -0700 Subject: fix compilation errors when enabling llvm --- src/Compilation.zig | 57 +++++++++++----- src/Module.zig | 2 +- src/Package/Module.zig | 76 +++++++++++---------- src/Sema.zig | 37 ++++++++-- src/glibc.zig | 23 ++++--- src/libcxx.zig | 182 +++++++++++++++++++++++++------------------------ src/libtsan.zig | 102 ++++++++++++++------------- src/libunwind.zig | 10 +-- src/link/Coff.zig | 4 ++ src/link/Coff/lld.zig | 23 +++---- src/link/Elf.zig | 20 +++--- src/main.zig | 2 +- src/mingw.zig | 21 ++++-- src/musl.zig | 39 +++++++---- src/wasi_libc.zig | 20 ++++-- 15 files changed, 363 insertions(+), 255 deletions(-) (limited to 'src/Package/Module.zig') diff --git a/src/Compilation.zig b/src/Compilation.zig index 7f3d696ecb..7314da3960 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -1410,7 +1410,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .inherited = .{}, .global = options.config, .parent = options.root_mod, - .builtin_mod = options.root_mod.deps.get("builtin").?, + .builtin_mod = options.root_mod.getBuiltinDependency(), }); const zcu = try arena.create(Module); @@ -3830,6 +3830,7 @@ pub fn obtainCObjectCacheManifest( // 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(owner_mod.sanitize_c); + man.hash.add(owner_mod.sanitize_thread); man.hash.addListOfBytes(owner_mod.cc_argv); man.hash.add(comp.config.link_libcpp); @@ -3970,10 +3971,13 @@ pub fn cImport(comp: *Compilation, c_src: []const u8, owner_mod: *Package.Module const dep_basename = std.fs.path.basename(out_dep_path); try man.addDepFilePost(zig_cache_tmp_dir, dep_basename); - if (comp.whole_cache_manifest) |whole_cache_manifest| { - comp.whole_cache_manifest_mutex.lock(); - defer comp.whole_cache_manifest_mutex.unlock(); - try whole_cache_manifest.addDepFilePost(zig_cache_tmp_dir, dep_basename); + switch (comp.cache_use) { + .whole => |whole| if (whole.cache_manifest) |whole_cache_manifest| { + whole.cache_manifest_mutex.lock(); + defer whole.cache_manifest_mutex.unlock(); + try whole_cache_manifest.addDepFilePost(zig_cache_tmp_dir, dep_basename); + }, + .incremental => {}, } const digest = man.final(); @@ -4425,10 +4429,15 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P const dep_basename = std.fs.path.basename(dep_file_path); // Add the files depended on to the cache system. try man.addDepFilePost(zig_cache_tmp_dir, dep_basename); - if (comp.whole_cache_manifest) |whole_cache_manifest| { - comp.whole_cache_manifest_mutex.lock(); - defer comp.whole_cache_manifest_mutex.unlock(); - try whole_cache_manifest.addDepFilePost(zig_cache_tmp_dir, dep_basename); + switch (comp.cache_use) { + .whole => |whole| { + if (whole.cache_manifest) |whole_cache_manifest| { + whole.cache_manifest_mutex.lock(); + defer whole.cache_manifest_mutex.unlock(); + try whole_cache_manifest.addDepFilePost(zig_cache_tmp_dir, dep_basename); + } + }, + .incremental => {}, } // Just to save disk space, we delete the file because it is never needed again. zig_cache_tmp_dir.deleteFile(dep_basename) catch |err| { @@ -4724,10 +4733,13 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32 const dep_basename = std.fs.path.basename(out_dep_path); // Add the files depended on to the cache system. try man.addDepFilePost(zig_cache_tmp_dir, dep_basename); - if (comp.whole_cache_manifest) |whole_cache_manifest| { - comp.whole_cache_manifest_mutex.lock(); - defer comp.whole_cache_manifest_mutex.unlock(); - try whole_cache_manifest.addDepFilePost(zig_cache_tmp_dir, dep_basename); + switch (comp.cache_use) { + .whole => |whole| if (whole.cache_manifest) |whole_cache_manifest| { + whole.cache_manifest_mutex.lock(); + defer whole.cache_manifest_mutex.unlock(); + try whole_cache_manifest.addDepFilePost(zig_cache_tmp_dir, dep_basename); + }, + .incremental => {}, } // Just to save disk space, we delete the file because it is never needed again. zig_cache_tmp_dir.deleteFile(dep_basename) catch |err| { @@ -4799,10 +4811,13 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32 for (dependencies_list.items) |dep_file_path| { try man.addFilePost(dep_file_path); - if (comp.whole_cache_manifest) |whole_cache_manifest| { - comp.whole_cache_manifest_mutex.lock(); - defer comp.whole_cache_manifest_mutex.unlock(); - try whole_cache_manifest.addFilePost(dep_file_path); + switch (comp.cache_use) { + .whole => |whole| if (whole.cache_manifest) |whole_cache_manifest| { + whole.cache_manifest_mutex.lock(); + defer whole.cache_manifest_mutex.unlock(); + try whole_cache_manifest.addFilePost(dep_file_path); + }, + .incremental => {}, } } @@ -6247,7 +6262,9 @@ pub fn build_crt_file( output_mode: std.builtin.OutputMode, misc_task_tag: MiscTask, prog_node: *std.Progress.Node, - c_source_files: []const CSourceFile, + /// These elements have to get mutated to add the owner module after it is + /// created within this function. + c_source_files: []CSourceFile, ) !void { const tracy_trace = trace(@src()); defer tracy_trace.end(); @@ -6305,6 +6322,10 @@ pub fn build_crt_file( .builtin_mod = null, }); + for (c_source_files) |*item| { + item.owner = root_mod; + } + const sub_compilation = try Compilation.create(gpa, .{ .local_cache_directory = comp.global_cache_directory, .global_cache_directory = comp.global_cache_directory, diff --git a/src/Module.zig b/src/Module.zig index 6d5a2f78a6..f2049df378 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -5275,7 +5275,7 @@ pub fn populateTestFunctions( ) !void { const gpa = mod.gpa; const ip = &mod.intern_pool; - const builtin_mod = mod.main_mod.deps.get("builtin").?; + const builtin_mod = mod.main_mod.getBuiltinDependency(); const builtin_file = (mod.importPkg(builtin_mod) catch unreachable).file; const root_decl = mod.declPtr(builtin_file.root_decl.unwrap().?); const builtin_namespace = mod.namespacePtr(root_decl.src_namespace); diff --git a/src/Package/Module.zig b/src/Package/Module.zig index 2d54c9296c..0ebd951cc6 100644 --- a/src/Package/Module.zig +++ b/src/Package/Module.zig @@ -310,7 +310,39 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module { break :b buf.items[0 .. buf.items.len - 1 :0].ptr; }; - const builtin_mod = options.builtin_mod orelse b: { + const mod = try arena.create(Module); + mod.* = .{ + .root = options.paths.root, + .root_src_path = options.paths.root_src_path, + .fully_qualified_name = options.fully_qualified_name, + .resolved_target = .{ + .result = target, + .is_native_os = resolved_target.is_native_os, + .is_native_abi = resolved_target.is_native_abi, + .llvm_cpu_features = llvm_cpu_features, + }, + .optimize_mode = optimize_mode, + .single_threaded = single_threaded, + .error_tracing = error_tracing, + .valgrind = valgrind, + .pic = pic, + .strip = strip, + .omit_frame_pointer = omit_frame_pointer, + .stack_check = stack_check, + .stack_protector = stack_protector, + .code_model = code_model, + .red_zone = red_zone, + .sanitize_c = sanitize_c, + .sanitize_thread = sanitize_thread, + .unwind_tables = unwind_tables, + .cc_argv = options.cc_argv, + .structured_cfg = structured_cfg, + .builtin_file = null, + }; + + const opt_builtin_mod = options.builtin_mod orelse b: { + if (!options.global.have_zcu) break :b null; + const generated_builtin_source = try Builtin.generate(.{ .target = target, .zig_backend = zig_backend, @@ -388,38 +420,10 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module { break :b new; }; - const mod = try arena.create(Module); - mod.* = .{ - .root = options.paths.root, - .root_src_path = options.paths.root_src_path, - .fully_qualified_name = options.fully_qualified_name, - .resolved_target = .{ - .result = target, - .is_native_os = resolved_target.is_native_os, - .is_native_abi = resolved_target.is_native_abi, - .llvm_cpu_features = llvm_cpu_features, - }, - .optimize_mode = optimize_mode, - .single_threaded = single_threaded, - .error_tracing = error_tracing, - .valgrind = valgrind, - .pic = pic, - .strip = strip, - .omit_frame_pointer = omit_frame_pointer, - .stack_check = stack_check, - .stack_protector = stack_protector, - .code_model = code_model, - .red_zone = red_zone, - .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); - mod.deps.putAssumeCapacityNoClobber("builtin", builtin_mod); + if (opt_builtin_mod) |builtin_mod| { + try mod.deps.ensureUnusedCapacity(arena, 1); + mod.deps.putAssumeCapacityNoClobber("builtin", builtin_mod); + } return mod; } @@ -462,8 +466,10 @@ pub fn createLimited(gpa: Allocator, options: LimitedOptions) Allocator.Error!*P return mod; } -pub fn getBuiltinDependency(m: *Module) *Module { - return m.deps.values()[0]; +pub fn getBuiltinDependency(m: Module) *Module { + const result = m.deps.values()[0]; + assert(result.isBuiltin()); + return result; } const Module = @This(); diff --git a/src/Sema.zig b/src/Sema.zig index 26afd285c7..c2e05e4a2c 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -5759,14 +5759,39 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr }; return sema.failWithOwnedErrorMsg(&child_block, msg); } - const c_import_mod = try Package.Module.create(comp.arena.allocator(), .{ - .root = .{ - .root_dir = Compilation.Directory.cwd(), - .sub_path = std.fs.path.dirname(c_import_res.out_zig_path) orelse "", + const parent_mod = parent_block.ownerModule(); + const c_import_mod = Package.Module.create(comp.arena.allocator(), .{ + .global_cache_directory = comp.global_cache_directory, + .paths = .{ + .root = .{ + .root_dir = Compilation.Directory.cwd(), + .sub_path = std.fs.path.dirname(c_import_res.out_zig_path) orelse "", + }, + .root_src_path = std.fs.path.basename(c_import_res.out_zig_path), }, - .root_src_path = std.fs.path.basename(c_import_res.out_zig_path), .fully_qualified_name = c_import_res.out_zig_path, - }); + .cc_argv = parent_mod.cc_argv, + .inherited = .{}, + .global = comp.config, + .parent = parent_mod, + .builtin_mod = parent_mod.getBuiltinDependency(), + }) catch |err| switch (err) { + // None of these are possible because we are creating a package with + // the exact same configuration as the parent package, which already + // passed these checks. + error.ValgrindUnsupportedOnTarget => unreachable, + error.TargetRequiresSingleThreaded => unreachable, + error.BackendRequiresSingleThreaded => unreachable, + error.TargetRequiresPic => unreachable, + error.PieRequiresPic => unreachable, + error.DynamicLinkingRequiresPic => unreachable, + error.TargetHasNoRedZone => unreachable, + error.StackCheckUnsupportedByTarget => unreachable, + error.StackProtectorUnsupportedByTarget => unreachable, + error.StackProtectorUnavailableWithoutLibC => unreachable, + + else => |e| return e, + }; const result = mod.importPkg(c_import_mod) catch |err| return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)}); diff --git a/src/glibc.zig b/src/glibc.zig index 0502bc3799..d478c6e939 100644 --- a/src/glibc.zig +++ b/src/glibc.zig @@ -170,7 +170,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr defer arena_allocator.deinit(); const arena = arena_allocator.allocator(); - const target = comp.getTarget(); + const target = comp.root_mod.resolved_target.result; const target_ver = target.os.version_range.linux.glibc; const start_old_init_fini = target_ver.order(.{ .major = 2, .minor = 33, .patch = 0 }) != .gt; @@ -196,12 +196,14 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr "-DASSEMBLER", "-Wa,--noexecstack", }); - return comp.build_crt_file("crti", .Obj, .@"glibc crti.o", prog_node, &.{ + var files = [_]Compilation.CSourceFile{ .{ .src_path = try start_asm_path(comp, arena, "crti.S"), .cache_exempt_flags = args.items, + .owner = comp.root_mod, }, - }); + }; + return comp.build_crt_file("crti", .Obj, .@"glibc crti.o", prog_node, &files); }, .crtn_o => { var args = std.ArrayList([]const u8).init(arena); @@ -215,12 +217,14 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr "-DASSEMBLER", "-Wa,--noexecstack", }); - return comp.build_crt_file("crtn", .Obj, .@"glibc crtn.o", prog_node, &.{ + var files = [_]Compilation.CSourceFile{ .{ .src_path = try start_asm_path(comp, arena, "crtn.S"), .cache_exempt_flags = args.items, + .owner = undefined, }, - }); + }; + return comp.build_crt_file("crtn", .Obj, .@"glibc crtn.o", prog_node, &files); }, .scrt1_o => { const start_o: Compilation.CSourceFile = blk: { @@ -244,6 +248,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr break :blk .{ .src_path = try start_asm_path(comp, arena, src_path), .cache_exempt_flags = args.items, + .owner = undefined, }; }; const abi_note_o: Compilation.CSourceFile = blk: { @@ -263,11 +268,11 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr break :blk .{ .src_path = try lib_path(comp, arena, lib_libc_glibc ++ "csu" ++ path.sep_str ++ "abi-note.S"), .cache_exempt_flags = args.items, + .owner = undefined, }; }; - return comp.build_crt_file("Scrt1", .Obj, .@"glibc Scrt1.o", prog_node, &.{ - start_o, abi_note_o, - }); + var files = [_]Compilation.CSourceFile{ start_o, abi_note_o }; + return comp.build_crt_file("Scrt1", .Obj, .@"glibc Scrt1.o", prog_node, &files); }, .libc_nonshared_a => { const s = path.sep_str; @@ -364,6 +369,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr files_buf[files_index] = .{ .src_path = try lib_path(comp, arena, dep.path), .cache_exempt_flags = args.items, + .owner = undefined, }; files_index += 1; } @@ -1065,6 +1071,7 @@ fn buildSharedLib( const c_source_files = [1]Compilation.CSourceFile{ .{ .src_path = try path.join(arena, &[_][]const u8{ bin_directory.path.?, asm_file_basename }), + .owner = undefined, }, }; diff --git a/src/libcxx.zig b/src/libcxx.zig index aedb1f3930..abcbc0187e 100644 --- a/src/libcxx.zig +++ b/src/libcxx.zig @@ -138,6 +138,50 @@ pub fn buildLibCXX(comp: *Compilation, prog_node: *std.Progress.Node) !void { const abi_namespace_arg = try std.fmt.allocPrint(arena, "-D_LIBCPP_ABI_NAMESPACE=__{d}", .{ @intFromEnum(comp.libcxx_abi_version), }); + + const optimize_mode = comp.compilerRtOptMode(); + const strip = comp.compilerRtStrip(); + + const config = try Compilation.Config.resolve(.{ + .output_mode = output_mode, + .link_mode = link_mode, + .resolved_target = comp.root_mod.resolved_target, + .is_test = false, + .have_zcu = false, + .emit_bin = true, + .root_optimize_mode = optimize_mode, + .root_strip = strip, + .link_libc = true, + .lto = comp.config.lto, + }); + + const root_mod = try Module.create(arena, .{ + .global_cache_directory = comp.global_cache_directory, + .paths = .{ + .root = .{ .root_dir = comp.zig_lib_directory }, + .root_src_path = "", + }, + .fully_qualified_name = "root", + .inherited = .{ + .resolved_target = comp.root_mod.resolved_target, + .strip = strip, + .stack_check = false, + .stack_protector = 0, + .sanitize_c = false, + .sanitize_thread = comp.config.any_sanitize_thread, + .red_zone = comp.root_mod.red_zone, + .omit_frame_pointer = comp.root_mod.omit_frame_pointer, + .valgrind = false, + .optimize_mode = optimize_mode, + .structured_cfg = comp.root_mod.structured_cfg, + .pic = comp.root_mod.pic, + }, + .global = config, + .cc_argv = &.{}, + .parent = null, + .builtin_mod = null, + }); + var c_source_files = try std.ArrayList(Compilation.CSourceFile).initCapacity(arena, libcxx_files.len); for (libcxx_files) |cxx_src| { @@ -224,52 +268,10 @@ pub fn buildLibCXX(comp: *Compilation, prog_node: *std.Progress.Node) !void { .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libcxx", cxx_src }), .extra_flags = cflags.items, .cache_exempt_flags = cache_exempt_flags.items, + .owner = root_mod, }); } - const optimize_mode = comp.compilerRtOptMode(); - const strip = comp.compilerRtStrip(); - - const config = try Compilation.Config.resolve(.{ - .output_mode = output_mode, - .link_mode = link_mode, - .resolved_target = comp.root_mod.resolved_target, - .is_test = false, - .have_zcu = false, - .emit_bin = true, - .root_optimize_mode = optimize_mode, - .root_strip = strip, - .link_libc = true, - .lto = comp.config.lto, - }); - - const root_mod = try Module.create(arena, .{ - .global_cache_directory = comp.global_cache_directory, - .paths = .{ - .root = .{ .root_dir = comp.zig_lib_directory }, - .root_src_path = "", - }, - .fully_qualified_name = "root", - .inherited = .{ - .resolved_target = comp.root_mod.resolved_target, - .strip = strip, - .stack_check = false, - .stack_protector = 0, - .sanitize_c = false, - .sanitize_thread = comp.config.any_sanitize_thread, - .red_zone = comp.root_mod.red_zone, - .omit_frame_pointer = comp.root_mod.omit_frame_pointer, - .valgrind = false, - .optimize_mode = optimize_mode, - .structured_cfg = comp.root_mod.structured_cfg, - .pic = comp.root_mod.pic, - }, - .global = config, - .cc_argv = &.{}, - .parent = null, - .builtin_mod = null, - }); - const sub_compilation = try Compilation.create(comp.gpa, .{ .local_cache_directory = comp.global_cache_directory, .global_cache_directory = comp.global_cache_directory, @@ -339,6 +341,53 @@ pub fn buildLibCXXABI(comp: *Compilation, prog_node: *std.Progress.Node) !void { const abi_namespace_arg = try std.fmt.allocPrint(arena, "-D_LIBCPP_ABI_NAMESPACE=__{d}", .{ @intFromEnum(comp.libcxx_abi_version), }); + + const optimize_mode = comp.compilerRtOptMode(); + const strip = comp.compilerRtStrip(); + const unwind_tables = true; + + const config = try Compilation.Config.resolve(.{ + .output_mode = output_mode, + .link_mode = link_mode, + .resolved_target = comp.root_mod.resolved_target, + .is_test = false, + .have_zcu = false, + .emit_bin = true, + .root_optimize_mode = optimize_mode, + .root_strip = strip, + .link_libc = true, + .any_unwind_tables = unwind_tables, + .lto = comp.config.lto, + }); + + const root_mod = try Module.create(arena, .{ + .global_cache_directory = comp.global_cache_directory, + .paths = .{ + .root = .{ .root_dir = comp.zig_lib_directory }, + .root_src_path = "", + }, + .fully_qualified_name = "root", + .inherited = .{ + .resolved_target = comp.root_mod.resolved_target, + .strip = strip, + .stack_check = false, + .stack_protector = 0, + .sanitize_c = false, + .sanitize_thread = comp.config.any_sanitize_thread, + .red_zone = comp.root_mod.red_zone, + .omit_frame_pointer = comp.root_mod.omit_frame_pointer, + .valgrind = false, + .optimize_mode = optimize_mode, + .structured_cfg = comp.root_mod.structured_cfg, + .unwind_tables = unwind_tables, + .pic = comp.root_mod.pic, + }, + .global = config, + .cc_argv = &.{}, + .parent = null, + .builtin_mod = null, + }); + var c_source_files = try std.ArrayList(Compilation.CSourceFile).initCapacity(arena, libcxxabi_files.len); for (libcxxabi_files) |cxxabi_src| { @@ -406,55 +455,10 @@ pub fn buildLibCXXABI(comp: *Compilation, prog_node: *std.Progress.Node) !void { .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libcxxabi", cxxabi_src }), .extra_flags = cflags.items, .cache_exempt_flags = cache_exempt_flags.items, + .owner = root_mod, }); } - const optimize_mode = comp.compilerRtOptMode(); - const strip = comp.compilerRtStrip(); - const unwind_tables = true; - - const config = try Compilation.Config.resolve(.{ - .output_mode = output_mode, - .link_mode = link_mode, - .resolved_target = comp.root_mod.resolved_target, - .is_test = false, - .have_zcu = false, - .emit_bin = true, - .root_optimize_mode = optimize_mode, - .root_strip = strip, - .link_libc = true, - .any_unwind_tables = unwind_tables, - .lto = comp.config.lto, - }); - - const root_mod = try Module.create(arena, .{ - .global_cache_directory = comp.global_cache_directory, - .paths = .{ - .root = .{ .root_dir = comp.zig_lib_directory }, - .root_src_path = "", - }, - .fully_qualified_name = "root", - .inherited = .{ - .resolved_target = comp.root_mod.resolved_target, - .strip = strip, - .stack_check = false, - .stack_protector = 0, - .sanitize_c = false, - .sanitize_thread = comp.config.any_sanitize_thread, - .red_zone = comp.root_mod.red_zone, - .omit_frame_pointer = comp.root_mod.omit_frame_pointer, - .valgrind = false, - .optimize_mode = optimize_mode, - .structured_cfg = comp.root_mod.structured_cfg, - .unwind_tables = unwind_tables, - .pic = comp.root_mod.pic, - }, - .global = config, - .cc_argv = &.{}, - .parent = null, - .builtin_mod = null, - }); - const sub_compilation = try Compilation.create(comp.gpa, .{ .local_cache_directory = comp.global_cache_directory, .global_cache_directory = comp.global_cache_directory, diff --git a/src/libtsan.zig b/src/libtsan.zig index 553597e485..a736c32713 100644 --- a/src/libtsan.zig +++ b/src/libtsan.zig @@ -34,6 +34,52 @@ pub fn buildTsan(comp: *Compilation, prog_node: *std.Progress.Node) !void { .basename = basename, }; + const optimize_mode = comp.compilerRtOptMode(); + const strip = comp.compilerRtStrip(); + + const config = try Compilation.Config.resolve(.{ + .output_mode = output_mode, + .link_mode = link_mode, + .resolved_target = comp.root_mod.resolved_target, + .is_test = false, + .have_zcu = false, + .emit_bin = true, + .root_optimize_mode = optimize_mode, + .root_strip = strip, + .link_libc = true, + }); + + const common_flags = [_][]const u8{ + "-DTSAN_CONTAINS_UBSAN=0", + }; + + const root_mod = try Module.create(arena, .{ + .global_cache_directory = comp.global_cache_directory, + .paths = .{ + .root = .{ .root_dir = comp.zig_lib_directory }, + .root_src_path = "", + }, + .fully_qualified_name = "root", + .inherited = .{ + .resolved_target = comp.root_mod.resolved_target, + .strip = strip, + .stack_check = false, + .stack_protector = 0, + .sanitize_c = false, + .sanitize_thread = false, + .red_zone = comp.root_mod.red_zone, + .omit_frame_pointer = comp.root_mod.omit_frame_pointer, + .valgrind = false, + .optimize_mode = optimize_mode, + .structured_cfg = comp.root_mod.structured_cfg, + .pic = true, + }, + .global = config, + .cc_argv = &common_flags, + .parent = null, + .builtin_mod = null, + }); + var c_source_files = std.ArrayList(Compilation.CSourceFile).init(arena); try c_source_files.ensureUnusedCapacity(tsan_sources.len); @@ -50,8 +96,9 @@ pub fn buildTsan(comp: *Compilation, prog_node: *std.Progress.Node) !void { try cflags.append("-fno-rtti"); c_source_files.appendAssumeCapacity(.{ - .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "tsan", tsan_src }), + .src_path = try comp.zig_lib_directory.join(arena, &.{ "tsan", tsan_src }), .extra_flags = cflags.items, + .owner = root_mod, }); } @@ -74,6 +121,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: *std.Progress.Node) !void { c_source_files.appendAssumeCapacity(.{ .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "tsan", tsan_src }), .extra_flags = cflags.items, + .owner = root_mod, }); } { @@ -94,6 +142,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: *std.Progress.Node) !void { c_source_files.appendAssumeCapacity(.{ .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "tsan", asm_source }), .extra_flags = cflags.items, + .owner = root_mod, }); } @@ -117,6 +166,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: *std.Progress.Node) !void { "tsan", "sanitizer_common", common_src, }), .extra_flags = cflags.items, + .owner = root_mod, }); } @@ -141,6 +191,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: *std.Progress.Node) !void { "tsan", "sanitizer_common", c_src, }), .extra_flags = cflags.items, + .owner = root_mod, }); } @@ -161,6 +212,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: *std.Progress.Node) !void { "tsan", "sanitizer_common", c_src, }), .extra_flags = cflags.items, + .owner = root_mod, }); } @@ -189,56 +241,10 @@ pub fn buildTsan(comp: *Compilation, prog_node: *std.Progress.Node) !void { "tsan", "interception", c_src, }), .extra_flags = cflags.items, + .owner = root_mod, }); } - const common_flags = [_][]const u8{ - "-DTSAN_CONTAINS_UBSAN=0", - }; - - const optimize_mode = comp.compilerRtOptMode(); - const strip = comp.compilerRtStrip(); - - const config = try Compilation.Config.resolve(.{ - .output_mode = output_mode, - .link_mode = link_mode, - .resolved_target = comp.root_mod.resolved_target, - .is_test = false, - .have_zcu = false, - .emit_bin = true, - .root_optimize_mode = optimize_mode, - .root_strip = strip, - .link_libc = true, - }); - - const root_mod = try Module.create(arena, .{ - .global_cache_directory = comp.global_cache_directory, - .paths = .{ - .root = .{ .root_dir = comp.zig_lib_directory }, - .root_src_path = "", - }, - .fully_qualified_name = "root", - .inherited = .{ - .resolved_target = comp.root_mod.resolved_target, - .strip = strip, - .stack_check = false, - .stack_protector = 0, - .sanitize_c = false, - .sanitize_thread = false, - .red_zone = comp.root_mod.red_zone, - .omit_frame_pointer = comp.root_mod.omit_frame_pointer, - .valgrind = false, - .optimize_mode = optimize_mode, - .structured_cfg = comp.root_mod.structured_cfg, - .pic = true, - .cc_argv = &common_flags, - }, - .global = config, - .cc_argv = &.{}, - .parent = null, - .builtin_mod = null, - }); - const sub_compilation = try Compilation.create(comp.gpa, .{ .local_cache_directory = comp.global_cache_directory, .global_cache_directory = comp.global_cache_directory, diff --git a/src/libunwind.zig b/src/libunwind.zig index c59b5255d2..0f23f8b352 100644 --- a/src/libunwind.zig +++ b/src/libunwind.zig @@ -33,7 +33,8 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: *std.Progress.Node) !void { // Disable LTO to avoid https://github.com/llvm/llvm-project/issues/56825 .lto = false, }); - const root_mod = Module.create(.{ + const root_mod = try Module.create(arena, .{ + .global_cache_directory = comp.global_cache_directory, .paths = .{ .root = .{ .root_dir = comp.zig_lib_directory }, .root_src_path = "", @@ -55,6 +56,8 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: *std.Progress.Node) !void { }, .global = config, .cc_argv = &.{}, + .parent = null, + .builtin_mod = null, }); const root_name = "unwind"; @@ -117,6 +120,7 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: *std.Progress.Node) !void { c_source_files[i] = .{ .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{unwind_src}), .extra_flags = cflags.items, + .owner = root_mod, }; } const sub_compilation = try Compilation.create(comp.gpa, .{ @@ -132,7 +136,6 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: *std.Progress.Node) !void { .thread_pool = comp.thread_pool, .libc_installation = comp.libc_installation, .emit_bin = emit_bin, - .link_mode = link_mode, .function_sections = comp.function_sections, .c_source_files = &c_source_files, .verbose_cc = comp.verbose_cc, @@ -150,8 +153,7 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: *std.Progress.Node) !void { try comp.updateSubCompilation(sub_compilation, .libunwind, prog_node); assert(comp.libunwind_static_lib == null); - - comp.libunwind_static_lib = try sub_compilation.toOwnedLock(); + comp.libunwind_static_lib = try sub_compilation.toCrtFile(); } const unwind_src_list = [_][]const u8{ diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 98c649ca84..b6a3979122 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -18,6 +18,8 @@ major_subsystem_version: u16, minor_subsystem_version: u16, lib_dirs: []const []const u8, entry_addr: ?u32, +module_definition_file: ?[]const u8, +pdb_out_path: ?[]const u8, ptr_width: PtrWidth, page_size: u32, @@ -425,6 +427,8 @@ pub fn createEmpty( .lib_dirs = options.lib_dirs, .entry_addr = math.cast(u32, options.entry_addr orelse 0) orelse return error.EntryAddressTooBig, + .module_definition_file = options.module_definition_file, + .pdb_out_path = options.pdb_out_path, }; const use_llvm = comp.config.use_llvm; diff --git a/src/link/Coff/lld.zig b/src/link/Coff/lld.zig index a94644a41e..39e6d5288d 100644 --- a/src/link/Coff/lld.zig +++ b/src/link/Coff/lld.zig @@ -82,7 +82,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod try man.addOptionalFile(module_obj_path); man.hash.addOptionalBytes(comp.config.entry); man.hash.add(self.base.stack_size); - man.hash.addOptional(self.image_base); + man.hash.add(self.image_base); man.hash.addListOfBytes(self.lib_dirs); man.hash.add(comp.skip_linker_dependencies); if (comp.config.link_libc) { @@ -102,10 +102,10 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod man.hash.add(self.tsaware); man.hash.add(self.nxcompat); man.hash.add(self.dynamicbase); - man.hash.addOptional(self.base.allow_shlib_undefined); + man.hash.add(self.base.allow_shlib_undefined); // strip does not need to go into the linker hash because it is part of the hash namespace - man.hash.addOptional(self.major_subsystem_version); - man.hash.addOptional(self.minor_subsystem_version); + man.hash.add(self.major_subsystem_version); + man.hash.add(self.minor_subsystem_version); man.hash.addOptional(comp.version); try man.addOptionalFile(self.module_definition_file); @@ -237,7 +237,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod try argv.append(try allocPrint(arena, "-OUT:{s}", .{full_out_path})); - if (self.implib_emit) |emit| { + if (comp.implib_emit) |emit| { const implib_out_path = try emit.directory.join(arena, &[_][]const u8{emit.sub_path}); try argv.append(try allocPrint(arena, "-IMPLIB:{s}", .{implib_out_path})); } @@ -310,16 +310,9 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod const Mode = enum { uefi, win32 }; const mode: Mode = mode: { if (resolved_subsystem) |subsystem| { - const subsystem_suffix = ss: { - if (self.major_subsystem_version) |major| { - if (self.minor_subsystem_version) |minor| { - break :ss try allocPrint(arena, ",{d}.{d}", .{ major, minor }); - } else { - break :ss try allocPrint(arena, ",{d}", .{major}); - } - } - break :ss ""; - }; + const subsystem_suffix = try allocPrint(arena, ",{d}.{d}", .{ + self.major_subsystem_version, self.minor_subsystem_version, + }); switch (subsystem) { .Console => { diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 52e08af665..e5e5c98ec0 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -23,6 +23,8 @@ soname: ?[]const u8, bind_global_refs_locally: bool, linker_script: ?[]const u8, version_script: ?[]const u8, +print_icf_sections: bool, +print_map: bool, ptr_width: PtrWidth, @@ -307,6 +309,8 @@ pub fn createEmpty( .bind_global_refs_locally = options.bind_global_refs_locally, .linker_script = options.linker_script, .version_script = options.version_script, + .print_icf_sections = options.print_icf_sections, + .print_map = options.print_map, }; if (use_llvm and comp.config.have_zcu) { self.llvm_object = try LlvmObject.create(arena, comp); @@ -1294,12 +1298,9 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node // Look for entry address in objects if not set by the incremental compiler. if (self.entry_index == null) { - const entry: ?[]const u8 = entry: { - if (comp.config.entry) |entry| break :entry entry; - if (!self.base.isDynLib()) break :entry "_start"; - break :entry null; - }; - self.entry_index = if (entry) |name| self.globalByName(name) else null; + if (comp.config.entry) |name| { + self.entry_index = self.globalByName(name); + } } if (self.base.gc_sections) { @@ -2420,7 +2421,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v // We can skip hashing libc and libc++ components that we are in charge of building from Zig // installation sources because they are always a product of the compiler version + target information. man.hash.addOptionalBytes(comp.config.entry); - man.hash.addOptional(self.image_base); + man.hash.add(self.image_base); man.hash.add(self.base.gc_sections); man.hash.addOptional(self.sort_section); man.hash.add(self.eh_frame_hdr); @@ -5896,7 +5897,7 @@ pub fn addSymbol(self: *Elf) !Symbol.Index { break :blk index; } else { log.debug(" (allocating symbol index {d})", .{self.symbols.items.len}); - const index = @as(Symbol.Index, @intCast(self.symbols.items.len)); + const index: Symbol.Index = @intCast(self.symbols.items.len); _ = self.symbols.addOneAssumeCapacity(); break :blk index; } @@ -5961,6 +5962,7 @@ pub fn getOrPutGlobal(self: *Elf, name: []const u8) !GetOrPutGlobalResult { const gop = try self.resolver.getOrPut(gpa, name_off); if (!gop.found_existing) { const index = try self.addSymbol(); + log.debug("added symbol '{s}' at index {d}", .{ name, index }); const global = self.symbol(index); global.name_offset = name_off; global.flags.global = true; @@ -5996,7 +5998,7 @@ pub fn getOrCreateComdatGroupOwner(self: *Elf, name: [:0]const u8) !GetOrCreateC const off = try self.strings.insert(gpa, name); const gop = try self.comdat_groups_table.getOrPut(gpa, off); if (!gop.found_existing) { - const index = @as(ComdatGroupOwner.Index, @intCast(self.comdat_groups_owners.items.len)); + const index: ComdatGroupOwner.Index = @intCast(self.comdat_groups_owners.items.len); const owner = try self.comdat_groups_owners.addOne(gpa); owner.* = .{}; gop.value_ptr.* = index; diff --git a/src/main.zig b/src/main.zig index f412658a67..a65c8959b3 100644 --- a/src/main.zig +++ b/src/main.zig @@ -3481,7 +3481,7 @@ fn buildOutputType( defer if (!comp_destroyed) comp.destroy(); if (show_builtin) { - const builtin_mod = comp.root_mod.deps.get("builtin").?; + const builtin_mod = comp.root_mod.getBuiltinDependency(); const source = builtin_mod.builtin_file.?.source; return std.io.getStdOut().writeAll(source); } diff --git a/src/mingw.zig b/src/mingw.zig index 5a36e00824..fb8972df21 100644 --- a/src/mingw.zig +++ b/src/mingw.zig @@ -41,14 +41,16 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr //"-D_UNICODE", //"-DWPRFLAG=1", }); - return comp.build_crt_file("crt2", .Obj, .@"mingw-w64 crt2.o", prog_node, &.{ + var files = [_]Compilation.CSourceFile{ .{ .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", "mingw", "crt", "crtexe.c", }), .extra_flags = args.items, + .owner = undefined, }, - }); + }; + return comp.build_crt_file("crt2", .Obj, .@"mingw-w64 crt2.o", prog_node, &files); }, .dllcrt2_o => { @@ -60,14 +62,16 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr "-U__CRTDLL__", "-D__MSVCRT__", }); - return comp.build_crt_file("dllcrt2", .Obj, .@"mingw-w64 dllcrt2.o", prog_node, &.{ + var files = [_]Compilation.CSourceFile{ .{ .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", "mingw", "crt", "crtdll.c", }), .extra_flags = args.items, + .owner = undefined, }, - }); + }; + return comp.build_crt_file("dllcrt2", .Obj, .@"mingw-w64 dllcrt2.o", prog_node, &files); }, .mingw32_lib => { @@ -97,6 +101,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr "libc", "mingw", "crt", dep, }), .extra_flags = args.items, + .owner = undefined, }; } return comp.build_crt_file("mingw32", .Lib, .@"mingw-w64 mingw32.lib", prog_node, &c_source_files); @@ -125,6 +130,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr (try c_source_files.addOne()).* = .{ .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", "mingw", dep }), .extra_flags = extra_flags, + .owner = undefined, }; } if (comp.getTarget().cpu.arch == .x86) { @@ -134,6 +140,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr "libc", "mingw", dep, }), .extra_flags = extra_flags, + .owner = undefined, }; } } else { @@ -143,6 +150,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr "libc", "mingw", dep, }), .extra_flags = extra_flags, + .owner = undefined, }; } } @@ -175,6 +183,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr "libc", "mingw", dep, }), .extra_flags = extra_flags, + .owner = undefined, }; } const target = comp.getTarget(); @@ -185,6 +194,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr "libc", "mingw", dep, }), .extra_flags = extra_flags, + .owner = undefined, }; } } else if (target.cpu.arch.isARM()) { @@ -194,6 +204,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr "libc", "mingw", dep, }), .extra_flags = extra_flags, + .owner = undefined, }; } } else if (target.cpu.arch.isAARCH64()) { @@ -203,6 +214,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr "libc", "mingw", dep, }), .extra_flags = extra_flags, + .owner = undefined, }; } } else { @@ -238,6 +250,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr "libc", "mingw", "libsrc", dep, }), .extra_flags = extra_flags, + .owner = undefined, }; } return comp.build_crt_file("uuid", .Lib, .@"mingw-w64 uuid.lib", prog_node, &c_source_files); diff --git a/src/musl.zig b/src/musl.zig index ce5c5b23dd..4a62d5eded 100644 --- a/src/musl.zig +++ b/src/musl.zig @@ -34,12 +34,14 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr try args.appendSlice(&[_][]const u8{ "-Qunused-arguments", }); - return comp.build_crt_file("crti", .Obj, .@"musl crti.o", prog_node, &.{ + var files = [_]Compilation.CSourceFile{ .{ .src_path = try start_asm_path(comp, arena, "crti.s"), .extra_flags = args.items, + .owner = undefined, }, - }); + }; + return comp.build_crt_file("crti", .Obj, .@"musl crti.o", prog_node, &files); }, .crtn_o => { var args = std.ArrayList([]const u8).init(arena); @@ -47,12 +49,14 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr try args.appendSlice(&[_][]const u8{ "-Qunused-arguments", }); - return comp.build_crt_file("crtn", .Obj, .@"musl crtn.o", prog_node, &.{ + var files = [_]Compilation.CSourceFile{ .{ .src_path = try start_asm_path(comp, arena, "crtn.s"), .extra_flags = args.items, + .owner = undefined, }, - }); + }; + return comp.build_crt_file("crtn", .Obj, .@"musl crtn.o", prog_node, &files); }, .crt1_o => { var args = std.ArrayList([]const u8).init(arena); @@ -61,14 +65,16 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr "-fno-stack-protector", "-DCRT", }); - return comp.build_crt_file("crt1", .Obj, .@"musl crt1.o", prog_node, &.{ + var files = [_]Compilation.CSourceFile{ .{ .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", "musl", "crt", "crt1.c", }), .extra_flags = args.items, + .owner = undefined, }, - }); + }; + return comp.build_crt_file("crt1", .Obj, .@"musl crt1.o", prog_node, &files); }, .rcrt1_o => { var args = std.ArrayList([]const u8).init(arena); @@ -78,14 +84,16 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr "-fno-stack-protector", "-DCRT", }); - return comp.build_crt_file("rcrt1", .Obj, .@"musl rcrt1.o", prog_node, &.{ + var files = [_]Compilation.CSourceFile{ .{ .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", "musl", "crt", "rcrt1.c", }), .extra_flags = args.items, + .owner = undefined, }, - }); + }; + return comp.build_crt_file("rcrt1", .Obj, .@"musl rcrt1.o", prog_node, &files); }, .scrt1_o => { var args = std.ArrayList([]const u8).init(arena); @@ -95,14 +103,16 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr "-fno-stack-protector", "-DCRT", }); - return comp.build_crt_file("Scrt1", .Obj, .@"musl Scrt1.o", prog_node, &.{ + var files = [_]Compilation.CSourceFile{ .{ .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", "musl", "crt", "Scrt1.c", }), .extra_flags = args.items, + .owner = undefined, }, - }); + }; + return comp.build_crt_file("Scrt1", .Obj, .@"musl Scrt1.o", prog_node, &files); }, .libc_a => { // When there is a src//foo.* then it should substitute for src/foo.* @@ -186,6 +196,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr c_source_file.* = .{ .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", src_file }), .extra_flags = args.items, + .owner = undefined, }; } return comp.build_crt_file("c", .Lib, .@"musl libc.a", prog_node, c_source_files.items); @@ -235,7 +246,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr .structured_cfg = comp.root_mod.structured_cfg, }, .global = config, - .cc_argv = &.{}, + .cc_argv = cc_argv, .parent = null, .builtin_mod = null, }); @@ -261,9 +272,11 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, .clang_passthrough_mode = comp.clang_passthrough_mode, .c_source_files = &[_]Compilation.CSourceFile{ - .{ .src_path = try comp.zig_lib_directory.join(arena, &.{ "libc", "musl", "libc.S" }) }, + .{ + .src_path = try comp.zig_lib_directory.join(arena, &.{ "libc", "musl", "libc.S" }), + .owner = root_mod, + }, }, - .cc_argv = cc_argv, .skip_linker_dependencies = true, .soname = "libc.so", }); diff --git a/src/wasi_libc.zig b/src/wasi_libc.zig index 2d5f0bc685..3c0ff26314 100644 --- a/src/wasi_libc.zig +++ b/src/wasi_libc.zig @@ -74,27 +74,31 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr var args = std.ArrayList([]const u8).init(arena); try addCCArgs(comp, arena, &args, .{}); try addLibcBottomHalfIncludes(comp, arena, &args); - return comp.build_crt_file("crt1-reactor", .Obj, .@"wasi crt1-reactor.o", prog_node, &.{ + var files = [_]Compilation.CSourceFile{ .{ .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", try sanitize(arena, crt1_reactor_src_file), }), .extra_flags = args.items, + .owner = undefined, }, - }); + }; + return comp.build_crt_file("crt1-reactor", .Obj, .@"wasi crt1-reactor.o", prog_node, &files); }, .crt1_command_o => { var args = std.ArrayList([]const u8).init(arena); try addCCArgs(comp, arena, &args, .{}); try addLibcBottomHalfIncludes(comp, arena, &args); - return comp.build_crt_file("crt1-command", .Obj, .@"wasi crt1-command.o", prog_node, &.{ + var files = [_]Compilation.CSourceFile{ .{ .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", try sanitize(arena, crt1_command_src_file), }), .extra_flags = args.items, + .owner = undefined, }, - }); + }; + return comp.build_crt_file("crt1-command", .Obj, .@"wasi crt1-command.o", prog_node, &files); }, .libc_a => { var libc_sources = std.ArrayList(Compilation.CSourceFile).init(arena); @@ -109,6 +113,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr "libc", try sanitize(arena, file_path), }), .extra_flags = args.items, + .owner = undefined, }); } } @@ -125,6 +130,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr "libc", try sanitize(arena, file_path), }), .extra_flags = args.items, + .owner = undefined, }); } } @@ -141,6 +147,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr "libc", try sanitize(arena, file_path), }), .extra_flags = args.items, + .owner = undefined, }); } } @@ -159,6 +166,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr "libc", try sanitize(arena, file_path), }), .extra_flags = args.items, + .owner = undefined, }); } try comp.build_crt_file("wasi-emulated-process-clocks", .Lib, .@"libwasi-emulated-process-clocks.a", prog_node, emu_clocks_sources.items); @@ -175,6 +183,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr "libc", try sanitize(arena, file_path), }), .extra_flags = args.items, + .owner = undefined, }); } try comp.build_crt_file("wasi-emulated-getpid", .Lib, .@"libwasi-emulated-getpid.a", prog_node, emu_getpid_sources.items); @@ -191,6 +200,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr "libc", try sanitize(arena, file_path), }), .extra_flags = args.items, + .owner = undefined, }); } try comp.build_crt_file("wasi-emulated-mman", .Lib, .@"libwasi-emulated-mman.a", prog_node, emu_mman_sources.items); @@ -208,6 +218,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr "libc", try sanitize(arena, file_path), }), .extra_flags = args.items, + .owner = undefined, }); } } @@ -224,6 +235,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: *std.Progr "libc", try sanitize(arena, file_path), }), .extra_flags = args.items, + .owner = undefined, }); } } -- cgit v1.2.3 From edccd68adf58273f44c57ef0d609ec09cc3fb41e Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 24 Dec 2023 19:20:41 -0700 Subject: Package.Module: fix typo in default red-zone setting oops, this was supposed to return true, not false. --- src/Package/Module.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Package/Module.zig') diff --git a/src/Package/Module.zig b/src/Package/Module.zig index 0ebd951cc6..3c3a1c81e6 100644 --- a/src/Package/Module.zig +++ b/src/Package/Module.zig @@ -187,7 +187,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module { if (!target_util.hasRedZone(target)) { if (options.inherited.red_zone == true) return error.TargetHasNoRedZone; - break :b true; + break :b false; } if (options.inherited.red_zone) |x| break :b x; if (options.parent) |p| break :b p.red_zone; -- cgit v1.2.3 From 196ddf010c97f2faf69513e61099a233d4270795 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 28 Dec 2023 17:42:23 -0700 Subject: frontend: fix populateTestFunctions accessing the wrong module The test runner reads the list of test function pointers from its own builtin module, which is the root_mod, not main_mod. --- src/Module.zig | 2 +- src/Package/Module.zig | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'src/Package/Module.zig') diff --git a/src/Module.zig b/src/Module.zig index 558c03d685..9d3810f671 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -5307,7 +5307,7 @@ pub fn populateTestFunctions( ) !void { const gpa = mod.gpa; const ip = &mod.intern_pool; - const builtin_mod = mod.main_mod.getBuiltinDependency(); + const builtin_mod = mod.root_mod.getBuiltinDependency(); const builtin_file = (mod.importPkg(builtin_mod) catch unreachable).file; const root_decl = mod.declPtr(builtin_file.root_decl.unwrap().?); const builtin_namespace = mod.namespacePtr(root_decl.src_namespace); diff --git a/src/Package/Module.zig b/src/Package/Module.zig index 3c3a1c81e6..66d5a21eab 100644 --- a/src/Package/Module.zig +++ b/src/Package/Module.zig @@ -466,6 +466,9 @@ pub fn createLimited(gpa: Allocator, options: LimitedOptions) Allocator.Error!*P return mod; } +/// Asserts that the module has a builtin module, which is not true for non-zig +/// modules such as ones only used for `@embedFile`, or the root module when +/// there is no Zig Compilation Unit. pub fn getBuiltinDependency(m: Module) *Module { const result = m.deps.values()[0]; assert(result.isBuiltin()); -- cgit v1.2.3