authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-12-10 15:25:06-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-01-01 17:51:18-07:00
log12de7e3472cb2292e75578d33a8b8cc91f1ef0b0
tree77d38282ed0b8cc4911df38b702c09762b52c681
parentb92e30ff0bd2b77a486451b21d17666a311407f3

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.

16 files changed, 3250 insertions(+), 2694 deletions(-)

CMakeLists.txt+1
......@@ -521,6 +521,7 @@ set(ZIG_STAGE2_SOURCES
521521 "${CMAKE_SOURCE_DIR}/src/Air.zig"
522522 "${CMAKE_SOURCE_DIR}/src/AstGen.zig"
523523 "${CMAKE_SOURCE_DIR}/src/Compilation.zig"
524 "${CMAKE_SOURCE_DIR}/src/Compilation/Config.zig"
524525 "${CMAKE_SOURCE_DIR}/src/Liveness.zig"
525526 "${CMAKE_SOURCE_DIR}/src/Module.zig"
526527 "${CMAKE_SOURCE_DIR}/src/Package.zig"
lib/std/Build/Cache.zig+14
......@@ -312,6 +312,20 @@ pub const HashHelper = struct {
312312 ) catch unreachable;
313313 return out_digest;
314314 }
315
316 pub fn oneShot(bytes: []const u8) [hex_digest_len]u8 {
317 var hasher: Hasher = hasher_init;
318 hasher.update(bytes);
319 var bin_digest: BinDigest = undefined;
320 hasher.final(&bin_digest);
321 var out_digest: [hex_digest_len]u8 = undefined;
322 _ = fmt.bufPrint(
323 &out_digest,
324 "{s}",
325 .{fmt.fmtSliceHexLower(&bin_digest)},
326 ) catch unreachable;
327 return out_digest;
328 }
315329};
316330
317331pub const Lock = struct {
lib/std/Build/Module.zig+4
......@@ -34,6 +34,7 @@ valgrind: ?bool,
3434pic: ?bool,
3535red_zone: ?bool,
3636omit_frame_pointer: ?bool,
37error_tracing: ?bool,
3738link_libc: ?bool,
3839link_libcpp: ?bool,
3940
......@@ -177,6 +178,7 @@ pub const CreateOptions = struct {
177178 /// Whether to omit the stack frame pointer. Frees up a register and makes it
178179 /// more difficult to obtain stack traces. Has target-dependent effects.
179180 omit_frame_pointer: ?bool = null,
181 error_tracing: ?bool = null,
180182};
181183
182184pub const Import = struct {
......@@ -216,6 +218,7 @@ pub fn init(m: *Module, owner: *std.Build, options: CreateOptions, compile: ?*St
216218 .pic = options.pic,
217219 .red_zone = options.red_zone,
218220 .omit_frame_pointer = options.omit_frame_pointer,
221 .error_tracing = options.error_tracing,
219222 .export_symbol_names = &.{},
220223 };
221224
......@@ -601,6 +604,7 @@ pub fn appendZigProcessFlags(
601604 try addFlag(zig_args, m.stack_check, "-fstack-check", "-fno-stack-check");
602605 try addFlag(zig_args, m.stack_protector, "-fstack-protector", "-fno-stack-protector");
603606 try addFlag(zig_args, m.omit_frame_pointer, "-fomit-frame-pointer", "-fno-omit-frame-pointer");
607 try addFlag(zig_args, m.error_tracing, "-ferror-tracing", "-fno-error-tracing");
604608 try addFlag(zig_args, m.sanitize_c, "-fsanitize-c", "-fno-sanitize-c");
605609 try addFlag(zig_args, m.sanitize_thread, "-fsanitize-thread", "-fno-sanitize-thread");
606610 try addFlag(zig_args, m.valgrind, "-fvalgrind", "-fno-valgrind");
src/Builtin.zig created+240
......@@ -0,0 +1,240 @@
1target: std.Target,
2zig_backend: std.builtin.CompilerBackend,
3output_mode: std.builtin.OutputMode,
4link_mode: std.builtin.LinkMode,
5is_test: bool,
6test_evented_io: bool,
7single_threaded: bool,
8link_libc: bool,
9link_libcpp: bool,
10optimize_mode: std.builtin.OptimizeMode,
11error_tracing: bool,
12valgrind: bool,
13sanitize_thread: bool,
14pic: bool,
15pie: bool,
16strip: bool,
17code_model: std.builtin.CodeModel,
18omit_frame_pointer: bool,
19wasi_exec_model: std.builtin.WasiExecModel,
20
21pub fn generate(opts: @This(), allocator: Allocator) Allocator.Error![:0]u8 {
22 var buffer = std.ArrayList(u8).init(allocator);
23 defer buffer.deinit();
24
25 const target = opts.target;
26 const generic_arch_name = target.cpu.arch.genericName();
27 const zig_backend = opts.zig_backend;
28
29 @setEvalBranchQuota(4000);
30 try buffer.writer().print(
31 \\const std = @import("std");
32 \\/// Zig version. When writing code that supports multiple versions of Zig, prefer
33 \\/// feature detection (i.e. with `@hasDecl` or `@hasField`) over version checks.
34 \\pub const zig_version = std.SemanticVersion.parse(zig_version_string) catch unreachable;
35 \\pub const zig_version_string = "{s}";
36 \\pub const zig_backend = std.builtin.CompilerBackend.{};
37 \\
38 \\pub const output_mode = std.builtin.OutputMode.{};
39 \\pub const link_mode = std.builtin.LinkMode.{};
40 \\pub const is_test = {};
41 \\pub const single_threaded = {};
42 \\pub const abi = std.Target.Abi.{};
43 \\pub const cpu: std.Target.Cpu = .{{
44 \\ .arch = .{},
45 \\ .model = &std.Target.{}.cpu.{},
46 \\ .features = std.Target.{}.featureSet(&[_]std.Target.{}.Feature{{
47 \\
48 , .{
49 build_options.version,
50 std.zig.fmtId(@tagName(zig_backend)),
51 std.zig.fmtId(@tagName(opts.output_mode)),
52 std.zig.fmtId(@tagName(opts.link_mode)),
53 opts.is_test,
54 opts.single_threaded,
55 std.zig.fmtId(@tagName(target.abi)),
56 std.zig.fmtId(@tagName(target.cpu.arch)),
57 std.zig.fmtId(generic_arch_name),
58 std.zig.fmtId(target.cpu.model.name),
59 std.zig.fmtId(generic_arch_name),
60 std.zig.fmtId(generic_arch_name),
61 });
62
63 for (target.cpu.arch.allFeaturesList(), 0..) |feature, index_usize| {
64 const index = @as(std.Target.Cpu.Feature.Set.Index, @intCast(index_usize));
65 const is_enabled = target.cpu.features.isEnabled(index);
66 if (is_enabled) {
67 try buffer.writer().print(" .{},\n", .{std.zig.fmtId(feature.name)});
68 }
69 }
70 try buffer.writer().print(
71 \\ }}),
72 \\}};
73 \\pub const os = std.Target.Os{{
74 \\ .tag = .{},
75 \\ .version_range = .{{
76 ,
77 .{std.zig.fmtId(@tagName(target.os.tag))},
78 );
79
80 switch (target.os.getVersionRange()) {
81 .none => try buffer.appendSlice(" .none = {} },\n"),
82 .semver => |semver| try buffer.writer().print(
83 \\ .semver = .{{
84 \\ .min = .{{
85 \\ .major = {},
86 \\ .minor = {},
87 \\ .patch = {},
88 \\ }},
89 \\ .max = .{{
90 \\ .major = {},
91 \\ .minor = {},
92 \\ .patch = {},
93 \\ }},
94 \\ }}}},
95 \\
96 , .{
97 semver.min.major,
98 semver.min.minor,
99 semver.min.patch,
100
101 semver.max.major,
102 semver.max.minor,
103 semver.max.patch,
104 }),
105 .linux => |linux| try buffer.writer().print(
106 \\ .linux = .{{
107 \\ .range = .{{
108 \\ .min = .{{
109 \\ .major = {},
110 \\ .minor = {},
111 \\ .patch = {},
112 \\ }},
113 \\ .max = .{{
114 \\ .major = {},
115 \\ .minor = {},
116 \\ .patch = {},
117 \\ }},
118 \\ }},
119 \\ .glibc = .{{
120 \\ .major = {},
121 \\ .minor = {},
122 \\ .patch = {},
123 \\ }},
124 \\ }}}},
125 \\
126 , .{
127 linux.range.min.major,
128 linux.range.min.minor,
129 linux.range.min.patch,
130
131 linux.range.max.major,
132 linux.range.max.minor,
133 linux.range.max.patch,
134
135 linux.glibc.major,
136 linux.glibc.minor,
137 linux.glibc.patch,
138 }),
139 .windows => |windows| try buffer.writer().print(
140 \\ .windows = .{{
141 \\ .min = {s},
142 \\ .max = {s},
143 \\ }}}},
144 \\
145 ,
146 .{ windows.min, windows.max },
147 ),
148 }
149 try buffer.appendSlice(
150 \\};
151 \\pub const target: std.Target = .{
152 \\ .cpu = cpu,
153 \\ .os = os,
154 \\ .abi = abi,
155 \\ .ofmt = object_format,
156 \\
157 );
158
159 if (target.dynamic_linker.get()) |dl| {
160 try buffer.writer().print(
161 \\ .dynamic_linker = std.Target.DynamicLinker.init("{s}"),
162 \\}};
163 \\
164 , .{dl});
165 } else {
166 try buffer.appendSlice(
167 \\ .dynamic_linker = std.Target.DynamicLinker.none,
168 \\};
169 \\
170 );
171 }
172
173 // This is so that compiler_rt and libc.zig libraries know whether they
174 // will eventually be linked with libc. They make different decisions
175 // about what to export depending on whether another libc will be linked
176 // in. For example, compiler_rt will not export the __chkstk symbol if it
177 // knows libc will provide it, and likewise c.zig will not export memcpy.
178 const link_libc = opts.link_libc;
179
180 try buffer.writer().print(
181 \\pub const object_format = std.Target.ObjectFormat.{};
182 \\pub const mode = std.builtin.OptimizeMode.{};
183 \\pub const link_libc = {};
184 \\pub const link_libcpp = {};
185 \\pub const have_error_return_tracing = {};
186 \\pub const valgrind_support = {};
187 \\pub const sanitize_thread = {};
188 \\pub const position_independent_code = {};
189 \\pub const position_independent_executable = {};
190 \\pub const strip_debug_info = {};
191 \\pub const code_model = std.builtin.CodeModel.{};
192 \\pub const omit_frame_pointer = {};
193 \\
194 , .{
195 std.zig.fmtId(@tagName(target.ofmt)),
196 std.zig.fmtId(@tagName(opts.optimize_mode)),
197 link_libc,
198 opts.link_libcpp,
199 opts.error_tracing,
200 opts.valgrind,
201 opts.sanitize_thread,
202 opts.pic,
203 opts.pie,
204 opts.strip,
205 std.zig.fmtId(@tagName(opts.code_model)),
206 opts.omit_frame_pointer,
207 });
208
209 if (target.os.tag == .wasi) {
210 const wasi_exec_model_fmt = std.zig.fmtId(@tagName(opts.wasi_exec_model));
211 try buffer.writer().print(
212 \\pub const wasi_exec_model = std.builtin.WasiExecModel.{};
213 \\
214 , .{wasi_exec_model_fmt});
215 }
216
217 if (opts.is_test) {
218 try buffer.appendSlice(
219 \\pub var test_functions: []const std.builtin.TestFn = undefined; // overwritten later
220 \\
221 );
222 if (opts.test_evented_io) {
223 try buffer.appendSlice(
224 \\pub const test_io_mode = .evented;
225 \\
226 );
227 } else {
228 try buffer.appendSlice(
229 \\pub const test_io_mode = .blocking;
230 \\
231 );
232 }
233 }
234
235 return buffer.toOwnedSliceSentinel(0);
236}
237
238const std = @import("std");
239const Allocator = std.mem.Allocator;
240const build_options = @import("build_options");
src/Compilation.zig+431-1026
......@@ -38,12 +38,43 @@ const Autodoc = @import("Autodoc.zig");
3838const Color = @import("main.zig").Color;
3939const resinator = @import("resinator.zig");
4040
41pub const Config = @import("Compilation/Config.zig");
42
4143/// General-purpose allocator. Used for both temporary and long-term storage.
4244gpa: Allocator,
4345/// Arena-allocated memory, mostly used during initialization. However, it can be used
4446/// for other things requiring the same lifetime as the `Compilation`.
4547arena: std.heap.ArenaAllocator,
46bin_file: *link.File,
48/// Not every Compilation compiles .zig code! For example you could do `zig build-exe foo.o`.
49/// TODO: rename to zcu: ?*Zcu
50module: ?*Module,
51/// All compilations have a root module because this is where some important
52/// settings are stored, such as target and optimization mode. This module
53/// might not have any .zig code associated with it, however.
54root_mod: *Package.Module,
55
56/// User-specified settings that have all the defaults resolved into concrete values.
57config: Config,
58
59/// This is `null` when `-fno-emit-bin` is used.
60bin_file: ?*link.File,
61
62/// The root path for the dynamic linker and system libraries (as well as frameworks on Darwin)
63sysroot: ?[]const u8,
64/// This is `null` when not building a Windows DLL, or when `-fno-emit-implib` is used.
65implib_emit: ?Emit,
66/// This is non-null when `-femit-docs` is provided.
67docs_emit: ?Emit,
68root_name: [:0]const u8,
69cache_mode: CacheMode,
70include_compiler_rt: bool,
71objects: []Compilation.LinkObject,
72/// These are *always* dynamically linked. Static libraries will be
73/// provided as positional arguments.
74system_libs: std.StringArrayHashMapUnmanaged(SystemLib),
75version: ?std.SemanticVersion,
76libc_installation: ?*const LibCInstallation,
77
4778c_object_table: std.AutoArrayHashMapUnmanaged(*CObject, void) = .{},
4879win32_resource_table: if (build_options.only_core_functionality) void else std.AutoArrayHashMapUnmanaged(*Win32Resource, void) =
4980 if (build_options.only_core_functionality) {} else .{},
......@@ -87,8 +118,6 @@ failed_win32_resources: if (build_options.only_core_functionality) void else std
87118misc_failures: std.AutoArrayHashMapUnmanaged(MiscTask, MiscError) = .{},
88119
89120keep_source_files_loaded: bool,
90c_frontend: CFrontend,
91sanitize_c: bool,
92121/// When this is `true` it means invoking clang as a sub-process is expected to inherit
93122/// stdin, stdout, stderr, and if it returns non success, to forward the exit code.
94123/// Otherwise we attempt to parse the error messages and expose them via the Compilation API.
......@@ -107,8 +136,6 @@ verbose_llvm_cpu_features: bool,
107136disable_c_depfile: bool,
108137time_report: bool,
109138stack_report: bool,
110unwind_tables: bool,
111test_evented_io: bool,
112139debug_compiler_runtime_libs: bool,
113140debug_compile_errors: bool,
114141job_queued_compiler_rt_lib: bool = false,
......@@ -118,7 +145,6 @@ formatted_panics: bool = false,
118145last_update_was_cache_hit: bool = false,
119146
120147c_source_files: []const CSourceFile,
121clang_argv: []const []const u8,
122148rc_source_files: []const RcSourceFile,
123149cache_parent: *Cache,
124150/// Path to own executable for invoking `zig clang`.
......@@ -194,7 +220,29 @@ emit_llvm_bc: ?EmitLoc,
194220work_queue_wait_group: WaitGroup = .{},
195221astgen_wait_group: WaitGroup = .{},
196222
197pub const default_stack_protector_buffer_size = 4;
223pub const Emit = struct {
224 /// Where the output will go.
225 directory: Directory,
226 /// Path to the output file, relative to `directory`.
227 sub_path: []const u8,
228
229 /// Returns the full path to `basename` if it were in the same directory as the
230 /// `Emit` sub_path.
231 pub fn basenamePath(emit: Emit, arena: Allocator, basename: [:0]const u8) ![:0]const u8 {
232 const full_path = if (emit.directory.path) |p|
233 try std.fs.path.join(arena, &[_][]const u8{ p, emit.sub_path })
234 else
235 emit.sub_path;
236
237 if (std.fs.path.dirname(full_path)) |dirname| {
238 return try std.fs.path.joinZ(arena, &.{ dirname, basename });
239 } else {
240 return basename;
241 }
242 }
243};
244
245pub const default_stack_protector_buffer_size = target_util.default_stack_protector_buffer_size;
198246pub const SemaError = Module.SemaError;
199247
200248pub const CRTFile = struct {
......@@ -208,8 +256,8 @@ pub const CRTFile = struct {
208256 }
209257};
210258
211// supported languages for "zig clang -x <lang>".
212// Loosely based on llvm-project/clang/include/clang/Driver/Types.def
259/// Supported languages for "zig clang -x <lang>".
260/// Loosely based on llvm-project/clang/include/clang/Driver/Types.def
213261pub const LangToExt = std.ComptimeStringMap(FileExt, .{
214262 .{ "c", .c },
215263 .{ "c-header", .h },
......@@ -226,16 +274,20 @@ pub const LangToExt = std.ComptimeStringMap(FileExt, .{
226274
227275/// For passing to a C compiler.
228276pub const CSourceFile = struct {
277 /// Many C compiler flags are determined by settings contained in the owning Module.
278 owner: *Package.Module,
229279 src_path: []const u8,
230280 extra_flags: []const []const u8 = &.{},
231281 /// Same as extra_flags except they are not added to the Cache hash.
232282 cache_exempt_flags: []const []const u8 = &.{},
233 // this field is non-null iff language was explicitly set with "-x lang".
283 /// This field is non-null if and only if the language was explicitly set
284 /// with "-x lang".
234285 ext: ?FileExt = null,
235286};
236287
237288/// For passing to resinator.
238289pub const RcSourceFile = struct {
290 owner: *Package.Module,
239291 src_path: []const u8,
240292 extra_flags: []const []const u8 = &.{},
241293};
......@@ -742,6 +794,22 @@ pub const EmitLoc = struct {
742794};
743795
744796pub const cache_helpers = struct {
797 pub fn addResolvedTarget(
798 hh: *Cache.HashHelper,
799 resolved_target: Package.Module.ResolvedTarget,
800 ) void {
801 const target = resolved_target.result;
802 hh.add(target.cpu.arch);
803 hh.addBytes(target.cpu.model.name);
804 hh.add(target.cpu.features.ints);
805 hh.add(target.os.tag);
806 hh.add(target.os.getVersionRange());
807 hh.add(target.abi);
808 hh.add(target.ofmt);
809 hh.add(resolved_target.is_native_os);
810 hh.add(resolved_target.is_native_abi);
811 }
812
745813 pub fn addEmitLoc(hh: *Cache.HashHelper, emit_loc: EmitLoc) void {
746814 hh.addBytes(emit_loc.basename);
747815 }
......@@ -751,7 +819,7 @@ pub const cache_helpers = struct {
751819 addEmitLoc(hh, optional_emit_loc orelse return);
752820 }
753821
754 pub fn hashCSource(self: *Cache.Manifest, c_source: Compilation.CSourceFile) !void {
822 pub fn hashCSource(self: *Cache.Manifest, c_source: CSourceFile) !void {
755823 _ = try self.addFile(c_source.src_path, null);
756824 // Hash the extra flags, with special care to call addFile for file parameters.
757825 // TODO this logic can likely be improved by utilizing clang_options_data.zig.
......@@ -770,8 +838,6 @@ pub const cache_helpers = struct {
770838 }
771839};
772840
773pub const CFrontend = enum { clang, aro };
774
775841pub const ClangPreprocessorMode = enum {
776842 no,
777843 /// This means we are doing `zig cc -E -o <path>`.
......@@ -798,11 +864,21 @@ pub const InitOptions = struct {
798864 zig_lib_directory: Directory,
799865 local_cache_directory: Directory,
800866 global_cache_directory: Directory,
801 target: Target,
802 root_name: []const u8,
803 main_mod: ?*Package.Module,
804 output_mode: std.builtin.OutputMode,
805867 thread_pool: *ThreadPool,
868 self_exe_path: ?[]const u8 = null,
869
870 /// Options that have been resolved by calling `resolveDefaults`.
871 config: Compilation.Config,
872
873 root_mod: *Package.Module,
874 /// Normally, `main_mod` and `root_mod` are the same. The exception is `zig
875 /// test`, in which `root_mod` is the test runner, and `main_mod` is the
876 /// user's source file which has the tests.
877 main_mod: ?*Package.Module,
878 /// This is provided so that the API user has a chance to tweak the
879 /// per-module settings of the standard library.
880 std_mod: *Package.Module,
881 root_name: []const u8,
806882 sysroot: ?[]const u8 = null,
807883 /// `null` means to not emit a binary file.
808884 emit_bin: ?EmitLoc,
......@@ -818,7 +894,6 @@ pub const InitOptions = struct {
818894 emit_docs: ?EmitLoc = null,
819895 /// `null` means to not emit an import lib.
820896 emit_implib: ?EmitLoc = null,
821 link_mode: ?std.builtin.LinkMode = null,
822897 dll_export_fns: ?bool = false,
823898 /// Normally when using LLD to link, Zig uses a file named "lld.id" in the
824899 /// same directory as the output binary which contains the hash of the link
......@@ -828,14 +903,12 @@ pub const InitOptions = struct {
828903 /// this flag would be set to disable this machinery to avoid false positives.
829904 disable_lld_caching: bool = false,
830905 cache_mode: CacheMode = .incremental,
831 optimize_mode: std.builtin.OptimizeMode = .Debug,
832906 keep_source_files_loaded: bool = false,
833 clang_argv: []const []const u8 = &[0][]const u8{},
834907 lib_dirs: []const []const u8 = &[0][]const u8{},
835908 rpath_list: []const []const u8 = &[0][]const u8{},
836909 symbol_wrap_set: std.StringArrayHashMapUnmanaged(void) = .{},
837 c_source_files: []const CSourceFile = &[0]CSourceFile{},
838 rc_source_files: []const RcSourceFile = &[0]RcSourceFile{},
910 c_source_files: []const CSourceFile = &.{},
911 rc_source_files: []const RcSourceFile = &.{},
839912 manifest_file: ?[]const u8 = null,
840913 rc_includes: RcIncludes = .any,
841914 link_objects: []LinkObject = &[0]LinkObject{},
......@@ -849,40 +922,16 @@ pub const InitOptions = struct {
849922 /// * mman
850923 /// * signal
851924 wasi_emulated_libs: []const wasi_libc.CRTFile = &[0]wasi_libc.CRTFile{},
852 link_libc: bool = false,
853 link_libcpp: bool = false,
854 link_libunwind: bool = false,
855 want_pic: ?bool = null,
856925 /// This means that if the output mode is an executable it will be a
857926 /// Position Independent Executable. If the output mode is not an
858927 /// executable this field is ignored.
859 want_pie: ?bool = null,
860 want_sanitize_c: ?bool = null,
861 want_stack_check: ?bool = null,
862 /// null means default.
863 /// 0 means no stack protector.
864 /// other number means stack protection with that buffer size.
865 want_stack_protector: ?u32 = null,
866 want_red_zone: ?bool = null,
867 omit_frame_pointer: ?bool = null,
868 want_valgrind: ?bool = null,
869 want_tsan: ?bool = null,
870928 want_compiler_rt: ?bool = null,
871929 want_lto: ?bool = null,
872 want_unwind_tables: ?bool = null,
873 use_llvm: ?bool = null,
874 use_lib_llvm: ?bool = null,
875 use_lld: ?bool = null,
876 use_clang: ?bool = null,
877 single_threaded: ?bool = null,
878 strip: ?bool = null,
879930 formatted_panics: ?bool = null,
880931 rdynamic: bool = false,
881932 function_sections: bool = false,
882933 data_sections: bool = false,
883934 no_builtin: bool = false,
884 is_native_os: bool,
885 is_native_abi: bool,
886935 time_report: bool = false,
887936 stack_report: bool = false,
888937 link_eh_frame_hdr: bool = false,
......@@ -893,14 +942,11 @@ pub const InitOptions = struct {
893942 linker_gc_sections: ?bool = null,
894943 linker_allow_shlib_undefined: ?bool = null,
895944 linker_bind_global_refs_locally: ?bool = null,
896 linker_import_memory: ?bool = null,
897 linker_export_memory: ?bool = null,
898945 linker_import_symbols: bool = false,
899946 linker_import_table: bool = false,
900947 linker_export_table: bool = false,
901948 linker_initial_memory: ?u64 = null,
902949 linker_max_memory: ?u64 = null,
903 linker_shared_memory: bool = false,
904950 linker_global_base: ?u64 = null,
905951 linker_export_symbol_names: []const []const u8 = &.{},
906952 linker_print_gc_sections: bool = false,
......@@ -938,8 +984,6 @@ pub const InitOptions = struct {
938984 verbose_llvm_bc: ?[]const u8 = null,
939985 verbose_cimport: bool = false,
940986 verbose_llvm_cpu_features: bool = false,
941 is_test: bool = false,
942 test_evented_io: bool = false,
943987 debug_compiler_runtime_libs: bool = false,
944988 debug_compile_errors: bool = false,
945989 /// Normally when you create a `Compilation`, Zig will automatically build
......@@ -952,23 +996,18 @@ pub const InitOptions = struct {
952996 force_undefined_symbols: std.StringArrayHashMapUnmanaged(void) = .{},
953997 stack_size_override: ?u64 = null,
954998 image_base_override: ?u64 = null,
955 self_exe_path: ?[]const u8 = null,
956999 version: ?std.SemanticVersion = null,
9571000 compatibility_version: ?std.SemanticVersion = null,
9581001 libc_installation: ?*const LibCInstallation = null,
959 machine_code_model: std.builtin.CodeModel = .default,
9601002 clang_preprocessor_mode: ClangPreprocessorMode = .no,
9611003 /// This is for stage1 and should be deleted upon completion of self-hosting.
9621004 color: Color = .auto,
9631005 reference_trace: ?u32 = null,
964 error_tracing: ?bool = null,
9651006 test_filter: ?[]const u8 = null,
9661007 test_name_prefix: ?[]const u8 = null,
9671008 test_runner_path: ?[]const u8 = null,
9681009 subsystem: ?std.Target.SubSystem = null,
9691010 dwarf_format: ?std.dwarf.Format = null,
970 /// WASI-only. Type of WASI execution model ("command" or "reactor").
971 wasi_exec_model: ?std.builtin.WasiExecModel = null,
9721011 /// (Zig compiler development) Enable dumping linker's state as JSON.
9731012 enable_link_snapshots: bool = false,
9741013 /// (Darwin) Install name of the dylib
......@@ -989,77 +1028,93 @@ pub const InitOptions = struct {
9891028 pdb_source_path: ?[]const u8 = null,
9901029 /// (Windows) PDB output path
9911030 pdb_out_path: ?[]const u8 = null,
992 error_limit: ?Module.ErrorInt = null,
1031 error_limit: ?Compilation.Module.ErrorInt = null,
9931032 /// (SPIR-V) whether to generate a structured control flow graph or not
9941033 want_structured_cfg: ?bool = null,
9951034};
9961035
9971036fn addModuleTableToCacheHash(
1037 gpa: Allocator,
1038 arena: Allocator,
9981039 hash: *Cache.HashHelper,
999 arena: *std.heap.ArenaAllocator,
1000 mod_table: Package.Module.Deps,
1001 seen_table: *std.AutoHashMap(*Package.Module, void),
1040 root_mod: *Package.Module,
10021041 hash_type: union(enum) { path_bytes, files: *Cache.Manifest },
10031042) (error{OutOfMemory} || std.os.GetCwdError)!void {
1004 const allocator = arena.allocator();
1005
1006 const module_indices = try allocator.alloc(u32, mod_table.count());
1007 // Copy over the hashmap entries to our slice
1008 for (module_indices, 0..) |*module_index, index| module_index.* = @intCast(index);
1009 // Sort the slice by package name
1010 mem.sortUnstable(u32, module_indices, &mod_table, struct {
1011 fn lessThan(deps: *const Package.Module.Deps, lhs: u32, rhs: u32) bool {
1012 const keys = deps.keys();
1013 return std.mem.lessThan(u8, keys[lhs], keys[rhs]);
1043 var seen_table: std.AutoArrayHashMapUnmanaged(*Package.Module, void) = .{};
1044 try seen_table.put(gpa, root_mod, {});
1045
1046 const SortByName = struct {
1047 names: []const []const u8,
1048
1049 pub fn lessThan(ctx: @This(), lhs_index: usize, rhs_index: usize) bool {
1050 const lhs_key = ctx.names[lhs_index];
1051 const rhs_key = ctx.names[rhs_index];
1052 return mem.lessThan(u8, lhs_key, rhs_key);
10141053 }
1015 }.lessThan);
1054 };
10161055
1017 for (module_indices) |module_index| {
1018 const module = mod_table.values()[module_index];
1019 if ((try seen_table.getOrPut(module)).found_existing) continue;
1056 var i: usize = 0;
1057 while (i < seen_table.count()) : (i += 1) {
1058 const mod = seen_table.keys()[i];
1059
1060 cache_helpers.addResolvedTarget(hash, mod.resolved_target);
1061 hash.add(mod.optimize_mode);
1062 hash.add(mod.code_model);
1063 hash.add(mod.single_threaded);
1064 hash.add(mod.error_tracing);
1065 hash.add(mod.valgrind);
1066 hash.add(mod.pic);
1067 hash.add(mod.strip);
1068 hash.add(mod.omit_frame_pointer);
1069 hash.add(mod.stack_check);
1070 hash.add(mod.red_zone);
1071 hash.add(mod.sanitize_c);
1072 hash.add(mod.sanitize_thread);
10201073
1021 // Finally insert the package name and path to the cache hash.
1022 hash.addBytes(mod_table.keys()[module_index]);
10231074 switch (hash_type) {
10241075 .path_bytes => {
1025 hash.addBytes(module.root_src_path);
1026 hash.addOptionalBytes(module.root.root_dir.path);
1027 hash.addBytes(module.root.sub_path);
1076 hash.addBytes(mod.root_src_path);
1077 hash.addOptionalBytes(mod.root.root_dir.path);
1078 hash.addBytes(mod.root.sub_path);
10281079 },
10291080 .files => |man| {
1030 const pkg_zig_file = try module.root.joinString(
1031 allocator,
1032 module.root_src_path,
1033 );
1081 const pkg_zig_file = try mod.root.joinString(arena, mod.root_src_path);
10341082 _ = try man.addFile(pkg_zig_file, null);
10351083 },
10361084 }
1037 // Recurse to handle the module's dependencies
1038 try addModuleTableToCacheHash(hash, arena, module.deps, seen_table, hash_type);
1085
1086 mod.deps.sortUnstable(SortByName{ .names = mod.deps.keys() });
1087
1088 hash.addListOfBytes(mod.deps.keys());
1089
1090 const deps = mod.deps.values();
1091 try seen_table.ensureUnusedCapacity(gpa, deps.len);
1092 for (deps) |dep| seen_table.putAssumeCapacity(dep, {});
10391093 }
10401094}
10411095
10421096pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1043 const is_dyn_lib = switch (options.output_mode) {
1097 const output_mode = options.config.output_mode;
1098 const is_dyn_lib = switch (output_mode) {
10441099 .Obj, .Exe => false,
1045 .Lib => (options.link_mode orelse .Static) == .Dynamic,
1100 .Lib => options.config.link_mode == .Dynamic,
10461101 };
1047 const is_exe_or_dyn_lib = switch (options.output_mode) {
1102 const is_exe_or_dyn_lib = switch (output_mode) {
10481103 .Obj => false,
10491104 .Lib => is_dyn_lib,
10501105 .Exe => true,
10511106 };
10521107
1053 // WASI-only. Resolve the optional exec-model option, defaults to command.
1054 const wasi_exec_model = if (options.target.os.tag != .wasi) undefined else options.wasi_exec_model orelse .command;
1055
10561108 if (options.linker_export_table and options.linker_import_table) {
10571109 return error.ExportTableAndImportTableConflict;
10581110 }
10591111
1112 const have_zcu = options.root_mod.root_src_path.len != 0;
1113
10601114 const comp: *Compilation = comp: {
1061 // For allocations that have the same lifetime as Compilation. This arena is used only during this
1062 // initialization and then is freed in deinit().
1115 // For allocations that have the same lifetime as Compilation. This
1116 // arena is used only during this initialization and then is freed in
1117 // deinit().
10631118 var arena_allocator = std.heap.ArenaAllocator.init(gpa);
10641119 errdefer arena_allocator.deinit();
10651120 const arena = arena_allocator.allocator();
......@@ -1069,366 +1124,145 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
10691124 const comp = try arena.create(Compilation);
10701125 const root_name = try arena.dupeZ(u8, options.root_name);
10711126
1072 // Make a decision on whether to use LLVM or our own backend.
1073 const use_lib_llvm = options.use_lib_llvm orelse build_options.have_llvm;
1074 const use_llvm = blk: {
1075 if (options.use_llvm) |explicit|
1076 break :blk explicit;
1077
1078 // If emitting to LLVM bitcode object format, must use LLVM backend.
1079 if (options.emit_llvm_ir != null or options.emit_llvm_bc != null)
1080 break :blk true;
1081
1082 // If we have no zig code to compile, no need for LLVM.
1083 if (options.main_mod == null)
1084 break :blk false;
1085
1086 // If we cannot use LLVM libraries, then our own backends will be a
1087 // better default since the LLVM backend can only produce bitcode
1088 // and not an object file or executable.
1089 if (!use_lib_llvm)
1090 break :blk false;
1091
1092 // If LLVM does not support the target, then we can't use it.
1093 if (!target_util.hasLlvmSupport(options.target, options.target.ofmt))
1094 break :blk false;
1095
1096 // Prefer LLVM for release builds.
1097 if (options.optimize_mode != .Debug)
1098 break :blk true;
1099
1100 // At this point we would prefer to use our own self-hosted backend,
1101 // because the compilation speed is better than LLVM. But only do it if
1102 // we are confident in the robustness of the backend.
1103 break :blk !target_util.selfHostedBackendIsAsRobustAsLlvm(options.target);
1104 };
1105 if (!use_llvm) {
1106 if (options.use_llvm == true) {
1107 return error.ZigCompilerNotBuiltWithLLVMExtensions;
1108 }
1109 if (options.emit_llvm_ir != null or options.emit_llvm_bc != null) {
1110 return error.EmittingLlvmModuleRequiresUsingLlvmBackend;
1111 }
1112 }
1127 const use_llvm = options.config.use_llvm;
11131128
11141129 // TODO: once we support incremental compilation for the LLVM backend via
11151130 // saving the LLVM module into a bitcode file and restoring it, along with
11161131 // compiler state, the second clause here can be removed so that incremental
11171132 // cache mode is used for LLVM backend too. We need some fuzz testing before
11181133 // that can be enabled.
1119 const cache_mode = if ((use_llvm or options.main_mod == null) and !options.disable_lld_caching)
1134 const cache_mode = if ((use_llvm or !have_zcu) and !options.disable_lld_caching)
11201135 CacheMode.whole
11211136 else
11221137 options.cache_mode;
11231138
1124 const tsan = options.want_tsan orelse false;
1125 // TSAN is implemented in C++ so it requires linking libc++.
1126 const link_libcpp = options.link_libcpp or tsan;
1127 const link_libc = link_libcpp or options.link_libc or options.link_libunwind or
1128 target_util.osRequiresLibC(options.target);
1129
1130 const link_libunwind = options.link_libunwind or
1131 (link_libcpp and target_util.libcNeedsLibUnwind(options.target));
1132 const unwind_tables = options.want_unwind_tables orelse
1133 (link_libunwind or target_util.needUnwindTables(options.target));
1134 const link_eh_frame_hdr = options.link_eh_frame_hdr or unwind_tables;
1135 const build_id = options.build_id orelse .none;
1139 const any_unwind_tables = options.config.any_unwind_tables;
11361140
1137 // Make a decision on whether to use LLD or our own linker.
1138 const use_lld = options.use_lld orelse blk: {
1139 if (options.target.isDarwin()) {
1140 break :blk false;
1141 }
1142
1143 if (!build_options.have_llvm)
1144 break :blk false;
1145
1146 if (options.target.ofmt == .c)
1147 break :blk false;
1148
1149 if (options.want_lto) |lto| {
1150 if (lto) {
1151 break :blk true;
1152 }
1153 }
1154
1155 // Our linker can't handle objects or most advanced options yet.
1156 if (options.link_objects.len != 0 or
1157 options.c_source_files.len != 0 or
1158 options.frameworks.len != 0 or
1159 options.system_lib_names.len != 0 or
1160 options.link_libc or options.link_libcpp or
1161 link_eh_frame_hdr or
1162 options.link_emit_relocs or
1163 options.output_mode == .Lib or
1164 options.linker_script != null or options.version_script != null or
1165 options.emit_implib != null or
1166 build_id != .none or
1167 options.symbol_wrap_set.count() > 0)
1168 {
1169 break :blk true;
1170 }
1171
1172 if (use_llvm) {
1173 // If stage1 generates an object file, self-hosted linker is not
1174 // yet sophisticated enough to handle that.
1175 break :blk options.main_mod != null;
1176 }
1177
1178 break :blk false;
1179 };
1180
1181 const lto = blk: {
1182 if (options.want_lto) |want_lto| {
1183 if (want_lto and !use_lld and !options.target.isDarwin())
1184 return error.LtoUnavailableWithoutLld;
1185 break :blk want_lto;
1186 } else if (!use_lld) {
1187 // zig ld LTO support is tracked by
1188 // https://github.com/ziglang/zig/issues/8680
1189 break :blk false;
1190 } else if (options.c_source_files.len == 0) {
1191 break :blk false;
1192 } else if (options.target.cpu.arch.isRISCV()) {
1193 // Clang and LLVM currently don't support RISC-V target-abi for LTO.
1194 // Compiling with LTO may fail or produce undesired results.
1195 // See https://reviews.llvm.org/D71387
1196 // See https://reviews.llvm.org/D102582
1197 break :blk false;
1198 } else switch (options.output_mode) {
1199 .Lib, .Obj => break :blk false,
1200 .Exe => switch (options.optimize_mode) {
1201 .Debug => break :blk false,
1202 .ReleaseSafe, .ReleaseFast, .ReleaseSmall => break :blk true,
1203 },
1204 }
1205 };
1206
1207 const must_dynamic_link = dl: {
1208 if (target_util.cannotDynamicLink(options.target))
1209 break :dl false;
1210 if (is_exe_or_dyn_lib and link_libc and
1211 (options.target.isGnuLibC() or target_util.osRequiresLibC(options.target)))
1212 {
1213 break :dl true;
1214 }
1215 const any_dyn_libs: bool = x: {
1216 if (options.system_lib_names.len != 0)
1217 break :x true;
1218 for (options.link_objects) |obj| {
1219 switch (classifyFileExt(obj.path)) {
1220 .shared_library => break :x true,
1221 else => continue,
1222 }
1223 }
1224 break :x false;
1225 };
1226 if (any_dyn_libs) {
1227 // When creating a executable that links to system libraries,
1228 // we require dynamic linking, but we must not link static libraries
1229 // or object files dynamically!
1230 break :dl (options.output_mode == .Exe);
1231 }
1141 const link_eh_frame_hdr = options.link_eh_frame_hdr or any_unwind_tables;
1142 const build_id = options.build_id orelse .none;
12321143
1233 break :dl false;
1234 };
1235 const default_link_mode: std.builtin.LinkMode = blk: {
1236 if (must_dynamic_link) {
1237 break :blk .Dynamic;
1238 } else if (is_exe_or_dyn_lib and link_libc and
1239 options.is_native_abi and options.target.abi.isMusl())
1240 {
1241 // If targeting the system's native ABI and the system's
1242 // libc is musl, link dynamically by default.
1243 break :blk .Dynamic;
1244 } else {
1245 break :blk .Static;
1246 }
1247 };
1248 const link_mode: std.builtin.LinkMode = if (options.link_mode) |lm| blk: {
1249 if (lm == .Static and must_dynamic_link) {
1250 return error.UnableToStaticLink;
1251 }
1252 break :blk lm;
1253 } else default_link_mode;
1144 const link_libc = options.config.link_libc;
12541145
12551146 const dll_export_fns = options.dll_export_fns orelse (is_dyn_lib or options.rdynamic);
12561147
12571148 const libc_dirs = try detectLibCIncludeDirs(
12581149 arena,
12591150 options.zig_lib_directory.path.?,
1260 options.target,
1261 options.is_native_abi,
1151 options.root_mod.resolved_target.result,
1152 options.root_mod.resolved_target.is_native_abi,
12621153 link_libc,
12631154 options.libc_installation,
12641155 );
12651156
1266 const rc_dirs = try detectWin32ResourceIncludeDirs(
1267 arena,
1268 options,
1269 );
1270
1271 const sysroot = options.sysroot orelse libc_dirs.sysroot;
1272
1273 const pie: bool = pie: {
1274 if (is_dyn_lib) {
1275 if (options.want_pie == true) return error.OutputModeForbidsPie;
1276 break :pie false;
1277 }
1278 if (target_util.requiresPIE(options.target)) {
1279 if (options.want_pie == false) return error.TargetRequiresPie;
1280 break :pie true;
1281 }
1282 if (tsan) {
1283 if (options.want_pie == false) return error.TsanRequiresPie;
1284 break :pie true;
1285 }
1286 if (options.want_pie) |want_pie| {
1287 break :pie want_pie;
1288 }
1289 break :pie false;
1290 };
1291
1292 const must_pic: bool = b: {
1293 if (target_util.requiresPIC(options.target, link_libc))
1294 break :b true;
1295 break :b link_mode == .Dynamic;
1296 };
1297 const pic = if (options.want_pic) |explicit| pic: {
1298 if (!explicit) {
1299 if (must_pic) {
1300 return error.TargetRequiresPIC;
1301 }
1302 if (pie) {
1303 return error.PIERequiresPIC;
1157 // The include directories used when preprocessing .rc files are separate from the
1158 // target. Which include directories are used is determined by `options.rc_includes`.
1159 //
1160 // Note: It should be okay that the include directories used when compiling .rc
1161 // files differ from the include directories used when compiling the main
1162 // binary, since the .res format is not dependent on anything ABI-related. The
1163 // only relevant differences would be things like `#define` constants being
1164 // different in the MinGW headers vs the MSVC headers, but any such
1165 // differences would likely be a MinGW bug.
1166 const rc_dirs = b: {
1167 // Set the includes to .none here when there are no rc files to compile
1168 var includes = if (options.rc_source_files.len > 0) options.rc_includes else .none;
1169 const target = options.root_mod.resolved_target.result;
1170 if (!options.root_mod.resolved_target.is_native_os or target.os.tag != .windows) {
1171 switch (includes) {
1172 // MSVC can't be found when the host isn't Windows, so short-circuit.
1173 .msvc => return error.WindowsSdkNotFound,
1174 // Skip straight to gnu since we won't be able to detect
1175 // MSVC on non-Windows hosts.
1176 .any => includes = .gnu,
1177 .none, .gnu => {},
13041178 }
13051179 }
1306 break :pic explicit;
1307 } else pie or must_pic;
1308
1309 // Make a decision on whether to use Clang or Aro for translate-c and compiling C files.
1310 const c_frontend: CFrontend = blk: {
1311 if (options.use_clang) |want_clang| {
1312 break :blk if (want_clang) .clang else .aro;
1313 }
1314 break :blk if (build_options.have_llvm) .clang else .aro;
1315 };
1316 if (!build_options.have_llvm and c_frontend == .clang) {
1317 return error.ZigCompilerNotBuiltWithLLVMExtensions;
1318 }
1319
1320 const is_safe_mode = switch (options.optimize_mode) {
1321 .Debug, .ReleaseSafe => true,
1322 .ReleaseFast, .ReleaseSmall => false,
1323 };
1324
1325 const sanitize_c = options.want_sanitize_c orelse is_safe_mode;
1326
1327 const stack_check: bool = options.want_stack_check orelse b: {
1328 if (!target_util.supportsStackProbing(options.target)) break :b false;
1329 break :b is_safe_mode;
1180 while (true) switch (includes) {
1181 .any, .msvc => break :b detectLibCIncludeDirs(
1182 arena,
1183 options.zig_lib_directory.path.?,
1184 .{
1185 .cpu = target.cpu,
1186 .os = target.os,
1187 .abi = .msvc,
1188 .ofmt = target.ofmt,
1189 },
1190 options.root_mod.resolved_target.is_native_abi,
1191 // The .rc preprocessor will need to know the libc include dirs even if we
1192 // are not linking libc, so force 'link_libc' to true
1193 true,
1194 options.libc_installation,
1195 ) catch |err| {
1196 if (includes == .any) {
1197 // fall back to mingw
1198 includes = .gnu;
1199 continue;
1200 }
1201 return err;
1202 },
1203 .gnu => break :b try detectLibCFromBuilding(arena, options.zig_lib_directory.path.?, .{
1204 .cpu = target.cpu,
1205 .os = target.os,
1206 .abi = .gnu,
1207 .ofmt = target.ofmt,
1208 }),
1209 .none => break :b LibCDirs{
1210 .libc_include_dir_list = &[0][]u8{},
1211 .libc_installation = null,
1212 .libc_framework_dir_list = &.{},
1213 .sysroot = null,
1214 .darwin_sdk_layout = null,
1215 },
1216 };
13301217 };
1331 if (stack_check and !target_util.supportsStackProbing(options.target))
1332 return error.StackCheckUnsupportedByTarget;
1333
1334 const stack_protector: u32 = sp: {
1335 const zig_backend = zigBackend(options.target, use_llvm);
1336 if (!target_util.supportsStackProtector(options.target, zig_backend)) {
1337 if (options.want_stack_protector) |x| {
1338 if (x > 0) return error.StackProtectorUnsupportedByTarget;
1339 }
1340 break :sp 0;
1341 }
1342
1343 // This logic is checking for linking libc because otherwise our start code
1344 // which is trying to set up TLS (i.e. the fs/gs registers) but the stack
1345 // protection code depends on fs/gs registers being already set up.
1346 // If we were able to annotate start code, or perhaps the entire std lib,
1347 // as being exempt from stack protection checks, we could change this logic
1348 // to supporting stack protection even when not linking libc.
1349 // TODO file issue about this
1350 if (!link_libc) {
1351 if (options.want_stack_protector) |x| {
1352 if (x > 0) return error.StackProtectorUnavailableWithoutLibC;
1353 }
1354 break :sp 0;
1355 }
13561218
1357 if (options.want_stack_protector) |x| break :sp x;
1358 if (is_safe_mode) break :sp default_stack_protector_buffer_size;
1359 break :sp 0;
1360 };
1219 const sysroot = options.sysroot orelse libc_dirs.sysroot;
13611220
13621221 const include_compiler_rt = options.want_compiler_rt orelse
13631222 (!options.skip_linker_dependencies and is_exe_or_dyn_lib);
13641223
1365 const single_threaded = st: {
1366 if (target_util.isSingleThreaded(options.target)) {
1367 if (options.single_threaded == false)
1368 return error.TargetRequiresSingleThreaded;
1369 break :st true;
1370 }
1371 if (options.main_mod != null) {
1372 const zig_backend = zigBackend(options.target, use_llvm);
1373 if (!target_util.supportsThreads(options.target, zig_backend)) {
1374 if (options.single_threaded == false)
1375 return error.BackendRequiresSingleThreaded;
1376 break :st true;
1377 }
1378 }
1379 break :st options.single_threaded orelse false;
1380 };
1381
1382 const llvm_cpu_features: ?[*:0]const u8 = if (use_llvm) blk: {
1383 var buf = std.ArrayList(u8).init(arena);
1384 for (options.target.cpu.arch.allFeaturesList(), 0..) |feature, index_usize| {
1385 const index = @as(Target.Cpu.Feature.Set.Index, @intCast(index_usize));
1386 const is_enabled = options.target.cpu.features.isEnabled(index);
1387
1388 if (feature.llvm_name) |llvm_name| {
1389 const plus_or_minus = "-+"[@intFromBool(is_enabled)];
1390 try buf.ensureUnusedCapacity(2 + llvm_name.len);
1391 buf.appendAssumeCapacity(plus_or_minus);
1392 buf.appendSliceAssumeCapacity(llvm_name);
1393 buf.appendSliceAssumeCapacity(",");
1394 }
1395 }
1396 if (buf.items.len == 0) break :blk "";
1397 assert(mem.endsWith(u8, buf.items, ","));
1398 buf.items[buf.items.len - 1] = 0;
1399 buf.shrinkAndFree(buf.items.len);
1400 break :blk buf.items[0 .. buf.items.len - 1 :0].ptr;
1401 } else null;
1224 if (include_compiler_rt and output_mode == .Obj) {
1225 // For objects, this mechanism relies on essentially `_ = @import("compiler-rt");`
1226 // injected into the object.
1227 const compiler_rt_mod = try Package.Module.create(arena, .{
1228 .global_cache_directory = options.global_cache_directory,
1229 .paths = .{
1230 .root = .{
1231 .root_dir = options.zig_lib_directory,
1232 },
1233 .root_src_path = "compiler_rt.zig",
1234 },
1235 .fully_qualified_name = "compiler_rt",
1236 .cc_argv = &.{},
1237 .inherited = .{},
1238 .global = options.config,
1239 .parent = options.root_mod,
1240 .builtin_mod = options.root_mod.getBuiltinDependency(),
1241 });
1242 try options.root_mod.deps.putNoClobber(arena, "compiler_rt", compiler_rt_mod);
1243 }
14021244
14031245 if (options.verbose_llvm_cpu_features) {
1404 if (llvm_cpu_features) |cf| print: {
1246 if (options.root_mod.resolved_target.llvm_cpu_features) |cf| print: {
1247 const target = options.root_mod.resolved_target.result;
14051248 std.debug.getStderrMutex().lock();
14061249 defer std.debug.getStderrMutex().unlock();
14071250 const stderr = std.io.getStdErr().writer();
1408 nosuspend stderr.print("compilation: {s}\n", .{options.root_name}) catch break :print;
1409 nosuspend stderr.print(" target: {s}\n", .{try options.target.zigTriple(arena)}) catch break :print;
1410 nosuspend stderr.print(" cpu: {s}\n", .{options.target.cpu.model.name}) catch break :print;
1411 nosuspend stderr.print(" features: {s}\n", .{cf}) catch {};
1251 nosuspend {
1252 stderr.print("compilation: {s}\n", .{options.root_name}) catch break :print;
1253 stderr.print(" target: {s}\n", .{try target.zigTriple(arena)}) catch break :print;
1254 stderr.print(" cpu: {s}\n", .{target.cpu.model.name}) catch break :print;
1255 stderr.print(" features: {s}\n", .{cf}) catch {};
1256 }
14121257 }
14131258 }
14141259
1415 const strip = options.strip orelse !target_util.hasDebugInfo(options.target);
1416 const valgrind: bool = b: {
1417 if (!target_util.hasValgrindSupport(options.target)) break :b false;
1418 if (options.want_valgrind) |explicit| break :b explicit;
1419 if (strip) break :b false;
1420 break :b options.optimize_mode == .Debug;
1421 };
1422 if (!valgrind and options.want_valgrind == true)
1423 return error.ValgrindUnsupportedOnTarget;
1424
1425 const red_zone = options.want_red_zone orelse target_util.hasRedZone(options.target);
1426 const omit_frame_pointer = options.omit_frame_pointer orelse (options.optimize_mode != .Debug);
1427 const linker_optimization: u8 = options.linker_optimization orelse switch (options.optimize_mode) {
1260 const linker_optimization: u8 = options.linker_optimization orelse switch (options.root_mod.optimize_mode) {
14281261 .Debug => @as(u8, 0),
14291262 else => @as(u8, 3),
14301263 };
1431 const formatted_panics = options.formatted_panics orelse (options.optimize_mode == .Debug);
1264 // TODO: https://github.com/ziglang/zig/issues/17969
1265 const formatted_panics = options.formatted_panics orelse (options.root_mod.optimize_mode == .Debug);
14321266
14331267 const error_limit = options.error_limit orelse (std.math.maxInt(u16) - 1);
14341268
......@@ -1453,43 +1287,25 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
14531287 // This is shared hasher state common to zig source and all C source files.
14541288 cache.hash.addBytes(build_options.version);
14551289 cache.hash.add(builtin.zig_backend);
1456 cache.hash.add(options.optimize_mode);
1457 cache.hash.add(options.target.cpu.arch);
1458 cache.hash.addBytes(options.target.cpu.model.name);
1459 cache.hash.add(options.target.cpu.features.ints);
1460 cache.hash.add(options.target.os.tag);
1461 cache.hash.add(options.target.os.getVersionRange());
1462 cache.hash.add(options.is_native_os);
1463 cache.hash.add(options.target.abi);
1464 cache.hash.add(options.target.ofmt);
1465 cache.hash.add(pic);
1466 cache.hash.add(pie);
1467 cache.hash.add(lto);
1468 cache.hash.add(unwind_tables);
1469 cache.hash.add(tsan);
1470 cache.hash.add(stack_check);
1471 cache.hash.add(stack_protector);
1472 cache.hash.add(red_zone);
1473 cache.hash.add(omit_frame_pointer);
1474 cache.hash.add(link_mode);
1290 cache.hash.add(options.config.pie);
1291 cache.hash.add(options.config.lto);
1292 cache.hash.add(options.config.link_mode);
14751293 cache.hash.add(options.function_sections);
14761294 cache.hash.add(options.data_sections);
14771295 cache.hash.add(options.no_builtin);
1478 cache.hash.add(strip);
14791296 cache.hash.add(link_libc);
1480 cache.hash.add(link_libcpp);
1481 cache.hash.add(link_libunwind);
1482 cache.hash.add(options.output_mode);
1483 cache.hash.add(options.machine_code_model);
1297 cache.hash.add(options.config.link_libcpp);
1298 cache.hash.add(options.config.link_libunwind);
1299 cache.hash.add(output_mode);
14841300 cache.hash.addOptional(options.dwarf_format);
14851301 cache_helpers.addOptionalEmitLoc(&cache.hash, options.emit_bin);
14861302 cache_helpers.addOptionalEmitLoc(&cache.hash, options.emit_implib);
14871303 cache_helpers.addOptionalEmitLoc(&cache.hash, options.emit_docs);
14881304 cache.hash.addBytes(options.root_name);
1489 if (options.target.os.tag == .wasi) cache.hash.add(wasi_exec_model);
1305 cache.hash.add(options.config.wasi_exec_model);
14901306 // TODO audit this and make sure everything is in it
14911307
1492 const module: ?*Module = if (options.main_mod) |main_mod| blk: {
1308 const zcu: ?*Module = if (have_zcu) blk: {
14931309 // Options that are specific to zig source files, that cannot be
14941310 // modified between incremental updates.
14951311 var hash = cache.hash;
......@@ -1502,13 +1318,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
15021318 // do want to namespace different source file names because they are
15031319 // likely different compilations and therefore this would be likely to
15041320 // cause cache hits.
1505 hash.addBytes(main_mod.root_src_path);
1506 hash.addOptionalBytes(main_mod.root.root_dir.path);
1507 hash.addBytes(main_mod.root.sub_path);
1508 {
1509 var seen_table = std.AutoHashMap(*Package.Module, void).init(arena);
1510 try addModuleTableToCacheHash(&hash, &arena_allocator, main_mod.deps, &seen_table, .path_bytes);
1511 }
1321 try addModuleTableToCacheHash(gpa, arena, &hash, options.root_mod, .path_bytes);
15121322 },
15131323 .whole => {
15141324 // In this case, we postpone adding the input source file until
......@@ -1518,13 +1328,11 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
15181328 }
15191329
15201330 // Synchronize with other matching comments: ZigOnlyHashStuff
1521 hash.add(valgrind);
1522 hash.add(single_threaded);
15231331 hash.add(use_llvm);
1524 hash.add(use_lib_llvm);
1332 hash.add(options.config.use_lib_llvm);
15251333 hash.add(dll_export_fns);
1526 hash.add(options.is_test);
1527 hash.add(options.test_evented_io);
1334 hash.add(options.config.is_test);
1335 hash.add(options.config.test_evented_io);
15281336 hash.addOptionalBytes(options.test_filter);
15291337 hash.addOptionalBytes(options.test_name_prefix);
15301338 hash.add(options.skip_linker_dependencies);
......@@ -1565,85 +1373,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
15651373 .path = try options.local_cache_directory.join(arena, &[_][]const u8{artifact_sub_dir}),
15661374 };
15671375
1568 const builtin_mod = try Package.Module.create(arena, .{
1569 .root = .{ .root_dir = zig_cache_artifact_directory },
1570 .root_src_path = "builtin.zig",
1571 .fully_qualified_name = "builtin",
1572 });
1573
1574 // When you're testing std, the main module is std. In that case,
1575 // we'll just set the std module to the main one, since avoiding
1576 // the errors caused by duplicating it is more effort than it's
1577 // worth.
1578 const main_mod_is_std = m: {
1579 const std_path = try std.fs.path.resolve(arena, &[_][]const u8{
1580 options.zig_lib_directory.path orelse ".",
1581 "std",
1582 "std.zig",
1583 });
1584 const main_path = try std.fs.path.resolve(arena, &[_][]const u8{
1585 main_mod.root.root_dir.path orelse ".",
1586 main_mod.root.sub_path,
1587 main_mod.root_src_path,
1588 });
1589 break :m mem.eql(u8, main_path, std_path);
1590 };
1591
1592 const std_mod = if (main_mod_is_std)
1593 main_mod
1594 else
1595 try Package.Module.create(arena, .{
1596 .root = .{
1597 .root_dir = options.zig_lib_directory,
1598 .sub_path = "std",
1599 },
1600 .root_src_path = "std.zig",
1601 .fully_qualified_name = "std",
1602 });
1603
1604 const root_mod = if (options.is_test) root_mod: {
1605 const test_mod = if (options.test_runner_path) |test_runner| test_mod: {
1606 const pkg = try Package.Module.create(arena, .{
1607 .root = .{
1608 .root_dir = Directory.cwd(),
1609 .sub_path = std.fs.path.dirname(test_runner) orelse "",
1610 },
1611 .root_src_path = std.fs.path.basename(test_runner),
1612 .fully_qualified_name = "root",
1613 });
1614
1615 pkg.deps = try main_mod.deps.clone(arena);
1616 break :test_mod pkg;
1617 } else try Package.Module.create(arena, .{
1618 .root = .{
1619 .root_dir = options.zig_lib_directory,
1620 },
1621 .root_src_path = "test_runner.zig",
1622 .fully_qualified_name = "root",
1623 });
1624
1625 break :root_mod test_mod;
1626 } else main_mod;
1627
1628 const compiler_rt_mod = if (include_compiler_rt and options.output_mode == .Obj) compiler_rt_mod: {
1629 break :compiler_rt_mod try Package.Module.create(arena, .{
1630 .root = .{
1631 .root_dir = options.zig_lib_directory,
1632 },
1633 .root_src_path = "compiler_rt.zig",
1634 .fully_qualified_name = "compiler_rt",
1635 });
1636 } else null;
1637
1638 {
1639 try main_mod.deps.ensureUnusedCapacity(arena, 4);
1640 main_mod.deps.putAssumeCapacity("builtin", builtin_mod);
1641 main_mod.deps.putAssumeCapacity("root", root_mod);
1642 main_mod.deps.putAssumeCapacity("std", std_mod);
1643 if (compiler_rt_mod) |m|
1644 main_mod.deps.putAssumeCapacity("compiler_rt", m);
1645 }
1646
16471376 // Pre-open the directory handles for cached ZIR code so that it does not need
16481377 // to redundantly happen for each AstGen operation.
16491378 const zir_sub_dir = "z";
......@@ -1674,13 +1403,14 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
16741403 // However we currently do not have serialization of such metadata, so for now
16751404 // we set up an empty Module that does the entire compilation fresh.
16761405
1677 const module = try arena.create(Module);
1678 errdefer module.deinit();
1679 module.* = .{
1406 const zcu = try arena.create(Module);
1407 errdefer zcu.deinit();
1408 zcu.* = .{
16801409 .gpa = gpa,
16811410 .comp = comp,
1682 .main_mod = main_mod,
1683 .root_mod = root_mod,
1411 .main_mod = options.main_mod orelse options.root_mod,
1412 .root_mod = options.root_mod,
1413 .std_mod = options.std_mod,
16841414 .zig_cache_artifact_directory = zig_cache_artifact_directory,
16851415 .global_zir_cache = global_zir_cache,
16861416 .local_zir_cache = local_zir_cache,
......@@ -1688,31 +1418,24 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
16881418 .tmp_hack_arena = std.heap.ArenaAllocator.init(gpa),
16891419 .error_limit = error_limit,
16901420 };
1691 try module.init();
1421 try zcu.init();
16921422
1693 break :blk module;
1423 break :blk zcu;
16941424 } else blk: {
16951425 if (options.emit_h != null) return error.NoZigModuleForCHeader;
16961426 break :blk null;
16971427 };
1698 errdefer if (module) |zm| zm.deinit();
1699
1700 const error_return_tracing = !strip and switch (options.optimize_mode) {
1701 .Debug, .ReleaseSafe => (!options.target.isWasm() or options.target.os.tag == .emscripten) and
1702 !options.target.cpu.arch.isBpf() and (options.error_tracing orelse true),
1703 .ReleaseFast => options.error_tracing orelse false,
1704 .ReleaseSmall => false,
1705 };
1428 errdefer if (zcu) |u| u.deinit();
17061429
17071430 // For resource management purposes.
17081431 var owned_link_dir: ?std.fs.Dir = null;
17091432 errdefer if (owned_link_dir) |*dir| dir.close();
17101433
1711 const bin_file_emit: ?link.Emit = blk: {
1434 const bin_file_emit: ?Emit = blk: {
17121435 const emit_bin = options.emit_bin orelse break :blk null;
17131436
17141437 if (emit_bin.directory) |directory| {
1715 break :blk link.Emit{
1438 break :blk Emit{
17161439 .directory = directory,
17171440 .sub_path = emit_bin.basename,
17181441 };
......@@ -1725,9 +1448,9 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
17251448 .incremental => {},
17261449 }
17271450
1728 if (module) |zm| {
1729 break :blk link.Emit{
1730 .directory = zm.zig_cache_artifact_directory,
1451 if (zcu) |u| {
1452 break :blk Emit{
1453 .directory = u.zig_cache_artifact_directory,
17311454 .sub_path = emit_bin.basename,
17321455 };
17331456 }
......@@ -1752,17 +1475,17 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
17521475 .handle = artifact_dir,
17531476 .path = try options.local_cache_directory.join(arena, &[_][]const u8{artifact_sub_dir}),
17541477 };
1755 break :blk link.Emit{
1478 break :blk Emit{
17561479 .directory = link_artifact_directory,
17571480 .sub_path = emit_bin.basename,
17581481 };
17591482 };
17601483
1761 const implib_emit: ?link.Emit = blk: {
1484 const implib_emit: ?Emit = blk: {
17621485 const emit_implib = options.emit_implib orelse break :blk null;
17631486
17641487 if (emit_implib.directory) |directory| {
1765 break :blk link.Emit{
1488 break :blk Emit{
17661489 .directory = directory,
17671490 .sub_path = emit_implib.basename,
17681491 };
......@@ -1776,13 +1499,13 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
17761499
17771500 // Use the same directory as the bin. The CLI already emits an
17781501 // error if -fno-emit-bin is combined with -femit-implib.
1779 break :blk link.Emit{
1502 break :blk Emit{
17801503 .directory = bin_file_emit.?.directory,
17811504 .sub_path = emit_implib.basename,
17821505 };
17831506 };
17841507
1785 const docs_emit: ?link.Emit = blk: {
1508 const docs_emit: ?Emit = blk: {
17861509 const emit_docs = options.emit_docs orelse break :blk null;
17871510
17881511 if (emit_docs.directory) |directory| {
......@@ -1805,7 +1528,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
18051528 };
18061529
18071530 break :blk .{
1808 .directory = module.?.zig_cache_artifact_directory,
1531 .directory = zcu.?.zig_cache_artifact_directory,
18091532 .sub_path = emit_docs.basename,
18101533 };
18111534 };
......@@ -1828,131 +1551,20 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
18281551 system_libs.putAssumeCapacity(lib_name, options.system_lib_infos[i]);
18291552 }
18301553
1831 const bin_file = try link.File.openPath(gpa, .{
1832 .emit = bin_file_emit,
1833 .implib_emit = implib_emit,
1834 .docs_emit = docs_emit,
1835 .root_name = root_name,
1836 .module = module,
1837 .target = options.target,
1838 .sysroot = sysroot,
1839 .output_mode = options.output_mode,
1840 .link_mode = link_mode,
1841 .optimize_mode = options.optimize_mode,
1842 .use_lld = use_lld,
1843 .use_llvm = use_llvm,
1844 .use_lib_llvm = use_lib_llvm,
1845 .link_libc = link_libc,
1846 .link_libcpp = link_libcpp,
1847 .link_libunwind = link_libunwind,
1848 .darwin_sdk_layout = libc_dirs.darwin_sdk_layout,
1849 .objects = options.link_objects,
1850 .frameworks = options.frameworks,
1851 .framework_dirs = options.framework_dirs,
1852 .system_libs = system_libs,
1853 .wasi_emulated_libs = options.wasi_emulated_libs,
1854 .lib_dirs = options.lib_dirs,
1855 .rpath_list = options.rpath_list,
1856 .symbol_wrap_set = options.symbol_wrap_set,
1857 .strip = strip,
1858 .is_native_os = options.is_native_os,
1859 .is_native_abi = options.is_native_abi,
1860 .function_sections = options.function_sections,
1861 .data_sections = options.data_sections,
1862 .no_builtin = options.no_builtin,
1863 .allow_shlib_undefined = options.linker_allow_shlib_undefined,
1864 .bind_global_refs_locally = options.linker_bind_global_refs_locally orelse false,
1865 .compress_debug_sections = options.linker_compress_debug_sections orelse .none,
1866 .module_definition_file = options.linker_module_definition_file,
1867 .sort_section = options.linker_sort_section,
1868 .import_memory = options.linker_import_memory orelse false,
1869 .export_memory = options.linker_export_memory orelse !(options.linker_import_memory orelse false),
1870 .import_symbols = options.linker_import_symbols,
1871 .import_table = options.linker_import_table,
1872 .export_table = options.linker_export_table,
1873 .initial_memory = options.linker_initial_memory,
1874 .max_memory = options.linker_max_memory,
1875 .shared_memory = options.linker_shared_memory,
1876 .global_base = options.linker_global_base,
1877 .export_symbol_names = options.linker_export_symbol_names,
1878 .print_gc_sections = options.linker_print_gc_sections,
1879 .print_icf_sections = options.linker_print_icf_sections,
1880 .print_map = options.linker_print_map,
1881 .opt_bisect_limit = options.linker_opt_bisect_limit,
1882 .z_nodelete = options.linker_z_nodelete,
1883 .z_notext = options.linker_z_notext,
1884 .z_defs = options.linker_z_defs,
1885 .z_origin = options.linker_z_origin,
1886 .z_nocopyreloc = options.linker_z_nocopyreloc,
1887 .z_now = options.linker_z_now,
1888 .z_relro = options.linker_z_relro,
1889 .z_common_page_size = options.linker_z_common_page_size,
1890 .z_max_page_size = options.linker_z_max_page_size,
1891 .tsaware = options.linker_tsaware,
1892 .nxcompat = options.linker_nxcompat,
1893 .dynamicbase = options.linker_dynamicbase,
1894 .linker_optimization = linker_optimization,
1895 .major_subsystem_version = options.major_subsystem_version,
1896 .minor_subsystem_version = options.minor_subsystem_version,
1897 .entry = options.entry,
1898 .stack_size_override = options.stack_size_override,
1899 .image_base_override = options.image_base_override,
1900 .include_compiler_rt = include_compiler_rt,
1901 .linker_script = options.linker_script,
1902 .version_script = options.version_script,
1903 .gc_sections = options.linker_gc_sections,
1904 .eh_frame_hdr = link_eh_frame_hdr,
1905 .emit_relocs = options.link_emit_relocs,
1906 .rdynamic = options.rdynamic,
1907 .soname = options.soname,
1908 .version = options.version,
1909 .compatibility_version = options.compatibility_version,
1910 .libc_installation = libc_dirs.libc_installation,
1911 .pic = pic,
1912 .pie = pie,
1913 .lto = lto,
1914 .valgrind = valgrind,
1915 .tsan = tsan,
1916 .stack_check = stack_check,
1917 .stack_protector = stack_protector,
1918 .red_zone = red_zone,
1919 .omit_frame_pointer = omit_frame_pointer,
1920 .single_threaded = single_threaded,
1921 .verbose_link = options.verbose_link,
1922 .machine_code_model = options.machine_code_model,
1923 .dll_export_fns = dll_export_fns,
1924 .error_return_tracing = error_return_tracing,
1925 .llvm_cpu_features = llvm_cpu_features,
1926 .skip_linker_dependencies = options.skip_linker_dependencies,
1927 .each_lib_rpath = options.each_lib_rpath orelse options.is_native_os,
1928 .build_id = build_id,
1929 .cache_mode = cache_mode,
1930 .disable_lld_caching = options.disable_lld_caching or cache_mode == .whole,
1931 .subsystem = options.subsystem,
1932 .is_test = options.is_test,
1933 .dwarf_format = options.dwarf_format,
1934 .wasi_exec_model = wasi_exec_model,
1935 .hash_style = options.hash_style,
1936 .enable_link_snapshots = options.enable_link_snapshots,
1937 .install_name = options.install_name,
1938 .entitlements = options.entitlements,
1939 .pagezero_size = options.pagezero_size,
1940 .headerpad_size = options.headerpad_size,
1941 .headerpad_max_install_names = options.headerpad_max_install_names,
1942 .dead_strip_dylibs = options.dead_strip_dylibs,
1943 .force_undefined_symbols = options.force_undefined_symbols,
1944 .pdb_source_path = options.pdb_source_path,
1945 .pdb_out_path = options.pdb_out_path,
1946 .want_structured_cfg = options.want_structured_cfg,
1947 });
1948 errdefer bin_file.destroy();
1554 const each_lib_rpath = options.each_lib_rpath orelse
1555 options.root_mod.resolved_target.is_native_os;
1556
19491557 comp.* = .{
19501558 .gpa = gpa,
19511559 .arena = arena_allocator,
1560 .module = zcu,
1561 .root_mod = options.root_mod,
1562 .config = options.config,
1563 .bin_file = null,
1564 .cache_mode = cache_mode,
19521565 .zig_lib_directory = options.zig_lib_directory,
19531566 .local_cache_directory = options.local_cache_directory,
19541567 .global_cache_directory = options.global_cache_directory,
1955 .bin_file = bin_file,
19561568 .whole_bin_sub_path = whole_bin_sub_path,
19571569 .whole_implib_sub_path = whole_implib_sub_path,
19581570 .whole_docs_sub_path = whole_docs_sub_path,
......@@ -1966,8 +1578,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
19661578 .astgen_work_queue = std.fifo.LinearFifo(*Module.File, .Dynamic).init(gpa),
19671579 .embed_file_work_queue = std.fifo.LinearFifo(*Module.EmbedFile, .Dynamic).init(gpa),
19681580 .keep_source_files_loaded = options.keep_source_files_loaded,
1969 .c_frontend = c_frontend,
1970 .clang_argv = options.clang_argv,
19711581 .c_source_files = options.c_source_files,
19721582 .rc_source_files = options.rc_source_files,
19731583 .cache_parent = cache,
......@@ -1975,7 +1585,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
19751585 .libc_include_dir_list = libc_dirs.libc_include_dir_list,
19761586 .libc_framework_dir_list = libc_dirs.libc_framework_dir_list,
19771587 .rc_include_dir_list = rc_dirs.libc_include_dir_list,
1978 .sanitize_c = sanitize_c,
19791588 .thread_pool = options.thread_pool,
19801589 .clang_passthrough_mode = options.clang_passthrough_mode,
19811590 .clang_preprocessor_mode = options.clang_preprocessor_mode,
......@@ -1994,22 +1603,110 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
19941603 .formatted_panics = formatted_panics,
19951604 .time_report = options.time_report,
19961605 .stack_report = options.stack_report,
1997 .unwind_tables = unwind_tables,
19981606 .test_filter = options.test_filter,
19991607 .test_name_prefix = options.test_name_prefix,
2000 .test_evented_io = options.test_evented_io,
20011608 .debug_compiler_runtime_libs = options.debug_compiler_runtime_libs,
20021609 .debug_compile_errors = options.debug_compile_errors,
20031610 .libcxx_abi_version = options.libcxx_abi_version,
1611 .implib_emit = implib_emit,
1612 .docs_emit = docs_emit,
1613 .root_name = root_name,
1614 .sysroot = sysroot,
1615 .system_libs = system_libs,
1616 .version = options.version,
1617 .libc_installation = libc_dirs.libc_installation,
1618 .include_compiler_rt = include_compiler_rt,
1619 .objects = options.link_objects,
20041620 };
1621
1622 if (bin_file_emit) |emit| {
1623 comp.bin_file = try link.File.open(arena, .{
1624 .comp = comp,
1625 .emit = emit,
1626 .optimization = linker_optimization,
1627 .linker_script = options.linker_script,
1628 .z_nodelete = options.linker_z_nodelete,
1629 .z_notext = options.linker_z_notext,
1630 .z_defs = options.linker_z_defs,
1631 .z_origin = options.linker_z_origin,
1632 .z_nocopyreloc = options.linker_z_nocopyreloc,
1633 .z_now = options.linker_z_now,
1634 .z_relro = options.linker_z_relro,
1635 .z_common_page_size = options.linker_z_common_page_size,
1636 .z_max_page_size = options.linker_z_max_page_size,
1637 .darwin_sdk_layout = libc_dirs.darwin_sdk_layout,
1638 .frameworks = options.frameworks,
1639 .framework_dirs = options.framework_dirs,
1640 .wasi_emulated_libs = options.wasi_emulated_libs,
1641 .lib_dirs = options.lib_dirs,
1642 .rpath_list = options.rpath_list,
1643 .symbol_wrap_set = options.symbol_wrap_set,
1644 .function_sections = options.function_sections,
1645 .data_sections = options.data_sections,
1646 .no_builtin = options.no_builtin,
1647 .allow_shlib_undefined = options.linker_allow_shlib_undefined,
1648 .bind_global_refs_locally = options.linker_bind_global_refs_locally orelse false,
1649 .compress_debug_sections = options.linker_compress_debug_sections orelse .none,
1650 .module_definition_file = options.linker_module_definition_file,
1651 .sort_section = options.linker_sort_section,
1652 .import_symbols = options.linker_import_symbols,
1653 .import_table = options.linker_import_table,
1654 .export_table = options.linker_export_table,
1655 .initial_memory = options.linker_initial_memory,
1656 .max_memory = options.linker_max_memory,
1657 .global_base = options.linker_global_base,
1658 .export_symbol_names = options.linker_export_symbol_names,
1659 .print_gc_sections = options.linker_print_gc_sections,
1660 .print_icf_sections = options.linker_print_icf_sections,
1661 .print_map = options.linker_print_map,
1662 .opt_bisect_limit = options.linker_opt_bisect_limit,
1663 .tsaware = options.linker_tsaware,
1664 .nxcompat = options.linker_nxcompat,
1665 .dynamicbase = options.linker_dynamicbase,
1666 .major_subsystem_version = options.major_subsystem_version,
1667 .minor_subsystem_version = options.minor_subsystem_version,
1668 .stack_size_override = options.stack_size_override,
1669 .image_base_override = options.image_base_override,
1670 .version_script = options.version_script,
1671 .gc_sections = options.linker_gc_sections,
1672 .eh_frame_hdr = link_eh_frame_hdr,
1673 .emit_relocs = options.link_emit_relocs,
1674 .rdynamic = options.rdynamic,
1675 .soname = options.soname,
1676 .compatibility_version = options.compatibility_version,
1677 .verbose_link = options.verbose_link,
1678 .dll_export_fns = dll_export_fns,
1679 .skip_linker_dependencies = options.skip_linker_dependencies,
1680 .parent_compilation_link_libc = options.parent_compilation_link_libc,
1681 .each_lib_rpath = each_lib_rpath,
1682 .build_id = build_id,
1683 .disable_lld_caching = options.disable_lld_caching or cache_mode == .whole,
1684 .subsystem = options.subsystem,
1685 .dwarf_format = options.dwarf_format,
1686 .hash_style = options.hash_style,
1687 .enable_link_snapshots = options.enable_link_snapshots,
1688 .install_name = options.install_name,
1689 .entitlements = options.entitlements,
1690 .pagezero_size = options.pagezero_size,
1691 .headerpad_size = options.headerpad_size,
1692 .headerpad_max_install_names = options.headerpad_max_install_names,
1693 .dead_strip_dylibs = options.dead_strip_dylibs,
1694 .force_undefined_symbols = options.force_undefined_symbols,
1695 .pdb_source_path = options.pdb_source_path,
1696 .pdb_out_path = options.pdb_out_path,
1697 .want_structured_cfg = options.want_structured_cfg,
1698 .entry_addr = null, // CLI does not expose this option (yet?)
1699 });
1700 }
1701
20051702 break :comp comp;
20061703 };
20071704 errdefer comp.destroy();
20081705
2009 const target = comp.getTarget();
1706 const target = options.root_mod.resolved_target.result;
20101707
2011 const capable_of_building_compiler_rt = canBuildLibCompilerRt(target, comp.bin_file.options.use_llvm);
2012 const capable_of_building_zig_libc = canBuildZigLibC(target, comp.bin_file.options.use_llvm);
1708 const capable_of_building_compiler_rt = canBuildLibCompilerRt(target, options.config.use_llvm);
1709 const capable_of_building_zig_libc = canBuildZigLibC(target, options.config.use_llvm);
20131710
20141711 // Add a `CObject` for each `c_source_files`.
20151712 try comp.c_object_table.ensureTotalCapacity(gpa, options.c_source_files.len);
......@@ -2109,7 +1806,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
21091806 });
21101807 }
21111808 comp.work_queue.writeAssumeCapacity(&[_]Job{
2112 .{ .wasi_libc_crt_file = wasi_libc.execModelCrtFile(wasi_exec_model) },
1809 .{ .wasi_libc_crt_file = wasi_libc.execModelCrtFile(options.config.wasi_exec_model) },
21131810 .{ .wasi_libc_crt_file = .libc_a },
21141811 });
21151812 }
......@@ -2171,7 +1868,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
21711868 if (is_exe_or_dyn_lib) {
21721869 log.debug("queuing a job to build compiler_rt_lib", .{});
21731870 comp.job_queued_compiler_rt_lib = true;
2174 } else if (options.output_mode != .Obj) {
1871 } else if (output_mode != .Obj) {
21751872 log.debug("queuing a job to build compiler_rt_obj", .{});
21761873 // In this case we are making a static library, so we ask
21771874 // for a compiler-rt object to put in it.
......@@ -2283,7 +1980,7 @@ pub fn clearMiscFailures(comp: *Compilation) void {
22831980}
22841981
22851982pub fn getTarget(self: Compilation) Target {
2286 return self.bin_file.options.target;
1983 return self.root_mod.resolved_target.result;
22871984}
22881985
22891986fn restorePrevZigCacheArtifactDirectory(comp: *Compilation, directory: *Directory) void {
......@@ -2436,7 +2133,7 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void
24362133
24372134 // Make sure std.zig is inside the import_table. We unconditionally need
24382135 // it for start.zig.
2439 const std_mod = module.main_mod.deps.get("std").?;
2136 const std_mod = module.std_mod;
24402137 _ = try module.importPkg(std_mod);
24412138
24422139 // Normally we rely on importing std to in turn import the root source file
......@@ -2449,7 +2146,7 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void
24492146 _ = try module.importPkg(module.main_mod);
24502147 }
24512148
2452 if (module.main_mod.deps.get("compiler_rt")) |compiler_rt_mod| {
2149 if (module.root_mod.deps.get("compiler_rt")) |compiler_rt_mod| {
24532150 _ = try module.importPkg(compiler_rt_mod);
24542151 }
24552152
......@@ -2474,7 +2171,7 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void
24742171 try comp.work_queue.writeItem(.{ .analyze_mod = module.main_mod });
24752172 }
24762173
2477 if (module.main_mod.deps.get("compiler_rt")) |compiler_rt_mod| {
2174 if (module.root_mod.deps.get("compiler_rt")) |compiler_rt_mod| {
24782175 try comp.work_queue.writeItem(.{ .analyze_mod = compiler_rt_mod });
24792176 }
24802177 }
......@@ -2699,16 +2396,7 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes
26992396 if (comp.bin_file.options.module) |mod| {
27002397 const main_zig_file = try mod.main_mod.root.joinString(arena, mod.main_mod.root_src_path);
27012398 _ = try man.addFile(main_zig_file, null);
2702 {
2703 var seen_table = std.AutoHashMap(*Package.Module, void).init(arena);
2704
2705 // Skip builtin.zig; it is useless as an input, and we don't want to have to
2706 // write it before checking for a cache hit.
2707 const builtin_mod = mod.main_mod.deps.get("builtin").?;
2708 try seen_table.put(builtin_mod, {});
2709
2710 try addModuleTableToCacheHash(&man.hash, &arena_allocator, mod.main_mod.deps, &seen_table, .{ .files = man });
2711 }
2399 try addModuleTableToCacheHash(gpa, arena, &man.hash, mod.main_mod, .{ .files = man });
27122400
27132401 // Synchronize with other matching comments: ZigOnlyHashStuff
27142402 man.hash.add(comp.bin_file.options.valgrind);
......@@ -2762,8 +2450,6 @@ fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifes
27622450 cache_helpers.addOptionalEmitLoc(&man.hash, comp.emit_llvm_ir);
27632451 cache_helpers.addOptionalEmitLoc(&man.hash, comp.emit_llvm_bc);
27642452
2765 man.hash.addListOfBytes(comp.clang_argv);
2766
27672453 man.hash.addOptional(comp.bin_file.options.stack_size_override);
27682454 man.hash.addOptional(comp.bin_file.options.image_base_override);
27692455 man.hash.addOptional(comp.bin_file.options.gc_sections);
......@@ -3341,7 +3027,7 @@ pub const ErrorNoteHashContext = struct {
33413027 const eb = ctx.eb.tmpBundle();
33423028 const msg_a = eb.nullTerminatedString(a.msg);
33433029 const msg_b = eb.nullTerminatedString(b.msg);
3344 if (!std.mem.eql(u8, msg_a, msg_b)) return false;
3030 if (!mem.eql(u8, msg_a, msg_b)) return false;
33453031
33463032 if (a.src_loc == .none and b.src_loc == .none) return true;
33473033 if (a.src_loc == .none or b.src_loc == .none) return false;
......@@ -3351,7 +3037,7 @@ pub const ErrorNoteHashContext = struct {
33513037 const src_path_a = eb.nullTerminatedString(src_a.src_path);
33523038 const src_path_b = eb.nullTerminatedString(src_b.src_path);
33533039
3354 return std.mem.eql(u8, src_path_a, src_path_b) and
3040 return mem.eql(u8, src_path_a, src_path_b) and
33553041 src_a.line == src_b.line and
33563042 src_a.column == src_b.column and
33573043 src_a.span_main == src_b.span_main;
......@@ -4149,7 +3835,7 @@ pub const CImportResult = struct {
41493835 cache_hit: bool,
41503836 errors: std.zig.ErrorBundle,
41513837
4152 pub fn deinit(result: *CImportResult, gpa: std.mem.Allocator) void {
3838 pub fn deinit(result: *CImportResult, gpa: mem.Allocator) void {
41533839 result.errors.deinit(gpa);
41543840 }
41553841};
......@@ -5321,9 +5007,9 @@ pub fn addCCArgs(
53215007 argv.appendAssumeCapacity(arg);
53225008 }
53235009 }
5324 const mcmodel = comp.bin_file.options.machine_code_model;
5325 if (mcmodel != .default) {
5326 try argv.append(try std.fmt.allocPrint(arena, "-mcmodel={s}", .{@tagName(mcmodel)}));
5010 const code_model = comp.bin_file.options.machine_code_model;
5011 if (code_model != .default) {
5012 try argv.append(try std.fmt.allocPrint(arena, "-mcmodel={s}", .{@tagName(code_model)}));
53275013 }
53285014
53295015 switch (target.os.tag) {
......@@ -5618,68 +5304,6 @@ fn failCObjWithOwnedDiagBundle(
56185304 return error.AnalysisFail;
56195305}
56205306
5621/// The include directories used when preprocessing .rc files are separate from the
5622/// target. Which include directories are used is determined by `options.rc_includes`.
5623///
5624/// Note: It should be okay that the include directories used when compiling .rc
5625/// files differ from the include directories used when compiling the main
5626/// binary, since the .res format is not dependent on anything ABI-related. The
5627/// only relevant differences would be things like `#define` constants being
5628/// different in the MinGW headers vs the MSVC headers, but any such
5629/// differences would likely be a MinGW bug.
5630fn detectWin32ResourceIncludeDirs(arena: Allocator, options: InitOptions) !LibCDirs {
5631 // Set the includes to .none here when there are no rc files to compile
5632 var includes = if (options.rc_source_files.len > 0) options.rc_includes else .none;
5633 if (builtin.target.os.tag != .windows) {
5634 switch (includes) {
5635 // MSVC can't be found when the host isn't Windows, so short-circuit.
5636 .msvc => return error.WindowsSdkNotFound,
5637 // Skip straight to gnu since we won't be able to detect MSVC on non-Windows hosts.
5638 .any => includes = .gnu,
5639 .none, .gnu => {},
5640 }
5641 }
5642 while (true) {
5643 switch (includes) {
5644 .any, .msvc => return detectLibCIncludeDirs(
5645 arena,
5646 options.zig_lib_directory.path.?,
5647 .{
5648 .cpu = options.target.cpu,
5649 .os = options.target.os,
5650 .abi = .msvc,
5651 .ofmt = options.target.ofmt,
5652 },
5653 options.is_native_abi,
5654 // The .rc preprocessor will need to know the libc include dirs even if we
5655 // are not linking libc, so force 'link_libc' to true
5656 true,
5657 options.libc_installation,
5658 ) catch |err| {
5659 if (includes == .any) {
5660 // fall back to mingw
5661 includes = .gnu;
5662 continue;
5663 }
5664 return err;
5665 },
5666 .gnu => return detectLibCFromBuilding(arena, options.zig_lib_directory.path.?, .{
5667 .cpu = options.target.cpu,
5668 .os = options.target.os,
5669 .abi = .gnu,
5670 .ofmt = options.target.ofmt,
5671 }),
5672 .none => return LibCDirs{
5673 .libc_include_dir_list = &[0][]u8{},
5674 .libc_installation = null,
5675 .libc_framework_dir_list = &.{},
5676 .sysroot = null,
5677 .darwin_sdk_layout = null,
5678 },
5679 }
5680 }
5681}
5682
56835307fn failWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, comptime format: []const u8, args: anytype) SemaError {
56845308 @setCold(true);
56855309 var bundle: ErrorBundle.Wip = undefined;
......@@ -6061,7 +5685,7 @@ const LibCDirs = struct {
60615685 libc_installation: ?*const LibCInstallation,
60625686 libc_framework_dir_list: []const []const u8,
60635687 sysroot: ?[]const u8,
6064 darwin_sdk_layout: ?link.DarwinSdkLayout,
5688 darwin_sdk_layout: ?link.File.MachO.SdkLayout,
60655689};
60665690
60675691fn getZigShippedLibCIncludeDirsDarwin(arena: Allocator, zig_lib_dir: []const u8) !LibCDirs {
......@@ -6374,7 +5998,7 @@ fn parseLldStderr(comp: *Compilation, comptime prefix: []const u8, stderr: []con
63745998 err.context_lines = try context_lines.toOwnedSlice();
63755999 }
63766000
6377 var split = std.mem.splitSequence(u8, line, "error: ");
6001 var split = mem.splitSequence(u8, line, "error: ");
63786002 _ = split.first();
63796003
63806004 const duped_msg = try std.fmt.allocPrint(comp.gpa, "{s}: {s}", .{ prefix, split.rest() });
......@@ -6427,7 +6051,7 @@ fn canBuildLibCompilerRt(target: std.Target, use_llvm: bool) bool {
64276051 .spirv32, .spirv64 => return false,
64286052 else => {},
64296053 }
6430 return switch (zigBackend(target, use_llvm)) {
6054 return switch (target_util.zigBackend(target, use_llvm)) {
64316055 .stage2_llvm => true,
64326056 .stage2_x86_64 => if (target.ofmt == .elf) true else build_options.have_llvm,
64336057 else => build_options.have_llvm,
......@@ -6445,7 +6069,7 @@ fn canBuildZigLibC(target: std.Target, use_llvm: bool) bool {
64456069 .spirv32, .spirv64 => return false,
64466070 else => {},
64476071 }
6448 return switch (zigBackend(target, use_llvm)) {
6072 return switch (target_util.zigBackend(target, use_llvm)) {
64496073 .stage2_llvm => true,
64506074 .stage2_x86_64 => if (target.ofmt == .elf) true else build_options.have_llvm,
64516075 else => build_options.have_llvm,
......@@ -6454,236 +6078,7 @@ fn canBuildZigLibC(target: std.Target, use_llvm: bool) bool {
64546078
64556079pub fn getZigBackend(comp: Compilation) std.builtin.CompilerBackend {
64566080 const target = comp.bin_file.options.target;
6457 return zigBackend(target, comp.bin_file.options.use_llvm);
6458}
6459
6460fn zigBackend(target: std.Target, use_llvm: bool) std.builtin.CompilerBackend {
6461 if (use_llvm) return .stage2_llvm;
6462 if (target.ofmt == .c) return .stage2_c;
6463 return switch (target.cpu.arch) {
6464 .wasm32, .wasm64 => std.builtin.CompilerBackend.stage2_wasm,
6465 .arm, .armeb, .thumb, .thumbeb => .stage2_arm,
6466 .x86_64 => .stage2_x86_64,
6467 .x86 => .stage2_x86,
6468 .aarch64, .aarch64_be, .aarch64_32 => .stage2_aarch64,
6469 .riscv64 => .stage2_riscv64,
6470 .sparc64 => .stage2_sparc64,
6471 .spirv64 => .stage2_spirv64,
6472 else => .other,
6473 };
6474}
6475
6476pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Allocator.Error![:0]u8 {
6477 const tracy_trace = trace(@src());
6478 defer tracy_trace.end();
6479
6480 var buffer = std.ArrayList(u8).init(allocator);
6481 defer buffer.deinit();
6482
6483 const target = comp.getTarget();
6484 const generic_arch_name = target.cpu.arch.genericName();
6485 const zig_backend = comp.getZigBackend();
6486
6487 @setEvalBranchQuota(4000);
6488 try buffer.writer().print(
6489 \\const std = @import("std");
6490 \\/// Zig version. When writing code that supports multiple versions of Zig, prefer
6491 \\/// feature detection (i.e. with `@hasDecl` or `@hasField`) over version checks.
6492 \\pub const zig_version = std.SemanticVersion.parse(zig_version_string) catch unreachable;
6493 \\pub const zig_version_string = "{s}";
6494 \\pub const zig_backend = std.builtin.CompilerBackend.{};
6495 \\
6496 \\pub const output_mode = std.builtin.OutputMode.{};
6497 \\pub const link_mode = std.builtin.LinkMode.{};
6498 \\pub const is_test = {};
6499 \\pub const single_threaded = {};
6500 \\pub const abi = std.Target.Abi.{};
6501 \\pub const cpu: std.Target.Cpu = .{{
6502 \\ .arch = .{},
6503 \\ .model = &std.Target.{}.cpu.{},
6504 \\ .features = std.Target.{}.featureSet(&[_]std.Target.{}.Feature{{
6505 \\
6506 , .{
6507 build_options.version,
6508 std.zig.fmtId(@tagName(zig_backend)),
6509 std.zig.fmtId(@tagName(comp.bin_file.options.output_mode)),
6510 std.zig.fmtId(@tagName(comp.bin_file.options.link_mode)),
6511 comp.bin_file.options.is_test,
6512 comp.bin_file.options.single_threaded,
6513 std.zig.fmtId(@tagName(target.abi)),
6514 std.zig.fmtId(@tagName(target.cpu.arch)),
6515 std.zig.fmtId(generic_arch_name),
6516 std.zig.fmtId(target.cpu.model.name),
6517 std.zig.fmtId(generic_arch_name),
6518 std.zig.fmtId(generic_arch_name),
6519 });
6520
6521 for (target.cpu.arch.allFeaturesList(), 0..) |feature, index_usize| {
6522 const index = @as(std.Target.Cpu.Feature.Set.Index, @intCast(index_usize));
6523 const is_enabled = target.cpu.features.isEnabled(index);
6524 if (is_enabled) {
6525 try buffer.writer().print(" .{},\n", .{std.zig.fmtId(feature.name)});
6526 }
6527 }
6528 try buffer.writer().print(
6529 \\ }}),
6530 \\}};
6531 \\pub const os = std.Target.Os{{
6532 \\ .tag = .{},
6533 \\ .version_range = .{{
6534 ,
6535 .{std.zig.fmtId(@tagName(target.os.tag))},
6536 );
6537
6538 switch (target.os.getVersionRange()) {
6539 .none => try buffer.appendSlice(" .none = {} },\n"),
6540 .semver => |semver| try buffer.writer().print(
6541 \\ .semver = .{{
6542 \\ .min = .{{
6543 \\ .major = {},
6544 \\ .minor = {},
6545 \\ .patch = {},
6546 \\ }},
6547 \\ .max = .{{
6548 \\ .major = {},
6549 \\ .minor = {},
6550 \\ .patch = {},
6551 \\ }},
6552 \\ }}}},
6553 \\
6554 , .{
6555 semver.min.major,
6556 semver.min.minor,
6557 semver.min.patch,
6558
6559 semver.max.major,
6560 semver.max.minor,
6561 semver.max.patch,
6562 }),
6563 .linux => |linux| try buffer.writer().print(
6564 \\ .linux = .{{
6565 \\ .range = .{{
6566 \\ .min = .{{
6567 \\ .major = {},
6568 \\ .minor = {},
6569 \\ .patch = {},
6570 \\ }},
6571 \\ .max = .{{
6572 \\ .major = {},
6573 \\ .minor = {},
6574 \\ .patch = {},
6575 \\ }},
6576 \\ }},
6577 \\ .glibc = .{{
6578 \\ .major = {},
6579 \\ .minor = {},
6580 \\ .patch = {},
6581 \\ }},
6582 \\ }}}},
6583 \\
6584 , .{
6585 linux.range.min.major,
6586 linux.range.min.minor,
6587 linux.range.min.patch,
6588
6589 linux.range.max.major,
6590 linux.range.max.minor,
6591 linux.range.max.patch,
6592
6593 linux.glibc.major,
6594 linux.glibc.minor,
6595 linux.glibc.patch,
6596 }),
6597 .windows => |windows| try buffer.writer().print(
6598 \\ .windows = .{{
6599 \\ .min = {s},
6600 \\ .max = {s},
6601 \\ }}}},
6602 \\
6603 ,
6604 .{ windows.min, windows.max },
6605 ),
6606 }
6607 try buffer.appendSlice(
6608 \\};
6609 \\pub const target: std.Target = .{
6610 \\ .cpu = cpu,
6611 \\ .os = os,
6612 \\ .abi = abi,
6613 \\ .ofmt = object_format,
6614 \\
6615 );
6616
6617 if (target.dynamic_linker.get()) |dl| {
6618 try buffer.writer().print(
6619 \\ .dynamic_linker = std.Target.DynamicLinker.init("{s}"),
6620 \\}};
6621 \\
6622 , .{dl});
6623 } else {
6624 try buffer.appendSlice(
6625 \\ .dynamic_linker = std.Target.DynamicLinker.none,
6626 \\};
6627 \\
6628 );
6629 }
6630
6631 try buffer.writer().print(
6632 \\pub const object_format = std.Target.ObjectFormat.{};
6633 \\pub const mode = std.builtin.OptimizeMode.{};
6634 \\pub const link_libc = {};
6635 \\pub const link_libcpp = {};
6636 \\pub const have_error_return_tracing = {};
6637 \\pub const valgrind_support = {};
6638 \\pub const sanitize_thread = {};
6639 \\pub const position_independent_code = {};
6640 \\pub const position_independent_executable = {};
6641 \\pub const strip_debug_info = {};
6642 \\pub const code_model = std.builtin.CodeModel.{};
6643 \\pub const omit_frame_pointer = {};
6644 \\
6645 , .{
6646 std.zig.fmtId(@tagName(target.ofmt)),
6647 std.zig.fmtId(@tagName(comp.bin_file.options.optimize_mode)),
6648 comp.bin_file.options.link_libc,
6649 comp.bin_file.options.link_libcpp,
6650 comp.bin_file.options.error_return_tracing,
6651 comp.bin_file.options.valgrind,
6652 comp.bin_file.options.tsan,
6653 comp.bin_file.options.pic,
6654 comp.bin_file.options.pie,
6655 comp.bin_file.options.strip,
6656 std.zig.fmtId(@tagName(comp.bin_file.options.machine_code_model)),
6657 comp.bin_file.options.omit_frame_pointer,
6658 });
6659
6660 if (target.os.tag == .wasi) {
6661 const wasi_exec_model_fmt = std.zig.fmtId(@tagName(comp.bin_file.options.wasi_exec_model));
6662 try buffer.writer().print(
6663 \\pub const wasi_exec_model = std.builtin.WasiExecModel.{};
6664 \\
6665 , .{wasi_exec_model_fmt});
6666 }
6667
6668 if (comp.bin_file.options.is_test) {
6669 try buffer.appendSlice(
6670 \\pub var test_functions: []const std.builtin.TestFn = undefined; // overwritten later
6671 \\
6672 );
6673 if (comp.test_evented_io) {
6674 try buffer.appendSlice(
6675 \\pub const test_io_mode = .evented;
6676 \\
6677 );
6678 } else {
6679 try buffer.appendSlice(
6680 \\pub const test_io_mode = .blocking;
6681 \\
6682 );
6683 }
6684 }
6685
6686 return buffer.toOwnedSliceSentinel(0);
6081 return target_util.zigBackend(target, comp.bin_file.options.use_llvm);
66876082}
66886083
66896084pub fn updateSubCompilation(
......@@ -6730,21 +6125,46 @@ fn buildOutputFromZig(
67306125 const tracy_trace = trace(@src());
67316126 defer tracy_trace.end();
67326127
6128 var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa);
6129 defer arena_allocator.deinit();
6130 const arena = arena_allocator.allocator();
6131
67336132 assert(output_mode != .Exe);
67346133
6735 var main_mod: Package.Module = .{
6736 .root = .{ .root_dir = comp.zig_lib_directory },
6737 .root_src_path = src_basename,
6134 const config = try Config.resolve(.{
6135 .output_mode = output_mode,
6136 .resolved_target = comp.root_mod.resolved_target,
6137 .is_test = false,
6138 .have_zcu = true,
6139 .emit_bin = true,
6140 .root_optimize_mode = comp.compilerRtOptMode(),
6141 });
6142
6143 const root_mod = Package.Module.create(.{
6144 .paths = .{
6145 .root = .{ .root_dir = comp.zig_lib_directory },
6146 .root_src_path = src_basename,
6147 },
67386148 .fully_qualified_name = "root",
6739 };
6149 .inherited = .{
6150 .strip = comp.compilerRtStrip(),
6151 .stack_check = false,
6152 .stack_protector = 0,
6153 .red_zone = comp.root_mod.red_zone,
6154 .omit_frame_pointer = comp.root_mod.omit_frame_pointer,
6155 .unwind_tables = comp.bin_file.options.eh_frame_hdr,
6156 .pic = comp.root_mod.pic,
6157 },
6158 .global = config,
6159 .cc_argv = &.{},
6160 });
67406161 const root_name = src_basename[0 .. src_basename.len - std.fs.path.extension(src_basename).len];
67416162 const target = comp.getTarget();
6742 const bin_basename = try std.zig.binNameAlloc(comp.gpa, .{
6163 const bin_basename = try std.zig.binNameAlloc(arena, .{
67436164 .root_name = root_name,
67446165 .target = target,
67456166 .output_mode = output_mode,
67466167 });
6747 defer comp.gpa.free(bin_basename);
67486168
67496169 const emit_bin = Compilation.EmitLoc{
67506170 .directory = null, // Put it in the cache directory.
......@@ -6754,33 +6174,18 @@ fn buildOutputFromZig(
67546174 .global_cache_directory = comp.global_cache_directory,
67556175 .local_cache_directory = comp.global_cache_directory,
67566176 .zig_lib_directory = comp.zig_lib_directory,
6177 .resolved = config,
67576178 .cache_mode = .whole,
6758 .target = target,
67596179 .root_name = root_name,
6760 .main_mod = &main_mod,
6761 .output_mode = output_mode,
6180 .root_mod = root_mod,
67626181 .thread_pool = comp.thread_pool,
67636182 .libc_installation = comp.bin_file.options.libc_installation,
67646183 .emit_bin = emit_bin,
6765 .optimize_mode = comp.compilerRtOptMode(),
67666184 .link_mode = .Static,
67676185 .function_sections = true,
67686186 .data_sections = true,
67696187 .no_builtin = true,
6770 .want_sanitize_c = false,
6771 .want_stack_check = false,
6772 .want_stack_protector = 0,
6773 .want_red_zone = comp.bin_file.options.red_zone,
6774 .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer,
6775 .want_valgrind = false,
6776 .want_tsan = false,
6777 .want_unwind_tables = comp.bin_file.options.eh_frame_hdr,
6778 .want_pic = comp.bin_file.options.pic,
6779 .want_pie = null,
67806188 .emit_h = null,
6781 .strip = comp.compilerRtStrip(),
6782 .is_native_os = comp.bin_file.options.is_native_os,
6783 .is_native_abi = comp.bin_file.options.is_native_abi,
67846189 .self_exe_path = comp.self_exe_path,
67856190 .verbose_cc = comp.verbose_cc,
67866191 .verbose_link = comp.bin_file.options.verbose_link,
......@@ -6815,7 +6220,7 @@ pub fn build_crt_file(
68156220 output_mode: std.builtin.OutputMode,
68166221 misc_task_tag: MiscTask,
68176222 prog_node: *std.Progress.Node,
6818 c_source_files: []const Compilation.CSourceFile,
6223 c_source_files: []const CSourceFile,
68196224) !void {
68206225 const tracy_trace = trace(@src());
68216226 defer tracy_trace.end();
src/Compilation/Config.zig created+382
......@@ -0,0 +1,382 @@
1//! User-specified settings that have all the defaults resolved into concrete values.
2
3have_zcu: bool,
4output_mode: std.builtin.OutputMode,
5link_mode: std.builtin.LinkMode,
6link_libc: bool,
7link_libcpp: bool,
8link_libunwind: bool,
9any_unwind_tables: bool,
10pie: bool,
11/// If this is true then linker code is responsible for making an LLVM IR
12/// Module, outputting it to an object file, and then linking that together
13/// with link options and other objects. Otherwise (depending on `use_lld`)
14/// linker code directly outputs and updates the final binary.
15use_llvm: bool,
16/// Whether or not the LLVM library API will be used by the LLVM backend.
17use_lib_llvm: bool,
18/// If this is true then linker code is responsible for outputting an object
19/// file and then using LLD to link it together with the link options and other
20/// objects. Otherwise (depending on `use_llvm`) linker code directly outputs
21/// and updates the final binary.
22use_lld: bool,
23c_frontend: CFrontend,
24lto: bool,
25/// WASI-only. Type of WASI execution model ("command" or "reactor").
26/// Always set to `command` for non-WASI targets.
27wasi_exec_model: std.builtin.WasiExecModel,
28import_memory: bool,
29export_memory: bool,
30shared_memory: bool,
31is_test: bool,
32test_evented_io: bool,
33entry: ?[]const u8,
34
35pub const CFrontend = enum { clang, aro };
36
37pub const Options = struct {
38 output_mode: std.builtin.OutputMode,
39 resolved_target: Module.ResolvedTarget,
40 is_test: bool,
41 have_zcu: bool,
42 emit_bin: bool,
43 root_optimize_mode: ?std.builtin.OptimizeMode = null,
44 link_mode: ?std.builtin.LinkMode = null,
45 ensure_libc_on_non_freestanding: bool = false,
46 ensure_libcpp_on_non_freestanding: bool = false,
47 any_non_single_threaded: bool = false,
48 any_sanitize_thread: bool = false,
49 any_unwind_tables: bool = false,
50 any_dyn_libs: bool = false,
51 c_source_files_len: usize = 0,
52 emit_llvm_ir: bool = false,
53 emit_llvm_bc: bool = false,
54 link_libc: ?bool = null,
55 link_libcpp: ?bool = null,
56 link_libunwind: ?bool = null,
57 pie: ?bool = null,
58 use_llvm: ?bool = null,
59 use_lib_llvm: ?bool = null,
60 use_lld: ?bool = null,
61 use_clang: ?bool = null,
62 lto: ?bool = null,
63 entry: union(enum) {
64 default,
65 disabled,
66 enabled,
67 named: []const u8,
68 } = .default,
69 /// WASI-only. Type of WASI execution model ("command" or "reactor").
70 wasi_exec_model: ?std.builtin.WasiExecModel = null,
71 import_memory: ?bool = null,
72 export_memory: ?bool = null,
73 shared_memory: ?bool = null,
74 test_evented_io: bool = false,
75};
76
77pub fn resolve(options: Options) !Config {
78 const target = options.resolved_target.result;
79
80 // WASI-only. Resolve the optional exec-model option, defaults to command.
81 if (target.os.tag != .wasi and options.wasi_exec_model != null)
82 return error.WasiExecModelRequiresWasi;
83 const wasi_exec_model = options.wasi_exec_model orelse .command;
84
85 const shared_memory = b: {
86 if (!target.cpu.arch.isWasm()) {
87 if (options.shared_memory == true) return error.SharedMemoryIsWasmOnly;
88 break :b false;
89 }
90 if (options.output_mode == .Obj) {
91 if (options.shared_memory == true) return error.ObjectFilesCannotShareMemory;
92 break :b false;
93 }
94 if (!std.Target.wasm.featureSetHasAll(target.cpu.features, .{ .atomics, .bulk_memory })) {
95 if (options.shared_memory == true)
96 return error.SharedMemoryRequiresAtomicsAndBulkMemory;
97 break :b false;
98 }
99 if (options.any_non_single_threaded) {
100 if (options.shared_memory == false)
101 return error.ThreadsRequireSharedMemory;
102 break :b true;
103 }
104 break :b options.shared_memory orelse false;
105 };
106
107 const entry: ?[]const u8 = switch (options.entry) {
108 .disabled => null,
109 .default => b: {
110 if (options.output_mode != .Exe) break :b null;
111 break :b target_util.defaultEntrySymbolName(target, wasi_exec_model) orelse
112 return error.UnknownTargetEntryPoint;
113 },
114 .enabled => target_util.defaultEntrySymbolName(target, wasi_exec_model) orelse
115 return error.UnknownTargetEntryPoint,
116 .named => |name| name,
117 };
118 if (entry != null and options.output_mode != .Exe)
119 return error.NonExecutableEntryPoint;
120
121 // *If* the LLVM backend were to be selected, should Zig use the LLVM
122 // library to build the LLVM module?
123 const use_lib_llvm = b: {
124 if (!build_options.have_llvm) {
125 if (options.use_lib_llvm == true) return error.LlvmLibraryUnavailable;
126 break :b false;
127 }
128 break :b options.use_lib_llvm orelse true;
129 };
130
131 const root_optimize_mode = options.root_optimize_mode orelse .Debug;
132
133 // Make a decision on whether to use LLVM backend for machine code generation.
134 // Note that using the LLVM backend does not necessarily mean using LLVM libraries.
135 // For example, Zig can emit .bc and .ll files directly, and this is still considered
136 // using "the LLVM backend".
137 const use_llvm = b: {
138 // If emitting to LLVM bitcode object format, must use LLVM backend.
139 if (options.emit_llvm_ir or options.emit_llvm_bc) {
140 if (options.use_llvm == false) return error.EmittingLlvmModuleRequiresLlvmBackend;
141 break :b true;
142 }
143
144 // If LLVM does not support the target, then we can't use it.
145 if (!target_util.hasLlvmSupport(target, target.ofmt)) {
146 if (options.use_llvm == true) return error.LlvmLacksTargetSupport;
147 break :b false;
148 }
149
150 if (options.use_llvm) |x| break :b x;
151
152 // If we have no zig code to compile, no need for LLVM.
153 if (!options.have_zcu) break :b false;
154
155 // If we cannot use LLVM libraries, then our own backends will be a
156 // better default since the LLVM backend can only produce bitcode
157 // and not an object file or executable.
158 if (!use_lib_llvm) break :b false;
159
160 // Prefer LLVM for release builds.
161 if (root_optimize_mode != .Debug) break :b true;
162
163 // At this point we would prefer to use our own self-hosted backend,
164 // because the compilation speed is better than LLVM. But only do it if
165 // we are confident in the robustness of the backend.
166 break :b !target_util.selfHostedBackendIsAsRobustAsLlvm(target);
167 };
168
169 if (!use_lib_llvm and use_llvm and options.emit_bin) {
170 // Explicit request to use LLVM to produce an object file, but without
171 // using LLVM libraries. Impossible.
172 return error.EmittingBinaryRequiresLlvmLibrary;
173 }
174
175 // Make a decision on whether to use LLD or our own linker.
176 const use_lld = b: {
177 if (target.isDarwin()) {
178 if (options.use_lld == true) return error.LldIncompatibleOs;
179 break :b false;
180 }
181
182 if (!build_options.have_llvm) {
183 if (options.use_lld == true) return error.LldUnavailable;
184 break :b false;
185 }
186
187 if (target.ofmt == .c) {
188 if (options.use_lld == true) return error.LldIncompatibleObjectFormat;
189 break :b false;
190 }
191
192 if (options.lto == true) {
193 if (options.use_lld == false) return error.LtoRequiresLld;
194 break :b true;
195 }
196
197 if (options.use_lld) |x| break :b x;
198 break :b true;
199 };
200
201 // Make a decision on whether to use Clang or Aro for translate-c and compiling C files.
202 const c_frontend: CFrontend = b: {
203 if (!build_options.have_llvm) {
204 if (options.use_clang == true) return error.ClangUnavailable;
205 break :b .aro;
206 }
207 if (options.use_clang) |clang| {
208 break :b if (clang) .clang else .aro;
209 }
210 break :b .clang;
211 };
212
213 const lto = b: {
214 if (!use_lld) {
215 // zig ld LTO support is tracked by
216 // https://github.com/ziglang/zig/issues/8680
217 if (options.lto == true) return error.LtoRequiresLld;
218 break :b false;
219 }
220
221 if (options.lto) |x| break :b x;
222 if (options.c_source_files_len == 0) break :b false;
223
224 if (target.cpu.arch.isRISCV()) {
225 // Clang and LLVM currently don't support RISC-V target-abi for LTO.
226 // Compiling with LTO may fail or produce undesired results.
227 // See https://reviews.llvm.org/D71387
228 // See https://reviews.llvm.org/D102582
229 break :b false;
230 }
231
232 break :b switch (options.output_mode) {
233 .Lib, .Obj => false,
234 .Exe => switch (root_optimize_mode) {
235 .Debug => false,
236 .ReleaseSafe, .ReleaseFast, .ReleaseSmall => true,
237 },
238 };
239 };
240
241 const link_libcpp = b: {
242 if (options.link_libcpp == true) break :b true;
243 if (options.any_sanitize_thread) {
244 // TSAN is (for now...) implemented in C++ so it requires linking libc++.
245 if (options.link_libcpp == false) return error.SanitizeThreadRequiresLibCpp;
246 break :b true;
247 }
248 if (options.ensure_libcpp_on_non_freestanding and target.os.tag != .freestanding)
249 break :b true;
250
251 break :b false;
252 };
253
254 const link_libunwind = b: {
255 if (link_libcpp and target_util.libcNeedsLibUnwind(target)) {
256 if (options.link_libunwind == false) return error.LibCppRequiresLibUnwind;
257 break :b true;
258 }
259 break :b options.link_libunwind orelse false;
260 };
261
262 const link_libc = b: {
263 if (target_util.osRequiresLibC(target)) {
264 if (options.link_libc == false) return error.OsRequiresLibC;
265 break :b true;
266 }
267 if (link_libcpp) {
268 if (options.link_libc == false) return error.LibCppRequiresLibC;
269 break :b true;
270 }
271 if (link_libunwind) {
272 if (options.link_libc == false) return error.LibUnwindRequiresLibC;
273 break :b true;
274 }
275 if (options.link_libc) |x| break :b x;
276 if (options.ensure_libc_on_non_freestanding and target.os.tag != .freestanding)
277 break :b true;
278
279 break :b false;
280 };
281
282 const any_unwind_tables = options.any_unwind_tables or
283 link_libunwind or target_util.needUnwindTables(target);
284
285 const link_mode = b: {
286 const explicitly_exe_or_dyn_lib = switch (options.output_mode) {
287 .Obj => false,
288 .Lib => (options.link_mode orelse .Static) == .Dynamic,
289 .Exe => true,
290 };
291
292 if (target_util.cannotDynamicLink(target)) {
293 if (options.link_mode == .Dynamic) return error.TargetCannotDynamicLink;
294 break :b .Static;
295 }
296 if (explicitly_exe_or_dyn_lib and link_libc and
297 (target.isGnuLibC() or target_util.osRequiresLibC(target)))
298 {
299 if (options.link_mode == .Static) return error.LibCRequiresDynamicLinking;
300 break :b .Dynamic;
301 }
302 // When creating a executable that links to system libraries, we
303 // require dynamic linking, but we must not link static libraries
304 // or object files dynamically!
305 if (options.any_dyn_libs and options.output_mode == .Exe) {
306 if (options.link_mode == .Static) return error.SharedLibrariesRequireDynamicLinking;
307 break :b .Dynamic;
308 }
309
310 if (options.link_mode) |link_mode| break :b link_mode;
311
312 if (explicitly_exe_or_dyn_lib and link_libc and
313 options.resolved_target.is_native_abi and target.abi.isMusl())
314 {
315 // If targeting the system's native ABI and the system's libc is
316 // musl, link dynamically by default.
317 break :b .Dynamic;
318 }
319
320 // Static is generally a better default. Fight me.
321 break :b .Static;
322 };
323
324 const import_memory = options.import_memory orelse false;
325 const export_memory = b: {
326 if (link_mode == .Dynamic) {
327 if (options.export_memory == true) return error.ExportMemoryAndDynamicIncompatible;
328 break :b false;
329 }
330 if (options.export_memory) |x| break :b x;
331 break :b !import_memory;
332 };
333
334 const pie: bool = b: {
335 switch (options.output_mode) {
336 .Obj, .Exe => {},
337 .Lib => if (link_mode == .Dynamic) {
338 if (options.pie == true) return error.DynamicLibraryPrecludesPie;
339 break :b false;
340 },
341 }
342 if (target_util.requiresPIE(target)) {
343 if (options.pie == false) return error.TargetRequiresPie;
344 break :b true;
345 }
346 if (options.any_sanitize_thread) {
347 if (options.pie == false) return error.SanitizeThreadRequiresPie;
348 break :b true;
349 }
350 if (options.pie) |pie| break :b pie;
351 break :b false;
352 };
353
354 return .{
355 .output_mode = options.output_mode,
356 .have_zcu = options.have_zcu,
357 .is_test = options.is_test,
358 .test_evented_io = options.test_evented_io,
359 .link_mode = link_mode,
360 .link_libc = link_libc,
361 .link_libcpp = link_libcpp,
362 .link_libunwind = link_libunwind,
363 .any_unwind_tables = any_unwind_tables,
364 .pie = pie,
365 .lto = lto,
366 .import_memory = import_memory,
367 .export_memory = export_memory,
368 .shared_memory = shared_memory,
369 .c_frontend = c_frontend,
370 .use_llvm = use_llvm,
371 .use_lib_llvm = use_lib_llvm,
372 .use_lld = use_lld,
373 .entry = entry,
374 .wasi_exec_model = wasi_exec_model,
375 };
376}
377
378const std = @import("std");
379const Module = @import("../Package.zig").Module;
380const Config = @This();
381const target_util = @import("../target.zig");
382const build_options = @import("build_options");
src/Module.zig+3-5
......@@ -59,6 +59,7 @@ root_mod: *Package.Module,
5959/// Normally, `main_mod` and `root_mod` are the same. The exception is `zig test`, in which
6060/// `root_mod` is the test runner, and `main_mod` is the user's source file which has the tests.
6161main_mod: *Package.Module,
62std_mod: *Package.Module,
6263sema_prog_node: std.Progress.Node = undefined,
6364
6465/// Used by AstGen worker to load and store ZIR cache.
......@@ -3599,7 +3600,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
35993600
36003601 // TODO: figure out how this works under incremental changes to builtin.zig!
36013602 const builtin_type_target_index: InternPool.Index = blk: {
3602 const std_mod = mod.main_mod.deps.get("std").?;
3603 const std_mod = mod.std_mod;
36033604 if (decl.getFileScope(mod).mod != std_mod) break :blk .none;
36043605 // We're in the std module.
36053606 const std_file = (try mod.importPkg(std_mod)).file;
......@@ -3924,10 +3925,7 @@ pub fn importFile(
39243925 import_string: []const u8,
39253926) !ImportFileResult {
39263927 if (std.mem.eql(u8, import_string, "std")) {
3927 return mod.importPkg(mod.main_mod.deps.get("std").?);
3928 }
3929 if (std.mem.eql(u8, import_string, "builtin")) {
3930 return mod.importPkg(mod.main_mod.deps.get("builtin").?);
3928 return mod.importPkg(mod.std_mod);
39313929 }
39323930 if (std.mem.eql(u8, import_string, "root")) {
39333931 return mod.importPkg(mod.root_mod);
src/Package/Module.zig+403-6
......@@ -1,6 +1,6 @@
11//! Corresponds to something that Zig source code can `@import`.
2//! Not to be confused with src/Module.zig which should be renamed
3//! to something else. https://github.com/ziglang/zig/issues/14307
2//! Not to be confused with src/Module.zig which will be renamed
3//! to Zcu. https://github.com/ziglang/zig/issues/14307
44
55/// Only files inside this directory can be imported.
66root: Package.Path,
......@@ -14,6 +14,26 @@ fully_qualified_name: []const u8,
1414/// responsible for detecting these names and using the correct package.
1515deps: Deps = .{},
1616
17resolved_target: ResolvedTarget,
18optimize_mode: std.builtin.OptimizeMode,
19code_model: std.builtin.CodeModel,
20single_threaded: bool,
21error_tracing: bool,
22valgrind: bool,
23pic: bool,
24strip: bool,
25omit_frame_pointer: bool,
26stack_check: bool,
27stack_protector: u32,
28red_zone: bool,
29sanitize_c: bool,
30sanitize_thread: bool,
31unwind_tables: bool,
32cc_argv: []const []const u8,
33
34/// The contents of `@import("builtin")` for this module.
35generated_builtin_source: []const u8,
36
1737pub const Deps = std.StringArrayHashMapUnmanaged(*Module);
1838
1939pub const Tree = struct {
......@@ -21,10 +41,382 @@ pub const Tree = struct {
2141 build_module_table: std.AutoArrayHashMapUnmanaged(MultiHashHexDigest, *Module),
2242};
2343
24pub fn create(allocator: Allocator, m: Module) Allocator.Error!*Module {
25 const new = try allocator.create(Module);
26 new.* = m;
27 return new;
44pub const CreateOptions = struct {
45 /// Where to store builtin.zig. The global cache directory is used because
46 /// it is a pure function based on CLI flags.
47 global_cache_directory: Cache.Directory,
48 paths: Paths,
49 fully_qualified_name: []const u8,
50
51 cc_argv: []const []const u8,
52 inherited: Inherited,
53 global: Compilation.Config,
54 /// If this is null then `resolved_target` must be non-null.
55 parent: ?*Package.Module,
56
57 builtin_mod: ?*Package.Module,
58
59 pub const Paths = struct {
60 root: Package.Path,
61 /// Relative to `root`. May contain path separators.
62 root_src_path: []const u8,
63 };
64
65 pub const Inherited = struct {
66 /// If this is null then `parent` must be non-null.
67 resolved_target: ?ResolvedTarget = null,
68 optimize_mode: ?std.builtin.OptimizeMode = null,
69 code_model: ?std.builtin.CodeModel = null,
70 single_threaded: ?bool = null,
71 error_tracing: ?bool = null,
72 valgrind: ?bool = null,
73 pic: ?bool = null,
74 strip: ?bool = null,
75 omit_frame_pointer: ?bool = null,
76 stack_check: ?bool = null,
77 /// null means default.
78 /// 0 means no stack protector.
79 /// other number means stack protection with that buffer size.
80 stack_protector: ?u32 = null,
81 red_zone: ?bool = null,
82 unwind_tables: ?bool = null,
83 sanitize_c: ?bool = null,
84 sanitize_thread: ?bool = null,
85 };
86};
87
88pub const ResolvedTarget = struct {
89 result: std.Target,
90 is_native_os: bool,
91 is_native_abi: bool,
92 llvm_cpu_features: ?[*:0]const u8 = null,
93};
94
95/// At least one of `parent` and `resolved_target` must be non-null.
96pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module {
97 const resolved_target = options.inherited.resolved_target orelse options.parent.?.resolved_target;
98 const target = resolved_target.result;
99
100 const optimize_mode = options.inherited.optimize_mode orelse
101 if (options.parent) |p| p.optimize_mode else .Debug;
102
103 const unwind_tables = options.inherited.unwind_tables orelse
104 if (options.parent) |p| p.unwind_tables else options.global.any_unwind_tables;
105
106 const strip = b: {
107 if (options.inherited.strip) |x| break :b x;
108 if (options.parent) |p| break :b p.strip;
109 if (optimize_mode == .ReleaseSmall) break :b true;
110 if (!target_util.hasDebugInfo(target)) break :b true;
111 break :b false;
112 };
113
114 const valgrind = b: {
115 if (!target_util.hasValgrindSupport(target)) {
116 if (options.inherited.valgrind == true)
117 return error.ValgrindUnsupportedOnTarget;
118 break :b false;
119 }
120 if (options.inherited.valgrind) |x| break :b x;
121 if (options.parent) |p| break :b p.valgrind;
122 if (strip) break :b false;
123 break :b optimize_mode == .Debug;
124 };
125
126 const zig_backend = target_util.zigBackend(target, options.global.use_llvm);
127
128 const single_threaded = b: {
129 if (target_util.alwaysSingleThreaded(target)) {
130 if (options.inherited.single_threaded == false)
131 return error.TargetRequiresSingleThreaded;
132 break :b true;
133 }
134
135 if (options.global.have_zcu) {
136 if (!target_util.supportsThreads(target, zig_backend)) {
137 if (options.inherited.single_threaded == false)
138 return error.BackendRequiresSingleThreaded;
139 break :b true;
140 }
141 }
142
143 if (options.inherited.single_threaded) |x| break :b x;
144 if (options.parent) |p| break :b p.single_threaded;
145 break :b target_util.defaultSingleThreaded(target);
146 };
147
148 const error_tracing = b: {
149 if (options.inherited.error_tracing) |x| break :b x;
150 if (options.parent) |p| break :b p.error_tracing;
151 if (strip) break :b false;
152 break :b switch (optimize_mode) {
153 .Debug => true,
154 .ReleaseSafe, .ReleaseFast, .ReleaseSmall => false,
155 };
156 };
157
158 const pic = b: {
159 if (target_util.requiresPIC(target, options.global.link_libc)) {
160 if (options.inherited.pic == false)
161 return error.TargetRequiresPic;
162 break :b true;
163 }
164 if (options.global.pie) {
165 if (options.inherited.pic == false)
166 return error.PieRequiresPic;
167 break :b true;
168 }
169 if (options.global.link_mode == .Dynamic) {
170 if (options.inherited.pic == false)
171 return error.DynamicLinkingRequiresPic;
172 break :b true;
173 }
174 if (options.inherited.pic) |x| break :b x;
175 if (options.parent) |p| break :b p.pic;
176 break :b false;
177 };
178
179 const red_zone = b: {
180 if (!target_util.hasRedZone(target)) {
181 if (options.inherited.red_zone == true)
182 return error.TargetHasNoRedZone;
183 break :b true;
184 }
185 if (options.inherited.red_zone) |x| break :b x;
186 if (options.parent) |p| break :b p.red_zone;
187 break :b true;
188 };
189
190 const omit_frame_pointer = b: {
191 if (options.inherited.omit_frame_pointer) |x| break :b x;
192 if (options.parent) |p| break :b p.omit_frame_pointer;
193 if (optimize_mode == .Debug) break :b false;
194 break :b true;
195 };
196
197 const sanitize_thread = b: {
198 if (options.inherited.sanitize_thread) |x| break :b x;
199 if (options.parent) |p| break :b p.sanitize_thread;
200 break :b false;
201 };
202
203 const code_model = b: {
204 if (options.inherited.code_model) |x| break :b x;
205 if (options.parent) |p| break :b p.code_model;
206 break :b .default;
207 };
208
209 const is_safe_mode = switch (optimize_mode) {
210 .Debug, .ReleaseSafe => true,
211 .ReleaseFast, .ReleaseSmall => false,
212 };
213
214 const sanitize_c = b: {
215 if (options.inherited.sanitize_c) |x| break :b x;
216 if (options.parent) |p| break :b p.sanitize_c;
217 break :b is_safe_mode;
218 };
219
220 const stack_check = b: {
221 if (!target_util.supportsStackProbing(target)) {
222 if (options.inherited.stack_check == true)
223 return error.StackCheckUnsupportedByTarget;
224 break :b false;
225 }
226 if (options.inherited.stack_check) |x| break :b x;
227 if (options.parent) |p| break :b p.stack_check;
228 break :b is_safe_mode;
229 };
230
231 const stack_protector: u32 = sp: {
232 if (!target_util.supportsStackProtector(target, zig_backend)) {
233 if (options.inherited.stack_protector) |x| {
234 if (x > 0) return error.StackProtectorUnsupportedByTarget;
235 }
236 break :sp 0;
237 }
238
239 // This logic is checking for linking libc because otherwise our start code
240 // which is trying to set up TLS (i.e. the fs/gs registers) but the stack
241 // protection code depends on fs/gs registers being already set up.
242 // If we were able to annotate start code, or perhaps the entire std lib,
243 // as being exempt from stack protection checks, we could change this logic
244 // to supporting stack protection even when not linking libc.
245 // TODO file issue about this
246 if (!options.global.link_libc) {
247 if (options.inherited.stack_protector) |x| {
248 if (x > 0) return error.StackProtectorUnavailableWithoutLibC;
249 }
250 break :sp 0;
251 }
252
253 if (options.inherited.stack_protector) |x| break :sp x;
254 if (options.parent) |p| break :sp p.stack_protector;
255 if (!is_safe_mode) break :sp 0;
256
257 break :sp target_util.default_stack_protector_buffer_size;
258 };
259
260 const llvm_cpu_features: ?[*:0]const u8 = b: {
261 if (resolved_target.llvm_cpu_features) |x| break :b x;
262 if (!options.global.use_llvm) break :b null;
263
264 var buf = std.ArrayList(u8).init(arena);
265 for (target.cpu.arch.allFeaturesList(), 0..) |feature, index_usize| {
266 const index = @as(std.Target.Cpu.Feature.Set.Index, @intCast(index_usize));
267 const is_enabled = target.cpu.features.isEnabled(index);
268
269 if (feature.llvm_name) |llvm_name| {
270 const plus_or_minus = "-+"[@intFromBool(is_enabled)];
271 try buf.ensureUnusedCapacity(2 + llvm_name.len);
272 buf.appendAssumeCapacity(plus_or_minus);
273 buf.appendSliceAssumeCapacity(llvm_name);
274 buf.appendSliceAssumeCapacity(",");
275 }
276 }
277 if (buf.items.len == 0) break :b "";
278 assert(std.mem.endsWith(u8, buf.items, ","));
279 buf.items[buf.items.len - 1] = 0;
280 buf.shrinkAndFree(buf.items.len);
281 break :b buf.items[0 .. buf.items.len - 1 :0].ptr;
282 };
283
284 const builtin_mod = options.builtin_mod orelse b: {
285 const generated_builtin_source = try Builtin.generate(.{
286 .target = target,
287 .zig_backend = zig_backend,
288 .output_mode = options.global.output_mode,
289 .link_mode = options.global.link_mode,
290 .is_test = options.global.is_test,
291 .test_evented_io = options.global.test_evented_io,
292 .single_threaded = single_threaded,
293 .link_libc = options.global.link_libc,
294 .link_libcpp = options.global.link_libcpp,
295 .optimize_mode = optimize_mode,
296 .error_tracing = error_tracing,
297 .valgrind = valgrind,
298 .sanitize_thread = sanitize_thread,
299 .pic = pic,
300 .pie = options.global.pie,
301 .strip = strip,
302 .code_model = code_model,
303 .omit_frame_pointer = omit_frame_pointer,
304 .wasi_exec_model = options.global.wasi_exec_model,
305 }, arena);
306
307 const digest = Cache.HashHelper.oneShot(generated_builtin_source);
308 const builtin_sub_path = try arena.dupe(u8, "b" ++ std.fs.path.sep_str ++ digest);
309 const new = try arena.create(Module);
310 new.* = .{
311 .root = .{
312 .root_dir = options.global_cache_directory,
313 .sub_path = builtin_sub_path,
314 },
315 .root_src_path = "builtin.zig",
316 .fully_qualified_name = if (options.parent == null)
317 "builtin"
318 else
319 try std.fmt.allocPrint(arena, "{s}.builtin", .{options.fully_qualified_name}),
320 .resolved_target = .{
321 .result = target,
322 .is_native_os = resolved_target.is_native_os,
323 .is_native_abi = resolved_target.is_native_abi,
324 .llvm_cpu_features = llvm_cpu_features,
325 },
326 .optimize_mode = optimize_mode,
327 .single_threaded = single_threaded,
328 .error_tracing = error_tracing,
329 .valgrind = valgrind,
330 .pic = pic,
331 .strip = strip,
332 .omit_frame_pointer = omit_frame_pointer,
333 .stack_check = stack_check,
334 .stack_protector = stack_protector,
335 .code_model = code_model,
336 .red_zone = red_zone,
337 .generated_builtin_source = generated_builtin_source,
338 .sanitize_c = sanitize_c,
339 .sanitize_thread = sanitize_thread,
340 .unwind_tables = unwind_tables,
341 .cc_argv = &.{},
342 };
343 break :b new;
344 };
345
346 const mod = try arena.create(Module);
347 mod.* = .{
348 .root = options.paths.root,
349 .root_src_path = options.paths.root_src_path,
350 .fully_qualified_name = options.fully_qualified_name,
351 .resolved_target = .{
352 .result = target,
353 .is_native_os = resolved_target.is_native_os,
354 .is_native_abi = resolved_target.is_native_abi,
355 .llvm_cpu_features = llvm_cpu_features,
356 },
357 .optimize_mode = optimize_mode,
358 .single_threaded = single_threaded,
359 .error_tracing = error_tracing,
360 .valgrind = valgrind,
361 .pic = pic,
362 .strip = strip,
363 .omit_frame_pointer = omit_frame_pointer,
364 .stack_check = stack_check,
365 .stack_protector = stack_protector,
366 .code_model = code_model,
367 .red_zone = red_zone,
368 .generated_builtin_source = builtin_mod.generated_builtin_source,
369 .sanitize_c = sanitize_c,
370 .sanitize_thread = sanitize_thread,
371 .unwind_tables = unwind_tables,
372 .cc_argv = options.cc_argv,
373 };
374
375 try mod.deps.ensureUnusedCapacity(arena, 1);
376 mod.deps.putAssumeCapacityNoClobber("builtin", builtin_mod);
377
378 return mod;
379}
380
381/// All fields correspond to `CreateOptions`.
382pub const LimitedOptions = struct {
383 root: Package.Path,
384 root_src_path: []const u8,
385 fully_qualified_name: []const u8,
386};
387
388/// This one can only be used if the Module will only be used for AstGen and earlier in
389/// the pipeline. Illegal behavior occurs if a limited module touches Sema.
390pub fn createLimited(gpa: Allocator, options: LimitedOptions) Allocator.Error!*Package.Module {
391 const mod = try gpa.create(Module);
392 mod.* = .{
393 .root = options.root,
394 .root_src_path = options.root_src_path,
395 .fully_qualified_name = options.fully_qualified_name,
396
397 .resolved_target = undefined,
398 .optimize_mode = undefined,
399 .code_model = undefined,
400 .single_threaded = undefined,
401 .error_tracing = undefined,
402 .valgrind = undefined,
403 .pic = undefined,
404 .strip = undefined,
405 .omit_frame_pointer = undefined,
406 .stack_check = undefined,
407 .stack_protector = undefined,
408 .red_zone = undefined,
409 .sanitize_c = undefined,
410 .sanitize_thread = undefined,
411 .unwind_tables = undefined,
412 .cc_argv = undefined,
413 .generated_builtin_source = undefined,
414 };
415 return mod;
416}
417
418pub fn getBuiltinDependency(m: *Module) *Module {
419 return m.deps.values()[0];
28420}
29421
30422const Module = @This();
......@@ -32,3 +424,8 @@ const Package = @import("../Package.zig");
32424const std = @import("std");
33425const Allocator = std.mem.Allocator;
34426const MultiHashHexDigest = Package.Manifest.MultiHashHexDigest;
427const target_util = @import("../target.zig");
428const Cache = std.Build.Cache;
429const Builtin = @import("../Builtin.zig");
430const assert = std.debug.assert;
431const Compilation = @import("../Compilation.zig");
src/Sema.zig+1-1
......@@ -36668,7 +36668,7 @@ fn getBuiltinDecl(sema: *Sema, block: *Block, name: []const u8) CompileError!Int
3666836668
3666936669 const mod = sema.mod;
3667036670 const ip = &mod.intern_pool;
36671 const std_mod = mod.main_mod.deps.get("std").?;
36671 const std_mod = mod.std_mod;
3667236672 const std_file = (mod.importPkg(std_mod) catch unreachable).file;
3667336673 const opt_builtin_inst = (try sema.namespaceLookupRef(
3667436674 block,
src/codegen/llvm.zig+12-26
......@@ -853,16 +853,9 @@ pub const Object = struct {
853853 /// want to iterate over it while adding entries to it.
854854 pub const DITypeMap = std.AutoArrayHashMapUnmanaged(InternPool.Index, AnnotatedDITypePtr);
855855
856 pub fn create(gpa: Allocator, options: link.Options) !*Object {
857 const obj = try gpa.create(Object);
858 errdefer gpa.destroy(obj);
859 obj.* = try Object.init(gpa, options);
860 return obj;
861 }
862
863 pub fn init(gpa: Allocator, options: link.Options) !Object {
864 const llvm_target_triple = try targetTriple(gpa, options.target);
865 defer gpa.free(llvm_target_triple);
856 pub fn create(arena: Allocator, options: link.File.OpenOptions) !*Object {
857 const gpa = options.comp.gpa;
858 const llvm_target_triple = try targetTriple(arena, options.target);
866859
867860 var builder = try Builder.init(.{
868861 .allocator = gpa,
......@@ -899,19 +892,14 @@ pub const Object = struct {
899892 // TODO: the only concern I have with this is WASI as either host or target, should
900893 // we leave the paths as relative then?
901894 const compile_unit_dir_z = blk: {
902 var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
903895 if (options.module) |mod| m: {
904 const d = try mod.root_mod.root.joinStringZ(builder.gpa, "");
896 const d = try mod.root_mod.root.joinStringZ(arena, "");
905897 if (d.len == 0) break :m;
906898 if (std.fs.path.isAbsolute(d)) break :blk d;
907 const abs = std.fs.realpath(d, &buf) catch break :blk d;
908 builder.gpa.free(d);
909 break :blk try builder.gpa.dupeZ(u8, abs);
899 break :blk std.fs.realpathAlloc(arena, d) catch d;
910900 }
911 const cwd = try std.process.getCwd(&buf);
912 break :blk try builder.gpa.dupeZ(u8, cwd);
901 break :blk try std.process.getCwdAlloc(arena);
913902 };
914 defer builder.gpa.free(compile_unit_dir_z);
915903
916904 builder.llvm.di_compile_unit = builder.llvm.di_builder.?.createCompileUnit(
917905 DW.LANG.C99,
......@@ -989,7 +977,8 @@ pub const Object = struct {
989977 }
990978 }
991979
992 return .{
980 const obj = try arena.create(Object);
981 obj.* = .{
993982 .gpa = gpa,
994983 .builder = builder,
995984 .module = options.module.?,
......@@ -1009,9 +998,11 @@ pub const Object = struct {
1009998 .null_opt_usize = .no_init,
1010999 .struct_field_map = .{},
10111000 };
1001 return obj;
10121002 }
10131003
1014 pub fn deinit(self: *Object, gpa: Allocator) void {
1004 pub fn deinit(self: *Object) void {
1005 const gpa = self.gpa;
10151006 self.di_map.deinit(gpa);
10161007 self.di_type_map.deinit(gpa);
10171008 if (self.builder.useLibLlvm()) {
......@@ -1028,11 +1019,6 @@ pub const Object = struct {
10281019 self.* = undefined;
10291020 }
10301021
1031 pub fn destroy(self: *Object, gpa: Allocator) void {
1032 self.deinit(gpa);
1033 gpa.destroy(self);
1034 }
1035
10361022 fn locPath(
10371023 arena: Allocator,
10381024 opt_loc: ?Compilation.EmitLoc,
......@@ -2899,7 +2885,7 @@ pub const Object = struct {
28992885 fn getStackTraceType(o: *Object) Allocator.Error!Type {
29002886 const mod = o.module;
29012887
2902 const std_mod = mod.main_mod.deps.get("std").?;
2888 const std_mod = mod.std_mod;
29032889 const std_file = (mod.importPkg(std_mod) catch unreachable).file;
29042890
29052891 const builtin_str = try mod.intern_pool.getOrPutString(mod.gpa, "builtin");
src/link.zig+182-343
......@@ -66,237 +66,18 @@ pub fn hashAddFrameworks(man: *Cache.Manifest, hm: []const Framework) !void {
6666
6767pub const producer_string = if (builtin.is_test) "zig test" else "zig " ++ build_options.version;
6868
69pub const Emit = struct {
70 /// Where the output will go.
71 directory: Compilation.Directory,
72 /// Path to the output file, relative to `directory`.
73 sub_path: []const u8,
74
75 /// Returns the full path to `basename` if it were in the same directory as the
76 /// `Emit` sub_path.
77 pub fn basenamePath(emit: Emit, arena: Allocator, basename: [:0]const u8) ![:0]const u8 {
78 const full_path = if (emit.directory.path) |p|
79 try fs.path.join(arena, &[_][]const u8{ p, emit.sub_path })
80 else
81 emit.sub_path;
82
83 if (fs.path.dirname(full_path)) |dirname| {
84 return try fs.path.joinZ(arena, &.{ dirname, basename });
85 } else {
86 return basename;
87 }
88 }
89};
90
91pub const Options = struct {
92 /// This is `null` when `-fno-emit-bin` is used.
93 emit: ?Emit,
94 /// This is `null` when not building a Windows DLL, or when `-fno-emit-implib` is used.
95 implib_emit: ?Emit,
96 /// This is non-null when `-femit-docs` is provided.
97 docs_emit: ?Emit,
98 target: std.Target,
99 output_mode: std.builtin.OutputMode,
100 link_mode: std.builtin.LinkMode,
101 optimize_mode: std.builtin.OptimizeMode,
102 machine_code_model: std.builtin.CodeModel,
103 root_name: [:0]const u8,
104 /// Not every Compilation compiles .zig code! For example you could do `zig build-exe foo.o`.
105 module: ?*Module,
106 /// The root path for the dynamic linker and system libraries (as well as frameworks on Darwin)
107 sysroot: ?[]const u8,
108 /// Used for calculating how much space to reserve for symbols in case the binary file
109 /// does not already have a symbol table.
110 symbol_count_hint: u64 = 32,
111 /// Used for calculating how much space to reserve for executable program code in case
112 /// the binary file does not already have such a section.
113 program_code_size_hint: u64 = 256 * 1024,
114 entry_addr: ?u64 = null,
115 entry: ?[]const u8,
116 stack_size_override: ?u64,
117 image_base_override: ?u64,
118 /// 0 means no stack protector
119 /// other value means stack protector with that buffer size.
120 stack_protector: u32,
121 cache_mode: CacheMode,
122 include_compiler_rt: bool,
123 /// Set to `true` to omit debug info.
124 strip: bool,
125 /// If this is true then this link code is responsible for outputting an object
126 /// file and then using LLD to link it together with the link options and other objects.
127 /// Otherwise (depending on `use_llvm`) this link code directly outputs and updates the final binary.
128 use_lld: bool,
129 /// If this is true then this link code is responsible for making an LLVM IR Module,
130 /// outputting it to an object file, and then linking that together with link options and
131 /// other objects.
132 /// Otherwise (depending on `use_lld`) this link code directly outputs and updates the final binary.
133 use_llvm: bool,
134 use_lib_llvm: bool,
135 link_libc: bool,
136 link_libcpp: bool,
137 link_libunwind: bool,
138 darwin_sdk_layout: ?DarwinSdkLayout,
139 function_sections: bool,
140 data_sections: bool,
141 no_builtin: bool,
142 eh_frame_hdr: bool,
143 emit_relocs: bool,
144 rdynamic: bool,
145 z_nodelete: bool,
146 z_notext: bool,
147 z_defs: bool,
148 z_origin: bool,
149 z_nocopyreloc: bool,
150 z_now: bool,
151 z_relro: bool,
152 z_common_page_size: ?u64,
153 z_max_page_size: ?u64,
154 tsaware: bool,
155 nxcompat: bool,
156 dynamicbase: bool,
157 linker_optimization: u8,
158 compress_debug_sections: CompressDebugSections,
159 bind_global_refs_locally: bool,
160 import_memory: bool,
161 export_memory: bool,
162 import_symbols: bool,
163 import_table: bool,
164 export_table: bool,
165 initial_memory: ?u64,
166 max_memory: ?u64,
167 shared_memory: bool,
168 export_symbol_names: []const []const u8,
169 global_base: ?u64,
170 is_native_os: bool,
171 is_native_abi: bool,
172 pic: bool,
173 pie: bool,
174 lto: bool,
175 valgrind: bool,
176 tsan: bool,
177 stack_check: bool,
178 red_zone: bool,
179 omit_frame_pointer: bool,
180 single_threaded: bool,
181 verbose_link: bool,
182 dll_export_fns: bool,
183 error_return_tracing: bool,
184 skip_linker_dependencies: bool,
185 each_lib_rpath: bool,
186 build_id: std.zig.BuildId,
187 disable_lld_caching: bool,
188 is_test: bool,
189 hash_style: HashStyle,
190 sort_section: ?SortSection,
191 major_subsystem_version: ?u32,
192 minor_subsystem_version: ?u32,
193 gc_sections: ?bool = null,
194 allow_shlib_undefined: ?bool,
195 subsystem: ?std.Target.SubSystem,
196 linker_script: ?[]const u8,
197 version_script: ?[]const u8,
198 soname: ?[]const u8,
199 llvm_cpu_features: ?[*:0]const u8,
200 print_gc_sections: bool,
201 print_icf_sections: bool,
202 print_map: bool,
203 opt_bisect_limit: i32,
204
205 objects: []Compilation.LinkObject,
206 framework_dirs: []const []const u8,
207 frameworks: []const Framework,
208 /// These are *always* dynamically linked. Static libraries will be
209 /// provided as positional arguments.
210 system_libs: std.StringArrayHashMapUnmanaged(SystemLib),
211 wasi_emulated_libs: []const wasi_libc.CRTFile,
212 // TODO: remove this. libraries are resolved by the frontend.
213 lib_dirs: []const []const u8,
214 rpath_list: []const []const u8,
215
216 /// List of symbols forced as undefined in the symbol table
217 /// thus forcing their resolution by the linker.
218 /// Corresponds to `-u <symbol>` for ELF/MachO and `/include:<symbol>` for COFF/PE.
219 force_undefined_symbols: std.StringArrayHashMapUnmanaged(void),
220 /// Use a wrapper function for symbol. Any undefined reference to symbol
221 /// will be resolved to __wrap_symbol. Any undefined reference to
222 /// __real_symbol will be resolved to symbol. This can be used to provide a
223 /// wrapper for a system function. The wrapper function should be called
224 /// __wrap_symbol. If it wishes to call the system function, it should call
225 /// __real_symbol.
226 symbol_wrap_set: std.StringArrayHashMapUnmanaged(void),
227
228 version: ?std.SemanticVersion,
229 compatibility_version: ?std.SemanticVersion,
230 libc_installation: ?*const LibCInstallation,
231
232 dwarf_format: ?std.dwarf.Format,
233
234 /// WASI-only. Type of WASI execution model ("command" or "reactor").
235 wasi_exec_model: std.builtin.WasiExecModel = undefined,
236
237 /// (Zig compiler development) Enable dumping of linker's state as JSON.
238 enable_link_snapshots: bool = false,
239
240 /// (Darwin) Install name for the dylib
241 install_name: ?[]const u8 = null,
242
243 /// (Darwin) Path to entitlements file
244 entitlements: ?[]const u8 = null,
245
246 /// (Darwin) size of the __PAGEZERO segment
247 pagezero_size: ?u64 = null,
248
249 /// (Darwin) set minimum space for future expansion of the load commands
250 headerpad_size: ?u32 = null,
251
252 /// (Darwin) set enough space as if all paths were MATPATHLEN
253 headerpad_max_install_names: bool = false,
254
255 /// (Darwin) remove dylibs that are unreachable by the entry point or exported symbols
256 dead_strip_dylibs: bool = false,
257
258 /// (Windows) PDB source path prefix to instruct the linker how to resolve relative
259 /// paths when consolidating CodeView streams into a single PDB file.
260 pdb_source_path: ?[]const u8 = null,
261
262 /// (Windows) PDB output path
263 pdb_out_path: ?[]const u8 = null,
264
265 /// (Windows) .def file to specify when linking
266 module_definition_file: ?[]const u8 = null,
267
268 /// (SPIR-V) whether to generate a structured control flow graph or not
269 want_structured_cfg: ?bool = null,
270
271 pub fn effectiveOutputMode(options: Options) std.builtin.OutputMode {
272 return if (options.use_lld) .Obj else options.output_mode;
273 }
274
275 pub fn move(self: *Options) Options {
276 const copied_state = self.*;
277 self.system_libs = .{};
278 self.force_undefined_symbols = .{};
279 return copied_state;
280 }
281};
282
28369pub const HashStyle = enum { sysv, gnu, both };
28470
28571pub const CompressDebugSections = enum { none, zlib, zstd };
28672
287/// The filesystem layout of darwin SDK elements.
288pub const DarwinSdkLayout = enum {
289 /// macOS SDK layout: TOP { /usr/include, /usr/lib, /System/Library/Frameworks }.
290 sdk,
291 /// Shipped libc layout: TOP { /lib/libc/include, /lib/libc/darwin, <NONE> }.
292 vendored,
293};
294
29573pub const File = struct {
29674 tag: Tag,
297 options: Options,
75
76 /// The owner of this output File.
77 comp: *Compilation,
78 emit: Compilation.Emit,
79
29880 file: ?fs.File,
299 allocator: Allocator,
30081 /// When linking with LLD, this linker code will output an object file only at
30182 /// this location, and then this path can be placed on the LLD linker line.
30283 intermediary_basename: ?[]const u8 = null,
......@@ -307,103 +88,132 @@ pub const File = struct {
30788
30889 child_pid: ?std.ChildProcess.Id = null,
30990
91 pub const OpenOptions = struct {
92 comp: *Compilation,
93 emit: Compilation.Emit,
94
95 symbol_count_hint: u64 = 32,
96 program_code_size_hint: u64 = 256 * 1024,
97
98 /// Virtual address of the entry point procedure relative to image base.
99 entry_addr: ?u64,
100 stack_size_override: ?u64,
101 image_base_override: ?u64,
102 function_sections: bool,
103 data_sections: bool,
104 no_builtin: bool,
105 eh_frame_hdr: bool,
106 emit_relocs: bool,
107 rdynamic: bool,
108 optimization: u8,
109 linker_script: ?[]const u8,
110 z_nodelete: bool,
111 z_notext: bool,
112 z_defs: bool,
113 z_origin: bool,
114 z_nocopyreloc: bool,
115 z_now: bool,
116 z_relro: bool,
117 z_common_page_size: ?u64,
118 z_max_page_size: ?u64,
119 tsaware: bool,
120 nxcompat: bool,
121 dynamicbase: bool,
122 compress_debug_sections: CompressDebugSections,
123 bind_global_refs_locally: bool,
124 import_symbols: bool,
125 import_table: bool,
126 export_table: bool,
127 initial_memory: ?u64,
128 max_memory: ?u64,
129 export_symbol_names: []const []const u8,
130 global_base: ?u64,
131 verbose_link: bool,
132 dll_export_fns: bool,
133 skip_linker_dependencies: bool,
134 parent_compilation_link_libc: bool,
135 each_lib_rpath: bool,
136 build_id: std.zig.BuildId,
137 disable_lld_caching: bool,
138 hash_style: HashStyle,
139 sort_section: ?SortSection,
140 major_subsystem_version: ?u32,
141 minor_subsystem_version: ?u32,
142 gc_sections: ?bool = null,
143 allow_shlib_undefined: ?bool,
144 subsystem: ?std.Target.SubSystem,
145 version_script: ?[]const u8,
146 soname: ?[]const u8,
147 print_gc_sections: bool,
148 print_icf_sections: bool,
149 print_map: bool,
150 opt_bisect_limit: i32,
151
152 /// List of symbols forced as undefined in the symbol table
153 /// thus forcing their resolution by the linker.
154 /// Corresponds to `-u <symbol>` for ELF/MachO and `/include:<symbol>` for COFF/PE.
155 force_undefined_symbols: std.StringArrayHashMapUnmanaged(void),
156 /// Use a wrapper function for symbol. Any undefined reference to symbol
157 /// will be resolved to __wrap_symbol. Any undefined reference to
158 /// __real_symbol will be resolved to symbol. This can be used to provide a
159 /// wrapper for a system function. The wrapper function should be called
160 /// __wrap_symbol. If it wishes to call the system function, it should call
161 /// __real_symbol.
162 symbol_wrap_set: std.StringArrayHashMapUnmanaged(void),
163
164 compatibility_version: ?std.SemanticVersion,
165
166 dwarf_format: ?std.dwarf.Format,
167
168 // TODO: remove this. libraries are resolved by the frontend.
169 lib_dirs: []const []const u8,
170 rpath_list: []const []const u8,
171
172 /// (Zig compiler development) Enable dumping of linker's state as JSON.
173 enable_link_snapshots: bool,
174
175 /// (Darwin) Install name for the dylib
176 install_name: ?[]const u8,
177 /// (Darwin) Path to entitlements file
178 entitlements: ?[]const u8,
179 /// (Darwin) size of the __PAGEZERO segment
180 pagezero_size: ?u64,
181 /// (Darwin) set minimum space for future expansion of the load commands
182 headerpad_size: ?u32,
183 /// (Darwin) set enough space as if all paths were MATPATHLEN
184 headerpad_max_install_names: bool,
185 /// (Darwin) remove dylibs that are unreachable by the entry point or exported symbols
186 dead_strip_dylibs: bool,
187 framework_dirs: []const []const u8,
188 frameworks: []const Framework,
189 darwin_sdk_layout: ?MachO.SdkLayout,
190
191 /// (Windows) PDB source path prefix to instruct the linker how to resolve relative
192 /// paths when consolidating CodeView streams into a single PDB file.
193 pdb_source_path: ?[]const u8,
194 /// (Windows) PDB output path
195 pdb_out_path: ?[]const u8,
196 /// (Windows) .def file to specify when linking
197 module_definition_file: ?[]const u8,
198
199 /// (SPIR-V) whether to generate a structured control flow graph or not
200 want_structured_cfg: ?bool,
201
202 wasi_emulated_libs: []const wasi_libc.CRTFile,
203 };
204
310205 /// Attempts incremental linking, if the file already exists. If
311206 /// incremental linking fails, falls back to truncating the file and
312207 /// rewriting it. A malicious file is detected as incremental link failure
313208 /// and does not cause Illegal Behavior. This operation is not atomic.
314 pub fn openPath(allocator: Allocator, options: Options) !*File {
315 const have_macho = !build_options.only_c;
316 if (have_macho and options.target.ofmt == .macho) {
317 return &(try MachO.openPath(allocator, options)).base;
318 }
319
320 if (options.emit == null) {
321 return switch (options.target.ofmt) {
322 .coff => &(try Coff.createEmpty(allocator, options)).base,
323 .elf => &(try Elf.createEmpty(allocator, options)).base,
324 .macho => unreachable,
325 .wasm => &(try Wasm.createEmpty(allocator, options)).base,
326 .plan9 => return &(try Plan9.createEmpty(allocator, options)).base,
327 .c => unreachable, // Reported error earlier.
328 .spirv => &(try SpirV.createEmpty(allocator, options)).base,
329 .nvptx => &(try NvPtx.createEmpty(allocator, options)).base,
330 .hex => return error.HexObjectFormatUnimplemented,
331 .raw => return error.RawObjectFormatUnimplemented,
332 .dxcontainer => return error.DirectXContainerObjectFormatUnimplemented,
333 };
334 }
335 const emit = options.emit.?;
336 const use_lld = build_options.have_llvm and options.use_lld; // comptime-known false when !have_llvm
337 const sub_path = if (use_lld) blk: {
338 if (options.module == null) {
339 // No point in opening a file, we would not write anything to it.
340 // Initialize with empty.
341 return switch (options.target.ofmt) {
342 .coff => &(try Coff.createEmpty(allocator, options)).base,
343 .elf => &(try Elf.createEmpty(allocator, options)).base,
344 .macho => unreachable,
345 .plan9 => &(try Plan9.createEmpty(allocator, options)).base,
346 .wasm => &(try Wasm.createEmpty(allocator, options)).base,
347 .c => unreachable, // Reported error earlier.
348 .spirv => &(try SpirV.createEmpty(allocator, options)).base,
349 .nvptx => &(try NvPtx.createEmpty(allocator, options)).base,
350 .hex => return error.HexObjectFormatUnimplemented,
351 .raw => return error.RawObjectFormatUnimplemented,
352 .dxcontainer => return error.DirectXContainerObjectFormatUnimplemented,
353 };
354 }
355 // Open a temporary object file, not the final output file because we
356 // want to link with LLD.
357 break :blk try std.fmt.allocPrint(allocator, "{s}{s}", .{
358 emit.sub_path, options.target.ofmt.fileExt(options.target.cpu.arch),
359 });
360 } else emit.sub_path;
361 errdefer if (use_lld) allocator.free(sub_path);
362
363 const file: *File = f: {
364 switch (options.target.ofmt) {
365 .coff => {
366 if (build_options.only_c) unreachable;
367 break :f &(try Coff.openPath(allocator, sub_path, options)).base;
368 },
369 .elf => {
370 if (build_options.only_c) unreachable;
371 break :f &(try Elf.openPath(allocator, sub_path, options)).base;
372 },
373 .macho => unreachable,
374 .plan9 => {
375 if (build_options.only_c) unreachable;
376 break :f &(try Plan9.openPath(allocator, sub_path, options)).base;
377 },
378 .wasm => {
379 if (build_options.only_c) unreachable;
380 break :f &(try Wasm.openPath(allocator, sub_path, options)).base;
381 },
382 .c => {
383 break :f &(try C.openPath(allocator, sub_path, options)).base;
384 },
385 .spirv => {
386 if (build_options.only_c) unreachable;
387 break :f &(try SpirV.openPath(allocator, sub_path, options)).base;
388 },
389 .nvptx => {
390 if (build_options.only_c) unreachable;
391 break :f &(try NvPtx.openPath(allocator, sub_path, options)).base;
392 },
393 .hex => return error.HexObjectFormatUnimplemented,
394 .raw => return error.RawObjectFormatUnimplemented,
395 .dxcontainer => return error.DirectXContainerObjectFormatUnimplemented,
396 }
397 };
398
399 if (use_lld) {
400 // TODO this intermediary_basename isn't enough; in the case of `zig build-exe`,
401 // we also want to put the intermediary object file in the cache while the
402 // main emit directory is the cwd.
403 file.intermediary_basename = sub_path;
209 /// `arena` is used for allocations with the same lifetime as the created File.
210 pub fn open(arena: Allocator, options: OpenOptions) !*File {
211 switch (Tag.fromObjectFormat(options.comp.root_mod.resolved_target.result.ofmt)) {
212 inline else => |tag| {
213 const ptr = try tag.Type().open(arena, options);
214 return &ptr.base;
215 },
404216 }
405
406 return file;
407217 }
408218
409219 pub fn cast(base: *File, comptime T: type) ?*T {
......@@ -664,56 +474,45 @@ pub const File = struct {
664474 pub fn destroy(base: *File) void {
665475 base.releaseLock();
666476 if (base.file) |f| f.close();
667 if (base.intermediary_basename) |sub_path| base.allocator.free(sub_path);
668 base.options.system_libs.deinit(base.allocator);
669 base.options.force_undefined_symbols.deinit(base.allocator);
670477 switch (base.tag) {
671478 .coff => {
672479 if (build_options.only_c) unreachable;
673480 const parent = @fieldParentPtr(Coff, "base", base);
674481 parent.deinit();
675 base.allocator.destroy(parent);
676482 },
677483 .elf => {
678484 if (build_options.only_c) unreachable;
679485 const parent = @fieldParentPtr(Elf, "base", base);
680486 parent.deinit();
681 base.allocator.destroy(parent);
682487 },
683488 .macho => {
684489 if (build_options.only_c) unreachable;
685490 const parent = @fieldParentPtr(MachO, "base", base);
686491 parent.deinit();
687 base.allocator.destroy(parent);
688492 },
689493 .c => {
690494 const parent = @fieldParentPtr(C, "base", base);
691495 parent.deinit();
692 base.allocator.destroy(parent);
693496 },
694497 .wasm => {
695498 if (build_options.only_c) unreachable;
696499 const parent = @fieldParentPtr(Wasm, "base", base);
697500 parent.deinit();
698 base.allocator.destroy(parent);
699501 },
700502 .spirv => {
701503 if (build_options.only_c) unreachable;
702504 const parent = @fieldParentPtr(SpirV, "base", base);
703505 parent.deinit();
704 base.allocator.destroy(parent);
705506 },
706507 .plan9 => {
707508 if (build_options.only_c) unreachable;
708509 const parent = @fieldParentPtr(Plan9, "base", base);
709510 parent.deinit();
710 base.allocator.destroy(parent);
711511 },
712512 .nvptx => {
713513 if (build_options.only_c) unreachable;
714514 const parent = @fieldParentPtr(NvPtx, "base", base);
715515 parent.deinit();
716 base.allocator.destroy(parent);
717516 },
718517 }
719518 }
......@@ -1197,6 +996,35 @@ pub const File = struct {
1197996 spirv,
1198997 plan9,
1199998 nvptx,
999
1000 pub fn Type(comptime tag: Tag) type {
1001 return switch (tag) {
1002 .coff => Coff,
1003 .elf => Elf,
1004 .macho => MachO,
1005 .c => C,
1006 .wasm => Wasm,
1007 .spirv => SpirV,
1008 .plan9 => Plan9,
1009 .nvptx => NvPtx,
1010 };
1011 }
1012
1013 pub fn fromObjectFormat(ofmt: std.Target.ObjectFormat) Tag {
1014 return switch (ofmt) {
1015 .coff => .coff,
1016 .elf => .elf,
1017 .macho => .macho,
1018 .wasm => .wasm,
1019 .plan9 => .plan9,
1020 .c => .c,
1021 .spirv => .spirv,
1022 .nvptx => .nvptx,
1023 .hex => @panic("TODO implement hex object format"),
1024 .raw => @panic("TODO implement raw object format"),
1025 .dxcontainer => @panic("TODO implement dxcontainer object format"),
1026 };
1027 }
12001028 };
12011029
12021030 pub const ErrorFlags = struct {
......@@ -1235,6 +1063,33 @@ pub const File = struct {
12351063 }
12361064 };
12371065
1066 pub fn effectiveOutputMode(
1067 use_lld: bool,
1068 output_mode: std.builtin.OutputMode,
1069 ) std.builtin.OutputMode {
1070 return if (use_lld) .Obj else output_mode;
1071 }
1072
1073 pub fn determineMode(
1074 use_lld: bool,
1075 output_mode: std.builtin.OutputMode,
1076 link_mode: std.builtin.LinkMode,
1077 ) fs.File.Mode {
1078 // On common systems with a 0o022 umask, 0o777 will still result in a file created
1079 // with 0o755 permissions, but it works appropriately if the system is configured
1080 // more leniently. As another data point, C's fopen seems to open files with the
1081 // 666 mode.
1082 const executable_mode = if (builtin.target.os.tag == .windows) 0 else 0o777;
1083 switch (effectiveOutputMode(use_lld, output_mode)) {
1084 .Lib => return switch (link_mode) {
1085 .Dynamic => executable_mode,
1086 .Static => fs.File.default_mode,
1087 },
1088 .Exe => return executable_mode,
1089 .Obj => return fs.File.default_mode,
1090 }
1091 }
1092
12381093 pub const C = @import("link/C.zig");
12391094 pub const Coff = @import("link/Coff.zig");
12401095 pub const Plan9 = @import("link/Plan9.zig");
......@@ -1245,19 +1100,3 @@ pub const File = struct {
12451100 pub const NvPtx = @import("link/NvPtx.zig");
12461101 pub const Dwarf = @import("link/Dwarf.zig");
12471102};
1248
1249pub fn determineMode(options: Options) fs.File.Mode {
1250 // On common systems with a 0o022 umask, 0o777 will still result in a file created
1251 // with 0o755 permissions, but it works appropriately if the system is configured
1252 // more leniently. As another data point, C's fopen seems to open files with the
1253 // 666 mode.
1254 const executable_mode = if (builtin.target.os.tag == .windows) 0 else 0o777;
1255 switch (options.effectiveOutputMode()) {
1256 .Lib => return switch (options.link_mode) {
1257 .Dynamic => executable_mode,
1258 .Static => fs.File.default_mode,
1259 },
1260 .Exe => return executable_mode,
1261 .Obj => return fs.File.default_mode,
1262 }
1263}
src/link/Coff.zig+169-146
......@@ -48,9 +48,6 @@ got_table_count_dirty: bool = true,
4848got_table_contents_dirty: bool = true,
4949imports_count_dirty: bool = true,
5050
51/// Virtual address of the entry point procedure relative to image base.
52entry_addr: ?u32 = null,
53
5451/// Table of tracked LazySymbols.
5552lazy_syms: LazySymbolTable = .{},
5653
......@@ -226,44 +223,150 @@ const ideal_factor = 3;
226223const minimum_text_block_size = 64;
227224pub const min_text_capacity = padToIdeal(minimum_text_block_size);
228225
229pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Coff {
230 assert(options.target.ofmt == .coff);
226pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Coff {
227 if (build_options.only_c) unreachable;
228 const target = options.comp.root_mod.resolved_target.result;
229 assert(target.ofmt == .coff);
230
231 const self = try createEmpty(arena, options);
232 errdefer self.base.destroy();
233
234 const use_lld = build_options.have_llvm and options.comp.config.use_lld;
235 const use_llvm = build_options.have_llvm and options.comp.config.use_llvm;
231236
232 if (options.use_llvm) {
233 return createEmpty(allocator, options);
237 if (use_lld and use_llvm) {
238 // LLVM emits the object file; LLD links it into the final product.
239 return self;
234240 }
235241
236 const self = try createEmpty(allocator, options);
237 errdefer self.base.destroy();
242 const sub_path = if (!use_lld) options.emit.sub_path else p: {
243 // Open a temporary object file, not the final output file because we
244 // want to link with LLD.
245 const o_file_path = try std.fmt.allocPrint(arena, "{s}{s}", .{
246 options.emit.sub_path, target.ofmt.fileExt(target.cpu.arch),
247 });
248 self.base.intermediary_basename = o_file_path;
249 break :p o_file_path;
250 };
238251
239 const file = try options.emit.?.directory.handle.createFile(sub_path, .{
252 self.base.file = try options.emit.directory.handle.createFile(sub_path, .{
240253 .truncate = false,
241254 .read = true,
242 .mode = link.determineMode(options),
255 .mode = link.File.determineMode(
256 use_lld,
257 options.comp.config.output_mode,
258 options.comp.config.link_mode,
259 ),
243260 });
244 self.base.file = file;
245261
246 try self.populateMissingMetadata();
262 assert(self.llvm_object == null);
263 const gpa = self.base.comp.gpa;
264
265 try self.strtab.buffer.ensureUnusedCapacity(gpa, @sizeOf(u32));
266 self.strtab.buffer.appendNTimesAssumeCapacity(0, @sizeOf(u32));
267
268 try self.temp_strtab.buffer.append(gpa, 0);
269
270 // Index 0 is always a null symbol.
271 try self.locals.append(gpa, .{
272 .name = [_]u8{0} ** 8,
273 .value = 0,
274 .section_number = .UNDEFINED,
275 .type = .{ .base_type = .NULL, .complex_type = .NULL },
276 .storage_class = .NULL,
277 .number_of_aux_symbols = 0,
278 });
279
280 if (self.text_section_index == null) {
281 const file_size: u32 = @intCast(options.program_code_size_hint);
282 self.text_section_index = try self.allocateSection(".text", file_size, .{
283 .CNT_CODE = 1,
284 .MEM_EXECUTE = 1,
285 .MEM_READ = 1,
286 });
287 }
288
289 if (self.got_section_index == null) {
290 const file_size = @as(u32, @intCast(options.symbol_count_hint)) * self.ptr_width.size();
291 self.got_section_index = try self.allocateSection(".got", file_size, .{
292 .CNT_INITIALIZED_DATA = 1,
293 .MEM_READ = 1,
294 });
295 }
296
297 if (self.rdata_section_index == null) {
298 const file_size: u32 = self.page_size;
299 self.rdata_section_index = try self.allocateSection(".rdata", file_size, .{
300 .CNT_INITIALIZED_DATA = 1,
301 .MEM_READ = 1,
302 });
303 }
304
305 if (self.data_section_index == null) {
306 const file_size: u32 = self.page_size;
307 self.data_section_index = try self.allocateSection(".data", file_size, .{
308 .CNT_INITIALIZED_DATA = 1,
309 .MEM_READ = 1,
310 .MEM_WRITE = 1,
311 });
312 }
313
314 if (self.idata_section_index == null) {
315 const file_size = @as(u32, @intCast(options.symbol_count_hint)) * self.ptr_width.size();
316 self.idata_section_index = try self.allocateSection(".idata", file_size, .{
317 .CNT_INITIALIZED_DATA = 1,
318 .MEM_READ = 1,
319 });
320 }
321
322 if (self.reloc_section_index == null) {
323 const file_size = @as(u32, @intCast(options.symbol_count_hint)) * @sizeOf(coff.BaseRelocation);
324 self.reloc_section_index = try self.allocateSection(".reloc", file_size, .{
325 .CNT_INITIALIZED_DATA = 1,
326 .MEM_DISCARDABLE = 1,
327 .MEM_READ = 1,
328 });
329 }
330
331 if (self.strtab_offset == null) {
332 const file_size = @as(u32, @intCast(self.strtab.buffer.items.len));
333 self.strtab_offset = self.findFreeSpace(file_size, @alignOf(u32)); // 4bytes aligned seems like a good idea here
334 log.debug("found strtab free space 0x{x} to 0x{x}", .{ self.strtab_offset.?, self.strtab_offset.? + file_size });
335 }
336
337 {
338 // We need to find out what the max file offset is according to section headers.
339 // Otherwise, we may end up with an COFF binary with file size not matching the final section's
340 // offset + it's filesize.
341 // TODO I don't like this here one bit
342 var max_file_offset: u64 = 0;
343 for (self.sections.items(.header)) |header| {
344 if (header.pointer_to_raw_data + header.size_of_raw_data > max_file_offset) {
345 max_file_offset = header.pointer_to_raw_data + header.size_of_raw_data;
346 }
347 }
348 try self.base.file.?.pwriteAll(&[_]u8{0}, max_file_offset);
349 }
247350
248351 return self;
249352}
250353
251pub fn createEmpty(gpa: Allocator, options: link.Options) !*Coff {
252 const ptr_width: PtrWidth = switch (options.target.ptrBitWidth()) {
354pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Coff {
355 const target = options.comp.root_mod.resolved_target.result;
356 const ptr_width: PtrWidth = switch (target.ptrBitWidth()) {
253357 0...32 => .p32,
254358 33...64 => .p64,
255359 else => return error.UnsupportedCOFFArchitecture,
256360 };
257 const page_size: u32 = switch (options.target.cpu.arch) {
361 const page_size: u32 = switch (target.cpu.arch) {
258362 else => 0x1000,
259363 };
260 const self = try gpa.create(Coff);
261 errdefer gpa.destroy(self);
364 const self = try arena.create(Coff);
262365 self.* = .{
263366 .base = .{
264367 .tag = .coff,
265 .options = options,
266 .allocator = gpa,
368 .comp = options.comp,
369 .emit = options.emit,
267370 .file = null,
268371 },
269372 .ptr_width = ptr_width,
......@@ -271,16 +374,17 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Coff {
271374 .data_directories = comptime mem.zeroes([coff.IMAGE_NUMBEROF_DIRECTORY_ENTRIES]coff.ImageDataDirectory),
272375 };
273376
274 if (options.use_llvm) {
275 self.llvm_object = try LlvmObject.create(gpa, options);
377 const use_llvm = build_options.have_llvm and options.comp.config.use_llvm;
378 if (use_llvm and options.comp.config.have_zcu) {
379 self.llvm_object = try LlvmObject.create(arena, options);
276380 }
277381 return self;
278382}
279383
280384pub fn deinit(self: *Coff) void {
281 const gpa = self.base.allocator;
385 const gpa = self.base.comp.gpa;
282386
283 if (self.llvm_object) |llvm_object| llvm_object.destroy(gpa);
387 if (self.llvm_object) |llvm_object| llvm_object.deinit();
284388
285389 for (self.objects.items) |*object| {
286390 object.deinit(gpa);
......@@ -349,97 +453,6 @@ pub fn deinit(self: *Coff) void {
349453 self.base_relocs.deinit(gpa);
350454}
351455
352fn populateMissingMetadata(self: *Coff) !void {
353 assert(self.llvm_object == null);
354 const gpa = self.base.allocator;
355
356 try self.strtab.buffer.ensureUnusedCapacity(gpa, @sizeOf(u32));
357 self.strtab.buffer.appendNTimesAssumeCapacity(0, @sizeOf(u32));
358
359 try self.temp_strtab.buffer.append(gpa, 0);
360
361 // Index 0 is always a null symbol.
362 try self.locals.append(gpa, .{
363 .name = [_]u8{0} ** 8,
364 .value = 0,
365 .section_number = .UNDEFINED,
366 .type = .{ .base_type = .NULL, .complex_type = .NULL },
367 .storage_class = .NULL,
368 .number_of_aux_symbols = 0,
369 });
370
371 if (self.text_section_index == null) {
372 const file_size = @as(u32, @intCast(self.base.options.program_code_size_hint));
373 self.text_section_index = try self.allocateSection(".text", file_size, .{
374 .CNT_CODE = 1,
375 .MEM_EXECUTE = 1,
376 .MEM_READ = 1,
377 });
378 }
379
380 if (self.got_section_index == null) {
381 const file_size = @as(u32, @intCast(self.base.options.symbol_count_hint)) * self.ptr_width.size();
382 self.got_section_index = try self.allocateSection(".got", file_size, .{
383 .CNT_INITIALIZED_DATA = 1,
384 .MEM_READ = 1,
385 });
386 }
387
388 if (self.rdata_section_index == null) {
389 const file_size: u32 = self.page_size;
390 self.rdata_section_index = try self.allocateSection(".rdata", file_size, .{
391 .CNT_INITIALIZED_DATA = 1,
392 .MEM_READ = 1,
393 });
394 }
395
396 if (self.data_section_index == null) {
397 const file_size: u32 = self.page_size;
398 self.data_section_index = try self.allocateSection(".data", file_size, .{
399 .CNT_INITIALIZED_DATA = 1,
400 .MEM_READ = 1,
401 .MEM_WRITE = 1,
402 });
403 }
404
405 if (self.idata_section_index == null) {
406 const file_size = @as(u32, @intCast(self.base.options.symbol_count_hint)) * self.ptr_width.size();
407 self.idata_section_index = try self.allocateSection(".idata", file_size, .{
408 .CNT_INITIALIZED_DATA = 1,
409 .MEM_READ = 1,
410 });
411 }
412
413 if (self.reloc_section_index == null) {
414 const file_size = @as(u32, @intCast(self.base.options.symbol_count_hint)) * @sizeOf(coff.BaseRelocation);
415 self.reloc_section_index = try self.allocateSection(".reloc", file_size, .{
416 .CNT_INITIALIZED_DATA = 1,
417 .MEM_DISCARDABLE = 1,
418 .MEM_READ = 1,
419 });
420 }
421
422 if (self.strtab_offset == null) {
423 const file_size = @as(u32, @intCast(self.strtab.buffer.items.len));
424 self.strtab_offset = self.findFreeSpace(file_size, @alignOf(u32)); // 4bytes aligned seems like a good idea here
425 log.debug("found strtab free space 0x{x} to 0x{x}", .{ self.strtab_offset.?, self.strtab_offset.? + file_size });
426 }
427
428 {
429 // We need to find out what the max file offset is according to section headers.
430 // Otherwise, we may end up with an COFF binary with file size not matching the final section's
431 // offset + it's filesize.
432 // TODO I don't like this here one bit
433 var max_file_offset: u64 = 0;
434 for (self.sections.items(.header)) |header| {
435 if (header.pointer_to_raw_data + header.size_of_raw_data > max_file_offset) {
436 max_file_offset = header.pointer_to_raw_data + header.size_of_raw_data;
437 }
438 }
439 try self.base.file.?.pwriteAll(&[_]u8{0}, max_file_offset);
440 }
441}
442
443456fn allocateSection(self: *Coff, name: []const u8, size: u32, flags: coff.SectionHeaderFlags) !u16 {
444457 const index = @as(u16, @intCast(self.sections.slice().len));
445458 const off = self.findFreeSpace(size, default_file_alignment);
......@@ -471,8 +484,9 @@ fn allocateSection(self: *Coff, name: []const u8, size: u32, flags: coff.Section
471484 .number_of_linenumbers = 0,
472485 .flags = flags,
473486 };
487 const gpa = self.base.comp.gpa;
474488 try self.setSectionName(&header, name);
475 try self.sections.append(self.base.allocator, .{ .header = header });
489 try self.sections.append(gpa, .{ .header = header });
476490 return index;
477491}
478492
......@@ -654,7 +668,7 @@ fn allocateAtom(self: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignme
654668}
655669
656670pub fn allocateSymbol(self: *Coff) !u32 {
657 const gpa = self.base.allocator;
671 const gpa = self.base.comp.gpa;
658672 try self.locals.ensureUnusedCapacity(gpa, 1);
659673
660674 const index = blk: {
......@@ -682,7 +696,7 @@ pub fn allocateSymbol(self: *Coff) !u32 {
682696}
683697
684698fn allocateGlobal(self: *Coff) !u32 {
685 const gpa = self.base.allocator;
699 const gpa = self.base.comp.gpa;
686700 try self.globals.ensureUnusedCapacity(gpa, 1);
687701
688702 const index = blk: {
......@@ -706,15 +720,16 @@ fn allocateGlobal(self: *Coff) !u32 {
706720}
707721
708722fn addGotEntry(self: *Coff, target: SymbolWithLoc) !void {
723 const gpa = self.base.comp.gpa;
709724 if (self.got_table.lookup.contains(target)) return;
710 const got_index = try self.got_table.allocateEntry(self.base.allocator, target);
725 const got_index = try self.got_table.allocateEntry(gpa, target);
711726 try self.writeOffsetTableEntry(got_index);
712727 self.got_table_count_dirty = true;
713728 self.markRelocsDirtyByTarget(target);
714729}
715730
716731pub fn createAtom(self: *Coff) !Atom.Index {
717 const gpa = self.base.allocator;
732 const gpa = self.base.comp.gpa;
718733 const atom_index = @as(Atom.Index, @intCast(self.atoms.items.len));
719734 const atom = try self.atoms.addOne(gpa);
720735 const sym_index = try self.allocateSymbol();
......@@ -759,7 +774,7 @@ fn writeAtom(self: *Coff, atom_index: Atom.Index, code: []u8) !void {
759774 file_offset + code.len,
760775 });
761776
762 const gpa = self.base.allocator;
777 const gpa = self.base.comp.gpa;
763778
764779 // Gather relocs which can be resolved.
765780 // We need to do this as we will be applying different slide values depending
......@@ -870,7 +885,7 @@ fn writeOffsetTableEntry(self: *Coff, index: usize) !void {
870885
871886 if (is_hot_update_compatible) {
872887 if (self.base.child_pid) |handle| {
873 const gpa = self.base.allocator;
888 const gpa = self.base.comp.gpa;
874889 const slide = @intFromPtr(self.hot_state.loaded_base_address.?);
875890 const actual_vmaddr = vmaddr + slide;
876891 const pvaddr = @as(*anyopaque, @ptrFromInt(actual_vmaddr));
......@@ -974,7 +989,7 @@ pub fn ptraceDetach(self: *Coff, handle: std.ChildProcess.Id) void {
974989fn freeAtom(self: *Coff, atom_index: Atom.Index) void {
975990 log.debug("freeAtom {d}", .{atom_index});
976991
977 const gpa = self.base.allocator;
992 const gpa = self.base.comp.gpa;
978993
979994 // Remove any relocs and base relocs associated with this Atom
980995 Atom.freeRelocations(self, atom_index);
......@@ -1061,7 +1076,8 @@ pub fn updateFunc(self: *Coff, mod: *Module, func_index: InternPool.Index, air:
10611076 self.freeUnnamedConsts(decl_index);
10621077 Atom.freeRelocations(self, atom_index);
10631078
1064 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
1079 const gpa = self.base.comp.gpa;
1080 var code_buffer = std.ArrayList(u8).init(gpa);
10651081 defer code_buffer.deinit();
10661082
10671083 const res = try codegen.generateFunction(
......@@ -1090,7 +1106,7 @@ pub fn updateFunc(self: *Coff, mod: *Module, func_index: InternPool.Index, air:
10901106}
10911107
10921108pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: InternPool.DeclIndex) !u32 {
1093 const gpa = self.base.allocator;
1109 const gpa = self.base.comp.gpa;
10941110 const mod = self.base.options.module.?;
10951111 const decl = mod.declPtr(decl_index);
10961112 const gop = try self.unnamed_const_atoms.getOrPut(gpa, decl_index);
......@@ -1121,7 +1137,7 @@ const LowerConstResult = union(enum) {
11211137};
11221138
11231139fn lowerConst(self: *Coff, name: []const u8, tv: TypedValue, required_alignment: InternPool.Alignment, sect_id: u16, src_loc: Module.SrcLoc) !LowerConstResult {
1124 const gpa = self.base.allocator;
1140 const gpa = self.base.comp.gpa;
11251141
11261142 var code_buffer = std.ArrayList(u8).init(gpa);
11271143 defer code_buffer.deinit();
......@@ -1174,13 +1190,14 @@ pub fn updateDecl(
11741190 return;
11751191 }
11761192
1193 const gpa = self.base.comp.gpa;
11771194 if (decl.isExtern(mod)) {
11781195 // TODO make this part of getGlobalSymbol
11791196 const variable = decl.getOwnedVariable(mod).?;
11801197 const name = mod.intern_pool.stringToSlice(decl.name);
11811198 const lib_name = mod.intern_pool.stringToSliceUnwrap(variable.lib_name);
11821199 const global_index = try self.getGlobalSymbol(name, lib_name);
1183 try self.need_got_table.put(self.base.allocator, global_index, {});
1200 try self.need_got_table.put(gpa, global_index, {});
11841201 return;
11851202 }
11861203
......@@ -1188,7 +1205,7 @@ pub fn updateDecl(
11881205 Atom.freeRelocations(self, atom_index);
11891206 const atom = self.getAtom(atom_index);
11901207
1191 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
1208 var code_buffer = std.ArrayList(u8).init(gpa);
11921209 defer code_buffer.deinit();
11931210
11941211 const decl_val = if (decl.val.getVariable(mod)) |variable| Value.fromInterned(variable.init) else decl.val;
......@@ -1220,7 +1237,7 @@ fn updateLazySymbolAtom(
12201237 atom_index: Atom.Index,
12211238 section_index: u16,
12221239) !void {
1223 const gpa = self.base.allocator;
1240 const gpa = self.base.comp.gpa;
12241241 const mod = self.base.options.module.?;
12251242
12261243 var required_alignment: InternPool.Alignment = .none;
......@@ -1281,8 +1298,9 @@ fn updateLazySymbolAtom(
12811298}
12821299
12831300pub fn getOrCreateAtomForLazySymbol(self: *Coff, sym: link.File.LazySymbol) !Atom.Index {
1301 const gpa = self.base.comp.gpa;
12841302 const mod = self.base.options.module.?;
1285 const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl(mod));
1303 const gop = try self.lazy_syms.getOrPut(gpa, sym.getDecl(mod));
12861304 errdefer _ = if (!gop.found_existing) self.lazy_syms.pop();
12871305 if (!gop.found_existing) gop.value_ptr.* = .{};
12881306 const metadata: struct { atom: *Atom.Index, state: *LazySymbolMetadata.State } = switch (sym.kind) {
......@@ -1305,7 +1323,8 @@ pub fn getOrCreateAtomForLazySymbol(self: *Coff, sym: link.File.LazySymbol) !Ato
13051323}
13061324
13071325pub fn getOrCreateAtomForDecl(self: *Coff, decl_index: InternPool.DeclIndex) !Atom.Index {
1308 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
1326 const gpa = self.base.comp.gpa;
1327 const gop = try self.decls.getOrPut(gpa, decl_index);
13091328 if (!gop.found_existing) {
13101329 gop.value_ptr.* = .{
13111330 .atom = try self.createAtom(),
......@@ -1401,7 +1420,7 @@ fn updateDeclCode(self: *Coff, decl_index: InternPool.DeclIndex, code: []u8, com
14011420}
14021421
14031422fn freeUnnamedConsts(self: *Coff, decl_index: InternPool.DeclIndex) void {
1404 const gpa = self.base.allocator;
1423 const gpa = self.base.comp.gpa;
14051424 const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return;
14061425 for (unnamed_consts.items) |atom_index| {
14071426 self.freeAtom(atom_index);
......@@ -1412,6 +1431,7 @@ fn freeUnnamedConsts(self: *Coff, decl_index: InternPool.DeclIndex) void {
14121431pub fn freeDecl(self: *Coff, decl_index: InternPool.DeclIndex) void {
14131432 if (self.llvm_object) |llvm_object| return llvm_object.freeDecl(decl_index);
14141433
1434 const gpa = self.base.comp.gpa;
14151435 const mod = self.base.options.module.?;
14161436 const decl = mod.declPtr(decl_index);
14171437
......@@ -1421,7 +1441,7 @@ pub fn freeDecl(self: *Coff, decl_index: InternPool.DeclIndex) void {
14211441 var kv = const_kv;
14221442 self.freeAtom(kv.value.atom);
14231443 self.freeUnnamedConsts(decl_index);
1424 kv.value.exports.deinit(self.base.allocator);
1444 kv.value.exports.deinit(gpa);
14251445 }
14261446}
14271447
......@@ -1476,7 +1496,7 @@ pub fn updateExports(
14761496
14771497 if (self.base.options.emit == null) return;
14781498
1479 const gpa = self.base.allocator;
1499 const gpa = self.base.comp.gpa;
14801500
14811501 const metadata = switch (exported) {
14821502 .decl_index => |decl_index| blk: {
......@@ -1574,7 +1594,7 @@ pub fn deleteDeclExport(
15741594 const name = mod.intern_pool.stringToSlice(name_ip);
15751595 const sym_index = metadata.getExportPtr(self, name) orelse return;
15761596
1577 const gpa = self.base.allocator;
1597 const gpa = self.base.comp.gpa;
15781598 const sym_loc = SymbolWithLoc{ .sym_index = sym_index.*, .file = null };
15791599 const sym = self.getSymbolPtr(sym_loc);
15801600 log.debug("deleting export '{s}'", .{name});
......@@ -1602,7 +1622,7 @@ pub fn deleteDeclExport(
16021622}
16031623
16041624fn resolveGlobalSymbol(self: *Coff, current: SymbolWithLoc) !void {
1605 const gpa = self.base.allocator;
1625 const gpa = self.base.comp.gpa;
16061626 const sym = self.getSymbol(current);
16071627 const sym_name = self.getSymbolName(current);
16081628
......@@ -1653,7 +1673,7 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
16531673 sub_prog_node.activate();
16541674 defer sub_prog_node.end();
16551675
1656 const gpa = self.base.allocator;
1676 const gpa = self.base.comp.gpa;
16571677
16581678 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
16591679
......@@ -1794,7 +1814,7 @@ pub fn lowerAnonDecl(
17941814 explicit_alignment: InternPool.Alignment,
17951815 src_loc: Module.SrcLoc,
17961816) !codegen.Result {
1797 const gpa = self.base.allocator;
1817 const gpa = self.base.comp.gpa;
17981818 const mod = self.base.options.module.?;
17991819 const ty = Type.fromInterned(mod.intern_pool.typeOf(decl_val));
18001820 const decl_alignment = switch (explicit_alignment) {
......@@ -1868,7 +1888,7 @@ pub fn getGlobalSymbol(self: *Coff, name: []const u8, lib_name_name: ?[]const u8
18681888 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };
18691889 gop.value_ptr.* = sym_loc;
18701890
1871 const gpa = self.base.allocator;
1891 const gpa = self.base.comp.gpa;
18721892 const sym = self.getSymbolPtr(sym_loc);
18731893 try self.setSymbolName(sym, name);
18741894 sym.storage_class = .EXTERNAL;
......@@ -1895,7 +1915,7 @@ pub fn updateDeclLineNumber(self: *Coff, module: *Module, decl_index: InternPool
18951915/// TODO: note that .ABSOLUTE is used as padding within each block; we could use this fact to do
18961916/// incremental updates and writes into the table instead of doing it all at once
18971917fn writeBaseRelocations(self: *Coff) !void {
1898 const gpa = self.base.allocator;
1918 const gpa = self.base.comp.gpa;
18991919
19001920 var page_table = std.AutoHashMap(u32, std.ArrayList(coff.BaseRelocation)).init(gpa);
19011921 defer {
......@@ -2006,7 +2026,7 @@ fn writeImportTables(self: *Coff) !void {
20062026 if (self.idata_section_index == null) return;
20072027 if (!self.imports_count_dirty) return;
20082028
2009 const gpa = self.base.allocator;
2029 const gpa = self.base.comp.gpa;
20102030
20112031 const ext = ".dll";
20122032 const header = &self.sections.items(.header)[self.idata_section_index.?];
......@@ -2154,7 +2174,8 @@ fn writeStrtab(self: *Coff) !void {
21542174
21552175 log.debug("writing strtab from 0x{x} to 0x{x}", .{ self.strtab_offset.?, self.strtab_offset.? + needed_size });
21562176
2157 var buffer = std.ArrayList(u8).init(self.base.allocator);
2177 const gpa = self.base.comp.gpa;
2178 var buffer = std.ArrayList(u8).init(gpa);
21582179 defer buffer.deinit();
21592180 try buffer.ensureTotalCapacityPrecise(needed_size);
21602181 buffer.appendSliceAssumeCapacity(self.strtab.buffer.items);
......@@ -2176,7 +2197,7 @@ fn writeDataDirectoriesHeaders(self: *Coff) !void {
21762197}
21772198
21782199fn writeHeader(self: *Coff) !void {
2179 const gpa = self.base.allocator;
2200 const gpa = self.base.comp.gpa;
21802201 var buffer = std.ArrayList(u8).init(gpa);
21812202 defer buffer.deinit();
21822203 const writer = buffer.writer();
......@@ -2499,7 +2520,7 @@ pub fn getOrPutGlobalPtr(self: *Coff, name: []const u8) !GetOrPutGlobalPtrResult
24992520 if (self.getGlobalPtr(name)) |ptr| {
25002521 return GetOrPutGlobalPtrResult{ .found_existing = true, .value_ptr = ptr };
25012522 }
2502 const gpa = self.base.allocator;
2523 const gpa = self.base.comp.gpa;
25032524 const global_index = try self.allocateGlobal();
25042525 const global_name = try gpa.dupe(u8, name);
25052526 _ = try self.resolver.put(gpa, global_name, global_index);
......@@ -2530,7 +2551,8 @@ fn setSectionName(self: *Coff, header: *coff.SectionHeader, name: []const u8) !v
25302551 @memset(header.name[name.len..], 0);
25312552 return;
25322553 }
2533 const offset = try self.strtab.insert(self.base.allocator, name);
2554 const gpa = self.base.comp.gpa;
2555 const offset = try self.strtab.insert(gpa, name);
25342556 const name_offset = fmt.bufPrint(&header.name, "/{d}", .{offset}) catch unreachable;
25352557 @memset(header.name[name_offset.len..], 0);
25362558}
......@@ -2549,7 +2571,8 @@ fn setSymbolName(self: *Coff, symbol: *coff.Symbol, name: []const u8) !void {
25492571 @memset(symbol.name[name.len..], 0);
25502572 return;
25512573 }
2552 const offset = try self.strtab.insert(self.base.allocator, name);
2574 const gpa = self.base.comp.gpa;
2575 const offset = try self.strtab.insert(gpa, name);
25532576 @memset(symbol.name[0..4], 0);
25542577 mem.writeInt(u32, symbol.name[4..8], offset, .little);
25552578}
src/link/Elf.zig+103-83
......@@ -200,26 +200,34 @@ pub const min_text_capacity = padToIdeal(minimum_atom_size);
200200
201201pub const PtrWidth = enum { p32, p64 };
202202
203pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Elf {
204 assert(options.target.ofmt == .elf);
203pub fn open(arena: Allocator, options: link.File.OpenOptions) !*Elf {
204 if (build_options.only_c) unreachable;
205 const target = options.comp.root_mod.resolved_target.result;
206 assert(target.ofmt == .elf);
205207
206 const self = try createEmpty(allocator, options);
208 const use_lld = build_options.have_llvm and options.comp.config.use_lld;
209 const use_llvm = build_options.have_llvm and options.comp.config.use_llvm;
210
211 const self = try createEmpty(arena, options);
207212 errdefer self.base.destroy();
208213
214 if (use_lld and use_llvm) {
215 // LLVM emits the object file; LLD links it into the final product.
216 return self;
217 }
218
209219 const is_obj = options.output_mode == .Obj;
210220 const is_obj_or_ar = is_obj or (options.output_mode == .Lib and options.link_mode == .Static);
211221
212 if (options.use_llvm) {
213 const use_lld = build_options.have_llvm and self.base.options.use_lld;
214 if (use_lld) return self;
215
216 if (options.module != null) {
217 self.base.intermediary_basename = try std.fmt.allocPrint(allocator, "{s}{s}", .{
218 sub_path, options.target.ofmt.fileExt(options.target.cpu.arch),
219 });
220 }
221 }
222 errdefer if (self.base.intermediary_basename) |path| allocator.free(path);
222 const sub_path = if (!use_lld) options.emit.sub_path else p: {
223 // Open a temporary object file, not the final output file because we
224 // want to link with LLD.
225 const o_file_path = try std.fmt.allocPrint(arena, "{s}{s}", .{
226 options.emit.sub_path, target.ofmt.fileExt(target.cpu.arch),
227 });
228 self.base.intermediary_basename = o_file_path;
229 break :p o_file_path;
230 };
223231
224232 self.base.file = try options.emit.?.directory.handle.createFile(sub_path, .{
225233 .truncate = false,
......@@ -227,24 +235,26 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
227235 .mode = link.determineMode(options),
228236 });
229237
238 const gpa = options.comp.gpa;
239
230240 // Index 0 is always a null symbol.
231 try self.symbols.append(allocator, .{});
241 try self.symbols.append(gpa, .{});
232242 // Index 0 is always a null symbol.
233 try self.symbols_extra.append(allocator, 0);
243 try self.symbols_extra.append(gpa, 0);
234244 // Allocate atom index 0 to null atom
235 try self.atoms.append(allocator, .{});
245 try self.atoms.append(gpa, .{});
236246 // Append null file at index 0
237 try self.files.append(allocator, .null);
247 try self.files.append(gpa, .null);
238248 // Append null byte to string tables
239 try self.shstrtab.append(allocator, 0);
240 try self.strtab.append(allocator, 0);
249 try self.shstrtab.append(gpa, 0);
250 try self.strtab.append(gpa, 0);
241251 // There must always be a null shdr in index 0
242252 _ = try self.addSection(.{ .name = "" });
243253 // Append null symbol in output symtab
244 try self.symtab.append(allocator, null_sym);
254 try self.symtab.append(gpa, null_sym);
245255
246256 if (!is_obj_or_ar) {
247 try self.dynstrtab.append(allocator, 0);
257 try self.dynstrtab.append(gpa, 0);
248258
249259 // Initialize PT_PHDR program header
250260 const p_align: u16 = switch (self.ptr_width) {
......@@ -283,10 +293,10 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
283293 }
284294
285295 if (options.module != null and !options.use_llvm) {
286 const index = @as(File.Index, @intCast(try self.files.addOne(allocator)));
296 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
287297 self.files.set(index, .{ .zig_object = .{
288298 .index = index,
289 .path = try std.fmt.allocPrint(self.base.allocator, "{s}.o", .{std.fs.path.stem(
299 .path = try std.fmt.allocPrint(arena, "{s}.o", .{std.fs.path.stem(
290300 options.module.?.main_mod.root_src_path,
291301 )}),
292302 } });
......@@ -298,16 +308,16 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
298308 return self;
299309}
300310
301pub fn createEmpty(gpa: Allocator, options: link.Options) !*Elf {
302 const ptr_width: PtrWidth = switch (options.target.ptrBitWidth()) {
311pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*Elf {
312 const target = options.comp.root_mod.resolved_target.result;
313 const ptr_width: PtrWidth = switch (target.ptrBitWidth()) {
303314 0...32 => .p32,
304315 33...64 => .p64,
305316 else => return error.UnsupportedELFArchitecture,
306317 };
307 const self = try gpa.create(Elf);
308 errdefer gpa.destroy(self);
318 const self = try arena.create(Elf);
309319
310 const page_size: u32 = switch (options.target.cpu.arch) {
320 const page_size: u32 = switch (target.cpu.arch) {
311321 .powerpc64le => 0x10000,
312322 .sparc64 => 0x2000,
313323 else => 0x1000,
......@@ -321,25 +331,25 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Elf {
321331 self.* = .{
322332 .base = .{
323333 .tag = .elf,
324 .options = options,
325 .allocator = gpa,
334 .comp = options.comp,
335 .emit = options.emit,
326336 .file = null,
327337 },
328338 .ptr_width = ptr_width,
329339 .page_size = page_size,
330340 .default_sym_version = default_sym_version,
331341 };
332 if (options.use_llvm and options.module != null) {
333 self.llvm_object = try LlvmObject.create(gpa, options);
342 if (options.use_llvm and options.comp.config.have_zcu) {
343 self.llvm_object = try LlvmObject.create(arena, options);
334344 }
335345
336346 return self;
337347}
338348
339349pub fn deinit(self: *Elf) void {
340 const gpa = self.base.allocator;
350 const gpa = self.base.comp.gpa;
341351
342 if (self.llvm_object) |llvm_object| llvm_object.destroy(gpa);
352 if (self.llvm_object) |llvm_object| llvm_object.deinit();
343353
344354 for (self.files.items(.tags), self.files.items(.data)) |tag, *data| switch (tag) {
345355 .null => {},
......@@ -496,10 +506,11 @@ fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u64) u64 {
496506
497507/// TODO move to ZigObject
498508pub fn initMetadata(self: *Elf) !void {
499 const gpa = self.base.allocator;
509 const gpa = self.base.comp.gpa;
500510 const ptr_size = self.ptrWidthBytes();
501 const ptr_bit_width = self.base.options.target.ptrBitWidth();
502 const is_linux = self.base.options.target.os.tag == .linux;
511 const target = self.base.comp.root_mod.resolved_target.result;
512 const ptr_bit_width = target.ptrBitWidth();
513 const is_linux = target.os.tag == .linux;
503514 const zig_object = self.zigObjectPtr().?;
504515
505516 const fillSection = struct {
......@@ -943,7 +954,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
943954 if (use_lld) return;
944955 }
945956
946 const gpa = self.base.allocator;
957 const gpa = self.base.comp.gpa;
947958 var sub_prog_node = prog_node.start("ELF Flush", 0);
948959 sub_prog_node.activate();
949960 defer sub_prog_node.end();
......@@ -952,7 +963,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
952963 defer arena_allocator.deinit();
953964 const arena = arena_allocator.allocator();
954965
955 const target = self.base.options.target;
966 const target = self.base.comp.root_mod.resolved_target.result;
956967 const directory = self.base.options.emit.?.directory; // Just an alias to make it shorter to type.
957968 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path});
958969 const module_obj_path: ?[]const u8 = if (self.base.intermediary_basename) |path| blk: {
......@@ -1303,7 +1314,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
13031314}
13041315
13051316pub fn flushStaticLib(self: *Elf, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void {
1306 const gpa = self.base.allocator;
1317 const gpa = self.base.comp.gpa;
13071318
13081319 var positionals = std.ArrayList(Compilation.LinkObject).init(gpa);
13091320 defer positionals.deinit();
......@@ -1447,7 +1458,7 @@ pub fn flushStaticLib(self: *Elf, comp: *Compilation, module_obj_path: ?[]const
14471458}
14481459
14491460pub fn flushObject(self: *Elf, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void {
1450 const gpa = self.base.allocator;
1461 const gpa = self.base.comp.gpa;
14511462
14521463 var positionals = std.ArrayList(Compilation.LinkObject).init(gpa);
14531464 defer positionals.deinit();
......@@ -1524,7 +1535,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
15241535 defer arena_allocator.deinit();
15251536 const arena = arena_allocator.allocator();
15261537
1527 const target = self.base.options.target;
1538 const target = self.base.comp.root_mod.resolved_target.result;
15281539 const directory = self.base.options.emit.?.directory; // Just an alias to make it shorter to type.
15291540 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path});
15301541 const module_obj_path: ?[]const u8 = if (self.base.intermediary_basename) |path| blk: {
......@@ -1574,7 +1585,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
15741585 }
15751586 } else {
15761587 if (!self.isStatic()) {
1577 if (self.base.options.target.dynamic_linker.get()) |path| {
1588 if (target.dynamic_linker.get()) |path| {
15781589 try argv.append("-dynamic-linker");
15791590 try argv.append(path);
15801591 }
......@@ -1842,7 +1853,7 @@ fn parseObject(self: *Elf, path: []const u8) ParseError!void {
18421853 const tracy = trace(@src());
18431854 defer tracy.end();
18441855
1845 const gpa = self.base.allocator;
1856 const gpa = self.base.comp.gpa;
18461857 const in_file = try std.fs.cwd().openFile(path, .{});
18471858 defer in_file.close();
18481859 const data = try in_file.readToEndAlloc(gpa, std.math.maxInt(u32));
......@@ -1862,7 +1873,7 @@ fn parseArchive(self: *Elf, path: []const u8, must_link: bool) ParseError!void {
18621873 const tracy = trace(@src());
18631874 defer tracy.end();
18641875
1865 const gpa = self.base.allocator;
1876 const gpa = self.base.comp.gpa;
18661877 const in_file = try std.fs.cwd().openFile(path, .{});
18671878 defer in_file.close();
18681879 const data = try in_file.readToEndAlloc(gpa, std.math.maxInt(u32));
......@@ -1888,7 +1899,7 @@ fn parseSharedObject(self: *Elf, lib: SystemLib) ParseError!void {
18881899 const tracy = trace(@src());
18891900 defer tracy.end();
18901901
1891 const gpa = self.base.allocator;
1902 const gpa = self.base.comp.gpa;
18921903 const in_file = try std.fs.cwd().openFile(lib.path, .{});
18931904 defer in_file.close();
18941905 const data = try in_file.readToEndAlloc(gpa, std.math.maxInt(u32));
......@@ -1910,7 +1921,7 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {
19101921 const tracy = trace(@src());
19111922 defer tracy.end();
19121923
1913 const gpa = self.base.allocator;
1924 const gpa = self.base.comp.gpa;
19141925 const in_file = try std.fs.cwd().openFile(lib.path, .{});
19151926 defer in_file.close();
19161927 const data = try in_file.readToEndAlloc(gpa, std.math.maxInt(u32));
......@@ -1996,7 +2007,7 @@ fn accessLibPath(
19962007 link_mode: ?std.builtin.LinkMode,
19972008) !bool {
19982009 const sep = fs.path.sep_str;
1999 const target = self.base.options.target;
2010 const target = self.base.comp.root_mod.resolved_target.result;
20002011 test_path.clearRetainingCapacity();
20012012 const prefix = if (link_mode != null) "lib" else "";
20022013 const suffix = if (link_mode) |mode| switch (mode) {
......@@ -2190,7 +2201,7 @@ fn claimUnresolvedObject(self: *Elf) void {
21902201/// This is also the point where we will report undefined symbols for any
21912202/// alloc sections.
21922203fn scanRelocs(self: *Elf) !void {
2193 const gpa = self.base.allocator;
2204 const gpa = self.base.comp.gpa;
21942205
21952206 var undefs = std.AutoHashMap(Symbol.Index, std.ArrayList(Atom.Index)).init(gpa);
21962207 defer {
......@@ -2293,7 +2304,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
22932304 const is_exe_or_dyn_lib = is_dyn_lib or self.base.options.output_mode == .Exe;
22942305 const have_dynamic_linker = self.base.options.link_libc and
22952306 self.base.options.link_mode == .Dynamic and is_exe_or_dyn_lib;
2296 const target = self.base.options.target;
2307 const target = self.base.comp.root_mod.resolved_target.result;
22972308 const gc_sections = self.base.options.gc_sections orelse !is_obj;
22982309 const stack_size = self.base.options.stack_size_override orelse 16777216;
22992310 const allow_shlib_undefined = self.base.options.allow_shlib_undefined orelse !self.base.options.is_native_os;
......@@ -2374,7 +2385,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
23742385 man.hash.addBytes(libc_installation.crt_dir.?);
23752386 }
23762387 if (have_dynamic_linker) {
2377 man.hash.addOptionalBytes(self.base.options.target.dynamic_linker.get());
2388 man.hash.addOptionalBytes(target.dynamic_linker.get());
23782389 }
23792390 }
23802391 man.hash.addOptionalBytes(self.base.options.soname);
......@@ -2687,7 +2698,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
26872698 }
26882699
26892700 if (have_dynamic_linker) {
2690 if (self.base.options.target.dynamic_linker.get()) |dynamic_linker| {
2701 if (target.dynamic_linker.get()) |dynamic_linker| {
26912702 try argv.append("-dynamic-linker");
26922703 try argv.append(dynamic_linker);
26932704 }
......@@ -2937,7 +2948,8 @@ fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !v
29372948}
29382949
29392950fn writeDwarfAddrAssumeCapacity(self: *Elf, buf: *std.ArrayList(u8), addr: u64) void {
2940 const target_endian = self.base.options.target.cpu.arch.endian();
2951 const target = self.base.comp.root_mod.resolved_target.result;
2952 const target_endian = target.cpu.arch.endian();
29412953 switch (self.ptr_width) {
29422954 .p32 => mem.writeInt(u32, buf.addManyAsArrayAssumeCapacity(4), @as(u32, @intCast(addr)), target_endian),
29432955 .p64 => mem.writeInt(u64, buf.addManyAsArrayAssumeCapacity(8), addr, target_endian),
......@@ -2945,8 +2957,9 @@ fn writeDwarfAddrAssumeCapacity(self: *Elf, buf: *std.ArrayList(u8), addr: u64)
29452957}
29462958
29472959fn writeShdrTable(self: *Elf) !void {
2948 const gpa = self.base.allocator;
2949 const target_endian = self.base.options.target.cpu.arch.endian();
2960 const gpa = self.base.comp.gpa;
2961 const target = self.base.comp.root_mod.resolved_target.result;
2962 const target_endian = target.cpu.arch.endian();
29502963 const foreign_endian = target_endian != builtin.cpu.arch.endian();
29512964 const shsize: u64 = switch (self.ptr_width) {
29522965 .p32 => @sizeOf(elf.Elf32_Shdr),
......@@ -3001,8 +3014,9 @@ fn writeShdrTable(self: *Elf) !void {
30013014}
30023015
30033016fn writePhdrTable(self: *Elf) !void {
3004 const gpa = self.base.allocator;
3005 const target_endian = self.base.options.target.cpu.arch.endian();
3017 const gpa = self.base.comp.gpa;
3018 const target = self.base.comp.root_mod.resolved_target.result;
3019 const target_endian = target.cpu.arch.endian();
30063020 const foreign_endian = target_endian != builtin.cpu.arch.endian();
30073021 const phdr_table = &self.phdrs.items[self.phdr_table_index.?];
30083022
......@@ -3054,7 +3068,8 @@ fn writeElfHeader(self: *Elf) !void {
30543068 };
30553069 index += 1;
30563070
3057 const endian = self.base.options.target.cpu.arch.endian();
3071 const target = self.base.comp.root_mod.resolved_target.result;
3072 const endian = target.cpu.arch.endian();
30583073 hdr_buf[index] = switch (endian) {
30593074 .little => elf.ELFDATA2LSB,
30603075 .big => elf.ELFDATA2MSB,
......@@ -3083,7 +3098,7 @@ fn writeElfHeader(self: *Elf) !void {
30833098 mem.writeInt(u16, hdr_buf[index..][0..2], @intFromEnum(elf_type), endian);
30843099 index += 2;
30853100
3086 const machine = self.base.options.target.cpu.arch.toElfMachine();
3101 const machine = target.cpu.arch.toElfMachine();
30873102 mem.writeInt(u16, hdr_buf[index..][0..2], @intFromEnum(machine), endian);
30883103 index += 2;
30893104
......@@ -3248,7 +3263,7 @@ fn addLinkerDefinedSymbols(self: *Elf) !void {
32483263
32493264 for (self.shdrs.items) |shdr| {
32503265 if (self.getStartStopBasename(shdr)) |name| {
3251 const gpa = self.base.allocator;
3266 const gpa = self.base.comp.gpa;
32523267 try self.start_stop_indexes.ensureUnusedCapacity(gpa, 2);
32533268
32543269 const start = try std.fmt.allocPrintZ(gpa, "__start_{s}", .{name});
......@@ -3394,6 +3409,7 @@ fn initOutputSections(self: *Elf) !void {
33943409}
33953410
33963411fn initSyntheticSections(self: *Elf) !void {
3412 const target = self.base.comp.root_mod.resolved_target.result;
33973413 const ptr_size = self.ptrWidthBytes();
33983414
33993415 const needs_eh_frame = for (self.objects.items) |index| {
......@@ -3503,7 +3519,7 @@ fn initSyntheticSections(self: *Elf) !void {
35033519 // a segfault in the dynamic linker trying to load a binary that is static
35043520 // and doesn't contain .dynamic section.
35053521 if (self.isStatic() and !self.base.options.pie) break :blk false;
3506 break :blk self.base.options.target.dynamic_linker.get() != null;
3522 break :blk target.dynamic_linker.get() != null;
35073523 };
35083524 if (needs_interp) {
35093525 self.interp_section_index = try self.addSection(.{
......@@ -3613,7 +3629,7 @@ fn initSectionsObject(self: *Elf) !void {
36133629}
36143630
36153631fn initComdatGroups(self: *Elf) !void {
3616 const gpa = self.base.allocator;
3632 const gpa = self.base.comp.gpa;
36173633
36183634 for (self.objects.items) |index| {
36193635 const object = self.file(index).?.object;
......@@ -3732,7 +3748,7 @@ fn initSpecialPhdrs(self: *Elf) !void {
37323748/// Ties are broken by the file prority which corresponds to the inclusion of input sections in this output section
37333749/// we are about to sort.
37343750fn sortInitFini(self: *Elf) !void {
3735 const gpa = self.base.allocator;
3751 const gpa = self.base.comp.gpa;
37363752
37373753 const Entry = struct {
37383754 priority: i32,
......@@ -3872,7 +3888,7 @@ fn sortPhdrs(self: *Elf) error{OutOfMemory}!void {
38723888 }
38733889 };
38743890
3875 const gpa = self.base.allocator;
3891 const gpa = self.base.comp.gpa;
38763892 var entries = try std.ArrayList(Entry).initCapacity(gpa, self.phdrs.items.len);
38773893 defer entries.deinit();
38783894 for (0..self.phdrs.items.len) |phndx| {
......@@ -3977,7 +3993,7 @@ fn sortShdrs(self: *Elf) !void {
39773993 }
39783994 };
39793995
3980 const gpa = self.base.allocator;
3996 const gpa = self.base.comp.gpa;
39813997 var entries = try std.ArrayList(Entry).initCapacity(gpa, self.shdrs.items.len);
39823998 defer entries.deinit();
39833999 for (0..self.shdrs.items.len) |shndx| {
......@@ -4004,7 +4020,7 @@ fn sortShdrs(self: *Elf) !void {
40044020}
40054021
40064022fn resetShdrIndexes(self: *Elf, backlinks: []const u16) !void {
4007 const gpa = self.base.allocator;
4023 const gpa = self.base.comp.gpa;
40084024
40094025 for (&[_]*?u16{
40104026 &self.eh_frame_section_index,
......@@ -4187,6 +4203,7 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u16) !void {
41874203}
41884204
41894205fn updateSectionSizes(self: *Elf) !void {
4206 const target = self.base.comp.root_mod.resolved_target.result;
41904207 for (self.output_sections.keys(), self.output_sections.values()) |shndx, atom_list| {
41914208 const shdr = &self.shdrs.items[shndx];
41924209 for (atom_list.items) |atom_index| {
......@@ -4244,7 +4261,7 @@ fn updateSectionSizes(self: *Elf) !void {
42444261 }
42454262
42464263 if (self.interp_section_index) |index| {
4247 self.shdrs.items[index].sh_size = self.base.options.target.dynamic_linker.get().?.len + 1;
4264 self.shdrs.items[index].sh_size = target.dynamic_linker.get().?.len + 1;
42484265 }
42494266
42504267 if (self.hash_section_index) |index| {
......@@ -4453,7 +4470,7 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void {
44534470 // as we are more interested in quick turnaround and compatibility
44544471 // with `findFreeSpace` mechanics than anything else.
44554472 const Cover = std.ArrayList(u16);
4456 const gpa = self.base.allocator;
4473 const gpa = self.base.comp.gpa;
44574474 var covers: [max_number_of_object_segments]Cover = undefined;
44584475 for (&covers) |*cover| {
44594476 cover.* = Cover.init(gpa);
......@@ -4691,7 +4708,7 @@ fn allocateAtoms(self: *Elf) void {
46914708}
46924709
46934710fn writeAtoms(self: *Elf) !void {
4694 const gpa = self.base.allocator;
4711 const gpa = self.base.comp.gpa;
46954712
46964713 var undefs = std.AutoHashMap(Symbol.Index, std.ArrayList(Atom.Index)).init(gpa);
46974714 defer {
......@@ -4779,7 +4796,7 @@ fn writeAtoms(self: *Elf) !void {
47794796}
47804797
47814798fn writeAtomsObject(self: *Elf) !void {
4782 const gpa = self.base.allocator;
4799 const gpa = self.base.comp.gpa;
47834800
47844801 // TODO iterate over `output_sections` directly
47854802 for (self.shdrs.items, 0..) |shdr, shndx| {
......@@ -4852,7 +4869,7 @@ fn updateSymtabSize(self: *Elf) !void {
48524869 var nglobals: u32 = 0;
48534870 var strsize: u32 = 0;
48544871
4855 const gpa = self.base.allocator;
4872 const gpa = self.base.comp.gpa;
48564873 var files = std.ArrayList(File.Index).init(gpa);
48574874 defer files.deinit();
48584875 try files.ensureTotalCapacityPrecise(self.objects.items.len + self.shared_objects.items.len + 2);
......@@ -4935,11 +4952,12 @@ fn updateSymtabSize(self: *Elf) !void {
49354952}
49364953
49374954fn writeSyntheticSections(self: *Elf) !void {
4938 const gpa = self.base.allocator;
4955 const target = self.base.comp.root_mod.resolved_target.result;
4956 const gpa = self.base.comp.gpa;
49394957
49404958 if (self.interp_section_index) |shndx| {
49414959 var buffer: [256]u8 = undefined;
4942 const interp = self.base.options.target.dynamic_linker.get().?;
4960 const interp = target.dynamic_linker.get().?;
49434961 @memcpy(buffer[0..interp.len], interp);
49444962 buffer[interp.len] = 0;
49454963 const contents = buffer[0 .. interp.len + 1];
......@@ -5065,7 +5083,7 @@ fn writeSyntheticSections(self: *Elf) !void {
50655083}
50665084
50675085fn writeSyntheticSectionsObject(self: *Elf) !void {
5068 const gpa = self.base.allocator;
5086 const gpa = self.base.comp.gpa;
50695087
50705088 for (self.output_rela_sections.values()) |sec| {
50715089 if (sec.atom_list.items.len == 0) continue;
......@@ -5135,7 +5153,7 @@ fn writeSyntheticSectionsObject(self: *Elf) !void {
51355153}
51365154
51375155fn writeComdatGroups(self: *Elf) !void {
5138 const gpa = self.base.allocator;
5156 const gpa = self.base.comp.gpa;
51395157 for (self.comdat_group_sections.items) |cgs| {
51405158 const shdr = self.shdrs.items[cgs.shndx];
51415159 const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;
......@@ -5160,7 +5178,8 @@ fn writeShStrtab(self: *Elf) !void {
51605178}
51615179
51625180fn writeSymtab(self: *Elf) !void {
5163 const gpa = self.base.allocator;
5181 const target = self.base.comp.root_mod.resolved_target.result;
5182 const gpa = self.base.comp.gpa;
51645183 const symtab_shdr = self.shdrs.items[self.symtab_section_index.?];
51655184 const strtab_shdr = self.shdrs.items[self.strtab_section_index.?];
51665185 const sym_size: u64 = switch (self.ptr_width) {
......@@ -5220,7 +5239,7 @@ fn writeSymtab(self: *Elf) !void {
52205239 self.plt_got.writeSymtab(self);
52215240 }
52225241
5223 const foreign_endian = self.base.options.target.cpu.arch.endian() != builtin.cpu.arch.endian();
5242 const foreign_endian = target.cpu.arch.endian() != builtin.cpu.arch.endian();
52245243 switch (self.ptr_width) {
52255244 .p32 => {
52265245 const buf = try gpa.alloc(elf.Elf32_Sym, self.symtab.items.len);
......@@ -5299,7 +5318,8 @@ fn ptrWidthBytes(self: Elf) u8 {
52995318/// Does not necessarily match `ptrWidthBytes` for example can be 2 bytes
53005319/// in a 32-bit ELF file.
53015320pub fn archPtrWidthBytes(self: Elf) u8 {
5302 return @as(u8, @intCast(@divExact(self.base.options.target.ptrBitWidth(), 8)));
5321 const target = self.base.comp.root_mod.resolved_target.result;
5322 return @intCast(@divExact(target.ptrBitWidth(), 8));
53035323}
53045324
53055325fn phdrTo32(phdr: elf.Elf64_Phdr) elf.Elf32_Phdr {
......@@ -5694,7 +5714,7 @@ pub const AddSectionOpts = struct {
56945714};
56955715
56965716pub fn addSection(self: *Elf, opts: AddSectionOpts) !u16 {
5697 const gpa = self.base.allocator;
5717 const gpa = self.base.comp.gpa;
56985718 const index = @as(u16, @intCast(self.shdrs.items.len));
56995719 const shdr = try self.shdrs.addOne(gpa);
57005720 shdr.* = .{
......@@ -5887,7 +5907,7 @@ const GetOrPutGlobalResult = struct {
58875907};
58885908
58895909pub fn getOrPutGlobal(self: *Elf, name: []const u8) !GetOrPutGlobalResult {
5890 const gpa = self.base.allocator;
5910 const gpa = self.base.comp.gpa;
58915911 const name_off = try self.strings.insert(gpa, name);
58925912 const gop = try self.resolver.getOrPut(gpa, name_off);
58935913 if (!gop.found_existing) {
......@@ -5923,7 +5943,7 @@ const GetOrCreateComdatGroupOwnerResult = struct {
59235943};
59245944
59255945pub fn getOrCreateComdatGroupOwner(self: *Elf, name: [:0]const u8) !GetOrCreateComdatGroupOwnerResult {
5926 const gpa = self.base.allocator;
5946 const gpa = self.base.comp.gpa;
59275947 const off = try self.strings.insert(gpa, name);
59285948 const gop = try self.comdat_groups_table.getOrPut(gpa, off);
59295949 if (!gop.found_existing) {
......@@ -6039,7 +6059,7 @@ pub fn insertDynString(self: *Elf, name: []const u8) error{OutOfMemory}!u32 {
60396059}
60406060
60416061fn reportUndefinedSymbols(self: *Elf, undefs: anytype) !void {
6042 const gpa = self.base.allocator;
6062 const gpa = self.base.comp.gpa;
60436063 const max_notes = 4;
60446064
60456065 try self.misc_errors.ensureUnusedCapacity(gpa, undefs.count());
src/link/MachO.zig+139-118
......@@ -143,14 +143,23 @@ tlv_table: TlvSymbolTable = .{},
143143/// Hot-code swapping state.
144144hot_state: if (is_hot_update_compatible) HotUpdateState else struct {} = .{},
145145
146pub fn openPath(allocator: Allocator, options: link.Options) !*MachO {
147 assert(options.target.ofmt == .macho);
146darwin_sdk_layout: ?SdkLayout,
147
148/// The filesystem layout of darwin SDK elements.
149pub const SdkLayout = enum {
150 /// macOS SDK layout: TOP { /usr/include, /usr/lib, /System/Library/Frameworks }.
151 sdk,
152 /// Shipped libc layout: TOP { /lib/libc/include, /lib/libc/darwin, <NONE> }.
153 vendored,
154};
148155
149 if (options.emit == null) {
150 return createEmpty(allocator, options);
151 }
156pub fn open(arena: Allocator, options: link.File.OpenOptions) !*MachO {
157 if (build_options.only_c) unreachable;
158 const target = options.comp.root_mod.resolved_target.result;
159 assert(target.ofmt == .macho);
152160
153 const emit = options.emit.?;
161 const gpa = options.comp.gpa;
162 const emit = options.emit;
154163 const mode: Mode = mode: {
155164 if (options.use_llvm or options.module == null or options.cache_mode == .whole)
156165 break :mode .zld;
......@@ -160,17 +169,16 @@ pub fn openPath(allocator: Allocator, options: link.Options) !*MachO {
160169 if (options.module == null) {
161170 // No point in opening a file, we would not write anything to it.
162171 // Initialize with empty.
163 return createEmpty(allocator, options);
172 return createEmpty(arena, options);
164173 }
165174 // Open a temporary object file, not the final output file because we
166175 // want to link with LLD.
167 break :blk try std.fmt.allocPrint(allocator, "{s}{s}", .{
168 emit.sub_path, options.target.ofmt.fileExt(options.target.cpu.arch),
176 break :blk try std.fmt.allocPrint(arena, "{s}{s}", .{
177 emit.sub_path, target.ofmt.fileExt(target.cpu.arch),
169178 });
170179 } else emit.sub_path;
171 errdefer if (mode == .zld) allocator.free(sub_path);
172180
173 const self = try createEmpty(allocator, options);
181 const self = try createEmpty(arena, options);
174182 errdefer self.base.destroy();
175183
176184 if (mode == .zld) {
......@@ -186,7 +194,6 @@ pub fn openPath(allocator: Allocator, options: link.Options) !*MachO {
186194 .read = true,
187195 .mode = link.determineMode(options),
188196 });
189 errdefer file.close();
190197 self.base.file = file;
191198
192199 if (!options.strip and options.module != null) {
......@@ -194,11 +201,10 @@ pub fn openPath(allocator: Allocator, options: link.Options) !*MachO {
194201 log.debug("creating {s}.dSYM bundle", .{sub_path});
195202
196203 const d_sym_path = try std.fmt.allocPrint(
197 allocator,
204 arena,
198205 "{s}.dSYM" ++ fs.path.sep_str ++ "Contents" ++ fs.path.sep_str ++ "Resources" ++ fs.path.sep_str ++ "DWARF",
199206 .{sub_path},
200207 );
201 defer allocator.free(d_sym_path);
202208
203209 var d_sym_bundle = try emit.directory.handle.makeOpenPath(d_sym_path, .{});
204210 defer d_sym_bundle.close();
......@@ -209,21 +215,21 @@ pub fn openPath(allocator: Allocator, options: link.Options) !*MachO {
209215 });
210216
211217 self.d_sym = .{
212 .allocator = allocator,
213 .dwarf = link.File.Dwarf.init(allocator, &self.base, .dwarf32),
218 .allocator = gpa,
219 .dwarf = link.File.Dwarf.init(gpa, &self.base, .dwarf32),
214220 .file = d_sym_file,
215221 };
216222 }
217223
218224 // Index 0 is always a null symbol.
219 try self.locals.append(allocator, .{
225 try self.locals.append(gpa, .{
220226 .n_strx = 0,
221227 .n_type = 0,
222228 .n_sect = 0,
223229 .n_desc = 0,
224230 .n_value = 0,
225231 });
226 try self.strtab.buffer.append(allocator, 0);
232 try self.strtab.buffer.append(gpa, 0);
227233
228234 try self.populateMissingMetadata();
229235
......@@ -234,15 +240,14 @@ pub fn openPath(allocator: Allocator, options: link.Options) !*MachO {
234240 return self;
235241}
236242
237pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO {
238 const self = try gpa.create(MachO);
239 errdefer gpa.destroy(self);
243pub fn createEmpty(arena: Allocator, options: link.File.OpenOptions) !*MachO {
244 const self = try arena.create(MachO);
240245
241246 self.* = .{
242247 .base = .{
243248 .tag = .macho,
244 .options = options,
245 .allocator = gpa,
249 .comp = options.comp,
250 .emit = options.emit,
246251 .file = null,
247252 },
248253 .mode = if (options.use_llvm or options.module == null or options.cache_mode == .whole)
......@@ -252,7 +257,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO {
252257 };
253258
254259 if (options.use_llvm and options.module != null) {
255 self.llvm_object = try LlvmObject.create(gpa, options);
260 self.llvm_object = try LlvmObject.create(arena, options);
256261 }
257262
258263 log.debug("selected linker mode '{s}'", .{@tagName(self.mode)});
......@@ -261,20 +266,15 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO {
261266}
262267
263268pub fn flush(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
264 if (self.base.options.emit == null) {
265 if (self.llvm_object) |llvm_object| {
266 try llvm_object.flushModule(comp, prog_node);
267 }
268 return;
269 }
269 const gpa = self.base.comp.gpa;
270270
271271 if (self.base.options.output_mode == .Lib and self.base.options.link_mode == .Static) {
272272 if (build_options.have_llvm) {
273273 return self.base.linkAsArchive(comp, prog_node);
274274 } else {
275 try self.misc_errors.ensureUnusedCapacity(self.base.allocator, 1);
275 try self.misc_errors.ensureUnusedCapacity(gpa, 1);
276276 self.misc_errors.appendAssumeCapacity(.{
277 .msg = try self.base.allocator.dupe(u8, "TODO: non-LLVM archiver for MachO object files"),
277 .msg = try gpa.dupe(u8, "TODO: non-LLVM archiver for MachO object files"),
278278 });
279279 return error.FlushFailure;
280280 }
......@@ -294,7 +294,8 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
294294 return try llvm_object.flushModule(comp, prog_node);
295295 }
296296
297 var arena_allocator = std.heap.ArenaAllocator.init(self.base.allocator);
297 const gpa = self.base.comp.gpa;
298 var arena_allocator = std.heap.ArenaAllocator.init(gpa);
298299 defer arena_allocator.deinit();
299300 const arena = arena_allocator.allocator();
300301
......@@ -391,7 +392,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
391392
392393 if (cache_miss) {
393394 for (self.dylibs.items) |*dylib| {
394 dylib.deinit(self.base.allocator);
395 dylib.deinit(gpa);
395396 }
396397 self.dylibs.clearRetainingCapacity();
397398 self.dylibs_map.clearRetainingCapacity();
......@@ -403,7 +404,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
403404 const in_file = try std.fs.cwd().openFile(path, .{});
404405 defer in_file.close();
405406
406 var parse_ctx = ParseErrorCtx.init(self.base.allocator);
407 var parse_ctx = ParseErrorCtx.init(gpa);
407408 defer parse_ctx.deinit();
408409
409410 self.parseLibrary(
......@@ -470,7 +471,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
470471 const section = self.sections.get(sym.n_sect - 1).header;
471472 const file_offset = section.offset + sym.n_value - section.addr;
472473
473 var code = std.ArrayList(u8).init(self.base.allocator);
474 var code = std.ArrayList(u8).init(gpa);
474475 defer code.deinit();
475476 try code.resize(math.cast(usize, atom.size) orelse return error.Overflow);
476477
......@@ -518,12 +519,12 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
518519 var codesig = CodeSignature.init(getPageSize(self.base.options.target.cpu.arch));
519520 codesig.code_directory.ident = self.base.options.emit.?.sub_path;
520521 if (self.base.options.entitlements) |path| {
521 try codesig.addEntitlements(self.base.allocator, path);
522 try codesig.addEntitlements(gpa, path);
522523 }
523524 try self.writeCodeSignaturePadding(&codesig);
524525 break :blk codesig;
525526 } else null;
526 defer if (codesig) |*csig| csig.deinit(self.base.allocator);
527 defer if (codesig) |*csig| csig.deinit(gpa);
527528
528529 // Write load commands
529530 var lc_buffer = std.ArrayList(u8).init(arena);
......@@ -555,12 +556,12 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
555556 });
556557 },
557558 .Lib => if (self.base.options.link_mode == .Dynamic) {
558 try load_commands.writeDylibIdLC(self.base.allocator, &self.base.options, lc_writer);
559 try load_commands.writeDylibIdLC(gpa, &self.base.options, lc_writer);
559560 },
560561 else => {},
561562 }
562563
563 try load_commands.writeRpathLCs(self.base.allocator, &self.base.options, lc_writer);
564 try load_commands.writeRpathLCs(gpa, &self.base.options, lc_writer);
564565 try lc_writer.writeStruct(macho.source_version_command{
565566 .version = 0,
566567 });
......@@ -644,7 +645,8 @@ pub fn resolveLibSystem(
644645 search_dirs: []const []const u8,
645646 out_libs: anytype,
646647) !void {
647 var tmp_arena_allocator = std.heap.ArenaAllocator.init(self.base.allocator);
648 const gpa = self.base.comp.gpa;
649 var tmp_arena_allocator = std.heap.ArenaAllocator.init(gpa);
648650 defer tmp_arena_allocator.deinit();
649651 const tmp_arena = tmp_arena_allocator.allocator();
650652
......@@ -775,7 +777,7 @@ fn parseObject(
775777 const tracy = trace(@src());
776778 defer tracy.end();
777779
778 const gpa = self.base.allocator;
780 const gpa = self.base.comp.gpa;
779781 const mtime: u64 = mtime: {
780782 const stat = file.stat() catch break :mtime 0;
781783 break :mtime @as(u64, @intCast(@divFloor(stat.mtime, 1_000_000_000)));
......@@ -868,7 +870,7 @@ pub fn parseFatLibrary(
868870 cpu_arch: std.Target.Cpu.Arch,
869871 ctx: *ParseErrorCtx,
870872) ParseError!u64 {
871 const gpa = self.base.allocator;
873 const gpa = self.base.comp.gpa;
872874
873875 const fat_archs = try fat.parseArchs(gpa, file);
874876 defer gpa.free(fat_archs);
......@@ -892,7 +894,7 @@ fn parseArchive(
892894 must_link: bool,
893895 ctx: *ParseErrorCtx,
894896) ParseError!void {
895 const gpa = self.base.allocator;
897 const gpa = self.base.comp.gpa;
896898
897899 // We take ownership of the file so that we can store it for the duration of symbol resolution.
898900 // TODO we shouldn't need to do that and could pre-parse the archive like we do for zld/ELF?
......@@ -973,7 +975,7 @@ fn parseDylib(
973975 dylib_options: DylibOpts,
974976 ctx: *ParseErrorCtx,
975977) ParseError!void {
976 const gpa = self.base.allocator;
978 const gpa = self.base.comp.gpa;
977979 const file_stat = try file.stat();
978980 const file_size = math.cast(usize, file_stat.size - offset) orelse return error.Overflow;
979981
......@@ -1019,7 +1021,7 @@ fn parseLibStub(
10191021 dylib_options: DylibOpts,
10201022 ctx: *ParseErrorCtx,
10211023) ParseError!void {
1022 const gpa = self.base.allocator;
1024 const gpa = self.base.comp.gpa;
10231025 var lib_stub = try LibStub.loadFromFile(gpa, file);
10241026 defer lib_stub.deinit();
10251027
......@@ -1072,7 +1074,7 @@ fn addDylib(self: *MachO, dylib: Dylib, dylib_options: DylibOpts, ctx: *ParseErr
10721074 }
10731075 }
10741076
1075 const gpa = self.base.allocator;
1077 const gpa = self.base.comp.gpa;
10761078 const gop = try self.dylibs_map.getOrPut(gpa, dylib.id.?.name);
10771079 if (gop.found_existing) return error.DylibAlreadyExists;
10781080
......@@ -1098,7 +1100,7 @@ pub fn parseDependentLibs(self: *MachO, dependent_libs: anytype) !void {
10981100 // 2) afterwards, we parse dependents of the included dylibs
10991101 // TODO this should not be performed if the user specifies `-flat_namespace` flag.
11001102 // See ld64 manpages.
1101 const gpa = self.base.allocator;
1103 const gpa = self.base.comp.gpa;
11021104
11031105 while (dependent_libs.readItem()) |dep_id| {
11041106 defer dep_id.id.deinit(gpa);
......@@ -1162,7 +1164,8 @@ pub fn writeAtom(self: *MachO, atom_index: Atom.Index, code: []u8) !void {
11621164 log.debug("writing atom for symbol {s} at file offset 0x{x}", .{ atom.getName(self), file_offset });
11631165
11641166 // Gather relocs which can be resolved.
1165 var relocs = std.ArrayList(*Relocation).init(self.base.allocator);
1167 const gpa = self.base.comp.gpa;
1168 var relocs = std.ArrayList(*Relocation).init(gpa);
11661169 defer relocs.deinit();
11671170
11681171 if (self.relocs.getPtr(atom_index)) |rels| {
......@@ -1237,7 +1240,7 @@ fn writeOffsetTableEntry(self: *MachO, index: usize) !void {
12371240fn writeStubHelperPreamble(self: *MachO) !void {
12381241 if (self.stub_helper_preamble_allocated) return;
12391242
1240 const gpa = self.base.allocator;
1243 const gpa = self.base.comp.gpa;
12411244 const cpu_arch = self.base.options.target.cpu.arch;
12421245 const size = stubs.stubHelperPreambleSize(cpu_arch);
12431246
......@@ -1290,7 +1293,7 @@ fn writeStubTableEntry(self: *MachO, index: usize) !void {
12901293 self.stub_table_count_dirty = false;
12911294 }
12921295
1293 const gpa = self.base.allocator;
1296 const gpa = self.base.comp.gpa;
12941297
12951298 const stubs_header = self.sections.items(.header)[stubs_sect_id];
12961299 const stub_helper_header = self.sections.items(.header)[stub_helper_sect_id];
......@@ -1469,7 +1472,7 @@ const CreateAtomOpts = struct {
14691472};
14701473
14711474pub fn createAtom(self: *MachO, sym_index: u32, opts: CreateAtomOpts) !Atom.Index {
1472 const gpa = self.base.allocator;
1475 const gpa = self.base.comp.gpa;
14731476 const index = @as(Atom.Index, @intCast(self.atoms.items.len));
14741477 const atom = try self.atoms.addOne(gpa);
14751478 atom.* = .{};
......@@ -1481,7 +1484,7 @@ pub fn createAtom(self: *MachO, sym_index: u32, opts: CreateAtomOpts) !Atom.Inde
14811484}
14821485
14831486pub fn createTentativeDefAtoms(self: *MachO) !void {
1484 const gpa = self.base.allocator;
1487 const gpa = self.base.comp.gpa;
14851488
14861489 for (self.globals.items) |global| {
14871490 const sym = self.getSymbolPtr(global);
......@@ -1536,7 +1539,8 @@ pub fn createDyldPrivateAtom(self: *MachO) !void {
15361539 .size = @sizeOf(u64),
15371540 .alignment = .@"8",
15381541 });
1539 try self.atom_by_index_table.putNoClobber(self.base.allocator, sym_index, atom_index);
1542 const gpa = self.base.comp.gpa;
1543 try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom_index);
15401544
15411545 if (self.data_section_index == null) {
15421546 self.data_section_index = try self.initSection("__DATA", "__data", .{});
......@@ -1560,7 +1564,7 @@ pub fn createDyldPrivateAtom(self: *MachO) !void {
15601564}
15611565
15621566fn createThreadLocalDescriptorAtom(self: *MachO, sym_name: []const u8, target: SymbolWithLoc) !Atom.Index {
1563 const gpa = self.base.allocator;
1567 const gpa = self.base.comp.gpa;
15641568 const size = 3 * @sizeOf(u64);
15651569 const required_alignment: Alignment = .@"1";
15661570 const sym_index = try self.allocateSymbol();
......@@ -1595,7 +1599,7 @@ fn createThreadLocalDescriptorAtom(self: *MachO, sym_name: []const u8, target: S
15951599pub fn createMhExecuteHeaderSymbol(self: *MachO) !void {
15961600 if (self.base.options.output_mode != .Exe) return;
15971601
1598 const gpa = self.base.allocator;
1602 const gpa = self.base.comp.gpa;
15991603 const sym_index = try self.allocateSymbol();
16001604 const sym_loc = SymbolWithLoc{ .sym_index = sym_index };
16011605 const sym = self.getSymbolPtr(sym_loc);
......@@ -1622,7 +1626,7 @@ pub fn createDsoHandleSymbol(self: *MachO) !void {
16221626 const global = self.getGlobalPtr("___dso_handle") orelse return;
16231627 if (!self.getSymbol(global.*).undf()) return;
16241628
1625 const gpa = self.base.allocator;
1629 const gpa = self.base.comp.gpa;
16261630 const sym_index = try self.allocateSymbol();
16271631 const sym_loc = SymbolWithLoc{ .sym_index = sym_index };
16281632 const sym = self.getSymbolPtr(sym_loc);
......@@ -1686,7 +1690,7 @@ pub fn resolveSymbols(self: *MachO) !void {
16861690}
16871691
16881692fn resolveGlobalSymbol(self: *MachO, current: SymbolWithLoc) !void {
1689 const gpa = self.base.allocator;
1693 const gpa = self.base.comp.gpa;
16901694 const sym = self.getSymbol(current);
16911695 const sym_name = self.getSymbolName(current);
16921696
......@@ -1800,7 +1804,7 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u32) !void {
18001804fn resolveSymbolsInArchives(self: *MachO) !void {
18011805 if (self.archives.items.len == 0) return;
18021806
1803 const gpa = self.base.allocator;
1807 const gpa = self.base.comp.gpa;
18041808 var next_sym: usize = 0;
18051809 loop: while (next_sym < self.unresolved.count()) {
18061810 const global = self.globals.items[self.unresolved.keys()[next_sym]];
......@@ -1829,7 +1833,7 @@ fn resolveSymbolsInArchives(self: *MachO) !void {
18291833fn resolveSymbolsInDylibs(self: *MachO) !void {
18301834 if (self.dylibs.items.len == 0) return;
18311835
1832 const gpa = self.base.allocator;
1836 const gpa = self.base.comp.gpa;
18331837 var next_sym: usize = 0;
18341838 loop: while (next_sym < self.unresolved.count()) {
18351839 const global_index = self.unresolved.keys()[next_sym];
......@@ -1899,6 +1903,7 @@ fn resolveSymbolsAtLoading(self: *MachO) !void {
18991903}
19001904
19011905fn resolveBoundarySymbols(self: *MachO) !void {
1906 const gpa = self.base.comp.gpa;
19021907 var next_sym: usize = 0;
19031908 while (next_sym < self.unresolved.count()) {
19041909 const global_index = self.unresolved.keys()[next_sym];
......@@ -1909,7 +1914,7 @@ fn resolveBoundarySymbols(self: *MachO) !void {
19091914 const sym_loc = SymbolWithLoc{ .sym_index = sym_index };
19101915 const sym = self.getSymbolPtr(sym_loc);
19111916 sym.* = .{
1912 .n_strx = try self.strtab.insert(self.base.allocator, self.getSymbolName(global.*)),
1917 .n_strx = try self.strtab.insert(gpa, self.getSymbolName(global.*)),
19131918 .n_type = macho.N_SECT | macho.N_EXT,
19141919 .n_sect = 0,
19151920 .n_desc = N_BOUNDARY,
......@@ -1929,9 +1934,9 @@ fn resolveBoundarySymbols(self: *MachO) !void {
19291934}
19301935
19311936pub fn deinit(self: *MachO) void {
1932 const gpa = self.base.allocator;
1937 const gpa = self.base.comp.gpa;
19331938
1934 if (self.llvm_object) |llvm_object| llvm_object.destroy(gpa);
1939 if (self.llvm_object) |llvm_object| llvm_object.deinit();
19351940
19361941 if (self.d_sym) |*d_sym| {
19371942 d_sym.deinit();
......@@ -2032,7 +2037,7 @@ pub fn deinit(self: *MachO) void {
20322037}
20332038
20342039fn freeAtom(self: *MachO, atom_index: Atom.Index) void {
2035 const gpa = self.base.allocator;
2040 const gpa = self.base.comp.gpa;
20362041 log.debug("freeAtom {d}", .{atom_index});
20372042
20382043 // Remove any relocs and base relocs associated with this Atom
......@@ -2124,7 +2129,8 @@ fn growAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignment:
21242129}
21252130
21262131pub fn allocateSymbol(self: *MachO) !u32 {
2127 try self.locals.ensureUnusedCapacity(self.base.allocator, 1);
2132 const gpa = self.base.comp.gpa;
2133 try self.locals.ensureUnusedCapacity(gpa, 1);
21282134
21292135 const index = blk: {
21302136 if (self.locals_free_list.popOrNull()) |index| {
......@@ -2150,7 +2156,8 @@ pub fn allocateSymbol(self: *MachO) !u32 {
21502156}
21512157
21522158fn allocateGlobal(self: *MachO) !u32 {
2153 try self.globals.ensureUnusedCapacity(self.base.allocator, 1);
2159 const gpa = self.base.comp.gpa;
2160 try self.globals.ensureUnusedCapacity(gpa, 1);
21542161
21552162 const index = blk: {
21562163 if (self.globals_free_list.popOrNull()) |index| {
......@@ -2171,7 +2178,8 @@ fn allocateGlobal(self: *MachO) !u32 {
21712178
21722179pub fn addGotEntry(self: *MachO, target: SymbolWithLoc) !void {
21732180 if (self.got_table.lookup.contains(target)) return;
2174 const got_index = try self.got_table.allocateEntry(self.base.allocator, target);
2181 const gpa = self.base.comp.gpa;
2182 const got_index = try self.got_table.allocateEntry(gpa, target);
21752183 if (self.got_section_index == null) {
21762184 self.got_section_index = try self.initSection("__DATA_CONST", "__got", .{
21772185 .flags = macho.S_NON_LAZY_SYMBOL_POINTERS,
......@@ -2186,7 +2194,8 @@ pub fn addGotEntry(self: *MachO, target: SymbolWithLoc) !void {
21862194
21872195pub fn addStubEntry(self: *MachO, target: SymbolWithLoc) !void {
21882196 if (self.stub_table.lookup.contains(target)) return;
2189 const stub_index = try self.stub_table.allocateEntry(self.base.allocator, target);
2197 const gpa = self.base.comp.gpa;
2198 const stub_index = try self.stub_table.allocateEntry(gpa, target);
21902199 if (self.stubs_section_index == null) {
21912200 self.stubs_section_index = try self.initSection("__TEXT", "__stubs", .{
21922201 .flags = macho.S_SYMBOL_STUBS |
......@@ -2212,7 +2221,8 @@ pub fn addStubEntry(self: *MachO, target: SymbolWithLoc) !void {
22122221
22132222pub fn addTlvPtrEntry(self: *MachO, target: SymbolWithLoc) !void {
22142223 if (self.tlv_ptr_table.lookup.contains(target)) return;
2215 _ = try self.tlv_ptr_table.allocateEntry(self.base.allocator, target);
2224 const gpa = self.base.comp.gpa;
2225 _ = try self.tlv_ptr_table.allocateEntry(gpa, target);
22162226 if (self.tlv_ptr_section_index == null) {
22172227 self.tlv_ptr_section_index = try self.initSection("__DATA", "__thread_ptrs", .{
22182228 .flags = macho.S_THREAD_LOCAL_VARIABLE_POINTERS,
......@@ -2236,7 +2246,8 @@ pub fn updateFunc(self: *MachO, mod: *Module, func_index: InternPool.Index, air:
22362246 self.freeUnnamedConsts(decl_index);
22372247 Atom.freeRelocations(self, atom_index);
22382248
2239 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
2249 const gpa = self.base.comp.gpa;
2250 var code_buffer = std.ArrayList(u8).init(gpa);
22402251 defer code_buffer.deinit();
22412252
22422253 var decl_state = if (self.d_sym) |*d_sym|
......@@ -2279,7 +2290,7 @@ pub fn updateFunc(self: *MachO, mod: *Module, func_index: InternPool.Index, air:
22792290}
22802291
22812292pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: InternPool.DeclIndex) !u32 {
2282 const gpa = self.base.allocator;
2293 const gpa = self.base.comp.gpa;
22832294 const mod = self.base.options.module.?;
22842295 const gop = try self.unnamed_const_atoms.getOrPut(gpa, decl_index);
22852296 if (!gop.found_existing) {
......@@ -2318,7 +2329,7 @@ fn lowerConst(
23182329 sect_id: u8,
23192330 src_loc: Module.SrcLoc,
23202331) !LowerConstResult {
2321 const gpa = self.base.allocator;
2332 const gpa = self.base.comp.gpa;
23222333
23232334 var code_buffer = std.ArrayList(u8).init(gpa);
23242335 defer code_buffer.deinit();
......@@ -2366,6 +2377,7 @@ pub fn updateDecl(self: *MachO, mod: *Module, decl_index: InternPool.DeclIndex)
23662377 const tracy = trace(@src());
23672378 defer tracy.end();
23682379
2380 const gpa = self.base.comp.gpa;
23692381 const decl = mod.declPtr(decl_index);
23702382
23712383 if (decl.val.getExternFunc(mod)) |_| {
......@@ -2375,8 +2387,8 @@ pub fn updateDecl(self: *MachO, mod: *Module, decl_index: InternPool.DeclIndex)
23752387 if (decl.isExtern(mod)) {
23762388 // TODO make this part of getGlobalSymbol
23772389 const name = mod.intern_pool.stringToSlice(decl.name);
2378 const sym_name = try std.fmt.allocPrint(self.base.allocator, "_{s}", .{name});
2379 defer self.base.allocator.free(sym_name);
2390 const sym_name = try std.fmt.allocPrint(gpa, "_{s}", .{name});
2391 defer gpa.free(sym_name);
23802392 _ = try self.addUndefined(sym_name, .{ .add_got = true });
23812393 return;
23822394 }
......@@ -2391,7 +2403,7 @@ pub fn updateDecl(self: *MachO, mod: *Module, decl_index: InternPool.DeclIndex)
23912403 const sym_index = self.getAtom(atom_index).getSymbolIndex().?;
23922404 Atom.freeRelocations(self, atom_index);
23932405
2394 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
2406 var code_buffer = std.ArrayList(u8).init(gpa);
23952407 defer code_buffer.deinit();
23962408
23972409 var decl_state: ?Dwarf.DeclState = if (self.d_sym) |*d_sym|
......@@ -2449,7 +2461,7 @@ fn updateLazySymbolAtom(
24492461 atom_index: Atom.Index,
24502462 section_index: u8,
24512463) !void {
2452 const gpa = self.base.allocator;
2464 const gpa = self.base.comp.gpa;
24532465 const mod = self.base.options.module.?;
24542466
24552467 var required_alignment: Alignment = .none;
......@@ -2515,7 +2527,8 @@ fn updateLazySymbolAtom(
25152527
25162528pub fn getOrCreateAtomForLazySymbol(self: *MachO, sym: File.LazySymbol) !Atom.Index {
25172529 const mod = self.base.options.module.?;
2518 const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl(mod));
2530 const gpa = self.base.comp.gpa;
2531 const gop = try self.lazy_syms.getOrPut(gpa, sym.getDecl(mod));
25192532 errdefer _ = if (!gop.found_existing) self.lazy_syms.pop();
25202533 if (!gop.found_existing) gop.value_ptr.* = .{};
25212534 const metadata: struct { atom: *Atom.Index, state: *LazySymbolMetadata.State } = switch (sym.kind) {
......@@ -2529,7 +2542,7 @@ pub fn getOrCreateAtomForLazySymbol(self: *MachO, sym: File.LazySymbol) !Atom.In
25292542 .unused => {
25302543 const sym_index = try self.allocateSymbol();
25312544 metadata.atom.* = try self.createAtom(sym_index, .{});
2532 try self.atom_by_index_table.putNoClobber(self.base.allocator, sym_index, metadata.atom.*);
2545 try self.atom_by_index_table.putNoClobber(gpa, sym_index, metadata.atom.*);
25332546 },
25342547 .pending_flush => return metadata.atom.*,
25352548 .flushed => {},
......@@ -2556,7 +2569,7 @@ fn updateThreadlocalVariable(self: *MachO, module: *Module, decl_index: InternPo
25562569 const init_sym_index = init_atom.getSymbolIndex().?;
25572570 Atom.freeRelocations(self, init_atom_index);
25582571
2559 const gpa = self.base.allocator;
2572 const gpa = self.base.comp.gpa;
25602573
25612574 var code_buffer = std.ArrayList(u8).init(gpa);
25622575 defer code_buffer.deinit();
......@@ -2640,11 +2653,12 @@ fn updateThreadlocalVariable(self: *MachO, module: *Module, decl_index: InternPo
26402653}
26412654
26422655pub fn getOrCreateAtomForDecl(self: *MachO, decl_index: InternPool.DeclIndex) !Atom.Index {
2643 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
2656 const gpa = self.base.comp.gpa;
2657 const gop = try self.decls.getOrPut(gpa, decl_index);
26442658 if (!gop.found_existing) {
26452659 const sym_index = try self.allocateSymbol();
26462660 const atom_index = try self.createAtom(sym_index, .{});
2647 try self.atom_by_index_table.putNoClobber(self.base.allocator, sym_index, atom_index);
2661 try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom_index);
26482662 gop.value_ptr.* = .{
26492663 .atom = atom_index,
26502664 .section = self.getDeclOutputSection(decl_index),
......@@ -2694,7 +2708,7 @@ fn getDeclOutputSection(self: *MachO, decl_index: InternPool.DeclIndex) u8 {
26942708}
26952709
26962710fn updateDeclCode(self: *MachO, decl_index: InternPool.DeclIndex, code: []u8) !u64 {
2697 const gpa = self.base.allocator;
2711 const gpa = self.base.comp.gpa;
26982712 const mod = self.base.options.module.?;
26992713 const decl = mod.declPtr(decl_index);
27002714
......@@ -2787,7 +2801,7 @@ pub fn updateExports(
27872801 const tracy = trace(@src());
27882802 defer tracy.end();
27892803
2790 const gpa = self.base.allocator;
2804 const gpa = self.base.comp.gpa;
27912805
27922806 const metadata = switch (exported) {
27932807 .decl_index => |decl_index| blk: {
......@@ -2912,7 +2926,7 @@ pub fn deleteDeclExport(
29122926 if (self.llvm_object) |_| return;
29132927 const metadata = self.decls.getPtr(decl_index) orelse return;
29142928
2915 const gpa = self.base.allocator;
2929 const gpa = self.base.comp.gpa;
29162930 const mod = self.base.options.module.?;
29172931 const exp_name = try std.fmt.allocPrint(gpa, "_{s}", .{mod.intern_pool.stringToSlice(name)});
29182932 defer gpa.free(exp_name);
......@@ -2941,7 +2955,7 @@ pub fn deleteDeclExport(
29412955}
29422956
29432957fn freeUnnamedConsts(self: *MachO, decl_index: InternPool.DeclIndex) void {
2944 const gpa = self.base.allocator;
2958 const gpa = self.base.comp.gpa;
29452959 const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return;
29462960 for (unnamed_consts.items) |atom| {
29472961 self.freeAtom(atom);
......@@ -2951,6 +2965,7 @@ fn freeUnnamedConsts(self: *MachO, decl_index: InternPool.DeclIndex) void {
29512965
29522966pub fn freeDecl(self: *MachO, decl_index: InternPool.DeclIndex) void {
29532967 if (self.llvm_object) |llvm_object| return llvm_object.freeDecl(decl_index);
2968 const gpa = self.base.comp.gpa;
29542969 const mod = self.base.options.module.?;
29552970 const decl = mod.declPtr(decl_index);
29562971
......@@ -2960,7 +2975,7 @@ pub fn freeDecl(self: *MachO, decl_index: InternPool.DeclIndex) void {
29602975 var kv = const_kv;
29612976 self.freeAtom(kv.value.atom);
29622977 self.freeUnnamedConsts(decl_index);
2963 kv.value.exports.deinit(self.base.allocator);
2978 kv.value.exports.deinit(gpa);
29642979 }
29652980
29662981 if (self.d_sym) |*d_sym| {
......@@ -2993,7 +3008,7 @@ pub fn lowerAnonDecl(
29933008 explicit_alignment: InternPool.Alignment,
29943009 src_loc: Module.SrcLoc,
29953010) !codegen.Result {
2996 const gpa = self.base.allocator;
3011 const gpa = self.base.comp.gpa;
29973012 const mod = self.base.options.module.?;
29983013 const ty = Type.fromInterned(mod.intern_pool.typeOf(decl_val));
29993014 const decl_alignment = switch (explicit_alignment) {
......@@ -3060,7 +3075,7 @@ pub fn getAnonDeclVAddr(self: *MachO, decl_val: InternPool.Index, reloc_info: li
30603075fn populateMissingMetadata(self: *MachO) !void {
30613076 assert(self.mode == .incremental);
30623077
3063 const gpa = self.base.allocator;
3078 const gpa = self.base.comp.gpa;
30643079 const cpu_arch = self.base.options.target.cpu.arch;
30653080 const pagezero_vmsize = self.calcPagezeroSize();
30663081
......@@ -3228,7 +3243,8 @@ const InitSectionOpts = struct {
32283243pub fn initSection(self: *MachO, segname: []const u8, sectname: []const u8, opts: InitSectionOpts) !u8 {
32293244 log.debug("creating section '{s},{s}'", .{ segname, sectname });
32303245 const index = @as(u8, @intCast(self.sections.slice().len));
3231 try self.sections.append(self.base.allocator, .{
3246 const gpa = self.base.comp.gpa;
3247 try self.sections.append(gpa, .{
32323248 .segment_index = undefined, // Segments will be created automatically later down the pipeline
32333249 .header = .{
32343250 .sectname = makeStaticString(sectname),
......@@ -3248,7 +3264,7 @@ fn allocateSection(self: *MachO, segname: []const u8, sectname: []const u8, opts
32483264 flags: u32 = macho.S_REGULAR,
32493265 reserved2: u32 = 0,
32503266}) !u8 {
3251 const gpa = self.base.allocator;
3267 const gpa = self.base.comp.gpa;
32523268 const page_size = getPageSize(self.base.options.target.cpu.arch);
32533269 // In incremental context, we create one section per segment pairing. This way,
32543270 // we can move the segment in raw file as we please.
......@@ -3521,7 +3537,7 @@ fn allocateAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignm
35213537
35223538pub fn getGlobalSymbol(self: *MachO, name: []const u8, lib_name: ?[]const u8) !u32 {
35233539 _ = lib_name;
3524 const gpa = self.base.allocator;
3540 const gpa = self.base.comp.gpa;
35253541 const sym_name = try std.fmt.allocPrint(gpa, "_{s}", .{name});
35263542 defer gpa.free(sym_name);
35273543 return self.addUndefined(sym_name, .{ .add_stub = true });
......@@ -3582,7 +3598,7 @@ pub fn writeLinkeditSegmentData(self: *MachO) !void {
35823598}
35833599
35843600fn collectRebaseDataFromTableSection(self: *MachO, sect_id: u8, rebase: *Rebase, table: anytype) !void {
3585 const gpa = self.base.allocator;
3601 const gpa = self.base.comp.gpa;
35863602 const header = self.sections.items(.header)[sect_id];
35873603 const segment_index = self.sections.items(.segment_index)[sect_id];
35883604 const segment = self.segments.items[segment_index];
......@@ -3605,7 +3621,7 @@ fn collectRebaseDataFromTableSection(self: *MachO, sect_id: u8, rebase: *Rebase,
36053621}
36063622
36073623fn collectRebaseData(self: *MachO, rebase: *Rebase) !void {
3608 const gpa = self.base.allocator;
3624 const gpa = self.base.comp.gpa;
36093625 const slice = self.sections.slice();
36103626
36113627 for (self.rebases.keys(), 0..) |atom_index, i| {
......@@ -3715,7 +3731,7 @@ fn collectRebaseData(self: *MachO, rebase: *Rebase) !void {
37153731}
37163732
37173733fn collectBindDataFromTableSection(self: *MachO, sect_id: u8, bind: anytype, table: anytype) !void {
3718 const gpa = self.base.allocator;
3734 const gpa = self.base.comp.gpa;
37193735 const header = self.sections.items(.header)[sect_id];
37203736 const segment_index = self.sections.items(.segment_index)[sect_id];
37213737 const segment = self.segments.items[segment_index];
......@@ -3746,7 +3762,7 @@ fn collectBindDataFromTableSection(self: *MachO, sect_id: u8, bind: anytype, tab
37463762}
37473763
37483764fn collectBindData(self: *MachO, bind: anytype, raw_bindings: anytype) !void {
3749 const gpa = self.base.allocator;
3765 const gpa = self.base.comp.gpa;
37503766 const slice = self.sections.slice();
37513767
37523768 for (raw_bindings.keys(), 0..) |atom_index, i| {
......@@ -3885,12 +3901,13 @@ fn collectBindData(self: *MachO, bind: anytype, raw_bindings: anytype) !void {
38853901
38863902fn collectLazyBindData(self: *MachO, bind: anytype) !void {
38873903 const sect_id = self.la_symbol_ptr_section_index orelse return;
3904 const gpa = self.base.comp.gpa;
38883905 try self.collectBindDataFromTableSection(sect_id, bind, self.stub_table);
3889 try bind.finalize(self.base.allocator, self);
3906 try bind.finalize(gpa, self);
38903907}
38913908
38923909fn collectExportData(self: *MachO, trie: *Trie) !void {
3893 const gpa = self.base.allocator;
3910 const gpa = self.base.comp.gpa;
38943911
38953912 // TODO handle macho.EXPORT_SYMBOL_FLAGS_REEXPORT and macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER.
38963913 log.debug("generating export trie", .{});
......@@ -3922,7 +3939,7 @@ fn writeDyldInfoData(self: *MachO) !void {
39223939 const tracy = trace(@src());
39233940 defer tracy.end();
39243941
3925 const gpa = self.base.allocator;
3942 const gpa = self.base.comp.gpa;
39263943
39273944 var rebase = Rebase{};
39283945 defer rebase.deinit(gpa);
......@@ -4046,7 +4063,7 @@ fn addSymbolToFunctionStarts(self: *MachO, sym_loc: SymbolWithLoc, addresses: *s
40464063}
40474064
40484065fn writeFunctionStarts(self: *MachO) !void {
4049 const gpa = self.base.allocator;
4066 const gpa = self.base.comp.gpa;
40504067 const seg = self.segments.items[self.header_segment_cmd_index.?];
40514068
40524069 // We need to sort by address first
......@@ -4133,7 +4150,7 @@ fn filterDataInCode(
41334150}
41344151
41354152pub fn writeDataInCode(self: *MachO) !void {
4136 const gpa = self.base.allocator;
4153 const gpa = self.base.comp.gpa;
41374154 var out_dice = std.ArrayList(macho.data_in_code_entry).init(gpa);
41384155 defer out_dice.deinit();
41394156
......@@ -4211,13 +4228,14 @@ fn addLocalToSymtab(self: *MachO, sym_loc: SymbolWithLoc, locals: *std.ArrayList
42114228 if (sym.n_desc == N_BOUNDARY) return; // boundary symbol, skip
42124229 if (sym.ext()) return; // an export lands in its own symtab section, skip
42134230 if (self.symbolIsTemp(sym_loc)) return; // local temp symbol, skip
4231 const gpa = self.base.comp.gpa;
42144232 var out_sym = sym;
4215 out_sym.n_strx = try self.strtab.insert(self.base.allocator, self.getSymbolName(sym_loc));
4233 out_sym.n_strx = try self.strtab.insert(gpa, self.getSymbolName(sym_loc));
42164234 try locals.append(out_sym);
42174235}
42184236
42194237fn writeSymtab(self: *MachO) !SymtabCtx {
4220 const gpa = self.base.allocator;
4238 const gpa = self.base.comp.gpa;
42214239
42224240 var locals = std.ArrayList(macho.nlist_64).init(gpa);
42234241 defer locals.deinit();
......@@ -4322,7 +4340,7 @@ fn generateSymbolStabs(
43224340) !void {
43234341 log.debug("generating stabs for '{s}'", .{object.name});
43244342
4325 const gpa = self.base.allocator;
4343 const gpa = self.base.comp.gpa;
43264344 var debug_info = object.parseDwarfInfo();
43274345
43284346 var lookup = DwarfInfo.AbbrevLookupTable.init(gpa);
......@@ -4450,7 +4468,7 @@ fn generateSymbolStabsForSymbol(
44504468 lookup: ?DwarfInfo.SubprogramLookupByName,
44514469 buf: *[4]macho.nlist_64,
44524470) ![]const macho.nlist_64 {
4453 const gpa = self.base.allocator;
4471 const gpa = self.base.comp.gpa;
44544472 const object = self.objects.items[sym_loc.getFile().?];
44554473 const sym = self.getSymbol(sym_loc);
44564474 const sym_name = self.getSymbolName(sym_loc);
......@@ -4536,7 +4554,7 @@ fn generateSymbolStabsForSymbol(
45364554}
45374555
45384556pub fn writeStrtab(self: *MachO) !void {
4539 const gpa = self.base.allocator;
4557 const gpa = self.base.comp.gpa;
45404558 const seg = self.getLinkeditSegmentPtr();
45414559 const offset = seg.fileoff + seg.filesize;
45424560 assert(mem.isAlignedGeneric(u64, offset, @alignOf(u64)));
......@@ -4565,7 +4583,7 @@ const SymtabCtx = struct {
45654583};
45664584
45674585pub fn writeDysymtab(self: *MachO, ctx: SymtabCtx) !void {
4568 const gpa = self.base.allocator;
4586 const gpa = self.base.comp.gpa;
45694587 const nstubs = @as(u32, @intCast(self.stub_table.lookup.count()));
45704588 const ngot_entries = @as(u32, @intCast(self.got_table.lookup.count()));
45714589 const nindirectsyms = nstubs * 2 + ngot_entries;
......@@ -4671,7 +4689,8 @@ pub fn writeCodeSignature(self: *MachO, comp: *const Compilation, code_sig: *Cod
46714689 const seg = self.segments.items[seg_id];
46724690 const offset = self.codesig_cmd.dataoff;
46734691
4674 var buffer = std.ArrayList(u8).init(self.base.allocator);
4692 const gpa = self.base.comp.gpa;
4693 var buffer = std.ArrayList(u8).init(gpa);
46754694 defer buffer.deinit();
46764695 try buffer.ensureTotalCapacityPrecise(code_sig.size());
46774696 try code_sig.writeAdhocSignature(comp, .{
......@@ -4817,7 +4836,7 @@ pub fn ptraceDetach(self: *MachO, pid: std.os.pid_t) !void {
48174836}
48184837
48194838pub fn addUndefined(self: *MachO, name: []const u8, flags: RelocFlags) !u32 {
4820 const gpa = self.base.allocator;
4839 const gpa = self.base.comp.gpa;
48214840
48224841 const gop = try self.getOrPutGlobalPtr(name);
48234842 const global_index = self.getGlobalIndex(name).?;
......@@ -4842,7 +4861,8 @@ pub fn addUndefined(self: *MachO, name: []const u8, flags: RelocFlags) !u32 {
48424861}
48434862
48444863fn updateRelocActions(self: *MachO, global_index: u32, flags: RelocFlags) !void {
4845 const act_gop = try self.actions.getOrPut(self.base.allocator, global_index);
4864 const gpa = self.base.comp.gpa;
4865 const act_gop = try self.actions.getOrPut(gpa, global_index);
48464866 if (!act_gop.found_existing) {
48474867 act_gop.value_ptr.* = .{};
48484868 }
......@@ -5022,7 +5042,7 @@ pub fn getOrPutGlobalPtr(self: *MachO, name: []const u8) !GetOrPutGlobalPtrResul
50225042 if (self.getGlobalPtr(name)) |ptr| {
50235043 return GetOrPutGlobalPtrResult{ .found_existing = true, .value_ptr = ptr };
50245044 }
5025 const gpa = self.base.allocator;
5045 const gpa = self.base.comp.gpa;
50265046 const global_index = try self.allocateGlobal();
50275047 const global_name = try gpa.dupe(u8, name);
50285048 _ = try self.resolver.put(gpa, global_name, global_index);
......@@ -5171,6 +5191,7 @@ pub fn handleAndReportParseError(
51715191 err: ParseError,
51725192 ctx: *const ParseErrorCtx,
51735193) error{OutOfMemory}!void {
5194 const gpa = self.base.comp.gpa;
51745195 const cpu_arch = self.base.options.target.cpu.arch;
51755196 switch (err) {
51765197 error.DylibAlreadyExists => {},
......@@ -5188,7 +5209,7 @@ pub fn handleAndReportParseError(
51885209 },
51895210 error.UnknownFileType => try self.reportParseError(path, "unknown file type", .{}),
51905211 error.InvalidTarget, error.InvalidTargetFatLibrary => {
5191 var targets_string = std.ArrayList(u8).init(self.base.allocator);
5212 var targets_string = std.ArrayList(u8).init(gpa);
51925213 defer targets_string.deinit();
51935214
51945215 if (ctx.detected_targets.items.len > 1) {
......@@ -5226,7 +5247,7 @@ fn reportMissingLibraryError(
52265247 comptime format: []const u8,
52275248 args: anytype,
52285249) error{OutOfMemory}!void {
5229 const gpa = self.base.allocator;
5250 const gpa = self.base.comp.gpa;
52305251 try self.misc_errors.ensureUnusedCapacity(gpa, 1);
52315252 const notes = try gpa.alloc(File.ErrorMsg, checked_paths.len);
52325253 errdefer gpa.free(notes);
......@@ -5246,7 +5267,7 @@ fn reportDependencyError(
52465267 comptime format: []const u8,
52475268 args: anytype,
52485269) error{OutOfMemory}!void {
5249 const gpa = self.base.allocator;
5270 const gpa = self.base.comp.gpa;
52505271 try self.misc_errors.ensureUnusedCapacity(gpa, 1);
52515272 var notes = try std.ArrayList(File.ErrorMsg).initCapacity(gpa, 2);
52525273 defer notes.deinit();
......@@ -5266,7 +5287,7 @@ pub fn reportParseError(
52665287 comptime format: []const u8,
52675288 args: anytype,
52685289) error{OutOfMemory}!void {
5269 const gpa = self.base.allocator;
5290 const gpa = self.base.comp.gpa;
52705291 try self.misc_errors.ensureUnusedCapacity(gpa, 1);
52715292 var notes = try gpa.alloc(File.ErrorMsg, 1);
52725293 errdefer gpa.free(notes);
......@@ -5283,7 +5304,7 @@ pub fn reportUnresolvedBoundarySymbol(
52835304 comptime format: []const u8,
52845305 args: anytype,
52855306) error{OutOfMemory}!void {
5286 const gpa = self.base.allocator;
5307 const gpa = self.base.comp.gpa;
52875308 try self.misc_errors.ensureUnusedCapacity(gpa, 1);
52885309 var notes = try gpa.alloc(File.ErrorMsg, 1);
52895310 errdefer gpa.free(notes);
......@@ -5295,7 +5316,7 @@ pub fn reportUnresolvedBoundarySymbol(
52955316}
52965317
52975318pub fn reportUndefined(self: *MachO) error{OutOfMemory}!void {
5298 const gpa = self.base.allocator;
5319 const gpa = self.base.comp.gpa;
52995320 const count = self.unresolved.count();
53005321 try self.misc_errors.ensureUnusedCapacity(gpa, count);
53015322
......@@ -5327,7 +5348,7 @@ fn reportSymbolCollision(
53275348 first: SymbolWithLoc,
53285349 other: SymbolWithLoc,
53295350) error{OutOfMemory}!void {
5330 const gpa = self.base.allocator;
5351 const gpa = self.base.comp.gpa;
53315352 try self.misc_errors.ensureUnusedCapacity(gpa, 1);
53325353
53335354 var notes = try std.ArrayList(File.ErrorMsg).initCapacity(gpa, 2);
......@@ -5355,7 +5376,7 @@ fn reportSymbolCollision(
53555376}
53565377
53575378fn reportUnhandledSymbolType(self: *MachO, sym_with_loc: SymbolWithLoc) error{OutOfMemory}!void {
5358 const gpa = self.base.allocator;
5379 const gpa = self.base.comp.gpa;
53595380 try self.misc_errors.ensureUnusedCapacity(gpa, 1);
53605381
53615382 const notes = try gpa.alloc(File.ErrorMsg, 1);
src/main.zig+1112-933
......@@ -269,8 +269,6 @@ pub fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
269269 }
270270 }
271271
272 defer log_scopes.deinit(gpa);
273
274272 const cmd = args[1];
275273 const cmd_args = args[2..];
276274 if (mem.eql(u8, cmd, "build-exe")) {
......@@ -321,7 +319,7 @@ pub fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
321319 } else if (mem.eql(u8, cmd, "init")) {
322320 return cmdInit(gpa, arena, cmd_args);
323321 } else if (mem.eql(u8, cmd, "targets")) {
324 const host = try std.zig.system.resolveTargetQuery(.{});
322 const host = resolveTargetQueryOrFatal(.{});
325323 const stdout = io.getStdOut().writer();
326324 return @import("print_targets.zig").cmdTargets(arena, cmd_args, stdout, host);
327325 } else if (mem.eql(u8, cmd, "version")) {
......@@ -404,37 +402,69 @@ const usage_build_generic =
404402 \\ --global-cache-dir [path] Override the global cache directory
405403 \\ --zig-lib-dir [path] Override path to Zig installation lib directory
406404 \\
407 \\Compile Options:
405 \\Global Compile Options:
406 \\ --name [name] Compilation unit name (not a file path)
407 \\ --libc [file] Provide a file which specifies libc paths
408 \\ -x language Treat subsequent input files as having type <language>
409 \\ --dep [[import=]name] Add an entry to the next module's import table
410 \\ --mod [name] [src] Create a module based on the current per-module settings.
411 \\ The first module is the main module.
412 \\ "std" can be configured by leaving src blank.
413 \\ After a --mod argument, per-module settings are reset.
414 \\ --error-limit [num] Set the maximum amount of distinct error values
415 \\ -fllvm Force using LLVM as the codegen backend
416 \\ -fno-llvm Prevent using LLVM as the codegen backend
417 \\ -flibllvm Force using the LLVM API in the codegen backend
418 \\ -fno-libllvm Prevent using the LLVM API in the codegen backend
419 \\ -fclang Force using Clang as the C/C++ compilation backend
420 \\ -fno-clang Prevent using Clang as the C/C++ compilation backend
421 \\ -fPIE Force-enable Position Independent Executable
422 \\ -fno-PIE Force-disable Position Independent Executable
423 \\ -flto Force-enable Link Time Optimization (requires LLVM extensions)
424 \\ -fno-lto Force-disable Link Time Optimization
425 \\ -fdll-export-fns Mark exported functions as DLL exports (Windows)
426 \\ -fno-dll-export-fns Force-disable marking exported functions as DLL exports
427 \\ -freference-trace[=num] Show num lines of reference trace per compile error
428 \\ -fno-reference-trace Disable reference trace
429 \\ -fbuiltin Enable implicit builtin knowledge of functions
430 \\ -fno-builtin Disable implicit builtin knowledge of functions
431 \\ -ffunction-sections Places each function in a separate section
432 \\ -fno-function-sections All functions go into same section
433 \\ -fdata-sections Places each data in a separate section
434 \\ -fno-data-sections All data go into same section
435 \\ -fformatted-panics Enable formatted safety panics
436 \\ -fno-formatted-panics Disable formatted safety panics
437 \\ -fstructured-cfg (SPIR-V) force SPIR-V kernels to use structured control flow
438 \\ -fno-structured-cfg (SPIR-V) force SPIR-V kernels to not use structured control flow
439 \\ -mexec-model=[value] (WASI) Execution model
440 \\
441 \\Per-Module Compile Options:
408442 \\ -target [name] <arch><sub>-<os>-<abi> see the targets command
443 \\ -O [mode] Choose what to optimize for
444 \\ Debug (default) Optimizations off, safety on
445 \\ ReleaseFast Optimize for performance, safety off
446 \\ ReleaseSafe Optimize for performance, safety on
447 \\ ReleaseSmall Optimize for small binary, safety off
448 \\ -ofmt=[fmt] Override target object format
449 \\ elf Executable and Linking Format
450 \\ c C source code
451 \\ wasm WebAssembly
452 \\ coff Common Object File Format (Windows)
453 \\ macho macOS relocatables
454 \\ spirv Standard, Portable Intermediate Representation V (SPIR-V)
455 \\ plan9 Plan 9 from Bell Labs object format
456 \\ hex (planned feature) Intel IHEX
457 \\ raw (planned feature) Dump machine code directly
409458 \\ -mcpu [cpu] Specify target CPU and feature set
410459 \\ -mcmodel=[default|tiny| Limit range of code and data virtual addresses
411460 \\ small|kernel|
412461 \\ medium|large]
413 \\ -x language Treat subsequent input files as having type <language>
414462 \\ -mred-zone Force-enable the "red-zone"
415463 \\ -mno-red-zone Force-disable the "red-zone"
416464 \\ -fomit-frame-pointer Omit the stack frame pointer
417465 \\ -fno-omit-frame-pointer Store the stack frame pointer
418 \\ -mexec-model=[value] (WASI) Execution model
419 \\ --name [name] Override root name (not a file path)
420 \\ -O [mode] Choose what to optimize for
421 \\ Debug (default) Optimizations off, safety on
422 \\ ReleaseFast Optimize for performance, safety off
423 \\ ReleaseSafe Optimize for performance, safety on
424 \\ ReleaseSmall Optimize for small binary, safety off
425 \\ --mod [name]:[deps]:[src] Make a module available for dependency under the given name
426 \\ deps: [dep],[dep],...
427 \\ dep: [[import=]name]
428 \\ --deps [dep],[dep],... Set dependency names for the root package
429 \\ dep: [[import=]name]
430 \\ --main-mod-path Set the directory of the root module
431 \\ --error-limit [num] Set the maximum amount of distinct error values
432466 \\ -fPIC Force-enable Position Independent Code
433467 \\ -fno-PIC Force-disable Position Independent Code
434 \\ -fPIE Force-enable Position Independent Executable
435 \\ -fno-PIE Force-disable Position Independent Executable
436 \\ -flto Force-enable Link Time Optimization (requires LLVM extensions)
437 \\ -fno-lto Force-disable Link Time Optimization
438468 \\ -fstack-check Enable stack probing in unsafe builds
439469 \\ -fno-stack-check Disable stack probing in safe builds
440470 \\ -fstack-protector Enable stack protection in unsafe builds
......@@ -445,47 +475,18 @@ const usage_build_generic =
445475 \\ -fno-valgrind Omit valgrind client requests in debug builds
446476 \\ -fsanitize-thread Enable Thread Sanitizer
447477 \\ -fno-sanitize-thread Disable Thread Sanitizer
448 \\ -fdll-export-fns Mark exported functions as DLL exports (Windows)
449 \\ -fno-dll-export-fns Force-disable marking exported functions as DLL exports
450478 \\ -funwind-tables Always produce unwind table entries for all functions
451479 \\ -fno-unwind-tables Never produce unwind table entries
452 \\ -fllvm Force using LLVM as the codegen backend
453 \\ -fno-llvm Prevent using LLVM as the codegen backend
454 \\ -flibllvm Force using the LLVM API in the codegen backend
455 \\ -fno-libllvm Prevent using the LLVM API in the codegen backend
456 \\ -fclang Force using Clang as the C/C++ compilation backend
457 \\ -fno-clang Prevent using Clang as the C/C++ compilation backend
458 \\ -freference-trace[=num] How many lines of reference trace should be shown per compile error
459 \\ -fno-reference-trace Disable reference trace
460480 \\ -ferror-tracing Enable error tracing in ReleaseFast mode
461481 \\ -fno-error-tracing Disable error tracing in Debug and ReleaseSafe mode
462482 \\ -fsingle-threaded Code assumes there is only one thread
463483 \\ -fno-single-threaded Code may not assume there is only one thread
464 \\ -fbuiltin Enable implicit builtin knowledge of functions
465 \\ -fno-builtin Disable implicit builtin knowledge of functions
466 \\ -ffunction-sections Places each function in a separate section
467 \\ -fno-function-sections All functions go into same section
468 \\ -fdata-sections Places each data in a separate section
469 \\ -fno-data-sections All data go into same section
470484 \\ -fstrip Omit debug symbols
471485 \\ -fno-strip Keep debug symbols
472 \\ -fformatted-panics Enable formatted safety panics
473 \\ -fno-formatted-panics Disable formatted safety panics
474 \\ -ofmt=[mode] Override target object format
475 \\ elf Executable and Linking Format
476 \\ c C source code
477 \\ wasm WebAssembly
478 \\ coff Common Object File Format (Windows)
479 \\ macho macOS relocatables
480 \\ spirv Standard, Portable Intermediate Representation V (SPIR-V)
481 \\ plan9 Plan 9 from Bell Labs object format
482 \\ hex (planned feature) Intel IHEX
483 \\ raw (planned feature) Dump machine code directly
484486 \\ -idirafter [dir] Add directory to AFTER include search path
485487 \\ -isystem [dir] Add directory to SYSTEM include search path
486488 \\ -I[dir] Add directory to include search path
487489 \\ -D[macro]=[value] Define C [macro] to [value] (1 if [value] omitted)
488 \\ --libc [file] Provide a file which specifies libc paths
489490 \\ -cflags [flags] -- Set extra flags for the next positional C source files
490491 \\ -rcflags [flags] -- Set extra flags for the next positional .rc source files
491492 \\ -rcincludes=[type] Set the type of includes to use when compiling .rc source files
......@@ -493,26 +494,8 @@ const usage_build_generic =
493494 \\ msvc Use msvc include paths (must be present on the system)
494495 \\ gnu Use mingw include paths (distributed with Zig)
495496 \\ none Do not use any autodetected include paths
496 \\ -fstructured-cfg (SPIR-V) force SPIR-V kernels to use structured control flow
497 \\ -fno-structured-cfg (SPIR-V) force SPIR-V kernels to not use structured control flow
498497 \\
499 \\Link Options:
500 \\ -l[lib], --library [lib] Link against system library (only if actually used)
501 \\ -needed-l[lib], Link against system library (even if unused)
502 \\ --needed-library [lib]
503 \\ -weak-l[lib] link against system library marking it and all
504 \\ -weak_library [lib] referenced symbols as weak
505 \\ -L[d], --library-directory [d] Add a directory to the library search path
506 \\ -search_paths_first For each library search path, check for dynamic
507 \\ lib then static lib before proceeding to next path.
508 \\ -search_paths_first_static For each library search path, check for static
509 \\ lib then dynamic lib before proceeding to next path.
510 \\ -search_dylibs_first Search for dynamic libs in all library search
511 \\ paths, then static libs.
512 \\ -search_static_first Search for static libs in all library search
513 \\ paths, then dynamic libs.
514 \\ -search_dylibs_only Only search for dynamic libs.
515 \\ -search_static_only Only search for static libs.
498 \\Global Link Options:
516499 \\ -T[script], --script [script] Use a custom linker script
517500 \\ --version-script [path] Provide a version .map file
518501 \\ --dynamic-linker [path] Set the dynamic interpreter path (usually ld.so)
......@@ -529,7 +512,6 @@ const usage_build_generic =
529512 \\ -fcompiler-rt Always include compiler-rt symbols in output
530513 \\ -fno-compiler-rt Prevent including compiler-rt symbols in output
531514 \\ -rdynamic Add all symbols to the dynamic symbol table
532 \\ -rpath [path] Add directory to the runtime library search path
533515 \\ -feach-lib-rpath Ensure adding rpath for each used dynamic library
534516 \\ -fno-each-lib-rpath Prevent adding rpath for each used dynamic library
535517 \\ -fallow-shlib-undefined Allows undefined symbols in shared libraries
......@@ -566,11 +548,6 @@ const usage_build_generic =
566548 \\ --subsystem [subsystem] (Windows) /SUBSYSTEM:<subsystem> to the linker
567549 \\ --stack [size] Override default stack size
568550 \\ --image-base [addr] Set base address for executable image
569 \\ -framework [name] (Darwin) link against framework
570 \\ -needed_framework [name] (Darwin) link against framework (even if unused)
571 \\ -needed_library [lib] link against system library (even if unused)
572 \\ -weak_framework [name] (Darwin) link against framework and mark it and all referenced symbols as weak
573 \\ -F[dir] (Darwin) add search path for frameworks
574551 \\ -install_name=[value] (Darwin) add dylib's install name
575552 \\ --entitlements [path] (Darwin) add path to entitlements file for embedding in code signature
576553 \\ -pagezero_size [value] (Darwin) size of the __PAGEZERO segment in hexadecimal notation
......@@ -587,6 +564,30 @@ const usage_build_generic =
587564 \\ --max-memory=[bytes] (WebAssembly) maximum size of the linear memory
588565 \\ --shared-memory (WebAssembly) use shared linear memory
589566 \\ --global-base=[addr] (WebAssembly) where to start to place global data
567 \\
568 \\Per-Module Link Options:
569 \\ -l[lib], --library [lib] Link against system library (only if actually used)
570 \\ -needed-l[lib], Link against system library (even if unused)
571 \\ --needed-library [lib]
572 \\ -weak-l[lib] link against system library marking it and all
573 \\ -weak_library [lib] referenced symbols as weak
574 \\ -L[d], --library-directory [d] Add a directory to the library search path
575 \\ -search_paths_first For each library search path, check for dynamic
576 \\ lib then static lib before proceeding to next path.
577 \\ -search_paths_first_static For each library search path, check for static
578 \\ lib then dynamic lib before proceeding to next path.
579 \\ -search_dylibs_first Search for dynamic libs in all library search
580 \\ paths, then static libs.
581 \\ -search_static_first Search for static libs in all library search
582 \\ paths, then dynamic libs.
583 \\ -search_dylibs_only Only search for dynamic libs.
584 \\ -search_static_only Only search for static libs.
585 \\ -rpath [path] Add directory to the runtime library search path
586 \\ -framework [name] (Darwin) link against framework
587 \\ -needed_framework [name] (Darwin) link against framework (even if unused)
588 \\ -needed_library [lib] link against system library (even if unused)
589 \\ -weak_framework [name] (Darwin) link against framework and mark it and all referenced symbols as weak
590 \\ -F[dir] (Darwin) add search path for frameworks
590591 \\ --export=[value] (WebAssembly) Force a symbol to be exported
591592 \\
592593 \\Test Options:
......@@ -758,9 +759,24 @@ const Framework = struct {
758759};
759760
760761const CliModule = struct {
761 mod: *Package.Module,
762 /// still in CLI arg format
763 deps_str: []const u8,
762 paths: Package.Module.CreateOptions.Paths,
763 cc_argv: []const []const u8,
764 inherited: Package.Module.CreateOptions.Inherited,
765 target_arch_os_abi: ?[]const u8,
766 target_mcpu: ?[]const u8,
767
768 deps: []const Dep,
769 resolved: ?*Package.Module,
770
771 c_source_files_start: usize,
772 c_source_files_end: usize,
773 rc_source_files_start: usize,
774 rc_source_files_end: usize,
775
776 pub const Dep = struct {
777 key: []const u8,
778 value: []const u8,
779 };
764780};
765781
766782fn buildOutputType(
......@@ -769,17 +785,12 @@ fn buildOutputType(
769785 all_args: []const []const u8,
770786 arg_mode: ArgMode,
771787) !void {
772 var color: Color = .auto;
773 var optimize_mode: std.builtin.OptimizeMode = .Debug;
774788 var provided_name: ?[]const u8 = null;
775 var link_mode: ?std.builtin.LinkMode = null;
776789 var dll_export_fns: ?bool = null;
777 var single_threaded: ?bool = null;
778790 var root_src_file: ?[]const u8 = null;
779791 var version: std.SemanticVersion = .{ .major = 0, .minor = 0, .patch = 0 };
780792 var have_version = false;
781793 var compatibility_version: ?std.SemanticVersion = null;
782 var strip: ?bool = null;
783794 var formatted_panics: ?bool = null;
784795 var function_sections = false;
785796 var data_sections = false;
......@@ -807,30 +818,11 @@ fn buildOutputType(
807818 var emit_docs: Emit = .no;
808819 var emit_implib: Emit = .yes_default_path;
809820 var emit_implib_arg_provided = false;
810 var target_arch_os_abi: []const u8 = "native";
821 var target_arch_os_abi: ?[]const u8 = null;
811822 var target_mcpu: ?[]const u8 = null;
812 var target_dynamic_linker: ?[]const u8 = null;
813 var target_ofmt: ?[]const u8 = null;
814 var output_mode: std.builtin.OutputMode = undefined;
815823 var emit_h: Emit = .no;
816824 var soname: SOName = undefined;
817 var ensure_libc_on_non_freestanding = false;
818 var ensure_libcpp_on_non_freestanding = false;
819 var link_libc = false;
820 var link_libcpp = false;
821 var link_libunwind = false;
822825 var want_native_include_dirs = false;
823 var want_pic: ?bool = null;
824 var want_pie: ?bool = null;
825 var want_lto: ?bool = null;
826 var want_unwind_tables: ?bool = null;
827 var want_sanitize_c: ?bool = null;
828 var want_stack_check: ?bool = null;
829 var want_stack_protector: ?u32 = null;
830 var want_red_zone: ?bool = null;
831 var omit_frame_pointer: ?bool = null;
832 var want_valgrind: ?bool = null;
833 var want_tsan: ?bool = null;
834826 var want_compiler_rt: ?bool = null;
835827 var rdynamic: bool = false;
836828 var linker_script: ?[]const u8 = null;
......@@ -841,15 +833,11 @@ fn buildOutputType(
841833 var linker_compress_debug_sections: ?link.CompressDebugSections = null;
842834 var linker_allow_shlib_undefined: ?bool = null;
843835 var linker_bind_global_refs_locally: ?bool = null;
844 var linker_import_memory: ?bool = null;
845 var linker_export_memory: ?bool = null;
846836 var linker_import_symbols: bool = false;
847837 var linker_import_table: bool = false;
848838 var linker_export_table: bool = false;
849 var linker_force_entry: ?bool = null;
850839 var linker_initial_memory: ?u64 = null;
851840 var linker_max_memory: ?u64 = null;
852 var linker_shared_memory: bool = false;
853841 var linker_global_base: ?u64 = null;
854842 var linker_print_gc_sections: bool = false;
855843 var linker_print_icf_sections: bool = false;
......@@ -869,23 +857,16 @@ fn buildOutputType(
869857 var linker_dynamicbase = true;
870858 var linker_optimization: ?u8 = null;
871859 var linker_module_definition_file: ?[]const u8 = null;
872 var test_evented_io = false;
873860 var test_no_exec = false;
874 var entry: ?[]const u8 = null;
875861 var force_undefined_symbols: std.StringArrayHashMapUnmanaged(void) = .{};
876862 var stack_size_override: ?u64 = null;
877863 var image_base_override: ?u64 = null;
878 var use_llvm: ?bool = null;
879 var use_lib_llvm: ?bool = null;
880 var use_lld: ?bool = null;
881 var use_clang: ?bool = null;
882864 var link_eh_frame_hdr = false;
883865 var link_emit_relocs = false;
884866 var each_lib_rpath: ?bool = null;
885867 var build_id: ?std.zig.BuildId = null;
886868 var sysroot: ?[]const u8 = null;
887869 var libc_paths_file: ?[]const u8 = try EnvVar.ZIG_LIBC.get(arena);
888 var machine_code_model: std.builtin.CodeModel = .default;
889870 var runtime_args_start: ?usize = null;
890871 var test_filter: ?[]const u8 = null;
891872 var test_name_prefix: ?[]const u8 = null;
......@@ -893,12 +874,10 @@ fn buildOutputType(
893874 var override_local_cache_dir: ?[]const u8 = try EnvVar.ZIG_LOCAL_CACHE_DIR.get(arena);
894875 var override_global_cache_dir: ?[]const u8 = try EnvVar.ZIG_GLOBAL_CACHE_DIR.get(arena);
895876 var override_lib_dir: ?[]const u8 = try EnvVar.ZIG_LIB_DIR.get(arena);
896 var main_mod_path: ?[]const u8 = null;
897877 var clang_preprocessor_mode: Compilation.ClangPreprocessorMode = .no;
898878 var subsystem: ?std.Target.SubSystem = null;
899879 var major_subsystem_version: ?u32 = null;
900880 var minor_subsystem_version: ?u32 = null;
901 var wasi_exec_model: ?std.builtin.WasiExecModel = null;
902881 var enable_link_snapshots: bool = false;
903882 var debug_incremental: bool = false;
904883 var install_name: ?[]const u8 = null;
......@@ -910,63 +889,100 @@ fn buildOutputType(
910889 var headerpad_size: ?u32 = null;
911890 var headerpad_max_install_names: bool = false;
912891 var dead_strip_dylibs: bool = false;
892 var contains_res_file: bool = false;
913893 var reference_trace: ?u32 = null;
914 var error_tracing: ?bool = null;
915894 var pdb_out_path: ?[]const u8 = null;
916895 var dwarf_format: ?std.dwarf.Format = null;
917896 var error_limit: ?Module.ErrorInt = null;
918897 var want_structured_cfg: ?bool = null;
919 // e.g. -m3dnow or -mno-outline-atomics. They correspond to std.Target llvm cpu feature names.
920 // This array is populated by zig cc frontend and then has to be converted to zig-style
921 // CPU features.
922 var llvm_m_args = std.ArrayList([]const u8).init(arena);
923 var system_libs = std.StringArrayHashMap(SystemLib).init(arena);
924 var wasi_emulated_libs = std.ArrayList(wasi_libc.CRTFile).init(arena);
925 var clang_argv = std.ArrayList([]const u8).init(arena);
926 var extra_cflags = std.ArrayList([]const u8).init(arena);
927 var extra_rcflags = std.ArrayList([]const u8).init(arena);
928898 // These are before resolving sysroot.
929 var lib_dir_args = std.ArrayList([]const u8).init(arena);
930 var rpath_list = std.ArrayList([]const u8).init(arena);
899 var lib_dir_args: std.ArrayListUnmanaged([]const u8) = .{};
900 var extra_cflags: std.ArrayListUnmanaged([]const u8) = .{};
901 var extra_rcflags: std.ArrayListUnmanaged([]const u8) = .{};
931902 var symbol_wrap_set: std.StringArrayHashMapUnmanaged(void) = .{};
932 var c_source_files = std.ArrayList(Compilation.CSourceFile).init(arena);
933 var rc_source_files = std.ArrayList(Compilation.RcSourceFile).init(arena);
903 var rpath_list: std.ArrayListUnmanaged([]const u8) = .{};
934904 var rc_includes: Compilation.RcIncludes = .any;
935 var res_files = std.ArrayList(Compilation.LinkObject).init(arena);
936905 var manifest_file: ?[]const u8 = null;
937 var link_objects = std.ArrayList(Compilation.LinkObject).init(arena);
938 var framework_dirs = std.ArrayList([]const u8).init(arena);
906 var link_objects: std.ArrayListUnmanaged(Compilation.LinkObject) = .{};
907 var framework_dirs: std.ArrayListUnmanaged([]const u8) = .{};
939908 var frameworks: std.StringArrayHashMapUnmanaged(Framework) = .{};
909 var linker_export_symbol_names: std.ArrayListUnmanaged([]const u8) = .{};
910
911 // Tracks the position in c_source_files which have already their owner populated.
912 var c_source_files_owner_index: usize = 0;
913 // Tracks the position in rc_source_files which have already their owner populated.
914 var rc_source_files_owner_index: usize = 0;
915
940916 // null means replace with the test executable binary
941917 var test_exec_args = std.ArrayList(?[]const u8).init(arena);
942 var linker_export_symbol_names = std.ArrayList([]const u8).init(arena);
918
919 // These get set by CLI flags and then snapshotted when a `--mod` flag is
920 // encountered.
921 var mod_opts: Package.Module.CreateOptions.Inherited = .{};
922
923 // These get appended to by CLI flags and then slurped when a `--mod` flag
924 // is encountered.
925 var cssan: ClangSearchSanitizer = .{};
926 var clang_argv: std.ArrayListUnmanaged([]const u8) = .{};
927 var deps: std.ArrayListUnmanaged(CliModule.Dep) = .{};
928
943929 // Contains every module specified via --mod. The dependencies are added
944930 // after argument parsing is completed. We use a StringArrayHashMap to make
945 // error output consistent.
946 var modules = std.StringArrayHashMap(CliModule).init(arena);
931 // error output consistent. "root" is special.
932 var create_module: CreateModule = .{
933 // Populated just before the call to `createModule`.
934 .global_cache_directory = undefined,
935 .object_format = null,
936 .dynamic_linker = null,
937 .modules = .{},
938 .opts = .{
939 .is_test = arg_mode == .zig_test,
940 // Populated while parsing CLI args.
941 .output_mode = undefined,
942 // Populated in the call to `createModule` for the root module.
943 .resolved_target = undefined,
944 .have_zcu = false,
945 // Populated just before the call to `createModule`.
946 .emit_llvm_ir = undefined,
947 // Populated just before the call to `createModule`.
948 .emit_llvm_bc = undefined,
949 // Populated just before the call to `createModule`.
950 .emit_bin = undefined,
951 // Populated just before the call to `createModule`.
952 .c_source_files_len = undefined,
953 },
954 // Populated in the call to `createModule` for the root module.
955 .resolved_options = undefined,
947956
948 // The dependency string for the root package
949 var root_deps_str: ?[]const u8 = null;
957 .system_libs = .{},
958 .external_system_libs = .{},
959 .resolved_system_libs = .{},
960 .wasi_emulated_libs = .{},
961
962 .c_source_files = .{},
963 .rc_source_files = .{},
964
965 .llvm_m_args = .{},
966 };
950967
951968 // before arg parsing, check for the NO_COLOR environment variable
952969 // if it exists, default the color setting to .off
953970 // explicit --color arguments will still override this setting.
954971 // Disable color on WASI per https://github.com/WebAssembly/WASI/issues/162
955 color = if (builtin.os.tag == .wasi or EnvVar.NO_COLOR.isSet()) .off else .auto;
972 var color: Color = if (builtin.os.tag == .wasi or EnvVar.NO_COLOR.isSet()) .off else .auto;
956973
957974 switch (arg_mode) {
958975 .build, .translate_c, .zig_test, .run => {
959 var optimize_mode_string: ?[]const u8 = null;
960976 switch (arg_mode) {
961977 .build => |m| {
962 output_mode = m;
978 create_module.opts.output_mode = m;
963979 },
964980 .translate_c => {
965981 emit_bin = .no;
966 output_mode = .Obj;
982 create_module.opts.output_mode = .Obj;
967983 },
968984 .zig_test, .run => {
969 output_mode = .Exe;
985 create_module.opts.output_mode = .Exe;
970986 },
971987 else => unreachable,
972988 }
......@@ -977,9 +993,6 @@ fn buildOutputType(
977993 .args = all_args[2..],
978994 };
979995
980 var cssan = ClangSearchSanitizer.init(gpa, &clang_argv);
981 defer cssan.map.deinit();
982
983996 var file_ext: ?Compilation.FileExt = null;
984997 args_loop: while (args_iter.next()) |arg| {
985998 if (mem.startsWith(u8, arg, "@")) {
......@@ -1002,49 +1015,73 @@ fn buildOutputType(
10021015 } else {
10031016 fatal("unexpected end-of-parameter mark: --", .{});
10041017 }
1005 } else if (mem.eql(u8, arg, "--mod")) {
1006 const info = args_iter.nextOrFatal();
1007 var info_it = mem.splitScalar(u8, info, ':');
1008 const mod_name = info_it.next() orelse fatal("expected non-empty argument after {s}", .{arg});
1009 const deps_str = info_it.next() orelse fatal("expected 'name:deps:path' after {s}", .{arg});
1010 const root_src_orig = info_it.rest();
1011 if (root_src_orig.len == 0) fatal("expected 'name:deps:path' after {s}", .{arg});
1012 if (mod_name.len == 0) fatal("empty name for module at '{s}'", .{root_src_orig});
1013
1014 const root_src = try introspect.resolvePath(arena, root_src_orig);
1015
1016 for ([_][]const u8{ "std", "root", "builtin" }) |name| {
1017 if (mem.eql(u8, mod_name, name)) {
1018 fatal("unable to add module '{s}' -> '{s}': conflicts with builtin module", .{
1019 mod_name, root_src,
1018 } else if (mem.eql(u8, arg, "--dep")) {
1019 var it = mem.splitScalar(u8, args_iter.nextOrFatal(), '=');
1020 const key = it.next().?;
1021 const value = it.next() orelse key;
1022 if (mem.eql(u8, key, "std") and !mem.eql(u8, value, "std")) {
1023 fatal("unable to import as '{s}': conflicts with builtin module", .{
1024 key,
1025 });
1026 }
1027 for ([_][]const u8{ "root", "builtin" }) |name| {
1028 if (mem.eql(u8, key, name)) {
1029 fatal("unable to import as '{s}': conflicts with builtin module", .{
1030 key,
10201031 });
10211032 }
10221033 }
1034 try deps.append(arena, .{
1035 .key = key,
1036 .value = value,
1037 });
1038 } else if (mem.eql(u8, arg, "--mod")) {
1039 const mod_name = args_iter.nextOrFatal();
1040 const root_src_orig = args_iter.nextOrFatal();
10231041
1024 if (modules.get(mod_name)) |value| {
1025 fatal("unable to add module '{s}' -> '{s}': already exists as '{s}'", .{
1026 mod_name, root_src, value.mod.root_src_path,
1042 const gop = try create_module.modules.getOrPut(arena, mod_name);
1043
1044 if (gop.found_existing) {
1045 fatal("unable to add module '{s}': already exists as '{s}'", .{
1046 mod_name, gop.value_ptr.paths.root_src_path,
10271047 });
10281048 }
10291049
1030 try modules.put(mod_name, .{
1031 .mod = try Package.Module.create(arena, .{
1050 // See duplicate logic: ModCreationGlobalFlags
1051 create_module.opts.have_zcu = true;
1052 if (mod_opts.single_threaded == false)
1053 create_module.opts.any_non_single_threaded = true;
1054 if (mod_opts.sanitize_thread == true)
1055 create_module.opts.any_sanitize_thread = true;
1056 if (mod_opts.unwind_tables == true)
1057 create_module.opts.any_unwind_tables = true;
1058
1059 const root_src = try introspect.resolvePath(arena, root_src_orig);
1060 try create_module.modules.put(arena, mod_name, .{
1061 .paths = .{
10321062 .root = .{
10331063 .root_dir = Cache.Directory.cwd(),
10341064 .sub_path = fs.path.dirname(root_src) orelse "",
10351065 },
10361066 .root_src_path = fs.path.basename(root_src),
1037 .fully_qualified_name = mod_name,
1038 }),
1039 .deps_str = deps_str,
1067 },
1068 .cc_argv = try clang_argv.toOwnedSlice(arena),
1069 .inherited = mod_opts,
1070 .target_arch_os_abi = target_arch_os_abi,
1071 .target_mcpu = target_mcpu,
1072 .deps = try deps.toOwnedSlice(arena),
1073 .resolved = null,
1074 .c_source_files_start = c_source_files_owner_index,
1075 .c_source_files_end = create_module.c_source_files.items.len,
1076 .rc_source_files_start = rc_source_files_owner_index,
1077 .rc_source_files_end = create_module.rc_source_files.items.len,
10401078 });
1041 } else if (mem.eql(u8, arg, "--deps")) {
1042 if (root_deps_str != null) {
1043 fatal("only one --deps argument is allowed", .{});
1044 }
1045 root_deps_str = args_iter.nextOrFatal();
1046 } else if (mem.eql(u8, arg, "--main-mod-path")) {
1047 main_mod_path = args_iter.nextOrFatal();
1079 cssan.reset();
1080 mod_opts = .{};
1081 target_arch_os_abi = null;
1082 target_mcpu = null;
1083 c_source_files_owner_index = create_module.c_source_files.items.len;
1084 rc_source_files_owner_index = create_module.rc_source_files.items.len;
10481085 } else if (mem.eql(u8, arg, "--error-limit")) {
10491086 const next_arg = args_iter.nextOrFatal();
10501087 error_limit = std.fmt.parseUnsigned(Module.ErrorInt, next_arg, 0) catch |err| {
......@@ -1057,7 +1094,7 @@ fn buildOutputType(
10571094 fatal("expected -- after -cflags", .{});
10581095 };
10591096 if (mem.eql(u8, next_arg, "--")) break;
1060 try extra_cflags.append(next_arg);
1097 try extra_cflags.append(arena, next_arg);
10611098 }
10621099 } else if (mem.eql(u8, arg, "-rcincludes")) {
10631100 rc_includes = parseRcIncludes(args_iter.nextOrFatal());
......@@ -1070,7 +1107,7 @@ fn buildOutputType(
10701107 fatal("expected -- after -rcflags", .{});
10711108 };
10721109 if (mem.eql(u8, next_arg, "--")) break;
1073 try extra_rcflags.append(next_arg);
1110 try extra_rcflags.append(arena, next_arg);
10741111 }
10751112 } else if (mem.startsWith(u8, arg, "-fstructured-cfg")) {
10761113 want_structured_cfg = true;
......@@ -1086,11 +1123,11 @@ fn buildOutputType(
10861123 } else if (mem.eql(u8, arg, "--subsystem")) {
10871124 subsystem = try parseSubSystem(args_iter.nextOrFatal());
10881125 } else if (mem.eql(u8, arg, "-O")) {
1089 optimize_mode_string = args_iter.nextOrFatal();
1126 mod_opts.optimize_mode = parseOptimizeMode(args_iter.nextOrFatal());
10901127 } else if (mem.startsWith(u8, arg, "-fentry=")) {
1091 entry = arg["-fentry=".len..];
1128 create_module.opts.entry = .{ .named = arg["-fentry=".len..] };
10921129 } else if (mem.eql(u8, arg, "--force_undefined")) {
1093 try force_undefined_symbols.put(gpa, args_iter.nextOrFatal(), {});
1130 try force_undefined_symbols.put(arena, args_iter.nextOrFatal(), {});
10941131 } else if (mem.eql(u8, arg, "--stack")) {
10951132 const next_arg = args_iter.nextOrFatal();
10961133 stack_size_override = std.fmt.parseUnsigned(u64, next_arg, 0) catch |err| {
......@@ -1106,17 +1143,17 @@ fn buildOutputType(
11061143 if (!mem.eql(u8, provided_name.?, fs.path.basename(provided_name.?)))
11071144 fatal("invalid package name '{s}': cannot contain folder separators", .{provided_name.?});
11081145 } else if (mem.eql(u8, arg, "-rpath")) {
1109 try rpath_list.append(args_iter.nextOrFatal());
1146 try rpath_list.append(arena, args_iter.nextOrFatal());
11101147 } else if (mem.eql(u8, arg, "--library-directory") or mem.eql(u8, arg, "-L")) {
1111 try lib_dir_args.append(args_iter.nextOrFatal());
1148 try lib_dir_args.append(arena, args_iter.nextOrFatal());
11121149 } else if (mem.eql(u8, arg, "-F")) {
1113 try framework_dirs.append(args_iter.nextOrFatal());
1150 try framework_dirs.append(arena, args_iter.nextOrFatal());
11141151 } else if (mem.eql(u8, arg, "-framework")) {
1115 try frameworks.put(gpa, args_iter.nextOrFatal(), .{});
1152 try frameworks.put(arena, args_iter.nextOrFatal(), .{});
11161153 } else if (mem.eql(u8, arg, "-weak_framework")) {
1117 try frameworks.put(gpa, args_iter.nextOrFatal(), .{ .weak = true });
1154 try frameworks.put(arena, args_iter.nextOrFatal(), .{ .weak = true });
11181155 } else if (mem.eql(u8, arg, "-needed_framework")) {
1119 try frameworks.put(gpa, args_iter.nextOrFatal(), .{ .needed = true });
1156 try frameworks.put(arena, args_iter.nextOrFatal(), .{ .needed = true });
11201157 } else if (mem.eql(u8, arg, "-install_name")) {
11211158 install_name = args_iter.nextOrFatal();
11221159 } else if (mem.startsWith(u8, arg, "--compress-debug-sections=")) {
......@@ -1168,7 +1205,7 @@ fn buildOutputType(
11681205 // We don't know whether this library is part of libc
11691206 // or libc++ until we resolve the target, so we append
11701207 // to the list for now.
1171 try system_libs.put(args_iter.nextOrFatal(), .{
1208 try create_module.system_libs.put(arena, args_iter.nextOrFatal(), .{
11721209 .needed = false,
11731210 .weak = false,
11741211 .preferred_mode = lib_preferred_mode,
......@@ -1179,38 +1216,37 @@ fn buildOutputType(
11791216 mem.eql(u8, arg, "-needed_library"))
11801217 {
11811218 const next_arg = args_iter.nextOrFatal();
1182 try system_libs.put(next_arg, .{
1219 try create_module.system_libs.put(arena, next_arg, .{
11831220 .needed = true,
11841221 .weak = false,
11851222 .preferred_mode = lib_preferred_mode,
11861223 .search_strategy = lib_search_strategy,
11871224 });
11881225 } else if (mem.eql(u8, arg, "-weak_library") or mem.eql(u8, arg, "-weak-l")) {
1189 try system_libs.put(args_iter.nextOrFatal(), .{
1226 try create_module.system_libs.put(arena, args_iter.nextOrFatal(), .{
11901227 .needed = false,
11911228 .weak = true,
11921229 .preferred_mode = lib_preferred_mode,
11931230 .search_strategy = lib_search_strategy,
11941231 });
11951232 } else if (mem.eql(u8, arg, "-D")) {
1196 try clang_argv.append(arg);
1197 try clang_argv.append(args_iter.nextOrFatal());
1233 try clang_argv.appendSlice(arena, &.{ arg, args_iter.nextOrFatal() });
11981234 } else if (mem.eql(u8, arg, "-I")) {
1199 try cssan.addIncludePath(.I, arg, args_iter.nextOrFatal(), false);
1235 try cssan.addIncludePath(arena, &clang_argv, .I, arg, args_iter.nextOrFatal(), false);
12001236 } else if (mem.eql(u8, arg, "-isystem")) {
1201 try cssan.addIncludePath(.isystem, arg, args_iter.nextOrFatal(), false);
1237 try cssan.addIncludePath(arena, &clang_argv, .isystem, arg, args_iter.nextOrFatal(), false);
12021238 } else if (mem.eql(u8, arg, "-iwithsysroot")) {
1203 try cssan.addIncludePath(.iwithsysroot, arg, args_iter.nextOrFatal(), false);
1239 try cssan.addIncludePath(arena, &clang_argv, .iwithsysroot, arg, args_iter.nextOrFatal(), false);
12041240 } else if (mem.eql(u8, arg, "-idirafter")) {
1205 try cssan.addIncludePath(.idirafter, arg, args_iter.nextOrFatal(), false);
1241 try cssan.addIncludePath(arena, &clang_argv, .idirafter, arg, args_iter.nextOrFatal(), false);
12061242 } else if (mem.eql(u8, arg, "-iframework")) {
12071243 const path = args_iter.nextOrFatal();
1208 try cssan.addIncludePath(.iframework, arg, path, false);
1209 try framework_dirs.append(path); // Forward to the backend as -F
1244 try cssan.addIncludePath(arena, &clang_argv, .iframework, arg, path, false);
1245 try framework_dirs.append(arena, path); // Forward to the backend as -F
12101246 } else if (mem.eql(u8, arg, "-iframeworkwithsysroot")) {
12111247 const path = args_iter.nextOrFatal();
1212 try cssan.addIncludePath(.iframeworkwithsysroot, arg, path, false);
1213 try framework_dirs.append(path); // Forward to the backend as -F
1248 try cssan.addIncludePath(arena, &clang_argv, .iframeworkwithsysroot, arg, path, false);
1249 try framework_dirs.append(arena, path); // Forward to the backend as -F
12141250 } else if (mem.eql(u8, arg, "--version")) {
12151251 const next_arg = args_iter.nextOrFatal();
12161252 version = std.SemanticVersion.parse(next_arg) catch |err| {
......@@ -1222,21 +1258,21 @@ fn buildOutputType(
12221258 } else if (mem.eql(u8, arg, "-mcpu")) {
12231259 target_mcpu = args_iter.nextOrFatal();
12241260 } else if (mem.eql(u8, arg, "-mcmodel")) {
1225 machine_code_model = parseCodeModel(args_iter.nextOrFatal());
1261 mod_opts.code_model = parseCodeModel(args_iter.nextOrFatal());
1262 } else if (mem.startsWith(u8, arg, "-mcmodel=")) {
1263 mod_opts.code_model = parseCodeModel(arg["-mcmodel=".len..]);
12261264 } else if (mem.startsWith(u8, arg, "-ofmt=")) {
1227 target_ofmt = arg["-ofmt=".len..];
1265 create_module.object_format = arg["-ofmt=".len..];
12281266 } else if (mem.startsWith(u8, arg, "-mcpu=")) {
12291267 target_mcpu = arg["-mcpu=".len..];
1230 } else if (mem.startsWith(u8, arg, "-mcmodel=")) {
1231 machine_code_model = parseCodeModel(arg["-mcmodel=".len..]);
12321268 } else if (mem.startsWith(u8, arg, "-O")) {
1233 optimize_mode_string = arg["-O".len..];
1269 mod_opts.optimize_mode = parseOptimizeMode(arg["-O".len..]);
12341270 } else if (mem.eql(u8, arg, "--dynamic-linker")) {
1235 target_dynamic_linker = args_iter.nextOrFatal();
1271 create_module.dynamic_linker = args_iter.nextOrFatal();
12361272 } else if (mem.eql(u8, arg, "--sysroot")) {
1237 sysroot = args_iter.nextOrFatal();
1238 try clang_argv.append("-isysroot");
1239 try clang_argv.append(sysroot.?);
1273 const next_arg = args_iter.nextOrFatal();
1274 sysroot = next_arg;
1275 try clang_argv.appendSlice(arena, &.{ "-isysroot", next_arg });
12401276 } else if (mem.eql(u8, arg, "--libc")) {
12411277 libc_paths_file = args_iter.nextOrFatal();
12421278 } else if (mem.eql(u8, arg, "--test-filter")) {
......@@ -1258,7 +1294,7 @@ fn buildOutputType(
12581294 warn("Zig was compiled without logging enabled (-Dlog). --debug-log has no effect.", .{});
12591295 _ = args_iter.nextOrFatal();
12601296 } else {
1261 try log_scopes.append(gpa, args_iter.nextOrFatal());
1297 try log_scopes.append(arena, args_iter.nextOrFatal());
12621298 }
12631299 } else if (mem.eql(u8, arg, "--listen")) {
12641300 const next_arg = args_iter.nextOrFatal();
......@@ -1298,7 +1334,7 @@ fn buildOutputType(
12981334 } else if (mem.eql(u8, arg, "--test-cmd-bin")) {
12991335 try test_exec_args.append(null);
13001336 } else if (mem.eql(u8, arg, "--test-evented-io")) {
1301 test_evented_io = true;
1337 create_module.opts.test_evented_io = true;
13021338 } else if (mem.eql(u8, arg, "--test-no-exec")) {
13031339 test_no_exec = true;
13041340 } else if (mem.eql(u8, arg, "-ftime-report")) {
......@@ -1306,65 +1342,65 @@ fn buildOutputType(
13061342 } else if (mem.eql(u8, arg, "-fstack-report")) {
13071343 stack_report = true;
13081344 } else if (mem.eql(u8, arg, "-fPIC")) {
1309 want_pic = true;
1345 mod_opts.pic = true;
13101346 } else if (mem.eql(u8, arg, "-fno-PIC")) {
1311 want_pic = false;
1347 mod_opts.pic = false;
13121348 } else if (mem.eql(u8, arg, "-fPIE")) {
1313 want_pie = true;
1349 create_module.opts.pie = true;
13141350 } else if (mem.eql(u8, arg, "-fno-PIE")) {
1315 want_pie = false;
1351 create_module.opts.pie = false;
13161352 } else if (mem.eql(u8, arg, "-flto")) {
1317 want_lto = true;
1353 create_module.opts.lto = true;
13181354 } else if (mem.eql(u8, arg, "-fno-lto")) {
1319 want_lto = false;
1355 create_module.opts.lto = false;
13201356 } else if (mem.eql(u8, arg, "-funwind-tables")) {
1321 want_unwind_tables = true;
1357 mod_opts.unwind_tables = true;
13221358 } else if (mem.eql(u8, arg, "-fno-unwind-tables")) {
1323 want_unwind_tables = false;
1359 mod_opts.unwind_tables = false;
13241360 } else if (mem.eql(u8, arg, "-fstack-check")) {
1325 want_stack_check = true;
1361 mod_opts.stack_check = true;
13261362 } else if (mem.eql(u8, arg, "-fno-stack-check")) {
1327 want_stack_check = false;
1363 mod_opts.stack_check = false;
13281364 } else if (mem.eql(u8, arg, "-fstack-protector")) {
1329 want_stack_protector = Compilation.default_stack_protector_buffer_size;
1365 mod_opts.stack_protector = Compilation.default_stack_protector_buffer_size;
13301366 } else if (mem.eql(u8, arg, "-fno-stack-protector")) {
1331 want_stack_protector = 0;
1367 mod_opts.stack_protector = 0;
13321368 } else if (mem.eql(u8, arg, "-mred-zone")) {
1333 want_red_zone = true;
1369 mod_opts.red_zone = true;
13341370 } else if (mem.eql(u8, arg, "-mno-red-zone")) {
1335 want_red_zone = false;
1371 mod_opts.red_zone = false;
13361372 } else if (mem.eql(u8, arg, "-fomit-frame-pointer")) {
1337 omit_frame_pointer = true;
1373 mod_opts.omit_frame_pointer = true;
13381374 } else if (mem.eql(u8, arg, "-fno-omit-frame-pointer")) {
1339 omit_frame_pointer = false;
1375 mod_opts.omit_frame_pointer = false;
13401376 } else if (mem.eql(u8, arg, "-fsanitize-c")) {
1341 want_sanitize_c = true;
1377 mod_opts.sanitize_c = true;
13421378 } else if (mem.eql(u8, arg, "-fno-sanitize-c")) {
1343 want_sanitize_c = false;
1379 mod_opts.sanitize_c = false;
13441380 } else if (mem.eql(u8, arg, "-fvalgrind")) {
1345 want_valgrind = true;
1381 mod_opts.valgrind = true;
13461382 } else if (mem.eql(u8, arg, "-fno-valgrind")) {
1347 want_valgrind = false;
1383 mod_opts.valgrind = false;
13481384 } else if (mem.eql(u8, arg, "-fsanitize-thread")) {
1349 want_tsan = true;
1385 mod_opts.sanitize_thread = true;
13501386 } else if (mem.eql(u8, arg, "-fno-sanitize-thread")) {
1351 want_tsan = false;
1387 mod_opts.sanitize_thread = false;
13521388 } else if (mem.eql(u8, arg, "-fllvm")) {
1353 use_llvm = true;
1389 create_module.opts.use_llvm = true;
13541390 } else if (mem.eql(u8, arg, "-fno-llvm")) {
1355 use_llvm = false;
1391 create_module.opts.use_llvm = false;
13561392 } else if (mem.eql(u8, arg, "-flibllvm")) {
1357 use_lib_llvm = true;
1393 create_module.opts.use_lib_llvm = true;
13581394 } else if (mem.eql(u8, arg, "-fno-libllvm")) {
1359 use_lib_llvm = false;
1395 create_module.opts.use_lib_llvm = false;
13601396 } else if (mem.eql(u8, arg, "-flld")) {
1361 use_lld = true;
1397 create_module.opts.use_lld = true;
13621398 } else if (mem.eql(u8, arg, "-fno-lld")) {
1363 use_lld = false;
1399 create_module.opts.use_lld = false;
13641400 } else if (mem.eql(u8, arg, "-fclang")) {
1365 use_clang = true;
1401 create_module.opts.use_clang = true;
13661402 } else if (mem.eql(u8, arg, "-fno-clang")) {
1367 use_clang = false;
1403 create_module.opts.use_clang = false;
13681404 } else if (mem.eql(u8, arg, "-freference-trace")) {
13691405 reference_trace = 256;
13701406 } else if (mem.startsWith(u8, arg, "-freference-trace=")) {
......@@ -1375,9 +1411,9 @@ fn buildOutputType(
13751411 } else if (mem.eql(u8, arg, "-fno-reference-trace")) {
13761412 reference_trace = null;
13771413 } else if (mem.eql(u8, arg, "-ferror-tracing")) {
1378 error_tracing = true;
1414 mod_opts.error_tracing = true;
13791415 } else if (mem.eql(u8, arg, "-fno-error-tracing")) {
1380 error_tracing = false;
1416 mod_opts.error_tracing = false;
13811417 } else if (mem.eql(u8, arg, "-rdynamic")) {
13821418 rdynamic = true;
13831419 } else if (mem.eql(u8, arg, "-fsoname")) {
......@@ -1432,11 +1468,11 @@ fn buildOutputType(
14321468 emit_implib = .no;
14331469 emit_implib_arg_provided = true;
14341470 } else if (mem.eql(u8, arg, "-dynamic")) {
1435 link_mode = .Dynamic;
1471 create_module.opts.link_mode = .Dynamic;
14361472 lib_preferred_mode = .Dynamic;
14371473 lib_search_strategy = .mode_first;
14381474 } else if (mem.eql(u8, arg, "-static")) {
1439 link_mode = .Static;
1475 create_module.opts.link_mode = .Static;
14401476 lib_preferred_mode = .Static;
14411477 lib_search_strategy = .no_fallback;
14421478 } else if (mem.eql(u8, arg, "-fdll-export-fns")) {
......@@ -1447,9 +1483,9 @@ fn buildOutputType(
14471483 show_builtin = true;
14481484 emit_bin = .no;
14491485 } else if (mem.eql(u8, arg, "-fstrip")) {
1450 strip = true;
1486 mod_opts.strip = true;
14511487 } else if (mem.eql(u8, arg, "-fno-strip")) {
1452 strip = false;
1488 mod_opts.strip = false;
14531489 } else if (mem.eql(u8, arg, "-gdwarf32")) {
14541490 dwarf_format = .@"32";
14551491 } else if (mem.eql(u8, arg, "-gdwarf64")) {
......@@ -1459,9 +1495,9 @@ fn buildOutputType(
14591495 } else if (mem.eql(u8, arg, "-fno-formatted-panics")) {
14601496 formatted_panics = false;
14611497 } else if (mem.eql(u8, arg, "-fsingle-threaded")) {
1462 single_threaded = true;
1498 mod_opts.single_threaded = true;
14631499 } else if (mem.eql(u8, arg, "-fno-single-threaded")) {
1464 single_threaded = false;
1500 mod_opts.single_threaded = false;
14651501 } else if (mem.eql(u8, arg, "-ffunction-sections")) {
14661502 function_sections = true;
14671503 } else if (mem.eql(u8, arg, "-fno-function-sections")) {
......@@ -1518,13 +1554,16 @@ fn buildOutputType(
15181554 fatal("unsupported linker extension flag: -z {s}", .{z_arg});
15191555 }
15201556 } else if (mem.eql(u8, arg, "--import-memory")) {
1521 linker_import_memory = true;
1557 create_module.opts.import_memory = true;
15221558 } else if (mem.eql(u8, arg, "-fentry")) {
1523 linker_force_entry = true;
1559 switch (create_module.opts.entry) {
1560 .default, .disabled => create_module.opts.entry = .enabled,
1561 .enabled, .named => {},
1562 }
15241563 } else if (mem.eql(u8, arg, "-fno-entry")) {
1525 linker_force_entry = false;
1564 create_module.opts.entry = .disabled;
15261565 } else if (mem.eql(u8, arg, "--export-memory")) {
1527 linker_export_memory = true;
1566 create_module.opts.export_memory = true;
15281567 } else if (mem.eql(u8, arg, "--import-symbols")) {
15291568 linker_import_symbols = true;
15301569 } else if (mem.eql(u8, arg, "--import-table")) {
......@@ -1536,11 +1575,11 @@ fn buildOutputType(
15361575 } else if (mem.startsWith(u8, arg, "--max-memory=")) {
15371576 linker_max_memory = parseIntSuffix(arg, "--max-memory=".len);
15381577 } else if (mem.eql(u8, arg, "--shared-memory")) {
1539 linker_shared_memory = true;
1578 create_module.opts.shared_memory = true;
15401579 } else if (mem.startsWith(u8, arg, "--global-base=")) {
15411580 linker_global_base = parseIntSuffix(arg, "--global-base=".len);
15421581 } else if (mem.startsWith(u8, arg, "--export=")) {
1543 try linker_export_symbol_names.append(arg["--export=".len..]);
1582 try linker_export_symbol_names.append(arena, arg["--export=".len..]);
15441583 } else if (mem.eql(u8, arg, "-Bsymbolic")) {
15451584 linker_bind_global_refs_locally = true;
15461585 } else if (mem.eql(u8, arg, "--gc-sections")) {
......@@ -1585,37 +1624,37 @@ fn buildOutputType(
15851624 } else if (mem.startsWith(u8, arg, "-T")) {
15861625 linker_script = arg[2..];
15871626 } else if (mem.startsWith(u8, arg, "-L")) {
1588 try lib_dir_args.append(arg[2..]);
1627 try lib_dir_args.append(arena, arg[2..]);
15891628 } else if (mem.startsWith(u8, arg, "-F")) {
1590 try framework_dirs.append(arg[2..]);
1629 try framework_dirs.append(arena, arg[2..]);
15911630 } else if (mem.startsWith(u8, arg, "-l")) {
15921631 // We don't know whether this library is part of libc
15931632 // or libc++ until we resolve the target, so we append
15941633 // to the list for now.
1595 try system_libs.put(arg["-l".len..], .{
1634 try create_module.system_libs.put(arena, arg["-l".len..], .{
15961635 .needed = false,
15971636 .weak = false,
15981637 .preferred_mode = lib_preferred_mode,
15991638 .search_strategy = lib_search_strategy,
16001639 });
16011640 } else if (mem.startsWith(u8, arg, "-needed-l")) {
1602 try system_libs.put(arg["-needed-l".len..], .{
1641 try create_module.system_libs.put(arena, arg["-needed-l".len..], .{
16031642 .needed = true,
16041643 .weak = false,
16051644 .preferred_mode = lib_preferred_mode,
16061645 .search_strategy = lib_search_strategy,
16071646 });
16081647 } else if (mem.startsWith(u8, arg, "-weak-l")) {
1609 try system_libs.put(arg["-weak-l".len..], .{
1648 try create_module.system_libs.put(arena, arg["-weak-l".len..], .{
16101649 .needed = false,
16111650 .weak = true,
16121651 .preferred_mode = lib_preferred_mode,
16131652 .search_strategy = lib_search_strategy,
16141653 });
16151654 } else if (mem.startsWith(u8, arg, "-D")) {
1616 try clang_argv.append(arg);
1655 try clang_argv.append(arena, arg);
16171656 } else if (mem.startsWith(u8, arg, "-I")) {
1618 try cssan.addIncludePath(.I, arg, arg[2..], true);
1657 try cssan.addIncludePath(arena, &clang_argv, .I, arg, arg[2..], true);
16191658 } else if (mem.eql(u8, arg, "-x")) {
16201659 const lang = args_iter.nextOrFatal();
16211660 if (mem.eql(u8, lang, "none")) {
......@@ -1626,23 +1665,27 @@ fn buildOutputType(
16261665 fatal("language not recognized: '{s}'", .{lang});
16271666 }
16281667 } else if (mem.startsWith(u8, arg, "-mexec-model=")) {
1629 wasi_exec_model = std.meta.stringToEnum(std.builtin.WasiExecModel, arg["-mexec-model=".len..]) orelse {
1630 fatal("expected [command|reactor] for -mexec-mode=[value], found '{s}'", .{arg["-mexec-model=".len..]});
1631 };
1668 create_module.opts.wasi_exec_model = parseWasiExecModel(arg["-mexec-model=".len..]);
16321669 } else {
16331670 fatal("unrecognized parameter: '{s}'", .{arg});
16341671 }
1635 } else switch (file_ext orelse
1636 Compilation.classifyFileExt(arg)) {
1637 .object, .static_library, .shared_library => try link_objects.append(.{ .path = arg }),
1638 .res => try res_files.append(.{ .path = arg }),
1672 } else switch (file_ext orelse Compilation.classifyFileExt(arg)) {
1673 .object, .static_library, .shared_library => {
1674 try link_objects.append(arena, .{ .path = arg });
1675 },
1676 .res => {
1677 try link_objects.append(arena, .{ .path = arg });
1678 contains_res_file = true;
1679 },
16391680 .manifest => {
16401681 if (manifest_file) |other| {
16411682 fatal("only one manifest file can be specified, found '{s}' after '{s}'", .{ arg, other });
16421683 } else manifest_file = arg;
16431684 },
16441685 .assembly, .assembly_with_cpp, .c, .cpp, .h, .ll, .bc, .m, .mm, .cu => {
1645 try c_source_files.append(.{
1686 try create_module.c_source_files.append(arena, .{
1687 // Populated after module creation.
1688 .owner = undefined,
16461689 .src_path = arg,
16471690 .extra_flags = try arena.dupe([]const u8, extra_cflags.items),
16481691 // duped when parsing the args.
......@@ -1650,7 +1693,9 @@ fn buildOutputType(
16501693 });
16511694 },
16521695 .rc => {
1653 try rc_source_files.append(.{
1696 try create_module.rc_source_files.append(arena, .{
1697 // Populated after module creation.
1698 .owner = undefined,
16541699 .src_path = arg,
16551700 .extra_flags = try arena.dupe([]const u8, extra_rcflags.items),
16561701 });
......@@ -1668,18 +1713,14 @@ fn buildOutputType(
16681713 },
16691714 }
16701715 }
1671 if (optimize_mode_string) |s| {
1672 optimize_mode = std.meta.stringToEnum(std.builtin.OptimizeMode, s) orelse
1673 fatal("unrecognized optimization mode: '{s}'", .{s});
1674 }
16751716 },
16761717 .cc, .cpp => {
16771718 if (build_options.only_c) unreachable;
16781719
16791720 emit_h = .no;
16801721 soname = .no;
1681 ensure_libc_on_non_freestanding = true;
1682 ensure_libcpp_on_non_freestanding = arg_mode == .cpp;
1722 create_module.opts.ensure_libc_on_non_freestanding = true;
1723 create_module.opts.ensure_libcpp_on_non_freestanding = arg_mode == .cpp;
16831724 want_native_include_dirs = true;
16841725 // Clang's driver enables this switch unconditionally.
16851726 // Disabling the emission of .eh_frame_hdr can unexpectedly break
......@@ -1733,24 +1774,30 @@ fn buildOutputType(
17331774 }
17341775 },
17351776 .other => {
1736 try clang_argv.appendSlice(it.other_args);
1777 try clang_argv.appendSlice(arena, it.other_args);
17371778 },
1738 .positional => switch (file_ext orelse
1739 Compilation.classifyFileExt(mem.sliceTo(it.only_arg, 0))) {
1779 .positional => switch (file_ext orelse Compilation.classifyFileExt(mem.sliceTo(it.only_arg, 0))) {
17401780 .assembly, .assembly_with_cpp, .c, .cpp, .ll, .bc, .h, .m, .mm, .cu => {
1741 try c_source_files.append(.{
1781 try create_module.c_source_files.append(arena, .{
1782 // Populated after module creation.
1783 .owner = undefined,
17421784 .src_path = it.only_arg,
17431785 .ext = file_ext, // duped while parsing the args.
17441786 });
17451787 },
1746 .unknown, .shared_library, .object, .static_library => try link_objects.append(.{
1747 .path = it.only_arg,
1748 .must_link = must_link,
1749 }),
1750 .res => try res_files.append(.{
1751 .path = it.only_arg,
1752 .must_link = must_link,
1753 }),
1788 .unknown, .shared_library, .object, .static_library => {
1789 try link_objects.append(arena, .{
1790 .path = it.only_arg,
1791 .must_link = must_link,
1792 });
1793 },
1794 .res => {
1795 try link_objects.append(arena, .{
1796 .path = it.only_arg,
1797 .must_link = must_link,
1798 });
1799 contains_res_file = true;
1800 },
17541801 .manifest => {
17551802 if (manifest_file) |other| {
17561803 fatal("only one manifest file can be specified, found '{s}' after previously specified manifest '{s}'", .{ it.only_arg, other });
......@@ -1760,7 +1807,11 @@ fn buildOutputType(
17601807 linker_module_definition_file = it.only_arg;
17611808 },
17621809 .rc => {
1763 try rc_source_files.append(.{ .src_path = it.only_arg });
1810 try create_module.rc_source_files.append(arena, .{
1811 // Populated after module creation.
1812 .owner = undefined,
1813 .src_path = it.only_arg,
1814 });
17641815 },
17651816 .zig => {
17661817 if (root_src_file) |other| {
......@@ -1777,13 +1828,13 @@ fn buildOutputType(
17771828 // more control over what's in the resulting
17781829 // binary: no extra rpaths and DSO filename exactly
17791830 // as provided. Hello, Go.
1780 try link_objects.append(.{
1831 try link_objects.append(arena, .{
17811832 .path = it.only_arg,
17821833 .must_link = must_link,
17831834 .loption = true,
17841835 });
17851836 } else {
1786 try system_libs.put(it.only_arg, .{
1837 try create_module.system_libs.put(arena, it.only_arg, .{
17871838 .needed = needed,
17881839 .weak = false,
17891840 .preferred_mode = lib_preferred_mode,
......@@ -1796,16 +1847,16 @@ fn buildOutputType(
17961847 // Never mind what we're doing, just pass the args directly. For example --help.
17971848 return process.exit(try clangMain(arena, all_args));
17981849 },
1799 .pic => want_pic = true,
1800 .no_pic => want_pic = false,
1801 .pie => want_pie = true,
1802 .no_pie => want_pie = false,
1803 .lto => want_lto = true,
1804 .no_lto => want_lto = false,
1805 .red_zone => want_red_zone = true,
1806 .no_red_zone => want_red_zone = false,
1807 .omit_frame_pointer => omit_frame_pointer = true,
1808 .no_omit_frame_pointer => omit_frame_pointer = false,
1850 .pic => mod_opts.pic = true,
1851 .no_pic => mod_opts.pic = false,
1852 .pie => create_module.opts.pie = true,
1853 .no_pie => create_module.opts.pie = false,
1854 .lto => create_module.opts.lto = true,
1855 .no_lto => create_module.opts.lto = false,
1856 .red_zone => mod_opts.red_zone = true,
1857 .no_red_zone => mod_opts.red_zone = false,
1858 .omit_frame_pointer => mod_opts.omit_frame_pointer = true,
1859 .no_omit_frame_pointer => mod_opts.omit_frame_pointer = false,
18091860 .function_sections => function_sections = true,
18101861 .no_function_sections => function_sections = false,
18111862 .data_sections => data_sections = true,
......@@ -1814,23 +1865,23 @@ fn buildOutputType(
18141865 .no_builtin => no_builtin = true,
18151866 .color_diagnostics => color = .on,
18161867 .no_color_diagnostics => color = .off,
1817 .stack_check => want_stack_check = true,
1818 .no_stack_check => want_stack_check = false,
1868 .stack_check => mod_opts.stack_check = true,
1869 .no_stack_check => mod_opts.stack_check = false,
18191870 .stack_protector => {
1820 if (want_stack_protector == null) {
1821 want_stack_protector = Compilation.default_stack_protector_buffer_size;
1871 if (mod_opts.stack_protector == null) {
1872 mod_opts.stack_protector = Compilation.default_stack_protector_buffer_size;
18221873 }
18231874 },
1824 .no_stack_protector => want_stack_protector = 0,
1825 .unwind_tables => want_unwind_tables = true,
1826 .no_unwind_tables => want_unwind_tables = false,
1875 .no_stack_protector => mod_opts.stack_protector = 0,
1876 .unwind_tables => mod_opts.unwind_tables = true,
1877 .no_unwind_tables => mod_opts.unwind_tables = false,
18271878 .nostdlib => {
1828 ensure_libc_on_non_freestanding = false;
1829 ensure_libcpp_on_non_freestanding = false;
1879 create_module.opts.ensure_libc_on_non_freestanding = false;
1880 create_module.opts.ensure_libcpp_on_non_freestanding = false;
18301881 },
1831 .nostdlib_cpp => ensure_libcpp_on_non_freestanding = false,
1882 .nostdlib_cpp => create_module.opts.ensure_libcpp_on_non_freestanding = false,
18321883 .shared => {
1833 link_mode = .Dynamic;
1884 create_module.opts.link_mode = .Dynamic;
18341885 is_shared_lib = true;
18351886 },
18361887 .rdynamic => rdynamic = true,
......@@ -1870,7 +1921,7 @@ fn buildOutputType(
18701921 } else if (mem.eql(u8, linker_arg, "--no-as-needed")) {
18711922 needed = true;
18721923 } else if (mem.eql(u8, linker_arg, "-no-pie")) {
1873 want_pie = false;
1924 create_module.opts.pie = false;
18741925 } else if (mem.eql(u8, linker_arg, "--sort-common")) {
18751926 // from ld.lld(1): --sort-common is ignored for GNU compatibility,
18761927 // this ignores plain --sort-common
......@@ -1912,50 +1963,50 @@ fn buildOutputType(
19121963 if (mem.eql(u8, level, "s") or
19131964 mem.eql(u8, level, "z"))
19141965 {
1915 optimize_mode = .ReleaseSmall;
1966 mod_opts.optimize_mode = .ReleaseSmall;
19161967 } else if (mem.eql(u8, level, "1") or
19171968 mem.eql(u8, level, "2") or
19181969 mem.eql(u8, level, "3") or
19191970 mem.eql(u8, level, "4") or
19201971 mem.eql(u8, level, "fast"))
19211972 {
1922 optimize_mode = .ReleaseFast;
1973 mod_opts.optimize_mode = .ReleaseFast;
19231974 } else if (mem.eql(u8, level, "g") or
19241975 mem.eql(u8, level, "0"))
19251976 {
1926 optimize_mode = .Debug;
1977 mod_opts.optimize_mode = .Debug;
19271978 } else {
1928 try clang_argv.appendSlice(it.other_args);
1979 try clang_argv.appendSlice(arena, it.other_args);
19291980 }
19301981 },
19311982 .debug => {
1932 strip = false;
1983 mod_opts.strip = false;
19331984 if (mem.eql(u8, it.only_arg, "g")) {
19341985 // We handled with strip = false above.
19351986 } else if (mem.eql(u8, it.only_arg, "g1") or
19361987 mem.eql(u8, it.only_arg, "gline-tables-only"))
19371988 {
19381989 // We handled with strip = false above. but we also want reduced debug info.
1939 try clang_argv.append("-gline-tables-only");
1990 try clang_argv.append(arena, "-gline-tables-only");
19401991 } else {
1941 try clang_argv.appendSlice(it.other_args);
1992 try clang_argv.appendSlice(arena, it.other_args);
19421993 }
19431994 },
19441995 .gdwarf32 => {
1945 strip = false;
1996 mod_opts.strip = false;
19461997 dwarf_format = .@"32";
19471998 },
19481999 .gdwarf64 => {
1949 strip = false;
2000 mod_opts.strip = false;
19502001 dwarf_format = .@"64";
19512002 },
19522003 .sanitize => {
19532004 if (mem.eql(u8, it.only_arg, "undefined")) {
1954 want_sanitize_c = true;
2005 mod_opts.sanitize_c = true;
19552006 } else if (mem.eql(u8, it.only_arg, "thread")) {
1956 want_tsan = true;
2007 mod_opts.sanitize_thread = true;
19572008 } else {
1958 try clang_argv.appendSlice(it.other_args);
2009 try clang_argv.appendSlice(arena, it.other_args);
19592010 }
19602011 },
19612012 .linker_script => linker_script = it.only_arg,
......@@ -1964,59 +2015,57 @@ fn buildOutputType(
19642015 // Have Clang print more infos, some tools such as CMake
19652016 // parse this to discover any implicit include and
19662017 // library dir to look-up into.
1967 try clang_argv.append("-v");
2018 try clang_argv.append(arena, "-v");
19682019 },
19692020 .dry_run => {
19702021 // This flag means "dry run". Clang will not actually output anything
19712022 // to the file system.
19722023 verbose_link = true;
19732024 disable_c_depfile = true;
1974 try clang_argv.append("-###");
2025 try clang_argv.append(arena, "-###");
19752026 },
19762027 .for_linker => try linker_args.append(it.only_arg),
19772028 .linker_input_z => {
19782029 try linker_args.append("-z");
19792030 try linker_args.append(it.only_arg);
19802031 },
1981 .lib_dir => try lib_dir_args.append(it.only_arg),
2032 .lib_dir => try lib_dir_args.append(arena, it.only_arg),
19822033 .mcpu => target_mcpu = it.only_arg,
1983 .m => try llvm_m_args.append(it.only_arg),
2034 .m => try create_module.llvm_m_args.append(arena, it.only_arg),
19842035 .dep_file => {
19852036 disable_c_depfile = true;
1986 try clang_argv.appendSlice(it.other_args);
2037 try clang_argv.appendSlice(arena, it.other_args);
19872038 },
19882039 .dep_file_to_stdout => { // -M, -MM
19892040 // "Like -MD, but also implies -E and writes to stdout by default"
19902041 // "Like -MMD, but also implies -E and writes to stdout by default"
19912042 c_out_mode = .preprocessor;
19922043 disable_c_depfile = true;
1993 try clang_argv.appendSlice(it.other_args);
2044 try clang_argv.appendSlice(arena, it.other_args);
19942045 },
1995 .framework_dir => try framework_dirs.append(it.only_arg),
1996 .framework => try frameworks.put(gpa, it.only_arg, .{}),
2046 .framework_dir => try framework_dirs.append(arena, it.only_arg),
2047 .framework => try frameworks.put(arena, it.only_arg, .{}),
19972048 .nostdlibinc => want_native_include_dirs = false,
1998 .strip => strip = true,
2049 .strip => mod_opts.strip = true,
19992050 .exec_model => {
2000 wasi_exec_model = std.meta.stringToEnum(std.builtin.WasiExecModel, it.only_arg) orelse {
2001 fatal("expected [command|reactor] for -mexec-mode=[value], found '{s}'", .{it.only_arg});
2002 };
2051 create_module.opts.wasi_exec_model = parseWasiExecModel(it.only_arg);
20032052 },
20042053 .sysroot => {
20052054 sysroot = it.only_arg;
20062055 },
20072056 .entry => {
2008 entry = it.only_arg;
2057 create_module.opts.entry = .{ .named = it.only_arg };
20092058 },
20102059 .force_undefined_symbol => {
2011 try force_undefined_symbols.put(gpa, it.only_arg, {});
2060 try force_undefined_symbols.put(arena, it.only_arg, {});
20122061 },
2013 .weak_library => try system_libs.put(it.only_arg, .{
2062 .weak_library => try create_module.system_libs.put(arena, it.only_arg, .{
20142063 .needed = false,
20152064 .weak = true,
20162065 .preferred_mode = lib_preferred_mode,
20172066 .search_strategy = lib_search_strategy,
20182067 }),
2019 .weak_framework => try frameworks.put(gpa, it.only_arg, .{ .weak = true }),
2068 .weak_framework => try frameworks.put(arena, it.only_arg, .{ .weak = true }),
20202069 .headerpad_max_install_names => headerpad_max_install_names = true,
20212070 .compress_debug_sections => {
20222071 if (it.only_arg.len == 0) {
......@@ -2077,14 +2126,14 @@ fn buildOutputType(
20772126 }
20782127 provided_name = name[prefix..end];
20792128 } else if (mem.eql(u8, arg, "-rpath")) {
2080 try rpath_list.append(linker_args_it.nextOrFatal());
2129 try rpath_list.append(arena, linker_args_it.nextOrFatal());
20812130 } else if (mem.eql(u8, arg, "--subsystem")) {
20822131 subsystem = try parseSubSystem(linker_args_it.nextOrFatal());
20832132 } else if (mem.eql(u8, arg, "-I") or
20842133 mem.eql(u8, arg, "--dynamic-linker") or
20852134 mem.eql(u8, arg, "-dynamic-linker"))
20862135 {
2087 target_dynamic_linker = linker_args_it.nextOrFatal();
2136 create_module.dynamic_linker = linker_args_it.nextOrFatal();
20882137 } else if (mem.eql(u8, arg, "-E") or
20892138 mem.eql(u8, arg, "--export-dynamic") or
20902139 mem.eql(u8, arg, "-export-dynamic"))
......@@ -2145,9 +2194,9 @@ fn buildOutputType(
21452194 } else if (mem.eql(u8, arg, "-Bsymbolic")) {
21462195 linker_bind_global_refs_locally = true;
21472196 } else if (mem.eql(u8, arg, "--import-memory")) {
2148 linker_import_memory = true;
2197 create_module.opts.import_memory = true;
21492198 } else if (mem.eql(u8, arg, "--export-memory")) {
2150 linker_export_memory = true;
2199 create_module.opts.export_memory = true;
21512200 } else if (mem.eql(u8, arg, "--import-symbols")) {
21522201 linker_import_symbols = true;
21532202 } else if (mem.eql(u8, arg, "--import-table")) {
......@@ -2155,7 +2204,7 @@ fn buildOutputType(
21552204 } else if (mem.eql(u8, arg, "--export-table")) {
21562205 linker_export_table = true;
21572206 } else if (mem.eql(u8, arg, "--no-entry")) {
2158 linker_force_entry = false;
2207 create_module.opts.entry = .disabled;
21592208 } else if (mem.eql(u8, arg, "--initial-memory")) {
21602209 const next_arg = linker_args_it.nextOrFatal();
21612210 linker_initial_memory = std.fmt.parseUnsigned(u32, eatIntPrefix(next_arg, 16), 16) catch |err| {
......@@ -2167,14 +2216,14 @@ fn buildOutputType(
21672216 fatal("unable to parse max memory size '{s}': {s}", .{ next_arg, @errorName(err) });
21682217 };
21692218 } else if (mem.eql(u8, arg, "--shared-memory")) {
2170 linker_shared_memory = true;
2219 create_module.opts.shared_memory = true;
21712220 } else if (mem.eql(u8, arg, "--global-base")) {
21722221 const next_arg = linker_args_it.nextOrFatal();
21732222 linker_global_base = std.fmt.parseUnsigned(u32, eatIntPrefix(next_arg, 16), 16) catch |err| {
21742223 fatal("unable to parse global base '{s}': {s}", .{ next_arg, @errorName(err) });
21752224 };
21762225 } else if (mem.eql(u8, arg, "--export")) {
2177 try linker_export_symbol_names.append(linker_args_it.nextOrFatal());
2226 try linker_export_symbol_names.append(arena, linker_args_it.nextOrFatal());
21782227 } else if (mem.eql(u8, arg, "--compress-debug-sections")) {
21792228 const arg1 = linker_args_it.nextOrFatal();
21802229 linker_compress_debug_sections = std.meta.stringToEnum(link.CompressDebugSections, arg1) orelse {
......@@ -2232,9 +2281,9 @@ fn buildOutputType(
22322281 };
22332282 have_version = true;
22342283 } else if (mem.eql(u8, arg, "-e") or mem.eql(u8, arg, "--entry")) {
2235 entry = linker_args_it.nextOrFatal();
2284 create_module.opts.entry = .{ .named = linker_args_it.nextOrFatal() };
22362285 } else if (mem.eql(u8, arg, "-u")) {
2237 try force_undefined_symbols.put(gpa, linker_args_it.nextOrFatal(), {});
2286 try force_undefined_symbols.put(arena, linker_args_it.nextOrFatal(), {});
22382287 } else if (mem.eql(u8, arg, "--stack") or mem.eql(u8, arg, "-stack_size")) {
22392288 const stack_size = linker_args_it.nextOrFatal();
22402289 stack_size_override = std.fmt.parseUnsigned(u64, stack_size, 0) catch |err| {
......@@ -2276,7 +2325,7 @@ fn buildOutputType(
22762325 {
22772326 // -s, --strip-all Strip all symbols
22782327 // -S, --strip-debug Strip debugging symbols
2279 strip = true;
2328 mod_opts.strip = true;
22802329 } else if (mem.eql(u8, arg, "--start-group") or
22812330 mem.eql(u8, arg, "--end-group"))
22822331 {
......@@ -2307,27 +2356,27 @@ fn buildOutputType(
23072356 fatal("unable to parse minor subsystem version '{s}': {s}", .{ minor, @errorName(err) });
23082357 };
23092358 } else if (mem.eql(u8, arg, "-framework")) {
2310 try frameworks.put(gpa, linker_args_it.nextOrFatal(), .{});
2359 try frameworks.put(arena, linker_args_it.nextOrFatal(), .{});
23112360 } else if (mem.eql(u8, arg, "-weak_framework")) {
2312 try frameworks.put(gpa, linker_args_it.nextOrFatal(), .{ .weak = true });
2361 try frameworks.put(arena, linker_args_it.nextOrFatal(), .{ .weak = true });
23132362 } else if (mem.eql(u8, arg, "-needed_framework")) {
2314 try frameworks.put(gpa, linker_args_it.nextOrFatal(), .{ .needed = true });
2363 try frameworks.put(arena, linker_args_it.nextOrFatal(), .{ .needed = true });
23152364 } else if (mem.eql(u8, arg, "-needed_library")) {
2316 try system_libs.put(linker_args_it.nextOrFatal(), .{
2365 try create_module.system_libs.put(arena, linker_args_it.nextOrFatal(), .{
23172366 .weak = false,
23182367 .needed = true,
23192368 .preferred_mode = lib_preferred_mode,
23202369 .search_strategy = lib_search_strategy,
23212370 });
23222371 } else if (mem.startsWith(u8, arg, "-weak-l")) {
2323 try system_libs.put(arg["-weak-l".len..], .{
2372 try create_module.system_libs.put(arena, arg["-weak-l".len..], .{
23242373 .weak = true,
23252374 .needed = false,
23262375 .preferred_mode = lib_preferred_mode,
23272376 .search_strategy = lib_search_strategy,
23282377 });
23292378 } else if (mem.eql(u8, arg, "-weak_library")) {
2330 try system_libs.put(linker_args_it.nextOrFatal(), .{
2379 try create_module.system_libs.put(arena, linker_args_it.nextOrFatal(), .{
23312380 .weak = true,
23322381 .needed = false,
23332382 .preferred_mode = lib_preferred_mode,
......@@ -2361,7 +2410,7 @@ fn buildOutputType(
23612410 } else if (mem.eql(u8, arg, "-install_name")) {
23622411 install_name = linker_args_it.nextOrFatal();
23632412 } else if (mem.eql(u8, arg, "-force_load")) {
2364 try link_objects.append(.{
2413 try link_objects.append(arena, .{
23652414 .path = linker_args_it.nextOrFatal(),
23662415 .must_link = true,
23672416 });
......@@ -2402,22 +2451,22 @@ fn buildOutputType(
24022451 }
24032452 }
24042453
2405 if (want_sanitize_c) |wsc| {
2406 if (wsc and optimize_mode == .ReleaseFast) {
2407 optimize_mode = .ReleaseSafe;
2454 if (mod_opts.sanitize_c) |wsc| {
2455 if (wsc and mod_opts.optimize_mode == .ReleaseFast) {
2456 mod_opts.optimize_mode = .ReleaseSafe;
24082457 }
24092458 }
24102459
24112460 switch (c_out_mode) {
24122461 .link => {
2413 output_mode = if (is_shared_lib) .Lib else .Exe;
2462 create_module.opts.output_mode = if (is_shared_lib) .Lib else .Exe;
24142463 emit_bin = if (out_path) |p| .{ .yes = p } else EmitBin.yes_a_out;
24152464 if (emit_llvm) {
24162465 fatal("-emit-llvm cannot be used when linking", .{});
24172466 }
24182467 },
24192468 .object => {
2420 output_mode = .Obj;
2469 create_module.opts.output_mode = .Obj;
24212470 if (emit_llvm) {
24222471 emit_bin = .no;
24232472 if (out_path) |p| {
......@@ -2434,7 +2483,7 @@ fn buildOutputType(
24342483 }
24352484 },
24362485 .assembly => {
2437 output_mode = .Obj;
2486 create_module.opts.output_mode = .Obj;
24382487 emit_bin = .no;
24392488 if (emit_llvm) {
24402489 if (out_path) |p| {
......@@ -2451,9 +2500,9 @@ fn buildOutputType(
24512500 }
24522501 },
24532502 .preprocessor => {
2454 output_mode = .Obj;
2503 create_module.opts.output_mode = .Obj;
24552504 // An error message is generated when there is more than 1 C source file.
2456 if (c_source_files.items.len != 1) {
2505 if (create_module.c_source_files.items.len != 1) {
24572506 // For example `zig cc` and no args should print the "no input files" message.
24582507 return process.exit(try clangMain(arena, all_args));
24592508 }
......@@ -2465,7 +2514,7 @@ fn buildOutputType(
24652514 }
24662515 },
24672516 }
2468 if (c_source_files.items.len == 0 and
2517 if (create_module.c_source_files.items.len == 0 and
24692518 link_objects.items.len == 0 and
24702519 root_src_file == null)
24712520 {
......@@ -2476,258 +2525,72 @@ fn buildOutputType(
24762525 },
24772526 }
24782527
2479 {
2480 // Resolve module dependencies
2481 var it = modules.iterator();
2482 while (it.next()) |kv| {
2483 const deps_str = kv.value_ptr.deps_str;
2484 var deps_it = ModuleDepIterator.init(deps_str);
2485 while (deps_it.next()) |dep| {
2486 if (dep.expose.len == 0) {
2487 fatal("module '{s}' depends on '{s}' with a blank name", .{
2488 kv.key_ptr.*, dep.name,
2489 });
2490 }
2491
2492 for ([_][]const u8{ "std", "root", "builtin" }) |name| {
2493 if (mem.eql(u8, dep.expose, name)) {
2494 fatal("unable to add module '{s}' under name '{s}': conflicts with builtin module", .{
2495 dep.name, dep.expose,
2496 });
2497 }
2498 }
2499
2500 const dep_mod = modules.get(dep.name) orelse {
2501 fatal("module '{s}' depends on module '{s}' which does not exist", .{
2502 kv.key_ptr.*, dep.name,
2503 });
2504 };
2505
2506 try kv.value_ptr.mod.deps.put(arena, dep.expose, dep_mod.mod);
2507 }
2508 }
2509 }
2510
2511 if (arg_mode == .build and optimize_mode == .ReleaseSmall and strip == null)
2512 strip = true;
2513
2514 if (arg_mode == .translate_c and c_source_files.items.len != 1) {
2515 fatal("translate-c expects exactly 1 source file (found {d})", .{c_source_files.items.len});
2528 if (arg_mode == .translate_c and create_module.c_source_files.items.len != 1) {
2529 fatal("translate-c expects exactly 1 source file (found {d})", .{create_module.c_source_files.items.len});
25162530 }
25172531
25182532 if (root_src_file == null and arg_mode == .zig_test) {
25192533 fatal("`zig test` expects a zig source file argument", .{});
25202534 }
25212535
2522 const root_name = if (provided_name) |n| n else blk: {
2523 if (arg_mode == .zig_test) {
2524 break :blk "test";
2525 } else if (root_src_file) |file| {
2526 const basename = fs.path.basename(file);
2527 break :blk basename[0 .. basename.len - fs.path.extension(basename).len];
2528 } else if (c_source_files.items.len >= 1) {
2529 const basename = fs.path.basename(c_source_files.items[0].src_path);
2530 break :blk basename[0 .. basename.len - fs.path.extension(basename).len];
2531 } else if (link_objects.items.len >= 1) {
2532 const basename = fs.path.basename(link_objects.items[0].path);
2533 break :blk basename[0 .. basename.len - fs.path.extension(basename).len];
2534 } else if (emit_bin == .yes) {
2535 const basename = fs.path.basename(emit_bin.yes);
2536 break :blk basename[0 .. basename.len - fs.path.extension(basename).len];
2537 } else if (rc_source_files.items.len >= 1) {
2538 const basename = fs.path.basename(rc_source_files.items[0].src_path);
2539 break :blk basename[0 .. basename.len - fs.path.extension(basename).len];
2540 } else if (res_files.items.len >= 1) {
2541 const basename = fs.path.basename(res_files.items[0].path);
2542 break :blk basename[0 .. basename.len - fs.path.extension(basename).len];
2543 } else if (show_builtin) {
2544 break :blk "builtin";
2545 } else if (arg_mode == .run) {
2546 fatal("`zig run` expects at least one positional argument", .{});
2547 // TODO once the attempt to unwrap error: LinkingWithoutZigSourceUnimplemented
2548 // is solved, remove the above fatal() and uncomment the `break` below.
2549 //break :blk "run";
2550 } else {
2551 fatal("expected a positional argument, -femit-bin=[path], --show-builtin, or --name [name]", .{});
2552 }
2553 };
2554
2555 var target_parse_options: std.Target.Query.ParseOptions = .{
2556 .arch_os_abi = target_arch_os_abi,
2557 .cpu_features = target_mcpu,
2558 .dynamic_linker = target_dynamic_linker,
2559 .object_format = target_ofmt,
2560 };
2561
2562 // Before passing the mcpu string in for parsing, we convert any -m flags that were
2563 // passed in via zig cc to zig-style.
2564 if (llvm_m_args.items.len != 0) {
2565 // If this returns null, we let it fall through to the case below which will
2566 // run the full parse function and do proper error handling.
2567 if (std.Target.Query.parseCpuArch(target_parse_options)) |cpu_arch| {
2568 var llvm_to_zig_name = std.StringHashMap([]const u8).init(gpa);
2569 defer llvm_to_zig_name.deinit();
2570
2571 for (cpu_arch.allFeaturesList()) |feature| {
2572 const llvm_name = feature.llvm_name orelse continue;
2573 try llvm_to_zig_name.put(llvm_name, feature.name);
2574 }
2575
2576 var mcpu_buffer = std.ArrayList(u8).init(gpa);
2577 defer mcpu_buffer.deinit();
2578
2579 try mcpu_buffer.appendSlice(target_mcpu orelse "baseline");
2580
2581 for (llvm_m_args.items) |llvm_m_arg| {
2582 if (mem.startsWith(u8, llvm_m_arg, "mno-")) {
2583 const llvm_name = llvm_m_arg["mno-".len..];
2584 const zig_name = llvm_to_zig_name.get(llvm_name) orelse {
2585 fatal("target architecture {s} has no LLVM CPU feature named '{s}'", .{
2586 @tagName(cpu_arch), llvm_name,
2587 });
2588 };
2589 try mcpu_buffer.append('-');
2590 try mcpu_buffer.appendSlice(zig_name);
2591 } else if (mem.startsWith(u8, llvm_m_arg, "m")) {
2592 const llvm_name = llvm_m_arg["m".len..];
2593 const zig_name = llvm_to_zig_name.get(llvm_name) orelse {
2594 fatal("target architecture {s} has no LLVM CPU feature named '{s}'", .{
2595 @tagName(cpu_arch), llvm_name,
2596 });
2597 };
2598 try mcpu_buffer.append('+');
2599 try mcpu_buffer.appendSlice(zig_name);
2600 } else {
2601 unreachable;
2602 }
2603 }
2604
2605 const adjusted_target_mcpu = try arena.dupe(u8, mcpu_buffer.items);
2606 std.log.debug("adjusted target_mcpu: {s}", .{adjusted_target_mcpu});
2607 target_parse_options.cpu_features = adjusted_target_mcpu;
2608 }
2609 }
2610
2611 const target_query = try parseTargetQueryOrReportFatalError(arena, target_parse_options);
2612 const target = try std.zig.system.resolveTargetQuery(target_query);
2613
2614 if (target.os.tag != .freestanding) {
2615 if (ensure_libc_on_non_freestanding)
2616 link_libc = true;
2617 if (ensure_libcpp_on_non_freestanding)
2618 link_libcpp = true;
2619 }
2620
2621 if (linker_force_entry) |force| {
2622 if (!force) {
2623 entry = null;
2624 } else if (entry == null and output_mode == .Exe) {
2625 entry = switch (target.ofmt) {
2626 .coff => "wWinMainCRTStartup",
2627 .macho => "_main",
2628 .elf, .plan9 => "_start",
2629 .wasm => defaultWasmEntryName(wasi_exec_model),
2630 else => |tag| fatal("No default entry point available for output format {s}", .{@tagName(tag)}),
2631 };
2632 }
2633 } else if (entry == null and target.isWasm() and output_mode == .Exe) {
2634 // For WebAssembly the compiler defaults to setting the entry name when no flags are set.
2635 entry = defaultWasmEntryName(wasi_exec_model);
2636 }
2637
2638 if (target.ofmt == .coff) {
2639 // Now that we know the target supports resources,
2640 // we can add the res files as link objects.
2641 for (res_files.items) |res_file| {
2642 try link_objects.append(res_file);
2643 }
2644 } else {
2645 if (manifest_file != null) {
2646 fatal("manifest file is not allowed unless the target object format is coff (Windows/UEFI)", .{});
2647 }
2648 if (rc_source_files.items.len != 0) {
2649 fatal("rc files are not allowed unless the target object format is coff (Windows/UEFI)", .{});
2650 }
2651 if (res_files.items.len != 0) {
2652 fatal("res files are not allowed unless the target object format is coff (Windows/UEFI)", .{});
2653 }
2654 }
2655
2656 if (target.cpu.arch.isWasm()) blk: {
2657 if (single_threaded == null) {
2658 single_threaded = true;
2659 }
2660 if (link_mode) |mode| {
2661 if (mode == .Dynamic) {
2662 if (linker_export_memory != null and linker_export_memory.?) {
2663 fatal("flags '-dynamic' and '--export-memory' are incompatible", .{});
2664 }
2665 // User did not supply `--export-memory` which is incompatible with -dynamic, therefore
2666 // set the flag to false to ensure it does not get enabled by default.
2667 linker_export_memory = false;
2668 }
2669 }
2670 if (wasi_exec_model != null and wasi_exec_model.? == .reactor) {
2671 if (entry) |entry_name| {
2672 if (!mem.eql(u8, "_initialize", entry_name)) {
2673 fatal("the entry symbol of the reactor model must be '_initialize', but found '{s}'", .{entry_name});
2674 }
2675 }
2676 }
2677 if (linker_shared_memory) {
2678 if (output_mode == .Obj) {
2679 fatal("shared memory is not allowed in object files", .{});
2680 }
2681
2682 if (!target.cpu.features.isEnabled(@intFromEnum(std.Target.wasm.Feature.atomics)) or
2683 !target.cpu.features.isEnabled(@intFromEnum(std.Target.wasm.Feature.bulk_memory)))
2684 {
2685 fatal("'atomics' and 'bulk-memory' features must be enabled to use shared memory", .{});
2686 }
2687 break :blk;
2688 }
2689
2690 // Single-threaded is the default for WebAssembly, so only when the user specified `-fno_single-threaded`
2691 // can they enable multithreaded WebAssembly builds.
2692 const is_single_threaded = single_threaded.?;
2693 if (!is_single_threaded) {
2694 fatal("'-fno-single-threaded' requires the linker feature shared-memory to be enabled using '--shared-memory'", .{});
2536 if (root_src_file) |unresolved_src_path| {
2537 if (create_module.modules.count() != 0) {
2538 fatal("main module provided both by '--mod {s} {}{s}' and by positional argument '{s}'", .{
2539 create_module.modules.keys()[0],
2540 create_module.modules.values()[0].paths.root,
2541 create_module.modules.values()[0].paths.root_src_path,
2542 unresolved_src_path,
2543 });
26952544 }
2696 }
26972545
2698 if (use_lld) |opt| {
2699 if (opt and target.isDarwin()) {
2700 fatal("LLD requested with Mach-O object format. Only the self-hosted linker is supported for this target.", .{});
2701 }
2702 }
2546 // See duplicate logic: ModCreationGlobalFlags
2547 create_module.opts.have_zcu = true;
2548 if (mod_opts.single_threaded == false)
2549 create_module.opts.any_non_single_threaded = true;
2550 if (mod_opts.sanitize_thread == true)
2551 create_module.opts.any_sanitize_thread = true;
2552 if (mod_opts.unwind_tables == true)
2553 create_module.opts.any_unwind_tables = true;
27032554
2704 if (want_lto) |opt| {
2705 if (opt and target.isDarwin()) {
2706 fatal("LTO is not yet supported with the Mach-O object format. More details: https://github.com/ziglang/zig/issues/8680", .{});
2707 }
2555 const src_path = try introspect.resolvePath(arena, unresolved_src_path);
2556 try create_module.modules.put(arena, "main", .{
2557 .paths = .{
2558 .root = .{
2559 .root_dir = Cache.Directory.cwd(),
2560 .sub_path = fs.path.dirname(src_path) orelse "",
2561 },
2562 .root_src_path = fs.path.basename(src_path),
2563 },
2564 .cc_argv = try clang_argv.toOwnedSlice(arena),
2565 .inherited = mod_opts,
2566 .target_arch_os_abi = target_arch_os_abi,
2567 .target_mcpu = target_mcpu,
2568 .deps = try deps.toOwnedSlice(arena),
2569 .resolved = null,
2570 .c_source_files_start = c_source_files_owner_index,
2571 .c_source_files_end = create_module.c_source_files.items.len,
2572 .rc_source_files_start = rc_source_files_owner_index,
2573 .rc_source_files_end = create_module.rc_source_files.items.len,
2574 });
2575 cssan.reset();
2576 mod_opts = .{};
2577 target_arch_os_abi = null;
2578 target_mcpu = null;
2579 c_source_files_owner_index = create_module.c_source_files.items.len;
2580 rc_source_files_owner_index = create_module.rc_source_files.items.len;
27082581 }
27092582
2710 if (comptime builtin.target.isDarwin()) {
2711 // If we want to link against frameworks, we need system headers.
2712 if (framework_dirs.items.len > 0 or frameworks.count() > 0)
2713 want_native_include_dirs = true;
2583 if (c_source_files_owner_index != create_module.c_source_files.items.len) {
2584 fatal("C source file '{s}' has no parent module", .{
2585 create_module.c_source_files.items[c_source_files_owner_index].src_path,
2586 });
27142587 }
27152588
2716 // Resolve the library path arguments with respect to sysroot.
2717 var lib_dirs = std.ArrayList([]const u8).init(arena);
2718 if (sysroot) |root| {
2719 for (lib_dir_args.items) |dir| {
2720 if (fs.path.isAbsolute(dir)) {
2721 const stripped_dir = dir[fs.path.diskDesignator(dir).len..];
2722 const full_path = try fs.path.join(arena, &[_][]const u8{ root, stripped_dir });
2723 try lib_dirs.append(full_path);
2724 }
2725 try lib_dirs.append(dir);
2726 }
2727 } else {
2728 lib_dirs = lib_dir_args;
2589 if (rc_source_files_owner_index != create_module.rc_source_files.items.len) {
2590 fatal("resource file '{s}' has no parent module", .{
2591 create_module.rc_source_files.items[rc_source_files_owner_index].src_path,
2592 });
27292593 }
2730 lib_dir_args = undefined; // From here we use lib_dirs instead.
27312594
27322595 const self_exe_path: ?[]const u8 = if (!process.can_spawn)
27332596 null
......@@ -2757,87 +2620,185 @@ fn buildOutputType(
27572620 };
27582621 defer zig_lib_directory.handle.close();
27592622
2760 // First, remove libc, libc++, and compiler_rt libraries from the system libraries list.
2761 // We need to know whether the set of system libraries contains anything besides these
2762 // to decide whether to trigger native path detection logic.
2763 var external_system_libs: std.MultiArrayList(struct {
2764 name: []const u8,
2765 info: SystemLib,
2766 }) = .{};
2623 var global_cache_directory: Compilation.Directory = l: {
2624 if (override_global_cache_dir) |p| {
2625 break :l .{
2626 .handle = try fs.cwd().makeOpenPath(p, .{}),
2627 .path = p,
2628 };
2629 }
2630 if (builtin.os.tag == .wasi) {
2631 break :l getWasiPreopen("/cache");
2632 }
2633 const p = try introspect.resolveGlobalCacheDir(arena);
2634 break :l .{
2635 .handle = try fs.cwd().makeOpenPath(p, .{}),
2636 .path = p,
2637 };
2638 };
2639 defer global_cache_directory.handle.close();
27672640
2768 var resolved_system_libs: std.MultiArrayList(struct {
2769 name: []const u8,
2770 lib: Compilation.SystemLib,
2771 }) = .{};
2641 create_module.global_cache_directory = global_cache_directory;
2642 create_module.opts.emit_llvm_ir = emit_llvm_ir != .no;
2643 create_module.opts.emit_llvm_bc = emit_llvm_bc != .no;
2644 create_module.opts.emit_bin = emit_bin != .no;
2645 create_module.opts.c_source_files_len = create_module.c_source_files.items.len;
27722646
2773 var libc_installation: ?LibCInstallation = null;
2774 if (libc_paths_file) |paths_file| {
2775 libc_installation = LibCInstallation.parse(arena, paths_file, target) catch |err| {
2776 fatal("unable to parse libc paths file at path {s}: {s}", .{ paths_file, @errorName(err) });
2777 };
2647 const main_mod = try createModule(gpa, arena, &create_module, 0, null, zig_lib_directory);
2648 for (create_module.modules.keys(), create_module.modules.values()) |key, cli_mod| {
2649 if (cli_mod.resolved == null)
2650 fatal("module '{s}' declared but not used", .{key});
27782651 }
27792652
2780 for (system_libs.keys(), system_libs.values()) |lib_name, info| {
2781 if (target.is_libc_lib_name(lib_name)) {
2782 link_libc = true;
2783 continue;
2784 }
2785 if (target.is_libcpp_lib_name(lib_name)) {
2786 link_libcpp = true;
2787 continue;
2788 }
2789 switch (target_util.classifyCompilerRtLibName(target, lib_name)) {
2790 .none => {},
2791 .only_libunwind, .both => {
2792 link_libunwind = true;
2793 continue;
2794 },
2795 .only_compiler_rt => {
2796 warn("ignoring superfluous library '{s}': this dependency is fulfilled instead by compiler-rt which zig unconditionally provides", .{lib_name});
2797 continue;
2653 // When you're testing std, the main module is std. In that case,
2654 // we'll just set the std module to the main one, since avoiding
2655 // the errors caused by duplicating it is more effort than it's
2656 // worth.
2657 const main_mod_is_std = m: {
2658 const std_path = try fs.path.resolve(arena, &.{
2659 zig_lib_directory.path orelse ".", "std", "std.zig",
2660 });
2661 const main_path = try fs.path.resolve(arena, &.{
2662 main_mod.root.root_dir.path orelse ".",
2663 main_mod.root.sub_path,
2664 main_mod.root_src_path,
2665 });
2666 break :m mem.eql(u8, main_path, std_path);
2667 };
2668
2669 const std_mod = m: {
2670 if (main_mod_is_std) break :m main_mod;
2671 if (create_module.modules.get("std")) |cli_mod| break :m cli_mod.resolved.?;
2672
2673 break :m try Package.Module.create(arena, .{
2674 .global_cache_directory = global_cache_directory,
2675 .paths = .{
2676 .root = .{
2677 .root_dir = zig_lib_directory,
2678 .sub_path = "std",
2679 },
2680 .root_src_path = "std.zig",
27982681 },
2799 }
2682 .fully_qualified_name = "std",
2683 .cc_argv = &.{},
2684 .inherited = .{},
2685 .global = create_module.resolved_options,
2686 .parent = main_mod,
2687 .builtin_mod = main_mod.getBuiltinDependency(),
2688 });
2689 };
28002690
2801 if (target.isMinGW()) {
2802 const exists = mingw.libExists(arena, target, zig_lib_directory, lib_name) catch |err| {
2803 fatal("failed to check zig installation for DLL import libs: {s}", .{
2804 @errorName(err),
2805 });
2806 };
2807 if (exists) {
2808 try resolved_system_libs.append(arena, .{
2809 .name = lib_name,
2810 .lib = .{
2811 .needed = true,
2812 .weak = false,
2813 .path = null,
2691 const root_mod = if (arg_mode == .zig_test) root_mod: {
2692 const test_mod = if (test_runner_path) |test_runner| test_mod: {
2693 const test_mod = try Package.Module.create(arena, .{
2694 .global_cache_directory = global_cache_directory,
2695 .paths = .{
2696 .root = .{
2697 .root_dir = Cache.Directory.cwd(),
2698 .sub_path = fs.path.dirname(test_runner) orelse "",
28142699 },
2815 });
2816 continue;
2817 }
2700 .root_src_path = fs.path.basename(test_runner),
2701 },
2702 .fully_qualified_name = "root",
2703 .cc_argv = &.{},
2704 .inherited = .{},
2705 .global = create_module.resolved_options,
2706 .parent = main_mod,
2707 .builtin_mod = main_mod.getBuiltinDependency(),
2708 });
2709 test_mod.deps = try main_mod.deps.clone(arena);
2710 break :test_mod test_mod;
2711 } else try Package.Module.create(arena, .{
2712 .global_cache_directory = global_cache_directory,
2713 .paths = .{
2714 .root = .{
2715 .root_dir = zig_lib_directory,
2716 },
2717 .root_src_path = "test_runner.zig",
2718 },
2719 .fully_qualified_name = "root",
2720 .cc_argv = &.{},
2721 .inherited = .{},
2722 .global = create_module.resolved_options,
2723 .parent = main_mod,
2724 .builtin_mod = main_mod.getBuiltinDependency(),
2725 });
2726
2727 break :root_mod test_mod;
2728 } else main_mod;
2729
2730 const target = main_mod.resolved_target.result;
2731
2732 if (target.ofmt != .coff) {
2733 if (manifest_file != null) {
2734 fatal("manifest file is not allowed unless the target object format is coff (Windows/UEFI)", .{});
2735 }
2736 if (create_module.rc_source_files.items.len != 0) {
2737 fatal("rc files are not allowed unless the target object format is coff (Windows/UEFI)", .{});
28182738 }
2739 if (contains_res_file) {
2740 fatal("res files are not allowed unless the target object format is coff (Windows/UEFI)", .{});
2741 }
2742 }
28192743
2820 if (fs.path.isAbsolute(lib_name)) {
2821 fatal("cannot use absolute path as a system library: {s}", .{lib_name});
2744 const root_name = if (provided_name) |n| n else blk: {
2745 if (arg_mode == .zig_test) {
2746 break :blk "test";
2747 } else if (root_src_file) |file| {
2748 const basename = fs.path.basename(file);
2749 break :blk basename[0 .. basename.len - fs.path.extension(basename).len];
2750 } else if (create_module.c_source_files.items.len >= 1) {
2751 const basename = fs.path.basename(create_module.c_source_files.items[0].src_path);
2752 break :blk basename[0 .. basename.len - fs.path.extension(basename).len];
2753 } else if (link_objects.items.len >= 1) {
2754 const basename = fs.path.basename(link_objects.items[0].path);
2755 break :blk basename[0 .. basename.len - fs.path.extension(basename).len];
2756 } else if (emit_bin == .yes) {
2757 const basename = fs.path.basename(emit_bin.yes);
2758 break :blk basename[0 .. basename.len - fs.path.extension(basename).len];
2759 } else if (create_module.rc_source_files.items.len >= 1) {
2760 const basename = fs.path.basename(create_module.rc_source_files.items[0].src_path);
2761 break :blk basename[0 .. basename.len - fs.path.extension(basename).len];
2762 } else if (show_builtin) {
2763 break :blk "builtin";
2764 } else if (arg_mode == .run) {
2765 fatal("`zig run` expects at least one positional argument", .{});
2766 // TODO once the attempt to unwrap error: LinkingWithoutZigSourceUnimplemented
2767 // is solved, remove the above fatal() and uncomment the `break` below.
2768 //break :blk "run";
2769 } else {
2770 fatal("expected a positional argument, -femit-bin=[path], --show-builtin, or --name [name]", .{});
28222771 }
2772 };
28232773
2824 if (target.os.tag == .wasi) {
2825 if (wasi_libc.getEmulatedLibCRTFile(lib_name)) |crt_file| {
2826 try wasi_emulated_libs.append(crt_file);
2827 continue;
2774 // Resolve the library path arguments with respect to sysroot.
2775 var lib_dirs: std.ArrayListUnmanaged([]const u8) = .{};
2776 if (sysroot) |root| {
2777 try lib_dirs.ensureUnusedCapacity(arena, lib_dir_args.items.len * 2);
2778 for (lib_dir_args.items) |dir| {
2779 if (fs.path.isAbsolute(dir)) {
2780 const stripped_dir = dir[fs.path.diskDesignator(dir).len..];
2781 const full_path = try fs.path.join(arena, &[_][]const u8{ root, stripped_dir });
2782 lib_dirs.appendAssumeCapacity(full_path);
28282783 }
2784 lib_dirs.appendAssumeCapacity(dir);
28292785 }
2786 } else {
2787 lib_dirs = lib_dir_args;
2788 }
2789 lib_dir_args = undefined; // From here we use lib_dirs instead.
28302790
2831 try external_system_libs.append(arena, .{
2832 .name = lib_name,
2833 .info = info,
2834 });
2791 if (main_mod.resolved_target.is_native_os and target.isDarwin()) {
2792 // If we want to link against frameworks, we need system headers.
2793 if (framework_dirs.items.len > 0 or frameworks.count() > 0)
2794 want_native_include_dirs = true;
28352795 }
2836 // After this point, external_system_libs is used instead of system_libs.
28372796
28382797 // Trigger native system library path detection if necessary.
2839 if (sysroot == null and target_query.isNativeOs() and target_query.isNativeAbi() and
2840 (external_system_libs.len != 0 or want_native_include_dirs))
2798 if (sysroot == null and
2799 main_mod.resolved_target.is_native_os and
2800 main_mod.resolved_target.is_native_abi and
2801 (create_module.external_system_libs.len != 0 or want_native_include_dirs))
28412802 {
28422803 const paths = std.zig.system.NativePaths.detect(arena, target) catch |err| {
28432804 fatal("unable to detect native system paths: {s}", .{@errorName(err)});
......@@ -2846,20 +2807,27 @@ fn buildOutputType(
28462807 warn("{s}", .{warning});
28472808 }
28482809
2849 try clang_argv.ensureUnusedCapacity(paths.include_dirs.items.len * 2);
2810 try clang_argv.ensureUnusedCapacity(arena, paths.include_dirs.items.len * 2);
28502811 for (paths.include_dirs.items) |include_dir| {
28512812 clang_argv.appendAssumeCapacity("-isystem");
28522813 clang_argv.appendAssumeCapacity(include_dir);
28532814 }
28542815
2855 try framework_dirs.appendSlice(paths.framework_dirs.items);
2856 try lib_dirs.appendSlice(paths.lib_dirs.items);
2857 try rpath_list.appendSlice(paths.rpaths.items);
2816 try framework_dirs.appendSlice(arena, paths.framework_dirs.items);
2817 try lib_dirs.appendSlice(arena, paths.lib_dirs.items);
2818 try rpath_list.appendSlice(arena, paths.rpaths.items);
2819 }
2820
2821 var libc_installation: ?LibCInstallation = null;
2822 if (libc_paths_file) |paths_file| {
2823 libc_installation = LibCInstallation.parse(arena, paths_file, target) catch |err| {
2824 fatal("unable to parse libc paths file at path {s}: {s}", .{ paths_file, @errorName(err) });
2825 };
28582826 }
28592827
28602828 if (builtin.target.os.tag == .windows and
28612829 target.abi == .msvc and
2862 external_system_libs.len != 0)
2830 create_module.external_system_libs.len != 0)
28632831 {
28642832 if (libc_installation == null) {
28652833 libc_installation = try LibCInstallation.findNative(.{
......@@ -2868,7 +2836,10 @@ fn buildOutputType(
28682836 .target = target,
28692837 });
28702838
2871 try lib_dirs.appendSlice(&.{ libc_installation.?.msvc_lib_dir.?, libc_installation.?.kernel32_lib_dir.? });
2839 try lib_dirs.appendSlice(arena, &.{
2840 libc_installation.?.msvc_lib_dir.?,
2841 libc_installation.?.kernel32_lib_dir.?,
2842 });
28722843 }
28732844 }
28742845
......@@ -2888,7 +2859,7 @@ fn buildOutputType(
28882859 preferred_mode: std.builtin.LinkMode,
28892860 }).init(arena);
28902861
2891 syslib: for (external_system_libs.items(.name), external_system_libs.items(.info)) |lib_name, info| {
2862 syslib: for (create_module.external_system_libs.items(.name), create_module.external_system_libs.items(.info)) |lib_name, info| {
28922863 // Checked in the first pass above while looking for libc libraries.
28932864 assert(!fs.path.isAbsolute(lib_name));
28942865
......@@ -2908,8 +2879,8 @@ fn buildOutputType(
29082879 )) {
29092880 const path = try arena.dupe(u8, test_path.items);
29102881 switch (info.preferred_mode) {
2911 .Static => try link_objects.append(.{ .path = path }),
2912 .Dynamic => try resolved_system_libs.append(arena, .{
2882 .Static => try link_objects.append(arena, .{ .path = path }),
2883 .Dynamic => try create_module.resolved_system_libs.append(arena, .{
29132884 .name = lib_name,
29142885 .lib = .{
29152886 .needed = info.needed,
......@@ -2942,8 +2913,8 @@ fn buildOutputType(
29422913 )) {
29432914 const path = try arena.dupe(u8, test_path.items);
29442915 switch (info.fallbackMode()) {
2945 .Static => try link_objects.append(.{ .path = path }),
2946 .Dynamic => try resolved_system_libs.append(arena, .{
2916 .Static => try link_objects.append(arena, .{ .path = path }),
2917 .Dynamic => try create_module.resolved_system_libs.append(arena, .{
29472918 .name = lib_name,
29482919 .lib = .{
29492920 .needed = info.needed,
......@@ -2976,8 +2947,8 @@ fn buildOutputType(
29762947 )) {
29772948 const path = try arena.dupe(u8, test_path.items);
29782949 switch (info.preferred_mode) {
2979 .Static => try link_objects.append(.{ .path = path }),
2980 .Dynamic => try resolved_system_libs.append(arena, .{
2950 .Static => try link_objects.append(arena, .{ .path = path }),
2951 .Dynamic => try create_module.resolved_system_libs.append(arena, .{
29812952 .name = lib_name,
29822953 .lib = .{
29832954 .needed = info.needed,
......@@ -3000,8 +2971,8 @@ fn buildOutputType(
30002971 )) {
30012972 const path = try arena.dupe(u8, test_path.items);
30022973 switch (info.fallbackMode()) {
3003 .Static => try link_objects.append(.{ .path = path }),
3004 .Dynamic => try resolved_system_libs.append(arena, .{
2974 .Static => try link_objects.append(arena, .{ .path = path }),
2975 .Dynamic => try create_module.resolved_system_libs.append(arena, .{
30052976 .name = lib_name,
30062977 .lib = .{
30072978 .needed = info.needed,
......@@ -3035,7 +3006,8 @@ fn buildOutputType(
30353006 process.exit(1);
30363007 }
30373008 }
3038 // After this point, resolved_system_libs is used instead of external_system_libs.
3009 // After this point, create_module.resolved_system_libs is used instead of
3010 // create_module.external_system_libs.
30393011
30403012 // We now repeat part of the process for frameworks.
30413013 var resolved_frameworks = std.ArrayList(Compilation.Framework).init(arena);
......@@ -3090,10 +3062,10 @@ fn buildOutputType(
30903062 }
30913063 // After this point, resolved_frameworks is used instead of frameworks.
30923064
3093 if (output_mode == .Obj and (target.ofmt == .coff or target.ofmt == .macho)) {
3094 const total_obj_count = c_source_files.items.len +
3065 if (create_module.opts.output_mode == .Obj and (target.ofmt == .coff or target.ofmt == .macho)) {
3066 const total_obj_count = create_module.c_source_files.items.len +
30953067 @intFromBool(root_src_file != null) +
3096 rc_source_files.items.len +
3068 create_module.rc_source_files.items.len +
30973069 link_objects.items.len;
30983070 if (total_obj_count > 1) {
30993071 fatal("{s} does not support linking multiple objects into one", .{@tagName(target.ofmt)});
......@@ -3141,8 +3113,8 @@ fn buildOutputType(
31413113 .basename = try std.zig.binNameAlloc(arena, .{
31423114 .root_name = root_name,
31433115 .target = target,
3144 .output_mode = output_mode,
3145 .link_mode = link_mode,
3116 .output_mode = create_module.opts.output_mode,
3117 .link_mode = create_module.opts.link_mode,
31463118 .version = optional_version,
31473119 }),
31483120 },
......@@ -3260,9 +3232,9 @@ fn buildOutputType(
32603232 };
32613233 defer emit_docs_resolved.deinit();
32623234
3263 const is_exe_or_dyn_lib = switch (output_mode) {
3235 const is_exe_or_dyn_lib = switch (create_module.opts.output_mode) {
32643236 .Obj => false,
3265 .Lib => (link_mode orelse .Static) == .Dynamic,
3237 .Lib => (create_module.opts.link_mode orelse .Static) == .Dynamic,
32663238 .Exe => true,
32673239 };
32683240 // Note that cmake when targeting Windows will try to execute
......@@ -3294,76 +3266,10 @@ fn buildOutputType(
32943266 };
32953267 defer emit_implib_resolved.deinit();
32963268
3297 const main_mod: ?*Package.Module = if (root_src_file) |unresolved_src_path| blk: {
3298 const src_path = try introspect.resolvePath(arena, unresolved_src_path);
3299 if (main_mod_path) |unresolved_main_mod_path| {
3300 const p = try introspect.resolvePath(arena, unresolved_main_mod_path);
3301 break :blk try Package.Module.create(arena, .{
3302 .root = .{
3303 .root_dir = Cache.Directory.cwd(),
3304 .sub_path = p,
3305 },
3306 .root_src_path = if (p.len == 0)
3307 src_path
3308 else
3309 try fs.path.relative(arena, p, src_path),
3310 .fully_qualified_name = "root",
3311 });
3312 } else {
3313 break :blk try Package.Module.create(arena, .{
3314 .root = .{
3315 .root_dir = Cache.Directory.cwd(),
3316 .sub_path = fs.path.dirname(src_path) orelse "",
3317 },
3318 .root_src_path = fs.path.basename(src_path),
3319 .fully_qualified_name = "root",
3320 });
3321 }
3322 } else null;
3323
3324 // Transfer packages added with --deps to the root package
3325 if (main_mod) |mod| {
3326 var it = ModuleDepIterator.init(root_deps_str orelse "");
3327 while (it.next()) |dep| {
3328 if (dep.expose.len == 0) {
3329 fatal("root module depends on '{s}' with a blank name", .{dep.name});
3330 }
3331
3332 for ([_][]const u8{ "std", "root", "builtin" }) |name| {
3333 if (mem.eql(u8, dep.expose, name)) {
3334 fatal("unable to add module '{s}' under name '{s}': conflicts with builtin module", .{ dep.name, dep.expose });
3335 }
3336 }
3337
3338 const dep_mod = modules.get(dep.name) orelse
3339 fatal("root module depends on module '{s}' which does not exist", .{dep.name});
3340
3341 try mod.deps.put(arena, dep.expose, dep_mod.mod);
3342 }
3343 }
3344
33453269 var thread_pool: ThreadPool = undefined;
33463270 try thread_pool.init(.{ .allocator = gpa });
33473271 defer thread_pool.deinit();
33483272
3349 var global_cache_directory: Compilation.Directory = l: {
3350 if (override_global_cache_dir) |p| {
3351 break :l .{
3352 .handle = try fs.cwd().makeOpenPath(p, .{}),
3353 .path = p,
3354 };
3355 }
3356 if (builtin.os.tag == .wasi) {
3357 break :l getWasiPreopen("/cache");
3358 }
3359 const p = try introspect.resolveGlobalCacheDir(arena);
3360 break :l .{
3361 .handle = try fs.cwd().makeOpenPath(p, .{}),
3362 .path = p,
3363 };
3364 };
3365 defer global_cache_directory.handle.close();
3366
33673273 var cleanup_local_cache_dir: ?fs.Dir = null;
33683274 defer if (cleanup_local_cache_dir) |*dir| dir.close();
33693275
......@@ -3379,37 +3285,37 @@ fn buildOutputType(
33793285 if (arg_mode == .run) {
33803286 break :l global_cache_directory;
33813287 }
3382 if (main_mod != null) {
3383 // search upwards from cwd until we find directory with build.zig
3384 const cwd_path = try process.getCwdAlloc(arena);
3385 const zig_cache = "zig-cache";
3386 var dirname: []const u8 = cwd_path;
3387 while (true) {
3388 const joined_path = try fs.path.join(arena, &.{
3389 dirname, Package.build_zig_basename,
3390 });
3391 if (fs.cwd().access(joined_path, .{})) |_| {
3392 const cache_dir_path = try fs.path.join(arena, &.{ dirname, zig_cache });
3393 const dir = try fs.cwd().makeOpenPath(cache_dir_path, .{});
3394 cleanup_local_cache_dir = dir;
3395 break :l .{ .handle = dir, .path = cache_dir_path };
3396 } else |err| switch (err) {
3397 error.FileNotFound => {
3398 dirname = fs.path.dirname(dirname) orelse {
3399 break :l global_cache_directory;
3400 };
3401 continue;
3402 },
3403 else => break :l global_cache_directory,
3404 }
3288
3289 // search upwards from cwd until we find directory with build.zig
3290 const cwd_path = try process.getCwdAlloc(arena);
3291 const zig_cache = "zig-cache";
3292 var dirname: []const u8 = cwd_path;
3293 while (true) {
3294 const joined_path = try fs.path.join(arena, &.{
3295 dirname, Package.build_zig_basename,
3296 });
3297 if (fs.cwd().access(joined_path, .{})) |_| {
3298 const cache_dir_path = try fs.path.join(arena, &.{ dirname, zig_cache });
3299 const dir = try fs.cwd().makeOpenPath(cache_dir_path, .{});
3300 cleanup_local_cache_dir = dir;
3301 break :l .{ .handle = dir, .path = cache_dir_path };
3302 } else |err| switch (err) {
3303 error.FileNotFound => {
3304 dirname = fs.path.dirname(dirname) orelse {
3305 break :l global_cache_directory;
3306 };
3307 continue;
3308 },
3309 else => break :l global_cache_directory,
34053310 }
34063311 }
3312
34073313 // Otherwise we really don't have a reasonable place to put the local cache directory,
34083314 // so we utilize the global one.
34093315 break :l global_cache_directory;
34103316 };
34113317
3412 for (c_source_files.items) |*src| {
3318 for (create_module.c_source_files.items) |*src| {
34133319 if (!mem.eql(u8, src.src_path, "-")) continue;
34143320
34153321 const ext = src.ext orelse
......@@ -3452,13 +3358,14 @@ fn buildOutputType(
34523358 .zig_lib_directory = zig_lib_directory,
34533359 .local_cache_directory = local_cache_directory,
34543360 .global_cache_directory = global_cache_directory,
3361 .thread_pool = &thread_pool,
3362 .self_exe_path = self_exe_path,
3363 .config = create_module.resolved_options,
34553364 .root_name = root_name,
3456 .target = target,
3457 .is_native_os = target_query.isNativeOs(),
3458 .is_native_abi = target_query.isNativeAbi(),
34593365 .sysroot = sysroot,
3460 .output_mode = output_mode,
34613366 .main_mod = main_mod,
3367 .root_mod = root_mod,
3368 .std_mod = std_mod,
34623369 .emit_bin = emit_bin_loc,
34633370 .emit_h = emit_h_resolved.data,
34643371 .emit_asm = emit_asm_resolved.data,
......@@ -3466,43 +3373,22 @@ fn buildOutputType(
34663373 .emit_llvm_bc = emit_llvm_bc_resolved.data,
34673374 .emit_docs = emit_docs_resolved.data,
34683375 .emit_implib = emit_implib_resolved.data,
3469 .link_mode = link_mode,
34703376 .dll_export_fns = dll_export_fns,
3471 .optimize_mode = optimize_mode,
34723377 .keep_source_files_loaded = false,
3473 .clang_argv = clang_argv.items,
34743378 .lib_dirs = lib_dirs.items,
34753379 .rpath_list = rpath_list.items,
34763380 .symbol_wrap_set = symbol_wrap_set,
3477 .c_source_files = c_source_files.items,
3478 .rc_source_files = rc_source_files.items,
3381 .c_source_files = create_module.c_source_files.items,
3382 .rc_source_files = create_module.rc_source_files.items,
34793383 .manifest_file = manifest_file,
34803384 .rc_includes = rc_includes,
34813385 .link_objects = link_objects.items,
34823386 .framework_dirs = framework_dirs.items,
34833387 .frameworks = resolved_frameworks.items,
3484 .system_lib_names = resolved_system_libs.items(.name),
3485 .system_lib_infos = resolved_system_libs.items(.lib),
3486 .wasi_emulated_libs = wasi_emulated_libs.items,
3487 .link_libc = link_libc,
3488 .link_libcpp = link_libcpp,
3489 .link_libunwind = link_libunwind,
3490 .want_pic = want_pic,
3491 .want_pie = want_pie,
3492 .want_lto = want_lto,
3493 .want_unwind_tables = want_unwind_tables,
3494 .want_sanitize_c = want_sanitize_c,
3495 .want_stack_check = want_stack_check,
3496 .want_stack_protector = want_stack_protector,
3497 .want_red_zone = want_red_zone,
3498 .omit_frame_pointer = omit_frame_pointer,
3499 .want_valgrind = want_valgrind,
3500 .want_tsan = want_tsan,
3388 .system_lib_names = create_module.resolved_system_libs.items(.name),
3389 .system_lib_infos = create_module.resolved_system_libs.items(.lib),
3390 .wasi_emulated_libs = create_module.wasi_emulated_libs.items,
35013391 .want_compiler_rt = want_compiler_rt,
3502 .use_llvm = use_llvm,
3503 .use_lib_llvm = use_lib_llvm,
3504 .use_lld = use_lld,
3505 .use_clang = use_clang,
35063392 .hash_style = hash_style,
35073393 .rdynamic = rdynamic,
35083394 .linker_script = linker_script,
......@@ -3513,14 +3399,11 @@ fn buildOutputType(
35133399 .linker_gc_sections = linker_gc_sections,
35143400 .linker_allow_shlib_undefined = linker_allow_shlib_undefined,
35153401 .linker_bind_global_refs_locally = linker_bind_global_refs_locally,
3516 .linker_import_memory = linker_import_memory,
3517 .linker_export_memory = linker_export_memory,
35183402 .linker_import_symbols = linker_import_symbols,
35193403 .linker_import_table = linker_import_table,
35203404 .linker_export_table = linker_export_table,
35213405 .linker_initial_memory = linker_initial_memory,
35223406 .linker_max_memory = linker_max_memory,
3523 .linker_shared_memory = linker_shared_memory,
35243407 .linker_print_gc_sections = linker_print_gc_sections,
35253408 .linker_print_icf_sections = linker_print_icf_sections,
35263409 .linker_print_map = linker_print_map,
......@@ -3546,18 +3429,13 @@ fn buildOutputType(
35463429 .minor_subsystem_version = minor_subsystem_version,
35473430 .link_eh_frame_hdr = link_eh_frame_hdr,
35483431 .link_emit_relocs = link_emit_relocs,
3549 .entry = entry,
35503432 .force_undefined_symbols = force_undefined_symbols,
35513433 .stack_size_override = stack_size_override,
35523434 .image_base_override = image_base_override,
3553 .strip = strip,
35543435 .formatted_panics = formatted_panics,
3555 .single_threaded = single_threaded,
35563436 .function_sections = function_sections,
35573437 .data_sections = data_sections,
35583438 .no_builtin = no_builtin,
3559 .self_exe_path = self_exe_path,
3560 .thread_pool = &thread_pool,
35613439 .clang_passthrough_mode = clang_passthrough_mode,
35623440 .clang_preprocessor_mode = clang_preprocessor_mode,
35633441 .version = optional_version,
......@@ -3571,21 +3449,17 @@ fn buildOutputType(
35713449 .verbose_llvm_bc = verbose_llvm_bc,
35723450 .verbose_cimport = verbose_cimport,
35733451 .verbose_llvm_cpu_features = verbose_llvm_cpu_features,
3574 .machine_code_model = machine_code_model,
35753452 .color = color,
35763453 .time_report = time_report,
35773454 .stack_report = stack_report,
3578 .is_test = arg_mode == .zig_test,
35793455 .each_lib_rpath = each_lib_rpath,
35803456 .build_id = build_id,
3581 .test_evented_io = test_evented_io,
35823457 .test_filter = test_filter,
35833458 .test_name_prefix = test_name_prefix,
35843459 .test_runner_path = test_runner_path,
35853460 .disable_lld_caching = !output_to_cache,
35863461 .subsystem = subsystem,
35873462 .dwarf_format = dwarf_format,
3588 .wasi_exec_model = wasi_exec_model,
35893463 .debug_compile_errors = debug_compile_errors,
35903464 .enable_link_snapshots = enable_link_snapshots,
35913465 .install_name = install_name,
......@@ -3595,7 +3469,6 @@ fn buildOutputType(
35953469 .headerpad_max_install_names = headerpad_max_install_names,
35963470 .dead_strip_dylibs = dead_strip_dylibs,
35973471 .reference_trace = reference_trace,
3598 .error_tracing = error_tracing,
35993472 .pdb_out_path = pdb_out_path,
36003473 .error_limit = error_limit,
36013474 .want_structured_cfg = want_structured_cfg,
......@@ -3702,7 +3575,7 @@ fn buildOutputType(
37023575 try test_exec_args.appendSlice(&.{ "-I", p });
37033576 }
37043577
3705 if (link_libc) {
3578 if (create_module.resolved_options.link_libc) {
37063579 try test_exec_args.append("-lc");
37073580 } else if (target.os.tag == .windows) {
37083581 try test_exec_args.appendSlice(&.{
......@@ -3711,14 +3584,15 @@ fn buildOutputType(
37113584 });
37123585 }
37133586
3714 if (!mem.eql(u8, target_arch_os_abi, "native")) {
3587 const first_cli_mod = create_module.modules.values()[0];
3588 if (first_cli_mod.target_arch_os_abi) |triple| {
37153589 try test_exec_args.append("-target");
3716 try test_exec_args.append(target_arch_os_abi);
3590 try test_exec_args.append(triple);
37173591 }
3718 if (target_mcpu) |mcpu| {
3592 if (first_cli_mod.target_mcpu) |mcpu| {
37193593 try test_exec_args.append(try std.fmt.allocPrint(arena, "-mcpu={s}", .{mcpu}));
37203594 }
3721 if (target_dynamic_linker) |dl| {
3595 if (create_module.dynamic_linker) |dl| {
37223596 try test_exec_args.append("--dynamic-linker");
37233597 try test_exec_args.append(dl);
37243598 }
......@@ -3742,7 +3616,7 @@ fn buildOutputType(
37423616 &comp_destroyed,
37433617 all_args,
37443618 runtime_args_start,
3745 link_libc,
3619 create_module.resolved_options.link_libc,
37463620 );
37473621 }
37483622
......@@ -3750,6 +3624,243 @@ fn buildOutputType(
37503624 return cleanExit();
37513625}
37523626
3627const CreateModule = struct {
3628 global_cache_directory: Cache.Directory,
3629 modules: std.StringArrayHashMapUnmanaged(CliModule),
3630 opts: Compilation.Config.Options,
3631 dynamic_linker: ?[]const u8,
3632 object_format: ?[]const u8,
3633 /// undefined until createModule() for the root module is called.
3634 resolved_options: Compilation.Config,
3635
3636 /// This one is used while collecting CLI options. The set of libs is used
3637 /// directly after computing the target and used to compute link_libc,
3638 /// link_libcpp, and then the libraries are filtered into
3639 /// `external_system_libs` and `resolved_system_libs`.
3640 system_libs: std.StringArrayHashMapUnmanaged(SystemLib),
3641 external_system_libs: std.MultiArrayList(struct {
3642 name: []const u8,
3643 info: SystemLib,
3644 }),
3645 resolved_system_libs: std.MultiArrayList(struct {
3646 name: []const u8,
3647 lib: Compilation.SystemLib,
3648 }),
3649 wasi_emulated_libs: std.ArrayListUnmanaged(wasi_libc.CRTFile),
3650
3651 c_source_files: std.ArrayListUnmanaged(Compilation.CSourceFile),
3652 rc_source_files: std.ArrayListUnmanaged(Compilation.RcSourceFile),
3653
3654 // e.g. -m3dnow or -mno-outline-atomics. They correspond to std.Target llvm cpu feature names.
3655 // This array is populated by zig cc frontend and then has to be converted to zig-style
3656 // CPU features.
3657 llvm_m_args: std.ArrayListUnmanaged([]const u8),
3658};
3659
3660fn createModule(
3661 gpa: Allocator,
3662 arena: Allocator,
3663 create_module: *CreateModule,
3664 index: usize,
3665 parent: ?*Package.Module,
3666 zig_lib_directory: Cache.Directory,
3667) Allocator.Error!*Package.Module {
3668 const cli_mod = &create_module.modules.values()[index];
3669 if (cli_mod.resolved) |m| return m;
3670
3671 const name = create_module.modules.keys()[index];
3672
3673 cli_mod.inherited.resolved_target = t: {
3674 // If the target is not overridden, use the parent's target. Of course,
3675 // if this is the root module then we need to proceed to resolve the
3676 // target.
3677 if (cli_mod.target_arch_os_abi == null and
3678 cli_mod.target_mcpu == null and
3679 create_module.dynamic_linker == null and
3680 create_module.object_format == null)
3681 {
3682 if (parent) |p| break :t p.resolved_target;
3683 }
3684
3685 var target_parse_options: std.Target.Query.ParseOptions = .{
3686 .arch_os_abi = cli_mod.target_arch_os_abi orelse "native",
3687 .cpu_features = cli_mod.target_mcpu,
3688 .dynamic_linker = create_module.dynamic_linker,
3689 .object_format = create_module.object_format,
3690 };
3691
3692 // Before passing the mcpu string in for parsing, we convert any -m flags that were
3693 // passed in via zig cc to zig-style.
3694 if (create_module.llvm_m_args.items.len != 0) {
3695 // If this returns null, we let it fall through to the case below which will
3696 // run the full parse function and do proper error handling.
3697 if (std.Target.Query.parseCpuArch(target_parse_options)) |cpu_arch| {
3698 var llvm_to_zig_name = std.StringHashMap([]const u8).init(gpa);
3699 defer llvm_to_zig_name.deinit();
3700
3701 for (cpu_arch.allFeaturesList()) |feature| {
3702 const llvm_name = feature.llvm_name orelse continue;
3703 try llvm_to_zig_name.put(llvm_name, feature.name);
3704 }
3705
3706 var mcpu_buffer = std.ArrayList(u8).init(gpa);
3707 defer mcpu_buffer.deinit();
3708
3709 try mcpu_buffer.appendSlice(cli_mod.target_mcpu orelse "baseline");
3710
3711 for (create_module.llvm_m_args.items) |llvm_m_arg| {
3712 if (mem.startsWith(u8, llvm_m_arg, "mno-")) {
3713 const llvm_name = llvm_m_arg["mno-".len..];
3714 const zig_name = llvm_to_zig_name.get(llvm_name) orelse {
3715 fatal("target architecture {s} has no LLVM CPU feature named '{s}'", .{
3716 @tagName(cpu_arch), llvm_name,
3717 });
3718 };
3719 try mcpu_buffer.append('-');
3720 try mcpu_buffer.appendSlice(zig_name);
3721 } else if (mem.startsWith(u8, llvm_m_arg, "m")) {
3722 const llvm_name = llvm_m_arg["m".len..];
3723 const zig_name = llvm_to_zig_name.get(llvm_name) orelse {
3724 fatal("target architecture {s} has no LLVM CPU feature named '{s}'", .{
3725 @tagName(cpu_arch), llvm_name,
3726 });
3727 };
3728 try mcpu_buffer.append('+');
3729 try mcpu_buffer.appendSlice(zig_name);
3730 } else {
3731 unreachable;
3732 }
3733 }
3734
3735 const adjusted_target_mcpu = try arena.dupe(u8, mcpu_buffer.items);
3736 std.log.debug("adjusted target_mcpu: {s}", .{adjusted_target_mcpu});
3737 target_parse_options.cpu_features = adjusted_target_mcpu;
3738 }
3739 }
3740
3741 const target_query = parseTargetQueryOrReportFatalError(arena, target_parse_options);
3742 const target = resolveTargetQueryOrFatal(target_query);
3743 break :t .{
3744 .result = target,
3745 .is_native_os = target_query.isNativeOs(),
3746 .is_native_abi = target_query.isNativeAbi(),
3747 };
3748 };
3749
3750 if (parent == null) {
3751 // This block is for initializing the fields of
3752 // `Compilation.Config.Options` that require knowledge of the
3753 // target (which was just now resolved for the root module above).
3754 const resolved_target = cli_mod.inherited.resolved_target.?;
3755 create_module.opts.resolved_target = resolved_target;
3756 create_module.opts.root_optimize_mode = cli_mod.inherited.optimize_mode;
3757 const target = resolved_target.result;
3758
3759 // First, remove libc, libc++, and compiler_rt libraries from the system libraries list.
3760 // We need to know whether the set of system libraries contains anything besides these
3761 // to decide whether to trigger native path detection logic.
3762 for (create_module.system_libs.keys(), create_module.system_libs.values()) |lib_name, info| {
3763 if (target.is_libc_lib_name(lib_name)) {
3764 create_module.opts.link_libc = true;
3765 continue;
3766 }
3767 if (target.is_libcpp_lib_name(lib_name)) {
3768 create_module.opts.link_libcpp = true;
3769 continue;
3770 }
3771 switch (target_util.classifyCompilerRtLibName(target, lib_name)) {
3772 .none => {},
3773 .only_libunwind, .both => {
3774 create_module.opts.link_libunwind = true;
3775 continue;
3776 },
3777 .only_compiler_rt => {
3778 warn("ignoring superfluous library '{s}': this dependency is fulfilled instead by compiler-rt which zig unconditionally provides", .{lib_name});
3779 continue;
3780 },
3781 }
3782
3783 if (target.isMinGW()) {
3784 const exists = mingw.libExists(arena, target, zig_lib_directory, lib_name) catch |err| {
3785 fatal("failed to check zig installation for DLL import libs: {s}", .{
3786 @errorName(err),
3787 });
3788 };
3789 if (exists) {
3790 try create_module.resolved_system_libs.append(arena, .{
3791 .name = lib_name,
3792 .lib = .{
3793 .needed = true,
3794 .weak = false,
3795 .path = null,
3796 },
3797 });
3798 continue;
3799 }
3800 }
3801
3802 if (fs.path.isAbsolute(lib_name)) {
3803 fatal("cannot use absolute path as a system library: {s}", .{lib_name});
3804 }
3805
3806 if (target.os.tag == .wasi) {
3807 if (wasi_libc.getEmulatedLibCRTFile(lib_name)) |crt_file| {
3808 try create_module.wasi_emulated_libs.append(arena, crt_file);
3809 continue;
3810 }
3811 }
3812
3813 try create_module.external_system_libs.append(arena, .{
3814 .name = lib_name,
3815 .info = info,
3816 });
3817 }
3818 // After this point, external_system_libs is used instead of system_libs.
3819
3820 create_module.resolved_options = Compilation.Config.resolve(create_module.opts) catch |err| switch (err) {
3821 else => fatal("unable to resolve compilation options: {s}", .{@errorName(err)}),
3822 };
3823 }
3824
3825 const mod = Package.Module.create(arena, .{
3826 .global_cache_directory = create_module.global_cache_directory,
3827 .paths = cli_mod.paths,
3828 .fully_qualified_name = name,
3829
3830 .cc_argv = cli_mod.cc_argv,
3831 .inherited = cli_mod.inherited,
3832 .global = create_module.resolved_options,
3833 .parent = parent,
3834 .builtin_mod = null,
3835 }) catch |err| switch (err) {
3836 error.ValgrindUnsupportedOnTarget => fatal("unable to create module '{s}': valgrind does not support the selected target CPU architecture", .{name}),
3837 error.TargetRequiresSingleThreaded => fatal("unable to create module '{s}': the selected target does not support multithreading", .{name}),
3838 error.BackendRequiresSingleThreaded => fatal("unable to create module '{s}': the selected machine code backend is limited to single-threaded applications", .{name}),
3839 error.TargetRequiresPic => fatal("unable to create module '{s}': the selected target requires position independent code", .{name}),
3840 error.PieRequiresPic => fatal("unable to create module '{s}': making a Position Independent Executable requires enabling Position Independent Code", .{name}),
3841 error.DynamicLinkingRequiresPic => fatal("unable to create module '{s}': dynamic linking requires enabling Position Independent Code", .{name}),
3842 error.TargetHasNoRedZone => fatal("unable to create module '{s}': the selected target does not have a red zone", .{name}),
3843 error.StackCheckUnsupportedByTarget => fatal("unable to create module '{s}': the selected target does not support stack checking", .{name}),
3844 error.StackProtectorUnsupportedByTarget => fatal("unable to create module '{s}': the selected target does not support stack protection", .{name}),
3845 error.StackProtectorUnavailableWithoutLibC => fatal("unable to create module '{s}': enabling stack protection requires libc", .{name}),
3846 error.OutOfMemory => return error.OutOfMemory,
3847 };
3848 cli_mod.resolved = mod;
3849
3850 for (create_module.c_source_files.items[cli_mod.c_source_files_start..cli_mod.c_source_files_end]) |*item| item.owner = mod;
3851
3852 for (create_module.rc_source_files.items[cli_mod.rc_source_files_start..cli_mod.rc_source_files_end]) |*item| item.owner = mod;
3853
3854 for (cli_mod.deps) |dep| {
3855 const dep_index = create_module.modules.getIndex(dep.key) orelse
3856 fatal("module '{s}' depends on non-existent module '{s}'", .{ name, dep.key });
3857 const dep_mod = try createModule(gpa, arena, create_module, dep_index, mod, zig_lib_directory);
3858 try mod.deps.put(arena, dep.key, dep_mod);
3859 }
3860
3861 return mod;
3862}
3863
37533864fn saveState(comp: *Compilation, debug_incremental: bool) void {
37543865 if (debug_incremental) {
37553866 comp.saveState() catch |err| {
......@@ -3984,36 +4095,10 @@ fn serveUpdateResults(s: *Server, comp: *Compilation) !void {
39844095 }
39854096}
39864097
3987const ModuleDepIterator = struct {
3988 split: mem.SplitIterator(u8, .scalar),
3989
3990 fn init(deps_str: []const u8) ModuleDepIterator {
3991 return .{ .split = mem.splitScalar(u8, deps_str, ',') };
3992 }
3993
3994 const Dependency = struct {
3995 expose: []const u8,
3996 name: []const u8,
3997 };
3998
3999 fn next(it: *ModuleDepIterator) ?Dependency {
4000 if (it.split.buffer.len == 0) return null; // don't return "" for the first iteration on ""
4001 const str = it.split.next() orelse return null;
4002 if (mem.indexOfScalar(u8, str, '=')) |i| {
4003 return .{
4004 .expose = str[0..i],
4005 .name = str[i + 1 ..],
4006 };
4007 } else {
4008 return .{ .expose = str, .name = str };
4009 }
4010 }
4011};
4012
40134098fn parseTargetQueryOrReportFatalError(
40144099 allocator: Allocator,
40154100 opts: std.Target.Query.ParseOptions,
4016) !std.Target.Query {
4101) std.Target.Query {
40174102 var opts_with_diags = opts;
40184103 var diags: std.Target.Query.ParseOptions.Diagnostics = .{};
40194104 if (opts_with_diags.diagnostics == null) {
......@@ -4057,7 +4142,9 @@ fn parseTargetQueryOrReportFatalError(
40574142 }
40584143 fatal("unknown object format: '{s}'", .{opts.object_format.?});
40594144 },
4060 else => |e| return e,
4145 else => |e| fatal("unable to parse target query '{s}': {s}", .{
4146 opts.arch_os_abi, @errorName(e),
4147 }),
40614148 };
40624149}
40634150
......@@ -4667,7 +4754,7 @@ fn detectRcIncludeDirs(arena: Allocator, zig_lib_dir: []const u8, auto_includes:
46674754 .os_tag = .windows,
46684755 .abi = .msvc,
46694756 };
4670 const target = try std.zig.system.resolveTargetQuery(target_query);
4757 const target = resolveTargetQueryOrFatal(target_query);
46714758 const is_native_abi = target_query.isNativeAbi();
46724759 const detected_libc = Compilation.detectLibCIncludeDirs(arena, zig_lib_dir, target, is_native_abi, true, null) catch |err| {
46734760 if (cur_includes == .any) {
......@@ -4695,7 +4782,7 @@ fn detectRcIncludeDirs(arena: Allocator, zig_lib_dir: []const u8, auto_includes:
46954782 .os_tag = .windows,
46964783 .abi = .gnu,
46974784 };
4698 const target = try std.zig.system.resolveTargetQuery(target_query);
4785 const target = resolveTargetQueryOrFatal(target_query);
46994786 const is_native_abi = target_query.isNativeAbi();
47004787 const detected_libc = try Compilation.detectLibCIncludeDirs(arena, zig_lib_dir, target, is_native_abi, true, null);
47014788 return .{
......@@ -4757,10 +4844,10 @@ pub fn cmdLibC(gpa: Allocator, args: []const []const u8) !void {
47574844 }
47584845 }
47594846
4760 const target_query = try parseTargetQueryOrReportFatalError(gpa, .{
4847 const target_query = parseTargetQueryOrReportFatalError(gpa, .{
47614848 .arch_os_abi = target_arch_os_abi,
47624849 });
4763 const target = try std.zig.system.resolveTargetQuery(target_query);
4850 const target = resolveTargetQueryOrFatal(target_query);
47644851
47654852 if (print_includes) {
47664853 var arena_state = std.heap.ArenaAllocator.init(gpa);
......@@ -5024,7 +5111,7 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
50245111 if (!build_options.enable_logging) {
50255112 warn("Zig was compiled without logging enabled (-Dlog). --debug-log has no effect.", .{});
50265113 } else {
5027 try log_scopes.append(gpa, args[i]);
5114 try log_scopes.append(arena, args[i]);
50285115 }
50295116 continue;
50305117 } else if (mem.eql(u8, arg, "--debug-compile-errors")) {
......@@ -5115,7 +5202,7 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
51155202 gimmeMoreOfThoseSweetSweetFileDescriptors();
51165203
51175204 const target_query: std.Target.Query = .{};
5118 const target = try std.zig.system.resolveTargetQuery(target_query);
5205 const target = resolveTargetQueryOrFatal(target_query);
51195206
51205207 const exe_basename = try std.zig.binNameAlloc(arena, .{
51215208 .root_name = "build",
......@@ -5130,29 +5217,80 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
51305217 try thread_pool.init(.{ .allocator = gpa });
51315218 defer thread_pool.deinit();
51325219
5133 var main_mod: Package.Module = if (override_build_runner) |build_runner_path|
5134 .{
5220 const main_mod_paths: Package.Module.CreateOptions.Paths = if (override_build_runner) |runner| .{
5221 .root = .{
5222 .root_dir = Cache.Directory.cwd(),
5223 .sub_path = fs.path.dirname(runner) orelse "",
5224 },
5225 .root_src_path = fs.path.basename(runner),
5226 } else .{
5227 .root = .{ .root_dir = zig_lib_directory },
5228 .root_src_path = "build_runner.zig",
5229 };
5230
5231 const config = try Compilation.Config.resolve(.{
5232 .output_mode = .Exe,
5233 .resolved_target = .{
5234 .result = target,
5235 .is_native_os = true,
5236 .is_native_abi = true,
5237 },
5238 .have_zcu = true,
5239 .emit_bin = true,
5240 .is_test = false,
5241 });
5242
5243 const root_mod = try Package.Module.create(arena, .{
5244 .global_cache_directory = global_cache_directory,
5245 .paths = main_mod_paths,
5246 .fully_qualified_name = "root",
5247 .cc_argv = &.{},
5248 .inherited = .{},
5249 .global = config,
5250 .parent = null,
5251 .builtin_mod = null,
5252 });
5253
5254 const builtin_mod = root_mod.getBuiltinDependency();
5255 const std_mod = try Package.Module.create(arena, .{
5256 .global_cache_directory = global_cache_directory,
5257 .paths = .{
51355258 .root = .{
5136 .root_dir = Cache.Directory.cwd(),
5137 .sub_path = fs.path.dirname(build_runner_path) orelse "",
5259 .root_dir = zig_lib_directory,
5260 .sub_path = "std",
51385261 },
5139 .root_src_path = fs.path.basename(build_runner_path),
5140 .fully_qualified_name = "root",
5141 }
5142 else
5143 .{
5144 .root = .{ .root_dir = zig_lib_directory },
5145 .root_src_path = "build_runner.zig",
5146 .fully_qualified_name = "root",
5147 };
5262 .root_src_path = "std.zig",
5263 },
5264 .fully_qualified_name = "std",
5265 .cc_argv = &.{},
5266 .inherited = .{},
5267 .global = config,
5268 .parent = root_mod,
5269 .builtin_mod = builtin_mod,
5270 });
51485271
5149 var build_mod: Package.Module = .{
5150 .root = .{ .root_dir = build_root.directory },
5151 .root_src_path = build_root.build_zig_basename,
5272 const build_mod = try Package.Module.create(arena, .{
5273 .global_cache_directory = global_cache_directory,
5274 .paths = .{
5275 .root = .{ .root_dir = build_root.directory },
5276 .root_src_path = build_root.build_zig_basename,
5277 },
51525278 .fully_qualified_name = "root.@build",
5153 };
5279 .cc_argv = &.{},
5280 .inherited = .{},
5281 .global = config,
5282 .parent = root_mod,
5283 .builtin_mod = builtin_mod,
5284 });
51545285 if (build_options.only_core_functionality) {
5155 try createEmptyDependenciesModule(arena, &main_mod, local_cache_directory);
5286 try createEmptyDependenciesModule(
5287 arena,
5288 root_mod,
5289 global_cache_directory,
5290 local_cache_directory,
5291 builtin_mod,
5292 config,
5293 );
51565294 } else {
51575295 var http_client: std.http.Client = .{ .allocator = gpa };
51585296 defer http_client.deinit();
......@@ -5196,7 +5334,7 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
51965334 .has_build_zig = true,
51975335 .oom_flag = false,
51985336
5199 .module = &build_mod,
5337 .module = build_mod,
52005338 };
52015339 job_queue.all_fetches.appendAssumeCapacity(&fetch);
52025340
......@@ -5225,8 +5363,11 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
52255363 const deps_mod = try createDependenciesModule(
52265364 arena,
52275365 source_buf.items,
5228 &main_mod,
5366 root_mod,
5367 global_cache_directory,
52295368 local_cache_directory,
5369 builtin_mod,
5370 config,
52305371 );
52315372
52325373 {
......@@ -5242,13 +5383,21 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
52425383 if (!f.has_build_zig)
52435384 continue;
52445385 const m = try Package.Module.create(arena, .{
5245 .root = try f.package_root.clone(arena),
5246 .root_src_path = Package.build_zig_basename,
5386 .global_cache_directory = global_cache_directory,
5387 .paths = .{
5388 .root = try f.package_root.clone(arena),
5389 .root_src_path = Package.build_zig_basename,
5390 },
52475391 .fully_qualified_name = try std.fmt.allocPrint(
52485392 arena,
52495393 "root.@dependencies.{s}",
52505394 .{&hash},
52515395 ),
5396 .cc_argv = &.{},
5397 .inherited = .{},
5398 .global = config,
5399 .parent = root_mod,
5400 .builtin_mod = builtin_mod,
52525401 });
52535402 const hash_cloned = try arena.dupe(u8, &hash);
52545403 deps_mod.deps.putAssumeCapacityNoClobber(hash_cloned, m);
......@@ -5276,21 +5425,19 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
52765425 }
52775426 }
52785427
5279 try main_mod.deps.put(arena, "@build", &build_mod);
5428 try root_mod.deps.put(arena, "@build", build_mod);
52805429
52815430 const comp = Compilation.create(gpa, .{
52825431 .zig_lib_directory = zig_lib_directory,
52835432 .local_cache_directory = local_cache_directory,
52845433 .global_cache_directory = global_cache_directory,
52855434 .root_name = "build",
5286 .target = target,
5287 .is_native_os = target_query.isNativeOs(),
5288 .is_native_abi = target_query.isNativeAbi(),
5289 .output_mode = .Exe,
5290 .main_mod = &main_mod,
5435 .config = config,
5436 .root_mod = root_mod,
5437 .main_mod = build_mod,
5438 .std_mod = std_mod,
52915439 .emit_bin = emit_bin,
52925440 .emit_h = null,
5293 .optimize_mode = .Debug,
52945441 .self_exe_path = self_exe_path,
52955442 .thread_pool = &thread_pool,
52965443 .verbose_cc = verbose_cc,
......@@ -5514,7 +5661,7 @@ pub fn cmdFmt(gpa: Allocator, arena: Allocator, args: []const []const u8) !void
55145661 .root_decl = .none,
55155662 };
55165663
5517 file.mod = try Package.Module.create(arena, .{
5664 file.mod = try Package.Module.createLimited(arena, .{
55185665 .root = Package.Path.cwd(),
55195666 .root_src_path = file.sub_file_path,
55205667 .fully_qualified_name = "root",
......@@ -5724,7 +5871,7 @@ fn fmtPathFile(
57245871 .root_decl = .none,
57255872 };
57265873
5727 file.mod = try Package.Module.create(fmt.arena, .{
5874 file.mod = try Package.Module.createLimited(fmt.arena, .{
57285875 .root = Package.Path.cwd(),
57295876 .root_src_path = file.sub_file_path,
57305877 .fully_qualified_name = "root",
......@@ -5804,15 +5951,13 @@ pub fn putAstErrorsIntoBundle(
58045951 .tree = tree,
58055952 .tree_loaded = true,
58065953 .zir = undefined,
5807 .mod = undefined,
5954 .mod = try Package.Module.createLimited(gpa, .{
5955 .root = Package.Path.cwd(),
5956 .root_src_path = path,
5957 .fully_qualified_name = "root",
5958 }),
58085959 .root_decl = .none,
58095960 };
5810
5811 file.mod = try Package.Module.create(gpa, .{
5812 .root = Package.Path.cwd(),
5813 .root_src_path = file.sub_file_path,
5814 .fully_qualified_name = "root",
5815 });
58165961 defer gpa.destroy(file.mod);
58175962
58185963 file.zir = try AstGen.generate(gpa, file.tree);
......@@ -6373,7 +6518,7 @@ pub fn cmdAstCheck(
63736518 file.stat.size = source.len;
63746519 }
63756520
6376 file.mod = try Package.Module.create(arena, .{
6521 file.mod = try Package.Module.createLimited(arena, .{
63776522 .root = Package.Path.cwd(),
63786523 .root_src_path = file.sub_file_path,
63796524 .fully_qualified_name = "root",
......@@ -6546,7 +6691,7 @@ pub fn cmdChangelist(
65466691 .root_decl = .none,
65476692 };
65486693
6549 file.mod = try Package.Module.create(arena, .{
6694 file.mod = try Package.Module.createLimited(arena, .{
65506695 .root = Package.Path.cwd(),
65516696 .root_src_path = file.sub_file_path,
65526697 .fully_qualified_name = "root",
......@@ -6669,7 +6814,7 @@ fn warnAboutForeignBinaries(
66696814 link_libc: bool,
66706815) !void {
66716816 const host_query: std.Target.Query = .{};
6672 const host_target = try std.zig.system.resolveTargetQuery(host_query);
6817 const host_target = resolveTargetQueryOrFatal(host_query);
66736818
66746819 switch (std.zig.system.getExternalExecutor(host_target, target, .{ .link_libc = link_libc })) {
66756820 .native => return,
......@@ -6809,18 +6954,22 @@ fn parseSubSystem(next_arg: []const u8) !std.Target.SubSystem {
68096954/// Silently ignore superfluous search dirs.
68106955/// Warn when a dir is added to multiple searchlists.
68116956const ClangSearchSanitizer = struct {
6812 argv: *std.ArrayList([]const u8),
6813 map: std.StringHashMap(Membership),
6957 map: std.StringHashMapUnmanaged(Membership) = .{},
68146958
6815 fn init(gpa: Allocator, argv: *std.ArrayList([]const u8)) @This() {
6816 return .{
6817 .argv = argv,
6818 .map = std.StringHashMap(Membership).init(gpa),
6819 };
6959 fn reset(self: *@This()) void {
6960 self.map.clearRetainingCapacity();
68206961 }
68216962
6822 fn addIncludePath(self: *@This(), group: Group, arg: []const u8, dir: []const u8, joined: bool) !void {
6823 const gopr = try self.map.getOrPut(dir);
6963 fn addIncludePath(
6964 self: *@This(),
6965 ally: Allocator,
6966 argv: *std.ArrayListUnmanaged([]const u8),
6967 group: Group,
6968 arg: []const u8,
6969 dir: []const u8,
6970 joined: bool,
6971 ) !void {
6972 const gopr = try self.map.getOrPut(ally, dir);
68246973 const m = gopr.value_ptr;
68256974 if (!gopr.found_existing) {
68266975 // init empty membership
......@@ -6867,8 +7016,9 @@ const ClangSearchSanitizer = struct {
68677016 if (m.iwithsysroot) warn(wtxt, .{ dir, "iframeworkwithsysroot", "iwithsysroot" });
68687017 },
68697018 }
6870 try self.argv.append(arg);
6871 if (!joined) try self.argv.append(dir);
7019 try argv.ensureUnusedCapacity(ally, 2);
7020 argv.appendAssumeCapacity(arg);
7021 if (!joined) argv.appendAssumeCapacity(dir);
68727022 }
68737023
68747024 const Group = enum { I, isystem, iwithsysroot, idirafter, iframework, iframeworkwithsysroot };
......@@ -7244,11 +7394,22 @@ fn cmdFetch(
72447394fn createEmptyDependenciesModule(
72457395 arena: Allocator,
72467396 main_mod: *Package.Module,
7397 global_cache_directory: Cache.Directory,
72477398 local_cache_directory: Cache.Directory,
7399 builtin_mod: *Package.Module,
7400 global_options: Compilation.Config,
72487401) !void {
72497402 var source = std.ArrayList(u8).init(arena);
72507403 try Package.Fetch.JobQueue.createEmptyDependenciesSource(&source);
7251 _ = try createDependenciesModule(arena, source.items, main_mod, local_cache_directory);
7404 _ = try createDependenciesModule(
7405 arena,
7406 source.items,
7407 main_mod,
7408 global_cache_directory,
7409 local_cache_directory,
7410 builtin_mod,
7411 global_options,
7412 );
72527413}
72537414
72547415/// Creates the dependencies.zig file and corresponding `Package.Module` for the
......@@ -7257,7 +7418,10 @@ fn createDependenciesModule(
72577418 arena: Allocator,
72587419 source: []const u8,
72597420 main_mod: *Package.Module,
7421 global_cache_directory: Cache.Directory,
72607422 local_cache_directory: Cache.Directory,
7423 builtin_mod: *Package.Module,
7424 global_options: Compilation.Config,
72617425) !*Package.Module {
72627426 // Atomically create the file in a directory named after the hash of its contents.
72637427 const basename = "dependencies.zig";
......@@ -7283,25 +7447,25 @@ fn createDependenciesModule(
72837447 );
72847448
72857449 const deps_mod = try Package.Module.create(arena, .{
7286 .root = .{
7287 .root_dir = local_cache_directory,
7288 .sub_path = o_dir_sub_path,
7450 .global_cache_directory = global_cache_directory,
7451 .paths = .{
7452 .root = .{
7453 .root_dir = local_cache_directory,
7454 .sub_path = o_dir_sub_path,
7455 },
7456 .root_src_path = basename,
72897457 },
7290 .root_src_path = basename,
72917458 .fully_qualified_name = "root.@dependencies",
7459 .parent = main_mod,
7460 .builtin_mod = builtin_mod,
7461 .cc_argv = &.{},
7462 .inherited = .{},
7463 .global = global_options,
72927464 });
72937465 try main_mod.deps.put(arena, "@dependencies", deps_mod);
72947466 return deps_mod;
72957467}
72967468
7297fn defaultWasmEntryName(exec_model: ?std.builtin.WasiExecModel) []const u8 {
7298 const model = exec_model orelse .command;
7299 if (model == .reactor) {
7300 return "_initialize";
7301 }
7302 return "_start";
7303}
7304
73057469const BuildRoot = struct {
73067470 directory: Cache.Directory,
73077471 build_zig_basename: []const u8,
......@@ -7509,3 +7673,18 @@ fn findTemplates(gpa: Allocator, arena: Allocator) Templates {
75097673 .buffer = std.ArrayList(u8).init(gpa),
75107674 };
75117675}
7676
7677fn parseOptimizeMode(s: []const u8) std.builtin.OptimizeMode {
7678 return std.meta.stringToEnum(std.builtin.OptimizeMode, s) orelse
7679 fatal("unrecognized optimization mode: '{s}'", .{s});
7680}
7681
7682fn parseWasiExecModel(s: []const u8) std.builtin.WasiExecModel {
7683 return std.meta.stringToEnum(std.builtin.WasiExecModel, s) orelse
7684 fatal("expected [command|reactor] for -mexec-mode=[value], found '{s}'", .{s});
7685}
7686
7687fn resolveTargetQueryOrFatal(target_query: std.Target.Query) std.Target {
7688 return std.zig.system.resolveTargetQuery(target_query) catch |err|
7689 fatal("unable to resolve target: {s}", .{@errorName(err)});
7690}
src/target.zig+54-7
......@@ -3,6 +3,8 @@ const Type = @import("type.zig").Type;
33const AddressSpace = std.builtin.AddressSpace;
44const Alignment = @import("InternPool.zig").Alignment;
55
6pub const default_stack_protector_buffer_size = 4;
7
68pub const ArchOsAbi = struct {
79 arch: std.Target.Cpu.Arch,
810 os: std.Target.Os.Tag,
......@@ -204,11 +206,18 @@ pub fn supports_fpic(target: std.Target) bool {
204206 return target.os.tag != .windows and target.os.tag != .uefi;
205207}
206208
207pub fn isSingleThreaded(target: std.Target) bool {
209pub fn alwaysSingleThreaded(target: std.Target) bool {
208210 _ = target;
209211 return false;
210212}
211213
214pub fn defaultSingleThreaded(target: std.Target) bool {
215 return switch (target.cpu.arch) {
216 .wasm32, .wasm64 => true,
217 else => false,
218 };
219}
220
212221/// Valgrind supports more, but Zig does not support them yet.
213222pub fn hasValgrindSupport(target: std.Target) bool {
214223 switch (target.cpu.arch) {
......@@ -375,12 +384,17 @@ pub fn classifyCompilerRtLibName(target: std.Target, name: []const u8) CompilerR
375384}
376385
377386pub fn hasDebugInfo(target: std.Target) bool {
378 if (target.cpu.arch.isNvptx()) {
379 // TODO: not sure how to test "ptx >= 7.5" with featureset
380 return std.Target.nvptx.featureSetHas(target.cpu.features, .ptx75);
381 }
382
383 return true;
387 return switch (target.cpu.arch) {
388 .nvptx, .nvptx64 => std.Target.nvptx.featureSetHas(target.cpu.features, .ptx75) or
389 std.Target.nvptx.featureSetHas(target.cpu.features, .ptx76) or
390 std.Target.nvptx.featureSetHas(target.cpu.features, .ptx77) or
391 std.Target.nvptx.featureSetHas(target.cpu.features, .ptx78) or
392 std.Target.nvptx.featureSetHas(target.cpu.features, .ptx80) or
393 std.Target.nvptx.featureSetHas(target.cpu.features, .ptx81),
394 .wasm32, .wasm64 => false,
395 .bpfel, .bpfeb => false,
396 else => true,
397 };
384398}
385399
386400pub fn defaultCompilerRtOptimizeMode(target: std.Target) std.builtin.OptimizeMode {
......@@ -619,3 +633,36 @@ pub fn fnCallConvAllowsZigTypes(target: std.Target, cc: std.builtin.CallingConve
619633 else => false,
620634 };
621635}
636
637pub fn zigBackend(target: std.Target, use_llvm: bool) std.builtin.CompilerBackend {
638 if (use_llvm) return .stage2_llvm;
639 if (target.ofmt == .c) return .stage2_c;
640 return switch (target.cpu.arch) {
641 .wasm32, .wasm64 => std.builtin.CompilerBackend.stage2_wasm,
642 .arm, .armeb, .thumb, .thumbeb => .stage2_arm,
643 .x86_64 => .stage2_x86_64,
644 .x86 => .stage2_x86,
645 .aarch64, .aarch64_be, .aarch64_32 => .stage2_aarch64,
646 .riscv64 => .stage2_riscv64,
647 .sparc64 => .stage2_sparc64,
648 .spirv64 => .stage2_spirv64,
649 else => .other,
650 };
651}
652
653pub fn defaultEntrySymbolName(
654 target: std.Target,
655 /// May be `undefined` when `target` is not WASI.
656 wasi_exec_model: std.builtin.WasiExecModel,
657) ?[]const u8 {
658 return switch (target.ofmt) {
659 .coff => "wWinMainCRTStartup",
660 .macho => "_main",
661 .elf, .plan9 => "_start",
662 .wasm => switch (wasi_exec_model) {
663 .reactor => "_initialize",
664 .command => "_start",
665 },
666 else => null,
667 };
668}