1const builtin = @import("builtin");
2const native_os = builtin.os.tag;
3
4const std = @import("std");
5const Io = std.Io;
6const assert = std.debug.assert;
7const fs = std.fs;
8const mem = std.mem;
9const process = std.process;
10const Allocator = mem.Allocator;
11const Ast = std.zig.Ast;
12const Color = std.zig.Color;
13const warn = std.log.warn;
14const cleanExit = std.process.cleanExit;
15const Cache = std.Build.Cache;
16const Path = std.Build.Cache.Path;
17const Directory = std.Build.Cache.Directory;
18const EnvVar = std.zig.EnvVar;
19const LibCInstallation = std.zig.LibCInstallation;
20const AstGen = std.zig.AstGen;
21const ZonGen = std.zig.ZonGen;
22const Server = std.zig.Server;
23const stringToEnum = std.meta.stringToEnum;
24
25pub const tracy = @import("tracy.zig");
26const Compilation = @import("Compilation.zig");
27const link = @import("link.zig");
28const build_options = @import("build_options");
29const wasi_libc = @import("libs/wasi_libc.zig");
30const target_util = @import("target.zig");
31const crash_report = @import("crash_report.zig");
32const Zcu = @import("Zcu.zig");
33const mingw = @import("libs/mingw.zig");
34const dev = @import("dev.zig");
35const Module = @import("Module.zig");
36
37test {
38 _ = @import("codegen.zig");
39 _ = @import("link/MappedFile.zig");
40}
41
42const thread_stack_size = 60 << 20;
43
44pub const std_options: std.Options = .{
45 .logFn = log,
46
47 .log_level = switch (builtin.mode) {
48 .debug => .debug,
49 .safe, .fast => .info,
50 .small => .err,
51 },
52};
53pub const std_options_cwd = if (native_os == .wasi) wasi_cwd else null;
54
55pub const panic = crash_report.panic;
56pub const debug = crash_report.debug;
57
58var preopens: std.process.Preopens = .empty;
59pub fn wasi_cwd() Io.Dir {
60 // Expect the first preopen to be current working directory.
61 const cwd_fd: std.posix.fd_t = 3;
62 assert(mem.eql(u8, preopens.map.keys()[cwd_fd], "."));
63 return .{ .handle = cwd_fd };
64}
65
66const fatal = std.process.fatal;
67
68/// This can be global since stdin is a singleton.
69var stdin_buffer: [4096]u8 align(std.heap.page_size_min) = undefined;
70/// This can be global since stdout is a singleton.
71var stdout_buffer: [4096]u8 align(std.heap.page_size_min) = undefined;
72
73/// Shaming all the locations that inappropriately use an O(N) search algorithm.
74/// Please delete this and fix the compilation errors!
75pub const @"bad O(N)" = void;
76
77const normal_usage =
78 \\Usage: zig [command] [options]
79 \\
80 \\Commands:
81 \\
82 \\ build Build project from build.zig
83 \\ fetch Copy a package into global cache and print its hash
84 \\ init Initialize a Zig package in the current directory
85 \\
86 \\ build-exe Create executable from source or object files
87 \\ build-lib Create library from source or object files
88 \\ build-obj Create object from source or object files
89 \\ test Perform unit testing
90 \\ test-obj Create object for unit testing
91 \\ run Create executable and run immediately
92 \\
93 \\ ast-check Look for simple compile errors in any set of files
94 \\ fmt Reformat Zig source into canonical form
95 \\ reduce Minimize a bug report
96 \\ translate-c Convert C code to Zig code
97 \\
98 \\ ar Combine object files into static archive
99 \\ cc Use Zig as a drop-in C compiler
100 \\ c++ Use Zig as a drop-in C++ compiler
101 \\ dlltool Use Zig as a drop-in dlltool.exe
102 \\ lib Use Zig as a drop-in lib.exe
103 \\ objcopy Manipulate executables and relocatables
104 \\ objdump Print information about executables and relocatables
105 \\ ranlib Use Zig as a drop-in ranlib
106 \\ rc Use Zig as a drop-in rc.exe
107 \\
108 \\ env Print lib path, std path, cache directory, and version
109 \\ help Print this help and exit
110 \\ std View standard library documentation in a browser
111 \\ libc Display native libc paths file or validate one
112 \\ targets List available compilation targets
113 \\ version Print version number and exit
114 \\ zen Print Zen of Zig and exit
115 \\
116 \\General Options:
117 \\
118 \\ -h, --help Print command-specific usage
119 \\
120;
121
122const debug_usage = normal_usage ++
123 \\
124 \\Debug Commands:
125 \\
126 \\ changelist Compute mappings from old ZIR to new ZIR
127 \\ dump-zir Dump a file containing cached ZIR
128 \\
129;
130
131const usage = if (build_options.enable_debug_extensions) debug_usage else normal_usage;
132
133var log_scopes: std.ArrayList([]const u8) = .empty;
134
135pub fn log(
136 comptime level: std.log.Level,
137 comptime scope: @EnumLiteral(),
138 comptime format: []const u8,
139 args: anytype,
140) void {
141 // Hide debug messages unless:
142 // * logging enabled with `-Dlog`.
143 // * the --debug-log arg for the scope has been provided
144 if (@backingInt(level) > @backingInt(std.options.log_level) or
145 @backingInt(level) > @backingInt(std.log.Level.info))
146 {
147 if (!build_options.enable_logging) return;
148
149 const scope_name = @tagName(scope);
150 for (log_scopes.items) |log_scope| {
151 if (mem.eql(u8, log_scope, scope_name))
152 break;
153 } else return;
154 }
155
156 // Otherwise, use the default implementation.
157 std.log.defaultLog(level, scope, format, args);
158}
159
160const use_safe_allocator = build_options.debug_gpa or
161 (native_os != .wasi and !builtin.link_libc and switch (builtin.mode) {
162 .debug, .safe => true,
163 .fast, .small => false,
164 });
165
166var safe_allocator: std.heap.SafeAllocator = .init(std.heap.page_allocator, .{
167 .stack_trace_frames = build_options.mem_leak_frames,
168});
169
170pub fn main(init: std.process.Init.Minimal) anyerror!void {
171 const root_gpa = if (use_safe_allocator)
172 safe_allocator.allocator()
173 else if (native_os == .wasi)
174 std.heap.wasm_allocator
175 else if (builtin.link_libc)
176 std.heap.c_allocator
177 else
178 std.heap.smp_allocator;
179 defer if (use_safe_allocator) {
180 _ = safe_allocator.deinit();
181 };
182 var io_impl: IoImpl = undefined;
183 switch (build_options.io_mode) {
184 .threaded => io_impl = .init(root_gpa, .{
185 .stack_size = thread_stack_size,
186
187 .argv0 = .init(init.args),
188 .environ = init.environ,
189 }),
190 .evented => try io_impl.init(root_gpa, .{
191 .argv0 = .init(init.args),
192 .environ = init.environ,
193
194 .backing_allocator_needs_mutex = false,
195 }),
196 }
197 defer io_impl.deinit();
198 io_impl_ptr = &io_impl;
199 const io = io_impl.io();
200 const gpa = switch (build_options.io_mode) {
201 .threaded => root_gpa,
202 .evented => io_impl.allocator(),
203 };
204 var arena_instance = std.heap.ArenaAllocator.init(gpa);
205 defer arena_instance.deinit();
206 const arena = arena_instance.allocator();
207
208 const args = try init.args.toSlice(arena);
209
210 if (args.len > 0) crash_report.zig_argv0 = args[0];
211
212 if (args.len <= 1) {
213 std.log.info("{s}", .{usage});
214 fatal("expected command argument", .{});
215 }
216
217 var environ_map = init.environ.createMap(arena) catch |err| fatal("failed to parse environment: {t}", .{err});
218
219 if (tracy.enable_allocation) {
220 var tracy_allocator: tracy.Allocator = .{ .parent_allocator = gpa };
221 return mainArgs(tracy_allocator.interface(), arena, io, args, &environ_map);
222 }
223
224 if (native_os == .wasi) {
225 preopens = try .init(arena);
226 }
227
228 return mainArgs(gpa, arena, io, args, &environ_map);
229}
230
231const Cmd = enum {
232 @"build-exe",
233 @"build-lib",
234 @"build-obj",
235 @"test",
236 @"test-obj",
237 run,
238
239 dlltool,
240 ranlib,
241 lib,
242 ar,
243
244 build,
245
246 clang,
247 @"-cc1",
248 @"-cc1as",
249
250 @"ld.lld",
251 @"lld-link",
252 @"wasm-ld",
253
254 cc,
255 @"c++",
256 @"translate-c",
257 rc,
258 fmt,
259 objcopy,
260 objdump,
261 fetch,
262 libc,
263 std,
264 init,
265 targets,
266 version,
267 env,
268 reduce,
269 zen,
270 @"ast-check",
271
272 help,
273 @"-h",
274 @"--help",
275
276 changelist,
277 @"dump-zir",
278};
279
280fn mainArgs(
281 gpa: Allocator,
282 arena: Allocator,
283 io: Io,
284 args: []const [:0]const u8,
285 environ_map: *process.Environ.Map,
286) !void {
287 if (process.can_replace and EnvVar.ZIG_IS_DETECTING_LIBC_PATHS.isSet(environ_map)) {
288 dev.check(.cc_command);
289 // In this case we have accidentally invoked ourselves as "the system C compiler"
290 // to figure out where libc is installed. This is essentially infinite recursion
291 // via child process execution due to the CC environment variable pointing to Zig.
292 // Here we ignore the CC environment variable and exec `cc` as a child process.
293 // However it's possible Zig is installed as *that* C compiler as well, which is
294 // why we have this additional environment variable here to check.
295
296 const inf_loop_env_key: EnvVar = .ZIG_IS_AVOIDING_CALLING_ITSELF;
297 if (inf_loop_env_key.isSet(environ_map)) {
298 fatal("{s}", .{
299 "The compilation links against libc, but Zig is unable to provide a libc " ++
300 "for this operating system, and no --libc " ++
301 "parameter was provided, so Zig attempted to invoke the system C compiler " ++
302 "in order to determine where libc is installed. However the system C " ++
303 "compiler is `zig cc`, so no libc installation was found.",
304 });
305 }
306 try environ_map.put(@tagName(inf_loop_env_key), "1");
307
308 // Some programs such as CMake will strip the `cc` and subsequent args from the
309 // CC environment variable. We detect and support this scenario here because of
310 // the ZIG_IS_DETECTING_LIBC_PATHS environment variable.
311 if (mem.eql(u8, args[1], "cc")) {
312 return process.replace(io, .{ .argv = args[1..], .environ_map = environ_map });
313 } else {
314 const modified_args = try arena.dupe([]const u8, args);
315 modified_args[0] = "cc";
316 return process.replace(io, .{ .argv = modified_args, .environ_map = environ_map });
317 }
318 }
319
320 const cmd = args[1];
321 const cmd_args = args[2..];
322 switch (stringToEnum(Cmd, cmd) orelse {
323 std.log.info("{s}", .{usage});
324 fatal("unknown command: {s}", .{args[1]});
325 }) {
326 .@"build-exe" => {
327 dev.check(.build_exe_command);
328 return buildOutputType(gpa, arena, io, args, .{ .build = .Exe }, environ_map);
329 },
330 .@"build-lib" => {
331 dev.check(.build_lib_command);
332 return buildOutputType(gpa, arena, io, args, .{ .build = .Lib }, environ_map);
333 },
334 .@"build-obj" => {
335 dev.check(.build_obj_command);
336 return buildOutputType(gpa, arena, io, args, .{ .build = .Obj }, environ_map);
337 },
338 .@"test" => {
339 dev.check(.test_command);
340 return buildOutputType(gpa, arena, io, args, .zig_test, environ_map);
341 },
342 .@"test-obj" => {
343 dev.check(.test_command);
344 return buildOutputType(gpa, arena, io, args, .zig_test_obj, environ_map);
345 },
346 .run => {
347 dev.check(.run_command);
348 return buildOutputType(gpa, arena, io, args, .run, environ_map);
349 },
350 .dlltool, .ranlib, .lib, .ar => {
351 dev.check(.ar_command);
352 return process.exit(try llvmArMain(arena, args));
353 },
354 .build, .fetch, .init, .libc => {
355 return jitCmd(gpa, arena, io, cmd_args, environ_map, .{
356 .cmd_name = "maker",
357 .root_src_path = "Maker.zig",
358 .prepend_cmd = cmd,
359 .prepend_zig_lib_dir_path = true,
360 .prepend_global_cache_path = true,
361 .prepend_zig_exe_path = true,
362 .prepend_seed = true,
363 .release_mode = .safe,
364 });
365 },
366 .clang, .@"-cc1", .@"-cc1as" => {
367 dev.check(.clang_command);
368 return process.exit(try clangMain(arena, args));
369 },
370 .@"ld.lld", .@"lld-link", .@"wasm-ld" => {
371 dev.check(.lld_linker);
372 return process.exit(try lldMain(arena, args, true));
373 },
374 .cc => {
375 dev.check(.cc_command);
376 return buildOutputType(gpa, arena, io, args, .cc, environ_map);
377 },
378 .@"c++" => {
379 dev.check(.cc_command);
380 return buildOutputType(gpa, arena, io, args, .cpp, environ_map);
381 },
382 .@"translate-c" => {
383 dev.check(.translate_c_command);
384 return buildOutputType(gpa, arena, io, args, .translate_c, environ_map);
385 },
386 .rc => {
387 const use_server = cmd_args.len > 0 and std.mem.eql(u8, cmd_args[0], "--zig-integration");
388 return jitCmd(gpa, arena, io, cmd_args, environ_map, .{
389 .cmd_name = "resinator",
390 .root_src_path = "resinator/main.zig",
391 .depend_on_aro = true,
392 .prepend_zig_lib_dir_path = true,
393 .server = use_server,
394 });
395 },
396 .fmt => {
397 dev.check(.fmt_command);
398 return @import("fmt.zig").run(gpa, arena, io, cmd_args);
399 },
400 .objcopy => {
401 return jitCmd(gpa, arena, io, cmd_args, environ_map, .{
402 .cmd_name = "objcopy",
403 .root_src_path = "objcopy.zig",
404 });
405 },
406 .objdump => {
407 return jitCmd(gpa, arena, io, cmd_args, environ_map, .{
408 .cmd_name = "objdump",
409 .root_src_path = "objdump.zig",
410 });
411 },
412 .std => {
413 return jitCmd(gpa, arena, io, cmd_args, environ_map, .{
414 .cmd_name = "std",
415 .root_src_path = "std-docs.zig",
416 .prepend_zig_lib_dir_path = true,
417 .prepend_zig_exe_path = true,
418 .prepend_global_cache_path = true,
419 });
420 },
421 .targets => {
422 dev.check(.targets_command);
423 const self_exe_path = switch (native_os) {
424 .wasi => {},
425 else => process.executablePathAlloc(io, arena) catch |err| fatal("unable to find zig self exe path: {t}", .{err}),
426 };
427 var dirs: std.zig.Directories = .init(arena, io, .{
428 .override_zig_lib = EnvVar.ZIG_LIB_DIR.get(environ_map),
429 .override_global_cache = EnvVar.ZIG_GLOBAL_CACHE_DIR.get(environ_map),
430 .build_root = null,
431 .local_cache_strat = .global,
432 .preopens = preopens,
433 .self_exe_path = self_exe_path,
434 .environ_map = environ_map,
435 .cwd = try std.zig.getResolvedCwd(io, arena),
436 });
437 defer dirs.deinit(io);
438 const host = std.zig.resolveTargetQueryOrFatal(io, .{});
439 var stdout_writer = Io.File.stdout().writer(io, &stdout_buffer);
440 try @import("print_targets.zig").cmdTargets(
441 arena,
442 io,
443 &dirs,
444 cmd_args,
445 &stdout_writer.interface,
446 &host,
447 );
448 return stdout_writer.interface.flush();
449 },
450 .version => {
451 dev.check(.version_command);
452 try Io.File.stdout().writeStreamingAll(io, build_options.version ++ "\n");
453 return;
454 },
455 .env => {
456 dev.check(.env_command);
457 const self_exe_path = switch (native_os) {
458 .wasi => args[0],
459 else => process.executablePathAlloc(io, arena) catch |err| fatal("unable to find zig self exe path: {t}", .{err}),
460 };
461 var dirs: std.zig.Directories = .init(arena, io, .{
462 .override_zig_lib = EnvVar.ZIG_LIB_DIR.get(environ_map),
463 .override_global_cache = EnvVar.ZIG_GLOBAL_CACHE_DIR.get(environ_map),
464 .build_root = null,
465 .local_cache_strat = .global,
466 .preopens = preopens,
467 .self_exe_path = if (native_os != .wasi) self_exe_path,
468 .environ_map = environ_map,
469 .cwd = try std.zig.getResolvedCwd(io, arena),
470 });
471 defer dirs.deinit(io);
472 const host = std.zig.resolveTargetQueryOrFatal(io, .{});
473 var stdout_writer = Io.File.stdout().writer(io, &stdout_buffer);
474 try @import("print_env.zig").cmdEnv(
475 arena,
476 &stdout_writer.interface,
477 &host,
478 environ_map,
479 &dirs,
480 self_exe_path,
481 );
482 return stdout_writer.interface.flush();
483 },
484 .reduce => {
485 return jitCmd(gpa, arena, io, cmd_args, environ_map, .{
486 .cmd_name = "reduce",
487 .root_src_path = "reduce.zig",
488 });
489 },
490 .zen => {
491 dev.check(.zen_command);
492 return Io.File.stdout().writeStreamingAll(io, info_zen);
493 },
494 .help, .@"-h", .@"--help" => {
495 dev.check(.help_command);
496 return Io.File.stdout().writeStreamingAll(io, usage);
497 },
498 .@"ast-check" => {
499 dev.check(.ast_check_command);
500 return cmdAstCheck(arena, io, cmd_args, environ_map);
501 },
502 .changelist => {
503 dev.check(.changelist_command);
504 return cmdChangelist(arena, io, cmd_args, environ_map);
505 },
506 .@"dump-zir" => {
507 dev.check(.dump_zir_command);
508 return cmdDumpZir(arena, io, cmd_args);
509 },
510 }
511}
512
513const compile_usage =
514 \\Usage: zig build-exe [options] [files]
515 \\ zig build-lib [options] [files]
516 \\ zig build-obj [options] [files]
517 \\ zig test [options] [files]
518 \\ zig run [options] [files] [-- [args]]
519 \\ zig translate-c [options] [file]
520 \\
521 \\Supported file types:
522 \\ .zig Zig source code
523 \\ .o ELF object file
524 \\ .o Mach-O (macOS) object file
525 \\ .o WebAssembly object file
526 \\ .obj COFF (Windows) object file
527 \\ .lib COFF (Windows) static library
528 \\ .a ELF static library
529 \\ .a Mach-O (macOS) static library
530 \\ .a WebAssembly static library
531 \\ .so ELF shared object (dynamic link)
532 \\ .dll Windows Dynamic Link Library
533 \\ .dylib Mach-O (macOS) dynamic library
534 \\ .tbd (macOS) text-based dylib definition
535 \\ .s Target-specific assembly source code
536 \\ .S Assembly with C preprocessor (requires LLVM extensions)
537 \\ .c C source code (requires LLVM extensions)
538 \\ .cxx .cc .C .cpp .c++ C++ source code (requires LLVM extensions)
539 \\ .m Objective-C source code (requires LLVM extensions)
540 \\ .mm Objective-C++ source code (requires LLVM extensions)
541 \\ .bc LLVM IR Module (requires LLVM extensions)
542 \\
543 \\General Options:
544 \\ -h, --help Print this help and exit
545 \\ --color [auto|off|on] Enable or disable colored error messages
546 \\ -j<N> Limit concurrent jobs (default is to use all CPU cores)
547 \\ -fincremental Enable incremental compilation
548 \\ -fno-incremental Disable incremental compilation
549 \\ -femit-bin[=path] (default) Output machine code
550 \\ -fno-emit-bin Do not output machine code
551 \\ -femit-asm[=path] Output .s (assembly code)
552 \\ -fno-emit-asm (default) Do not output .s (assembly code)
553 \\ -femit-llvm-ir[=path] Produce a .ll file with optimized LLVM IR (requires LLVM extensions)
554 \\ -fno-emit-llvm-ir (default) Do not produce a .ll file with optimized LLVM IR
555 \\ -femit-llvm-bc[=path] Produce an optimized LLVM module as a .bc file (requires LLVM extensions)
556 \\ -fno-emit-llvm-bc (default) Do not produce an optimized LLVM module as a .bc file
557 \\ -femit-h[=path] Generate a C header file (.h)
558 \\ -fno-emit-h (default) Do not generate a C header file (.h)
559 \\ -femit-docs[=path] Create a docs/ dir with html documentation
560 \\ -fno-emit-docs (default) Do not produce docs/ dir with html documentation
561 \\ -femit-implib[=path] (default) Produce an import .lib when building a Windows DLL
562 \\ -fno-emit-implib Do not produce an import .lib when building a Windows DLL
563 \\ --show-builtin Output the source of @import("builtin") then exit
564 \\ --cache-dir [path] Override the local cache directory
565 \\ --global-cache-dir [path] Override the global cache directory
566 \\ --zig-lib-dir [path] Override path to Zig installation lib directory
567 \\ --build-root [path] Override path to project source files
568 \\
569 \\Global Compile Options:
570 \\ --name [name] Compilation unit name (not a file path)
571 \\ -M[name][=src] Create a module based on the current per-module settings.
572 \\ The first module is the main module.
573 \\ "std" can be configured by omitting src
574 \\ After a -M argument, per-module settings are reset.
575 \\ --libc [file] Provide a file which specifies libc paths
576 \\ -x [language] Treat subsequent input files as having type <language>
577 \\ --error-limit [num] Set the maximum amount of distinct error values
578 \\ -fllvm Force using LLVM as the codegen backend
579 \\ -fno-llvm Prevent using LLVM as the codegen backend
580 \\ -flibllvm Force using the LLVM API in the codegen backend
581 \\ -fno-libllvm Prevent using the LLVM API in the codegen backend
582 \\ -fclang Force using Clang as the C/C++ compilation backend
583 \\ -fno-clang Prevent using Clang as the C/C++ compilation backend
584 \\ -fPIE Force-enable Position Independent Executable
585 \\ -fno-PIE Force-disable Position Independent Executable
586 \\ -flto Force-enable Link Time Optimization (requires LLVM extensions)
587 \\ -fno-lto Force-disable Link Time Optimization
588 \\ -fdll-export-fns Mark exported functions as DLL exports (Windows)
589 \\ -fno-dll-export-fns Force-disable marking exported functions as DLL exports
590 \\ -freference-trace[=num] Show num lines of reference trace per compile error
591 \\ -fno-reference-trace Disable reference trace
592 \\ -ffunction-sections Places each function in a separate section
593 \\ -fno-function-sections All functions go into same section
594 \\ -fdata-sections Places each data in a separate section
595 \\ -fno-data-sections All data go into same section
596 \\ -mexec-model=[value] (WASI) Execution model
597 \\ -municode (Windows) Use wmain/wWinMain as entry point
598 \\ --time-report Send timing diagnostics to '--listen' clients
599 \\
600 \\Per-Module Compile Options:
601 \\ --dep [[import=]name] Add an entry to the next module's import table
602 \\ -target [name] <arch><sub>-<os>-<abi> see the targets command
603 \\ -O [mode] Choose what to optimize for
604 \\ debug (default) Prioritize bug detection, accurate debug info, compilation speed
605 \\ fast Prioritize runtime performance. Safety checks off.
606 \\ safe Enable both safety checks and machine code optimizations
607 \\ small Prioritize small binary size. Safety checks off.
608 \\ -ofmt=[fmt] Override target object format
609 \\ elf Executable and Linking Format
610 \\ c C source code
611 \\ wasm WebAssembly
612 \\ coff Common Object File Format (Windows)
613 \\ macho macOS relocatables
614 \\ spirv Standard, Portable Intermediate Representation V (SPIR-V)
615 \\ plan9 Plan 9 from Bell Labs object format
616 \\ hex (planned feature) Intel IHEX
617 \\ raw (planned feature) Dump machine code directly
618 \\ -mcpu [cpu] Specify target CPU and feature set
619 \\ -mcmodel=[model] Limit range of code and data virtual addresses
620 \\ default
621 \\ extreme
622 \\ kernel
623 \\ large
624 \\ medany
625 \\ medium
626 \\ medlow
627 \\ medmid
628 \\ normal
629 \\ small
630 \\ tiny
631 \\ -mred-zone Force-enable the "red-zone"
632 \\ -mno-red-zone Force-disable the "red-zone"
633 \\ -fomit-frame-pointer Omit the stack frame pointer
634 \\ -fno-omit-frame-pointer Store the stack frame pointer
635 \\ -fPIC Force-enable Position Independent Code
636 \\ -fno-PIC Force-disable Position Independent Code
637 \\ -fstack-check Enable stack probing in unsafe builds
638 \\ -fno-stack-check Disable stack probing in safe builds
639 \\ -fstack-protector Enable stack protection in unsafe builds
640 \\ -fno-stack-protector Disable stack protection in safe builds
641 \\ -fvalgrind Include valgrind client requests in release builds
642 \\ -fno-valgrind Omit valgrind client requests in debug builds
643 \\ -fsanitize-c[=mode] Enable C undefined behavior detection in unsafe builds
644 \\ trap Insert trap instructions on undefined behavior
645 \\ full (Default) Insert runtime calls on undefined behavior
646 \\ -fno-sanitize-c Disable C undefined behavior detection in safe builds
647 \\ -fsanitize-thread Enable Thread Sanitizer
648 \\ -fno-sanitize-thread Disable Thread Sanitizer
649 \\ -ffuzz Enable fuzz testing instrumentation
650 \\ -fno-fuzz Disable fuzz testing instrumentation
651 \\ -fbuiltin Enable implicit builtin knowledge of functions
652 \\ -fno-builtin Disable implicit builtin knowledge of functions
653 \\ -funwind-tables Always produce unwind table entries for all functions
654 \\ -fasync-unwind-tables Always produce asynchronous unwind table entries for all functions
655 \\ -fno-unwind-tables Never produce unwind table entries
656 \\ -ferror-tracing Enable error tracing in release builds
657 \\ -fno-error-tracing Disable error tracing in debug builds
658 \\ -fsingle-threaded Code assumes there is only one thread
659 \\ -fno-single-threaded Code may not assume there is only one thread
660 \\ -fstrip Omit debug symbols
661 \\ -fno-strip Keep debug symbols
662 \\ -idirafter [dir] Add directory to AFTER include search path
663 \\ -isystem [dir] Add directory to SYSTEM include search path
664 \\ -I[dir] Add directory to include search path
665 \\ --embed-dir=[dir] Add directory to embed search path
666 \\ -D[macro]=[value] Define C [macro] to [value] (1 if [value] omitted)
667 \\ -cflags [flags] -- Set extra flags for the next positional C source files
668 \\ -rcflags [flags] -- Set extra flags for the next positional .rc source files
669 \\ -rcincludes=[type] Set the type of includes to use when compiling .rc source files
670 \\ any (default) Use msvc if available, fall back to gnu
671 \\ msvc Use msvc include paths (must be present on the system)
672 \\ gnu Use mingw include paths (distributed with Zig)
673 \\ none Do not use any autodetected include paths
674 \\
675 \\Global Link Options:
676 \\ -T[script], --script [script] Use a custom linker script
677 \\ --version-script [path] Provide a version .map file
678 \\ --undefined-version Allow version scripts to refer to undefined symbols
679 \\ --no-undefined-version (default) Disallow version scripts from referring to undefined symbols
680 \\ --enable-new-dtags Use the new behavior for dynamic tags (RUNPATH)
681 \\ --disable-new-dtags Use the old behavior for dynamic tags (RPATH)
682 \\ --dynamic-linker [path] Set the dynamic interpreter path (usually ld.so)
683 \\ --no-dynamic-linker Do not set any dynamic interpreter path
684 \\ --sysroot [path] Set the system root directory (usually /)
685 \\ --version [ver] Dynamic library semver
686 \\ -fentry Enable entry point with default symbol name
687 \\ -fentry=[name] Override the entry point symbol name
688 \\ -fno-entry Do not output any entry point
689 \\ --force_undefined [name] Specify the symbol must be defined for the link to succeed
690 \\ -fsoname[=name] Override the default SONAME value
691 \\ -fno-soname Disable emitting a SONAME
692 \\ -flld Force using LLD as the linker
693 \\ -fno-lld Prevent using LLD as the linker
694 \\ -fcompiler-rt Always include compiler-rt symbols in output
695 \\ -fno-compiler-rt Prevent including compiler-rt symbols in output
696 \\ -fubsan-rt Always include ubsan-rt symbols in the output
697 \\ -fno-ubsan-rt Prevent including ubsan-rt symbols in the output
698 \\ -rdynamic Add all symbols to the dynamic symbol table
699 \\ -feach-lib-rpath Ensure adding rpath for each used dynamic library
700 \\ -fno-each-lib-rpath Prevent adding rpath for each used dynamic library
701 \\ -fallow-shlib-undefined Allows undefined symbols in shared libraries
702 \\ -fno-allow-shlib-undefined Disallows undefined symbols in shared libraries
703 \\ -fallow-so-scripts Allows .so files to be GNU ld scripts
704 \\ -fno-allow-so-scripts (default) .so files must be ELF files
705 \\ --build-id[=style] At a minor link-time expense, embeds a build ID in binaries
706 \\ fast 8-byte non-cryptographic hash (COFF, ELF, WASM)
707 \\ sha1, tree 20-byte cryptographic hash (ELF, WASM)
708 \\ md5 16-byte cryptographic hash (ELF)
709 \\ uuid 16-byte random UUID (ELF, WASM)
710 \\ 0x[hexstring] Constant ID, maximum 32 bytes (ELF, WASM)
711 \\ none (default) No build ID
712 \\ --eh-frame-hdr Enable C++ exception handling by passing --eh-frame-hdr to linker
713 \\ --no-eh-frame-hdr Disable C++ exception handling by passing --no-eh-frame-hdr to linker
714 \\ --emit-relocs Enable output of relocation sections for post build tools
715 \\ -z [arg] Set linker extension flags
716 \\ nodelete Indicate that the object cannot be deleted from a process
717 \\ notext Permit read-only relocations in read-only segments
718 \\ defs Force a fatal error if any undefined symbols remain
719 \\ undefs Reverse of -z defs
720 \\ origin Indicate that the object must have its origin processed
721 \\ nocopyreloc Disable the creation of copy relocations
722 \\ now (default) Force all relocations to be processed on load
723 \\ lazy Don't force all relocations to be processed on load
724 \\ relro (default) Force all relocations to be read-only after processing
725 \\ norelro Don't force all relocations to be read-only after processing
726 \\ common-page-size=[bytes] Set the common page size for ELF binaries
727 \\ max-page-size=[bytes] Set the max page size for ELF binaries
728 \\ -dynamic Force output to be dynamically linked
729 \\ -static Force output to be statically linked
730 \\ -Bsymbolic Bind global references locally
731 \\ --compress-debug-sections=[e] Debug section compression settings
732 \\ none No compression
733 \\ zlib Compression with deflate/inflate
734 \\ zstd Compression with zstandard
735 \\ --gc-sections Force removal of functions and data that are unreachable by the entry point or exported symbols
736 \\ --no-gc-sections Don't force removal of unreachable functions and data
737 \\ --sort-section=[value] Sort wildcard section patterns by 'name' or 'alignment'
738 \\ --subsystem [subsystem] (Windows) /SUBSYSTEM:<subsystem> to the linker
739 \\ --stack [size] Override default stack size
740 \\ --image-base [addr] Set base address for executable image
741 \\ -install_name=[value] (Darwin) add dylib's install name
742 \\ --entitlements [path] (Darwin) add path to entitlements file for embedding in code signature
743 \\ -pagezero_size [value] (Darwin) size of the __PAGEZERO segment in hexadecimal notation
744 \\ -headerpad [value] (Darwin) set minimum space for future expansion of the load commands in hexadecimal notation
745 \\ -headerpad_max_install_names (Darwin) set enough space as if all paths were MAXPATHLEN
746 \\ -dead_strip (Darwin) remove functions and data that are unreachable by the entry point or exported symbols
747 \\ -dead_strip_dylibs (Darwin) remove dylibs that are unreachable by the entry point or exported symbols
748 \\ -ObjC (Darwin) force load all members of static archives that implement an Objective-C class or category
749 \\ --import-memory (WebAssembly) import memory from the environment
750 \\ --export-memory (WebAssembly) export memory to the host (Default unless --import-memory used)
751 \\ --import-symbols (WebAssembly) import missing symbols from the host environment
752 \\ --import-table (WebAssembly) import function table from the host environment
753 \\ --export-table (WebAssembly) export function table to the host environment
754 \\ --growable-table (WebAssembly) remove maximum size from function table, allowing table to grow
755 \\ --initial-memory=[bytes] (WebAssembly) initial size of the linear memory
756 \\ --max-memory=[bytes] (WebAssembly) maximum size of the linear memory
757 \\ --shared-memory (WebAssembly) use shared linear memory
758 \\ --global-base=[addr] (WebAssembly) where to start to place global data
759 \\
760 \\Per-Module Link Options:
761 \\ -l[lib], --library [lib] Link against system library (only if actually used)
762 \\ -needed-l[lib], Link against system library (even if unused)
763 \\ --needed-library [lib]
764 \\ -weak-l[lib] link against system library marking it and all
765 \\ -weak_library [lib] referenced symbols as weak
766 \\ -L[d], --library-directory [d] Add a directory to the library search path
767 \\ -search_paths_first For each library search path, check for dynamic
768 \\ lib then static lib before proceeding to next path.
769 \\ -search_paths_first_static For each library search path, check for static
770 \\ lib then dynamic lib before proceeding to next path.
771 \\ -search_dylibs_first Search for dynamic libs in all library search
772 \\ paths, then static libs.
773 \\ -search_static_first Search for static libs in all library search
774 \\ paths, then dynamic libs.
775 \\ -search_dylibs_only Only search for dynamic libs.
776 \\ -search_static_only Only search for static libs.
777 \\ -rpath [path] Add directory to the runtime library search path
778 \\ -framework [name] (Darwin) link against framework
779 \\ -needed_framework [name] (Darwin) link against framework (even if unused)
780 \\ -needed_library [lib] (Darwin) link against system library (even if unused)
781 \\ -weak_framework [name] (Darwin) link against framework and mark it and all referenced symbols as weak
782 \\ -F[dir] (Darwin) add search path for frameworks
783 \\ --export=[value] (WebAssembly) Force a symbol to be exported
784 \\
785 \\Test Options:
786 \\ --test-filter [text] Skip tests that do not match any filter
787 \\ --test-cmd [arg] Specify test execution command one arg at a time
788 \\ --test-cmd-bin Appends test binary path to test cmd args
789 \\ --test-no-exec Compiles test binary without running it
790 \\ --test-runner [path] Specify a custom test runner
791 \\ --test-execve Runs the test binary with execve if available instead of as a child process
792 \\
793 \\Debug Options (Zig Compiler Development):
794 \\ -fopt-bisect-limit=[limit] Only run [limit] first LLVM optimization passes
795 \\ -fstack-report Print stack size diagnostics
796 \\ --verbose-link Display linker invocations
797 \\ --verbose-cc Display C compiler invocations
798 \\ --verbose-air Enable compiler debug output for Zig AIR
799 \\ --verbose-intern-pool Enable compiler debug output for InternPool
800 \\ --verbose-generic-instances Enable compiler debug output for generic instance generation
801 \\ --verbose-llvm-ir[=path] Enable compiler debug output for unoptimized LLVM IR
802 \\ --verbose-llvm-bc=[path] Enable compiler debug output for unoptimized LLVM BC
803 \\ --verbose-cimport Enable compiler debug output for C imports
804 \\ --verbose-llvm-cpu-features Enable compiler debug output for LLVM CPU features
805 \\ --debug-log [scope] Enable printing debug/info log messages for scope
806 \\ --debug-compile-errors Crash with helpful diagnostics at the first compile error
807 \\ --debug-link-snapshot Enable dumping of the linker's state in JSON format
808 \\ --debug-rt[=mode] Build compiler runtime libraries with [mode] optimization
809 \\ (debug if [=mode] is omitted)
810 \\ --debug-incremental Enable incremental compilation debug features
811 \\
812;
813
814const SOName = union(enum) {
815 no,
816 yes_default_value,
817 yes: []const u8,
818};
819
820const EmitBin = union(enum) {
821 no,
822 yes_default_path,
823 yes: []const u8,
824 yes_a_out,
825};
826
827const Emit = union(enum) {
828 no,
829 yes_default_path,
830 yes: []const u8,
831
832 const OutputToCacheReason = enum { listen, @"zig run", @"zig test" };
833 fn resolve(emit: Emit, io: Io, default_basename: []const u8, output_to_cache: ?OutputToCacheReason) Compilation.CreateOptions.Emit {
834 return switch (emit) {
835 .no => .no,
836 .yes_default_path => if (output_to_cache != null) .yes_cache else .{ .yes_path = default_basename },
837 .yes => |path| if (output_to_cache) |reason| {
838 switch (reason) {
839 .listen => fatal("--listen incompatible with explicit output path {q}", .{path}),
840 .@"zig run", .@"zig test" => fatal(
841 "{q} with explicit output path {q} requires explicit '-femit-bin=path' or '-fno-emit-bin'",
842 .{ @tagName(reason), path },
843 ),
844 }
845 } else e: {
846 // If there's a dirname, check that dir exists. This will give a more descriptive error than `Compilation` otherwise would.
847 if (fs.path.dirname(path)) |dir_path| {
848 var dir = Io.Dir.cwd().openDir(io, dir_path, .{}) catch |err| {
849 fatal("unable to open output directory {q}: {t}", .{ dir_path, err });
850 };
851 dir.close(io);
852 }
853 break :e .{ .yes_path = path };
854 },
855 };
856 }
857};
858
859const ArgMode = union(enum) {
860 build: std.lang.OutputMode,
861 cc,
862 cpp,
863 translate_c,
864 zig_test,
865 zig_test_obj,
866 run,
867};
868
869const Listen = union(enum) {
870 none,
871 stdio: if (dev.env.supports(.stdio_listen)) void else noreturn,
872 ip4: if (dev.env.supports(.network_listen)) Io.net.Ip4Address else noreturn,
873};
874
875const ArgsIterator = struct {
876 resp_file: ?ArgIteratorResponseFile = null,
877 args: []const []const u8,
878 i: usize = 0,
879 fn next(it: *@This()) ?[]const u8 {
880 if (it.i >= it.args.len) {
881 if (it.resp_file) |*resp| return resp.next();
882 return null;
883 }
884 defer it.i += 1;
885 return it.args[it.i];
886 }
887 fn nextOrFatal(it: *@This()) []const u8 {
888 if (it.i >= it.args.len) {
889 if (it.resp_file) |*resp| if (resp.next()) |ret| return ret;
890 fatal("expected parameter after {s}", .{it.args[it.i - 1]});
891 }
892 defer it.i += 1;
893 return it.args[it.i];
894 }
895};
896
897/// Similar to `link.Framework` except it doesn't store yet unresolved
898/// path to the framework.
899const Framework = struct {
900 needed: bool = false,
901 weak: bool = false,
902};
903
904const CliModule = struct {
905 root_path: []const u8,
906 root_src_path: []const u8,
907 cc_argv: []const []const u8,
908 inherited: Module.CreateOptions.Inherited,
909 target_arch_os_abi: ?[]const u8,
910 target_mcpu: ?[]const u8,
911 dynamic_linker: ?[]const u8,
912
913 deps: []const Dep,
914 resolved: ?*Module,
915
916 c_source_files_start: usize,
917 c_source_files_end: usize,
918 rc_source_files_start: usize,
919 rc_source_files_end: usize,
920
921 const Dep = struct {
922 key: []const u8,
923 value: []const u8,
924 };
925};
926
927fn buildOutputType(
928 gpa: Allocator,
929 arena: Allocator,
930 io: Io,
931 all_args: []const []const u8,
932 arg_mode: ArgMode,
933 environ_map: *process.Environ.Map,
934) !void {
935 var provided_name: ?[]const u8 = null;
936 var root_src_file: ?[]const u8 = null;
937 var version: std.SemanticVersion = .{ .major = 0, .minor = 0, .patch = 0 };
938 var have_version = false;
939 var compatibility_version: ?std.SemanticVersion = null;
940 var function_sections = false;
941 var data_sections = false;
942 var listen: Listen = .none;
943 var debug_compile_errors = false;
944 var debug_incremental = false;
945 var verbose_link = (native_os != .wasi or builtin.link_libc) and
946 EnvVar.ZIG_VERBOSE_LINK.isSet(environ_map);
947 var verbose_cc = (native_os != .wasi or builtin.link_libc) and
948 EnvVar.ZIG_VERBOSE_CC.isSet(environ_map);
949 var verbose_air = false;
950 var verbose_intern_pool = false;
951 var verbose_generic_instances = false;
952 var verbose_llvm_ir: ?[]const u8 = null;
953 var verbose_llvm_bc: ?[]const u8 = null;
954 var link_depfile: ?[]const u8 = null;
955 var verbose_llvm_cpu_features = false;
956 var time_report = false;
957 var stack_report = false;
958 var show_builtin = false;
959 var emit_bin: EmitBin = .yes_default_path;
960 var emit_asm: Emit = .no;
961 var emit_llvm_ir: Emit = .no;
962 var emit_llvm_bc: Emit = .no;
963 var emit_docs: Emit = .no;
964 var emit_implib: Emit = .yes_default_path;
965 var emit_implib_arg_provided = false;
966 var target_arch_os_abi: ?[]const u8 = null;
967 var target_mcpu: ?[]const u8 = null;
968 var dynamic_linker: ?[]const u8 = null;
969 var emit_h: Emit = .no;
970 var soname: SOName = undefined;
971 var want_compiler_rt: ?bool = null;
972 var zig_cc_explicitly_link_compiler_rt = false;
973 var want_ubsan_rt: ?bool = null;
974 var linker_script: ?[]const u8 = null;
975 var version_script: ?[]const u8 = null;
976 var linker_repro: ?bool = null;
977 var linker_allow_undefined_version: bool = false;
978 var linker_enable_new_dtags: ?bool = null;
979 var disable_c_depfile = false;
980 var linker_sort_section: ?link.File.Lld.Elf.SortSection = null;
981 var linker_gc_sections: ?bool = null;
982 var linker_compress_debug_sections: ?std.zig.CompressDebugSections = null;
983 var linker_allow_shlib_undefined: ?bool = null;
984 var allow_so_scripts: bool = false;
985 var linker_bind_global_refs_locally: ?bool = null;
986 var linker_import_symbols: bool = false;
987 var linker_import_table: bool = false;
988 var linker_export_table: bool = false;
989 var linker_growable_table: bool = false;
990 var linker_initial_memory: ?u64 = null;
991 var linker_max_memory: ?u64 = null;
992 var linker_global_base: ?u64 = null;
993 var linker_print_gc_sections: bool = false;
994 var linker_print_icf_sections: bool = false;
995 var linker_print_map: bool = false;
996 var linker_nmagic: bool = false;
997 var linker_fatal_warnings: bool = false;
998 var llvm_opt_bisect_limit: c_int = -1;
999 var linker_z_nocopyreloc = false;
1000 var linker_z_nodelete = false;
1001 var linker_z_notext = false;
1002 var linker_z_defs = false;
1003 var linker_z_origin = false;
1004 var linker_z_now = true;
1005 var linker_z_relro = true;
1006 var linker_z_common_page_size: ?u64 = null;
1007 var linker_z_max_page_size: ?u64 = null;
1008 var linker_tsaware = false;
1009 var linker_nxcompat = false;
1010 var linker_dynamicbase = true;
1011 var linker_optimization: ?[]const u8 = null;
1012 var linker_module_definition_file: ?[]const u8 = null;
1013 var test_no_exec = false;
1014 var test_execve = false;
1015 var entry: Compilation.CreateOptions.Entry = .default;
1016 var force_undefined_symbols: std.array_hash_map.String(void) = .empty;
1017 var stack_size: ?u64 = null;
1018 var image_base: ?u64 = null;
1019 var link_eh_frame_hdr = false;
1020 var link_emit_relocs = false;
1021 var build_id: ?std.zig.BuildId = null;
1022 var runtime_args_start: ?usize = null;
1023 var test_filters: std.ArrayList([]const u8) = .empty;
1024 var test_runner_path: ?[]const u8 = null;
1025 var override_local_cache_dir: ?[]const u8 = EnvVar.ZIG_LOCAL_CACHE_DIR.get(environ_map);
1026 var override_global_cache_dir: ?[]const u8 = EnvVar.ZIG_GLOBAL_CACHE_DIR.get(environ_map);
1027 var override_lib_dir: ?[]const u8 = EnvVar.ZIG_LIB_DIR.get(environ_map);
1028 var clang_preprocessor_mode: Compilation.ClangPreprocessorMode = .no;
1029 var subsystem: ?std.zig.Subsystem = null;
1030 var major_subsystem_version: ?u16 = null;
1031 var minor_subsystem_version: ?u16 = null;
1032 var mingw_unicode_entry_point: bool = false;
1033 var enable_link_snapshots: bool = false;
1034 var debug_compiler_runtime_libs: ?std.lang.Optimize = null;
1035 var install_name: ?[]const u8 = null;
1036 var hash_style: link.File.Lld.Elf.HashStyle = .both;
1037 var entitlements: ?[]const u8 = null;
1038 var pagezero_size: ?u64 = null;
1039 var lib_search_strategy: link.UnresolvedInput.SearchStrategy = .paths_first;
1040 var lib_preferred_mode: std.lang.LinkMode = .dynamic;
1041 var headerpad_size: ?u32 = null;
1042 var headerpad_max_install_names: bool = false;
1043 var dead_strip_dylibs: bool = false;
1044 var force_load_objc: bool = false;
1045 var discard_local_symbols: bool = false;
1046 var contains_res_file: bool = false;
1047 var reference_trace: ?u32 = null;
1048 var pdb_out_path: ?[]const u8 = null;
1049 var error_limit: ?Zcu.ErrorInt = null;
1050 // These are before resolving sysroot.
1051 var extra_cflags: std.ArrayList([]const u8) = .empty;
1052 var extra_rcflags: std.ArrayList([]const u8) = .empty;
1053 var symbol_wrap_set: std.array_hash_map.String(void) = .empty;
1054 var rc_includes: std.zig.RcIncludes = .any;
1055 var manifest_file: ?[]const u8 = null;
1056 var linker_export_symbol_names: std.ArrayList([]const u8) = .empty;
1057 var build_root_path: ?[]const u8 = null;
1058
1059 // Tracks the position in c_source_files which have already their owner populated.
1060 var c_source_files_owner_index: usize = 0;
1061 // Tracks the position in rc_source_files which have already their owner populated.
1062 var rc_source_files_owner_index: usize = 0;
1063
1064 // null means replace with the test executable binary
1065 var test_exec_args: std.ArrayList(?[]const u8) = .empty;
1066
1067 // These get set by CLI flags and then snapshotted when a `-M` flag is
1068 // encountered.
1069 var mod_opts: Module.CreateOptions.Inherited = .{};
1070
1071 // These get appended to by CLI flags and then slurped when a `-M` flag
1072 // is encountered.
1073 var cssan: ClangSearchSanitizer = .{};
1074 var cc_argv: std.ArrayList([]const u8) = .empty;
1075 var deps: std.ArrayList(CliModule.Dep) = .empty;
1076
1077 // We need to raise the FD limit *before* CLI parsing, because we open link inputs during CLI
1078 // parsing (in `createModule`), so a large number of link inputs could push us past the limit on
1079 // targets with a low soft limit (e.g. macOS has a default limit of 256).
1080 process.raiseFileDescriptorLimit();
1081
1082 // Contains every module specified via -M. The dependencies are added
1083 // after argument parsing is completed. We use a StringArrayHashMap to make
1084 // error output consistent. "root" is special.
1085 var create_module: CreateModule = .{
1086 // Populated just before the call to `createModule`.
1087 .dirs = undefined,
1088 .object_format = null,
1089 .modules = .empty,
1090 .opts = .{
1091 .is_test = switch (arg_mode) {
1092 .zig_test, .zig_test_obj => true,
1093 .build, .cc, .cpp, .translate_c, .run => false,
1094 },
1095 // Populated while parsing CLI args.
1096 .output_mode = undefined,
1097 // Populated in the call to `createModule` for the root module.
1098 .resolved_target = undefined,
1099 .have_zcu = false,
1100 // Populated just before the call to `createModule`.
1101 .emit_llvm_ir = undefined,
1102 // Populated just before the call to `createModule`.
1103 .emit_llvm_bc = undefined,
1104 // Populated just before the call to `createModule`.
1105 .emit_bin = undefined,
1106 // Populated just before the call to `createModule`.
1107 .any_c_source_files = undefined,
1108 },
1109 // Populated in the call to `createModule` for the root module.
1110 .resolved_options = undefined,
1111
1112 .cli_link_inputs = .empty,
1113 .windows_libs = .empty,
1114 .link_inputs = .empty,
1115
1116 .c_source_files = .empty,
1117 .rc_source_files = .empty,
1118
1119 .llvm_m_args = .empty,
1120 .sysroot = null,
1121 .lib_directories = .empty, // populated by createModule()
1122 .lib_dir_args = .empty, // populated from CLI arg parsing
1123 .libc_installation = null,
1124 .want_native_include_dirs = false,
1125 .frameworks = .empty,
1126 .framework_dirs = .empty,
1127 .rpath_list = .empty,
1128 .each_lib_rpath = null,
1129 .libc_paths_file = EnvVar.ZIG_LIBC.get(environ_map),
1130 .native_system_include_paths = &.{},
1131 };
1132 defer create_module.link_inputs.deinit(gpa);
1133
1134 var color: Color = Color.settingFromEnvironment(environ_map);
1135 var n_jobs: ?u32 = null;
1136
1137 switch (arg_mode) {
1138 .build, .translate_c, .zig_test, .zig_test_obj, .run => {
1139 switch (arg_mode) {
1140 .build => |m| {
1141 create_module.opts.output_mode = m;
1142 },
1143 .translate_c => {
1144 emit_bin = .no;
1145 create_module.opts.output_mode = .Obj;
1146 },
1147 .zig_test, .run => {
1148 create_module.opts.output_mode = .Exe;
1149 },
1150 .zig_test_obj => {
1151 create_module.opts.output_mode = .Obj;
1152 },
1153 else => unreachable,
1154 }
1155
1156 soname = .yes_default_value;
1157
1158 var args_iter = ArgsIterator{
1159 .args = all_args[2..],
1160 };
1161
1162 var file_ext: ?Compilation.FileExt = null;
1163 args_loop: while (args_iter.next()) |arg| {
1164 if (mem.cutPrefix(u8, arg, "@")) |resp_file_path| {
1165 // This is a "compiler response file". We must parse the file and treat its
1166 // contents as command line parameters.
1167 args_iter.resp_file = initArgIteratorResponseFile(arena, io, resp_file_path) catch |err|
1168 fatal("unable to read response file {q}: {t}", .{ resp_file_path, err });
1169 } else if (mem.startsWith(u8, arg, "-")) {
1170 if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
1171 try Io.File.stdout().writeStreamingAll(io, compile_usage);
1172 return cleanExit(io);
1173 } else if (mem.eql(u8, arg, "--")) {
1174 if (arg_mode == .run) {
1175 // args_iter.i is 1, referring the next arg after "--" in ["--", ...]
1176 // Add +2 to the index so it is relative to all_args
1177 runtime_args_start = args_iter.i + 2;
1178 break :args_loop;
1179 } else {
1180 fatal("unexpected end-of-parameter mark: --", .{});
1181 }
1182 } else if (mem.eql(u8, arg, "--dep")) {
1183 const next_arg = args_iter.nextOrFatal();
1184 const key, const value = mem.cutScalar(u8, next_arg, '=') orelse .{ next_arg, next_arg };
1185 if (mem.eql(u8, key, "std") and !mem.eql(u8, value, "std")) {
1186 fatal("unable to import as {q}: conflicts with builtin module", .{key});
1187 }
1188 for ([_][]const u8{ "root", "builtin" }) |name| {
1189 if (mem.eql(u8, key, name)) {
1190 fatal("unable to import as {q}: conflicts with builtin module", .{key});
1191 }
1192 }
1193 try deps.append(arena, .{
1194 .key = key,
1195 .value = value,
1196 });
1197 } else if (mem.cutPrefix(u8, arg, "-M")) |rest| {
1198 const mod_name, const root_src_orig = mem.cutScalar(u8, rest, '=') orelse .{ rest, null };
1199 try handleModArg(
1200 arena,
1201 mod_name,
1202 root_src_orig,
1203 &create_module,
1204 &mod_opts,
1205 &cc_argv,
1206 &target_arch_os_abi,
1207 &target_mcpu,
1208 &dynamic_linker,
1209 &deps,
1210 &c_source_files_owner_index,
1211 &rc_source_files_owner_index,
1212 &cssan,
1213 );
1214 } else if (mem.eql(u8, arg, "--error-limit")) {
1215 const next_arg = args_iter.nextOrFatal();
1216 error_limit = std.fmt.parseUnsigned(Zcu.ErrorInt, next_arg, 0) catch |err| {
1217 fatal("unable to parse error limit {q}: {t}", .{ next_arg, err });
1218 };
1219 } else if (mem.eql(u8, arg, "-cflags")) {
1220 extra_cflags.shrinkRetainingCapacity(0);
1221 while (true) {
1222 const next_arg = args_iter.next() orelse {
1223 fatal("expected -- after -cflags", .{});
1224 };
1225 if (mem.eql(u8, next_arg, "--")) break;
1226 try extra_cflags.append(arena, next_arg);
1227 }
1228 } else if (mem.eql(u8, arg, "-rcincludes")) {
1229 rc_includes = parseRcIncludes(args_iter.nextOrFatal());
1230 } else if (mem.cutPrefix(u8, arg, "-rcincludes=")) |rest| {
1231 rc_includes = parseRcIncludes(rest);
1232 } else if (mem.eql(u8, arg, "-rcflags")) {
1233 extra_rcflags.shrinkRetainingCapacity(0);
1234 while (true) {
1235 const next_arg = args_iter.next() orelse {
1236 fatal("expected -- after -rcflags", .{});
1237 };
1238 if (mem.eql(u8, next_arg, "--")) break;
1239 try extra_rcflags.append(arena, next_arg);
1240 }
1241 } else if (mem.eql(u8, arg, "--color")) {
1242 const next_arg = args_iter.next() orelse {
1243 fatal("expected [auto|on|off] after --color", .{});
1244 };
1245 color = stringToEnum(Color, next_arg) orelse {
1246 fatal("expected [auto|on|off] after --color, found {q}", .{next_arg});
1247 };
1248 } else if (mem.cutPrefix(u8, arg, "-j")) |str| {
1249 const num = std.fmt.parseUnsigned(u32, str, 10) catch |err| {
1250 fatal("unable to parse jobs count {q}: {t}", .{ str, err });
1251 };
1252 if (num < 1) {
1253 fatal("number of jobs must be at least 1", .{});
1254 }
1255 n_jobs = num;
1256 } else if (mem.eql(u8, arg, "--subsystem")) {
1257 subsystem = try parseSubsystem(args_iter.nextOrFatal());
1258 } else if (mem.eql(u8, arg, "-O")) {
1259 mod_opts.optimize_mode = parseOptimizeMode(args_iter.nextOrFatal());
1260 } else if (mem.cutPrefix(u8, arg, "-fentry=")) |rest| {
1261 entry = .{ .named = rest };
1262 } else if (mem.eql(u8, arg, "--force_undefined")) {
1263 try force_undefined_symbols.put(arena, args_iter.nextOrFatal(), {});
1264 } else if (mem.eql(u8, arg, "--discard-all")) {
1265 discard_local_symbols = true;
1266 } else if (mem.eql(u8, arg, "--stack")) {
1267 stack_size = parseStackSize(args_iter.nextOrFatal());
1268 } else if (mem.eql(u8, arg, "--image-base")) {
1269 image_base = parseImageBase(args_iter.nextOrFatal());
1270 } else if (mem.eql(u8, arg, "--name")) {
1271 provided_name = args_iter.nextOrFatal();
1272 if (!mem.eql(u8, provided_name.?, fs.path.basename(provided_name.?)))
1273 fatal("invalid package name {q}: cannot contain folder separators", .{provided_name.?});
1274 } else if (mem.eql(u8, arg, "-rpath")) {
1275 try create_module.rpath_list.append(arena, args_iter.nextOrFatal());
1276 } else if (mem.eql(u8, arg, "--library-directory") or mem.eql(u8, arg, "-L")) {
1277 try create_module.lib_dir_args.append(arena, args_iter.nextOrFatal());
1278 } else if (mem.eql(u8, arg, "-F")) {
1279 try create_module.framework_dirs.append(arena, args_iter.nextOrFatal());
1280 } else if (mem.eql(u8, arg, "-framework")) {
1281 try create_module.frameworks.put(arena, args_iter.nextOrFatal(), .{});
1282 } else if (mem.eql(u8, arg, "-weak_framework")) {
1283 try create_module.frameworks.put(arena, args_iter.nextOrFatal(), .{ .weak = true });
1284 } else if (mem.eql(u8, arg, "-needed_framework")) {
1285 try create_module.frameworks.put(arena, args_iter.nextOrFatal(), .{ .needed = true });
1286 } else if (mem.eql(u8, arg, "-install_name")) {
1287 install_name = args_iter.nextOrFatal();
1288 } else if (mem.cutPrefix(u8, arg, "--compress-debug-sections=")) |param| {
1289 linker_compress_debug_sections = stringToEnum(std.zig.CompressDebugSections, param) orelse {
1290 fatal("expected --compress-debug-sections=[none|zlib|zstd], found: {s}", .{param});
1291 };
1292 } else if (mem.eql(u8, arg, "--compress-debug-sections")) {
1293 linker_compress_debug_sections = .zlib;
1294 } else if (mem.eql(u8, arg, "-pagezero_size")) {
1295 const next_arg = args_iter.nextOrFatal();
1296 pagezero_size = std.fmt.parseUnsigned(u64, eatIntPrefix(next_arg, 16), 16) catch |err| {
1297 fatal("unable to parse pagezero size {q}: {t}", .{ next_arg, err });
1298 };
1299 } else if (mem.eql(u8, arg, "-search_paths_first")) {
1300 lib_search_strategy = .paths_first;
1301 lib_preferred_mode = .dynamic;
1302 } else if (mem.eql(u8, arg, "-search_paths_first_static")) {
1303 lib_search_strategy = .paths_first;
1304 lib_preferred_mode = .static;
1305 } else if (mem.eql(u8, arg, "-search_dylibs_first")) {
1306 lib_search_strategy = .mode_first;
1307 lib_preferred_mode = .dynamic;
1308 } else if (mem.eql(u8, arg, "-search_static_first")) {
1309 lib_search_strategy = .mode_first;
1310 lib_preferred_mode = .static;
1311 } else if (mem.eql(u8, arg, "-search_dylibs_only")) {
1312 lib_search_strategy = .no_fallback;
1313 lib_preferred_mode = .dynamic;
1314 } else if (mem.eql(u8, arg, "-search_static_only")) {
1315 lib_search_strategy = .no_fallback;
1316 lib_preferred_mode = .static;
1317 } else if (mem.eql(u8, arg, "-headerpad")) {
1318 const next_arg = args_iter.nextOrFatal();
1319 headerpad_size = std.fmt.parseUnsigned(u32, eatIntPrefix(next_arg, 16), 16) catch |err| {
1320 fatal("unable to parse headerpad size {q}: {t}", .{ next_arg, err });
1321 };
1322 } else if (mem.eql(u8, arg, "-headerpad_max_install_names")) {
1323 headerpad_max_install_names = true;
1324 } else if (mem.eql(u8, arg, "-dead_strip")) {
1325 linker_gc_sections = true;
1326 } else if (mem.eql(u8, arg, "-dead_strip_dylibs")) {
1327 dead_strip_dylibs = true;
1328 } else if (mem.eql(u8, arg, "-ObjC")) {
1329 force_load_objc = true;
1330 } else if (mem.eql(u8, arg, "-T") or mem.eql(u8, arg, "--script")) {
1331 linker_script = args_iter.nextOrFatal();
1332 } else if (mem.eql(u8, arg, "-version-script") or mem.eql(u8, arg, "--version-script")) {
1333 version_script = args_iter.nextOrFatal();
1334 } else if (mem.eql(u8, arg, "--undefined-version")) {
1335 linker_allow_undefined_version = true;
1336 } else if (mem.eql(u8, arg, "--no-undefined-version")) {
1337 linker_allow_undefined_version = false;
1338 } else if (mem.eql(u8, arg, "--enable-new-dtags")) {
1339 linker_enable_new_dtags = true;
1340 } else if (mem.eql(u8, arg, "--disable-new-dtags")) {
1341 linker_enable_new_dtags = false;
1342 } else if (mem.eql(u8, arg, "--library") or mem.eql(u8, arg, "-l")) {
1343 // We don't know whether this library is part of libc
1344 // or libc++ until we resolve the target, so we append
1345 // to the list for now.
1346 try create_module.cli_link_inputs.append(arena, .{ .name_query = .{
1347 .name = args_iter.nextOrFatal(),
1348 .query = .{
1349 .needed = false,
1350 .weak = false,
1351 .preferred_mode = lib_preferred_mode,
1352 .search_strategy = lib_search_strategy,
1353 .allow_so_scripts = allow_so_scripts,
1354 },
1355 } });
1356 } else if (mem.eql(u8, arg, "--needed-library") or
1357 mem.eql(u8, arg, "-needed-l") or
1358 mem.eql(u8, arg, "-needed_library"))
1359 {
1360 const next_arg = args_iter.nextOrFatal();
1361 try create_module.cli_link_inputs.append(arena, .{ .name_query = .{
1362 .name = next_arg,
1363 .query = .{
1364 .needed = true,
1365 .weak = false,
1366 .preferred_mode = lib_preferred_mode,
1367 .search_strategy = lib_search_strategy,
1368 .allow_so_scripts = allow_so_scripts,
1369 },
1370 } });
1371 } else if (mem.eql(u8, arg, "-weak_library") or mem.eql(u8, arg, "-weak-l")) {
1372 try create_module.cli_link_inputs.append(arena, .{ .name_query = .{
1373 .name = args_iter.nextOrFatal(),
1374 .query = .{
1375 .needed = false,
1376 .weak = true,
1377 .preferred_mode = lib_preferred_mode,
1378 .search_strategy = lib_search_strategy,
1379 .allow_so_scripts = allow_so_scripts,
1380 },
1381 } });
1382 } else if (mem.eql(u8, arg, "-D")) {
1383 try cc_argv.appendSlice(arena, &.{ arg, args_iter.nextOrFatal() });
1384 } else if (mem.eql(u8, arg, "-I")) {
1385 try cssan.addIncludePath(arena, &cc_argv, .I, arg, args_iter.nextOrFatal(), false);
1386 } else if (mem.cutPrefix(u8, arg, "--embed-dir=")) |rest| {
1387 try cssan.addIncludePath(arena, &cc_argv, .embed_dir, arg, rest, true);
1388 } else if (mem.eql(u8, arg, "-isystem")) {
1389 try cssan.addIncludePath(arena, &cc_argv, .isystem, arg, args_iter.nextOrFatal(), false);
1390 } else if (mem.eql(u8, arg, "-iwithsysroot")) {
1391 try cssan.addIncludePath(arena, &cc_argv, .iwithsysroot, arg, args_iter.nextOrFatal(), false);
1392 } else if (mem.eql(u8, arg, "-idirafter")) {
1393 try cssan.addIncludePath(arena, &cc_argv, .idirafter, arg, args_iter.nextOrFatal(), false);
1394 } else if (mem.eql(u8, arg, "-iframework")) {
1395 const path = args_iter.nextOrFatal();
1396 try cssan.addIncludePath(arena, &cc_argv, .iframework, arg, path, false);
1397 try create_module.framework_dirs.append(arena, path); // Forward to the backend as -F
1398 } else if (mem.eql(u8, arg, "-iframeworkwithsysroot")) {
1399 const path = args_iter.nextOrFatal();
1400 try cssan.addIncludePath(arena, &cc_argv, .iframeworkwithsysroot, arg, path, false);
1401 try create_module.framework_dirs.append(arena, path); // Forward to the backend as -F
1402 } else if (mem.eql(u8, arg, "--version")) {
1403 const next_arg = args_iter.nextOrFatal();
1404 version = std.SemanticVersion.parse(next_arg) catch |err| {
1405 fatal("unable to parse --version {q}: {t}", .{ next_arg, err });
1406 };
1407 have_version = true;
1408 } else if (mem.eql(u8, arg, "-target")) {
1409 target_arch_os_abi = args_iter.nextOrFatal();
1410 } else if (mem.eql(u8, arg, "-mcpu")) {
1411 target_mcpu = args_iter.nextOrFatal();
1412 } else if (mem.eql(u8, arg, "-mcmodel")) {
1413 mod_opts.code_model = parseCodeModel(args_iter.nextOrFatal());
1414 } else if (mem.cutPrefix(u8, arg, "-mcmodel=")) |rest| {
1415 mod_opts.code_model = parseCodeModel(rest);
1416 } else if (mem.cutPrefix(u8, arg, "-ofmt=")) |rest| {
1417 create_module.object_format = rest;
1418 } else if (mem.cutPrefix(u8, arg, "-mcpu=")) |rest| {
1419 target_mcpu = rest;
1420 } else if (mem.cutPrefix(u8, arg, "-O")) |rest| {
1421 mod_opts.optimize_mode = parseOptimizeMode(rest);
1422 } else if (mem.eql(u8, arg, "--dynamic-linker")) {
1423 dynamic_linker = args_iter.nextOrFatal();
1424 } else if (mem.eql(u8, arg, "--no-dynamic-linker")) {
1425 dynamic_linker = "";
1426 } else if (mem.eql(u8, arg, "--sysroot")) {
1427 const next_arg = args_iter.nextOrFatal();
1428 create_module.sysroot = next_arg;
1429 try cc_argv.appendSlice(arena, &.{ "-isysroot", next_arg });
1430 } else if (mem.eql(u8, arg, "--libc")) {
1431 create_module.libc_paths_file = args_iter.nextOrFatal();
1432 } else if (mem.eql(u8, arg, "--test-filter")) {
1433 try test_filters.append(arena, args_iter.nextOrFatal());
1434 } else if (mem.eql(u8, arg, "--test-runner")) {
1435 test_runner_path = args_iter.nextOrFatal();
1436 } else if (mem.eql(u8, arg, "--test-cmd")) {
1437 try test_exec_args.append(arena, args_iter.nextOrFatal());
1438 } else if (mem.eql(u8, arg, "--cache-dir")) {
1439 override_local_cache_dir = args_iter.nextOrFatal();
1440 } else if (mem.eql(u8, arg, "--global-cache-dir")) {
1441 override_global_cache_dir = args_iter.nextOrFatal();
1442 } else if (mem.eql(u8, arg, "--zig-lib-dir")) {
1443 override_lib_dir = args_iter.nextOrFatal();
1444 } else if (mem.eql(u8, arg, "--build-root")) {
1445 build_root_path = args_iter.nextOrFatal();
1446 } else if (mem.eql(u8, arg, "--debug-log")) {
1447 try addDebugLog(arena, args_iter.nextOrFatal());
1448 } else if (mem.eql(u8, arg, "--listen")) {
1449 const next_arg = args_iter.nextOrFatal();
1450 if (mem.eql(u8, next_arg, "-")) {
1451 dev.check(.stdio_listen);
1452 listen = .stdio;
1453 } else {
1454 dev.check(.network_listen);
1455 // example: --listen 127.0.0.1:9000
1456 const host, const port_text = mem.cutScalar(u8, next_arg, ':') orelse .{ next_arg, "14735" };
1457 const port = std.fmt.parseInt(u16, port_text, 10) catch |err|
1458 fatal("invalid port number: {q}: {t}", .{ port_text, err });
1459 listen = .{ .ip4 = Io.net.Ip4Address.parse(host, port) catch |err|
1460 fatal("invalid host: {q}: {t}", .{ host, err }) };
1461 }
1462 } else if (mem.eql(u8, arg, "--listen=-")) {
1463 dev.check(.stdio_listen);
1464 listen = .stdio;
1465 } else if (mem.eql(u8, arg, "--debug-link-snapshot")) {
1466 if (!build_options.enable_debug_extensions) {
1467 warn("Zig was compiled without debug extensions. --debug-link-snapshot has no effect.", .{});
1468 } else {
1469 enable_link_snapshots = true;
1470 }
1471 } else if (mem.eql(u8, arg, "--debug-rt")) {
1472 debug_compiler_runtime_libs = .debug;
1473 } else if (mem.cutPrefix(u8, arg, "--debug-rt=")) |rest| {
1474 debug_compiler_runtime_libs = parseOptimizeMode(rest);
1475 } else if (mem.eql(u8, arg, "--debug-incremental")) {
1476 if (build_options.enable_debug_extensions) {
1477 debug_incremental = true;
1478 } else {
1479 warn("Zig was compiled without debug extensions. --debug-incremental has no effect.", .{});
1480 }
1481 } else if (mem.eql(u8, arg, "-fincremental")) {
1482 dev.check(.incremental);
1483 create_module.opts.incremental = true;
1484 } else if (mem.eql(u8, arg, "-fno-incremental")) {
1485 create_module.opts.incremental = false;
1486 } else if (mem.eql(u8, arg, "--entitlements")) {
1487 entitlements = args_iter.nextOrFatal();
1488 } else if (mem.eql(u8, arg, "-fcompiler-rt")) {
1489 want_compiler_rt = true;
1490 } else if (mem.eql(u8, arg, "-fno-compiler-rt")) {
1491 want_compiler_rt = false;
1492 } else if (mem.eql(u8, arg, "-fubsan-rt")) {
1493 want_ubsan_rt = true;
1494 } else if (mem.eql(u8, arg, "-fno-ubsan-rt")) {
1495 want_ubsan_rt = false;
1496 } else if (mem.eql(u8, arg, "-feach-lib-rpath")) {
1497 create_module.each_lib_rpath = true;
1498 } else if (mem.eql(u8, arg, "-fno-each-lib-rpath")) {
1499 create_module.each_lib_rpath = false;
1500 } else if (mem.eql(u8, arg, "--test-cmd-bin")) {
1501 try test_exec_args.append(arena, null);
1502 } else if (mem.eql(u8, arg, "--test-no-exec")) {
1503 test_no_exec = true;
1504 } else if (mem.eql(u8, arg, "--time-report")) {
1505 time_report = true;
1506 } else if (mem.eql(u8, arg, "--test-execve")) {
1507 test_execve = true;
1508 } else if (mem.eql(u8, arg, "-fstack-report")) {
1509 stack_report = true;
1510 } else if (mem.eql(u8, arg, "-fPIC")) {
1511 mod_opts.pic = true;
1512 } else if (mem.eql(u8, arg, "-fno-PIC")) {
1513 mod_opts.pic = false;
1514 } else if (mem.eql(u8, arg, "-fPIE")) {
1515 create_module.opts.pie = true;
1516 } else if (mem.eql(u8, arg, "-fno-PIE")) {
1517 create_module.opts.pie = false;
1518 } else if (mem.eql(u8, arg, "-flto")) {
1519 create_module.opts.lto = .full;
1520 } else if (mem.cutPrefix(u8, arg, "-flto=")) |mode| {
1521 if (mem.eql(u8, mode, "full")) {
1522 create_module.opts.lto = .full;
1523 } else if (mem.eql(u8, mode, "thin")) {
1524 create_module.opts.lto = .thin;
1525 } else {
1526 fatal("invalid -flto mode: {q}; must be \"full\" or \"thin\"", .{mode});
1527 }
1528 } else if (mem.eql(u8, arg, "-fno-lto")) {
1529 create_module.opts.lto = .none;
1530 } else if (mem.eql(u8, arg, "-funwind-tables")) {
1531 mod_opts.unwind_tables = .sync;
1532 } else if (mem.eql(u8, arg, "-fasync-unwind-tables")) {
1533 mod_opts.unwind_tables = .async;
1534 } else if (mem.eql(u8, arg, "-fno-unwind-tables")) {
1535 mod_opts.unwind_tables = .none;
1536 } else if (mem.eql(u8, arg, "-fstack-check")) {
1537 mod_opts.stack_check = true;
1538 } else if (mem.eql(u8, arg, "-fno-stack-check")) {
1539 mod_opts.stack_check = false;
1540 } else if (mem.eql(u8, arg, "-fstack-protector")) {
1541 mod_opts.stack_protector = Compilation.default_stack_protector_buffer_size;
1542 } else if (mem.eql(u8, arg, "-fno-stack-protector")) {
1543 mod_opts.stack_protector = 0;
1544 } else if (mem.eql(u8, arg, "-mred-zone")) {
1545 mod_opts.red_zone = true;
1546 } else if (mem.eql(u8, arg, "-mno-red-zone")) {
1547 mod_opts.red_zone = false;
1548 } else if (mem.eql(u8, arg, "-fomit-frame-pointer")) {
1549 mod_opts.omit_frame_pointer = true;
1550 } else if (mem.eql(u8, arg, "-fno-omit-frame-pointer")) {
1551 mod_opts.omit_frame_pointer = false;
1552 } else if (mem.eql(u8, arg, "-fsanitize-c")) {
1553 mod_opts.sanitize_c = .full;
1554 } else if (mem.cutPrefix(u8, arg, "-fsanitize-c=")) |mode| {
1555 if (mem.eql(u8, mode, "trap")) {
1556 mod_opts.sanitize_c = .trap;
1557 } else if (mem.eql(u8, mode, "full")) {
1558 mod_opts.sanitize_c = .full;
1559 } else {
1560 fatal("invalid -fsanitize-c mode: {q}; must be \"trap\" or \"full\"", .{mode});
1561 }
1562 } else if (mem.eql(u8, arg, "-fno-sanitize-c")) {
1563 mod_opts.sanitize_c = .off;
1564 } else if (mem.eql(u8, arg, "-fvalgrind")) {
1565 mod_opts.valgrind = true;
1566 } else if (mem.eql(u8, arg, "-fno-valgrind")) {
1567 mod_opts.valgrind = false;
1568 } else if (mem.eql(u8, arg, "-fsanitize-thread")) {
1569 mod_opts.sanitize_thread = true;
1570 } else if (mem.eql(u8, arg, "-fno-sanitize-thread")) {
1571 mod_opts.sanitize_thread = false;
1572 } else if (mem.eql(u8, arg, "-ffuzz")) {
1573 mod_opts.fuzz = true;
1574 } else if (mem.eql(u8, arg, "-fno-fuzz")) {
1575 mod_opts.fuzz = false;
1576 } else if (mem.eql(u8, arg, "-fllvm")) {
1577 create_module.opts.use_llvm = true;
1578 } else if (mem.eql(u8, arg, "-fno-llvm")) {
1579 create_module.opts.use_llvm = false;
1580 } else if (mem.eql(u8, arg, "-flibllvm")) {
1581 create_module.opts.use_lib_llvm = true;
1582 } else if (mem.eql(u8, arg, "-fno-libllvm")) {
1583 create_module.opts.use_lib_llvm = false;
1584 } else if (mem.eql(u8, arg, "-flld")) {
1585 create_module.opts.use_lld = true;
1586 } else if (mem.eql(u8, arg, "-fno-lld")) {
1587 create_module.opts.use_lld = false;
1588 } else if (mem.eql(u8, arg, "-fnew-linker")) {
1589 create_module.opts.use_new_linker = true;
1590 } else if (mem.eql(u8, arg, "-fno-new-linker")) {
1591 create_module.opts.use_new_linker = false;
1592 } else if (mem.eql(u8, arg, "-fclang")) {
1593 create_module.opts.use_clang = true;
1594 } else if (mem.eql(u8, arg, "-fno-clang")) {
1595 create_module.opts.use_clang = false;
1596 } else if (mem.eql(u8, arg, "-fsanitize-coverage-trace-pc-guard")) {
1597 create_module.opts.san_cov_trace_pc_guard = true;
1598 } else if (mem.eql(u8, arg, "-fno-sanitize-coverage-trace-pc-guard")) {
1599 create_module.opts.san_cov_trace_pc_guard = false;
1600 } else if (mem.eql(u8, arg, "-freference-trace")) {
1601 reference_trace = 256;
1602 } else if (mem.cutPrefix(u8, arg, "-freference-trace=")) |num| {
1603 reference_trace = std.fmt.parseUnsigned(u32, num, 10) catch |err| {
1604 fatal("unable to parse reference_trace count {q}: {t}", .{ num, err });
1605 };
1606 } else if (mem.eql(u8, arg, "-fno-reference-trace")) {
1607 reference_trace = null;
1608 } else if (mem.eql(u8, arg, "-ferror-tracing")) {
1609 mod_opts.error_tracing = true;
1610 } else if (mem.eql(u8, arg, "-fno-error-tracing")) {
1611 mod_opts.error_tracing = false;
1612 } else if (mem.eql(u8, arg, "-rdynamic")) {
1613 create_module.opts.rdynamic = true;
1614 } else if (mem.eql(u8, arg, "-fsoname")) {
1615 soname = .yes_default_value;
1616 } else if (mem.cutPrefix(u8, arg, "-fsoname=")) |rest| {
1617 soname = .{ .yes = rest };
1618 } else if (mem.eql(u8, arg, "-fno-soname")) {
1619 soname = .no;
1620 } else if (mem.eql(u8, arg, "-femit-bin")) {
1621 emit_bin = .yes_default_path;
1622 } else if (mem.cutPrefix(u8, arg, "-femit-bin=")) |rest| {
1623 emit_bin = .{ .yes = rest };
1624 } else if (mem.eql(u8, arg, "-fno-emit-bin")) {
1625 emit_bin = .no;
1626 } else if (mem.eql(u8, arg, "-femit-h")) {
1627 fatal("-femit-h is currently broken, see https://github.com/ziglang/zig/issues/9698", .{});
1628 emit_h = .yes_default_path;
1629 } else if (mem.cutPrefix(u8, arg, "-femit-h=")) |rest| {
1630 emit_h = .{ .yes = rest };
1631 } else if (mem.eql(u8, arg, "-fno-emit-h")) {
1632 emit_h = .no;
1633 } else if (mem.eql(u8, arg, "-femit-asm")) {
1634 emit_asm = .yes_default_path;
1635 } else if (mem.cutPrefix(u8, arg, "-femit-asm=")) |rest| {
1636 emit_asm = .{ .yes = rest };
1637 } else if (mem.eql(u8, arg, "-fno-emit-asm")) {
1638 emit_asm = .no;
1639 } else if (mem.eql(u8, arg, "-femit-llvm-ir")) {
1640 emit_llvm_ir = .yes_default_path;
1641 } else if (mem.cutPrefix(u8, arg, "-femit-llvm-ir=")) |rest| {
1642 emit_llvm_ir = .{ .yes = rest };
1643 } else if (mem.eql(u8, arg, "-fno-emit-llvm-ir")) {
1644 emit_llvm_ir = .no;
1645 } else if (mem.eql(u8, arg, "-femit-llvm-bc")) {
1646 emit_llvm_bc = .yes_default_path;
1647 } else if (mem.cutPrefix(u8, arg, "-femit-llvm-bc=")) |rest| {
1648 emit_llvm_bc = .{ .yes = rest };
1649 } else if (mem.eql(u8, arg, "-fno-emit-llvm-bc")) {
1650 emit_llvm_bc = .no;
1651 } else if (mem.eql(u8, arg, "-femit-docs")) {
1652 emit_docs = .yes_default_path;
1653 } else if (mem.cutPrefix(u8, arg, "-femit-docs=")) |rest| {
1654 emit_docs = .{ .yes = rest };
1655 } else if (mem.eql(u8, arg, "-fno-emit-docs")) {
1656 emit_docs = .no;
1657 } else if (mem.eql(u8, arg, "-femit-implib")) {
1658 emit_implib = .yes_default_path;
1659 emit_implib_arg_provided = true;
1660 } else if (mem.cutPrefix(u8, arg, "-femit-implib=")) |rest| {
1661 emit_implib = .{ .yes = rest };
1662 emit_implib_arg_provided = true;
1663 } else if (mem.eql(u8, arg, "-fno-emit-implib")) {
1664 emit_implib = .no;
1665 emit_implib_arg_provided = true;
1666 } else if (mem.eql(u8, arg, "-dynamic")) {
1667 create_module.opts.link_mode = .dynamic;
1668 lib_preferred_mode = .dynamic;
1669 lib_search_strategy = .mode_first;
1670 } else if (mem.eql(u8, arg, "-static")) {
1671 create_module.opts.link_mode = .static;
1672 lib_preferred_mode = .static;
1673 lib_search_strategy = .no_fallback;
1674 } else if (mem.eql(u8, arg, "-fdll-export-fns")) {
1675 create_module.opts.dll_export_fns = true;
1676 } else if (mem.eql(u8, arg, "-fno-dll-export-fns")) {
1677 create_module.opts.dll_export_fns = false;
1678 } else if (mem.eql(u8, arg, "--show-builtin")) {
1679 show_builtin = true;
1680 emit_bin = .no;
1681 } else if (mem.eql(u8, arg, "-fstrip")) {
1682 mod_opts.strip = true;
1683 } else if (mem.eql(u8, arg, "-fno-strip")) {
1684 mod_opts.strip = false;
1685 } else if (mem.eql(u8, arg, "-gdwarf32")) {
1686 create_module.opts.debug_format = .{ .dwarf = .@"32" };
1687 } else if (mem.eql(u8, arg, "-gdwarf64")) {
1688 create_module.opts.debug_format = .{ .dwarf = .@"64" };
1689 } else if (mem.eql(u8, arg, "-fsingle-threaded")) {
1690 mod_opts.single_threaded = true;
1691 } else if (mem.eql(u8, arg, "-fno-single-threaded")) {
1692 mod_opts.single_threaded = false;
1693 } else if (mem.eql(u8, arg, "-ffunction-sections")) {
1694 function_sections = true;
1695 } else if (mem.eql(u8, arg, "-fno-function-sections")) {
1696 function_sections = false;
1697 } else if (mem.eql(u8, arg, "-fdata-sections")) {
1698 data_sections = true;
1699 } else if (mem.eql(u8, arg, "-fno-data-sections")) {
1700 data_sections = false;
1701 } else if (mem.eql(u8, arg, "-fbuiltin")) {
1702 mod_opts.no_builtin = false;
1703 } else if (mem.eql(u8, arg, "-fno-builtin")) {
1704 mod_opts.no_builtin = true;
1705 } else if (mem.cutPrefix(u8, arg, "-fopt-bisect-limit=")) |next_arg| {
1706 llvm_opt_bisect_limit = std.fmt.parseInt(c_int, next_arg, 0) catch |err|
1707 fatal("unable to parse {q}: {t}", .{ arg, err });
1708 } else if (mem.eql(u8, arg, "--eh-frame-hdr")) {
1709 link_eh_frame_hdr = true;
1710 } else if (mem.eql(u8, arg, "--no-eh-frame-hdr")) {
1711 link_eh_frame_hdr = false;
1712 } else if (mem.eql(u8, arg, "--dynamicbase")) {
1713 linker_dynamicbase = true;
1714 } else if (mem.eql(u8, arg, "--no-dynamicbase")) {
1715 linker_dynamicbase = false;
1716 } else if (mem.eql(u8, arg, "--emit-relocs")) {
1717 link_emit_relocs = true;
1718 } else if (mem.eql(u8, arg, "-fallow-shlib-undefined")) {
1719 linker_allow_shlib_undefined = true;
1720 } else if (mem.eql(u8, arg, "-fno-allow-shlib-undefined")) {
1721 linker_allow_shlib_undefined = false;
1722 } else if (mem.eql(u8, arg, "-fallow-so-scripts")) {
1723 allow_so_scripts = true;
1724 } else if (mem.eql(u8, arg, "-fno-allow-so-scripts")) {
1725 allow_so_scripts = false;
1726 } else if (mem.eql(u8, arg, "-z")) {
1727 const z_arg = args_iter.nextOrFatal();
1728 if (mem.eql(u8, z_arg, "nodelete")) {
1729 linker_z_nodelete = true;
1730 } else if (mem.eql(u8, z_arg, "notext")) {
1731 linker_z_notext = true;
1732 } else if (mem.eql(u8, z_arg, "defs")) {
1733 linker_z_defs = true;
1734 } else if (mem.eql(u8, z_arg, "undefs")) {
1735 linker_z_defs = false;
1736 } else if (mem.eql(u8, z_arg, "origin")) {
1737 linker_z_origin = true;
1738 } else if (mem.eql(u8, z_arg, "nocopyreloc")) {
1739 linker_z_nocopyreloc = true;
1740 } else if (mem.eql(u8, z_arg, "now")) {
1741 linker_z_now = true;
1742 } else if (mem.eql(u8, z_arg, "lazy")) {
1743 linker_z_now = false;
1744 } else if (mem.eql(u8, z_arg, "relro")) {
1745 linker_z_relro = true;
1746 } else if (mem.eql(u8, z_arg, "norelro")) {
1747 linker_z_relro = false;
1748 } else if (prefixedIntArg(z_arg, "common-page-size=")) |int| {
1749 linker_z_common_page_size = int;
1750 } else if (prefixedIntArg(z_arg, "max-page-size=")) |int| {
1751 linker_z_max_page_size = int;
1752 } else {
1753 fatal("unsupported linker extension flag: -z {s}", .{z_arg});
1754 }
1755 } else if (mem.eql(u8, arg, "--import-memory")) {
1756 create_module.opts.import_memory = true;
1757 } else if (mem.eql(u8, arg, "-fentry")) {
1758 switch (entry) {
1759 .default, .disabled => entry = .enabled,
1760 .enabled, .named => {},
1761 }
1762 } else if (mem.eql(u8, arg, "-fno-entry")) {
1763 entry = .disabled;
1764 } else if (mem.eql(u8, arg, "--export-memory")) {
1765 create_module.opts.export_memory = true;
1766 } else if (mem.eql(u8, arg, "--import-symbols")) {
1767 linker_import_symbols = true;
1768 } else if (mem.eql(u8, arg, "--import-table")) {
1769 linker_import_table = true;
1770 } else if (mem.eql(u8, arg, "--export-table")) {
1771 linker_export_table = true;
1772 } else if (mem.eql(u8, arg, "--growable-table")) {
1773 linker_growable_table = true;
1774 } else if (prefixedIntArg(arg, "--initial-memory=")) |int| {
1775 linker_initial_memory = int;
1776 } else if (prefixedIntArg(arg, "--max-memory=")) |int| {
1777 linker_max_memory = int;
1778 } else if (mem.eql(u8, arg, "--shared-memory")) {
1779 create_module.opts.shared_memory = true;
1780 } else if (prefixedIntArg(arg, "--global-base=")) |int| {
1781 linker_global_base = int;
1782 } else if (mem.cutPrefix(u8, arg, "--export=")) |rest| {
1783 try linker_export_symbol_names.append(arena, rest);
1784 } else if (mem.eql(u8, arg, "-Bsymbolic")) {
1785 linker_bind_global_refs_locally = true;
1786 } else if (mem.eql(u8, arg, "--gc-sections")) {
1787 linker_gc_sections = true;
1788 } else if (mem.eql(u8, arg, "--no-gc-sections")) {
1789 linker_gc_sections = false;
1790 } else if (mem.eql(u8, arg, "--build-id")) {
1791 build_id = .fast;
1792 } else if (mem.cutPrefix(u8, arg, "--build-id=")) |style| {
1793 build_id = std.zig.BuildId.parse(style) catch |err| {
1794 fatal("unable to parse --build-id style {q}: {t}", .{ style, err });
1795 };
1796 } else if (mem.eql(u8, arg, "--debug-compile-errors")) {
1797 if (build_options.enable_debug_extensions) {
1798 debug_compile_errors = true;
1799 } else {
1800 warn("Zig was compiled without debug extensions. --debug-compile-errors has no effect.", .{});
1801 }
1802 } else if (mem.eql(u8, arg, "--verbose-link")) {
1803 verbose_link = true;
1804 } else if (mem.eql(u8, arg, "--verbose-cc")) {
1805 verbose_cc = true;
1806 } else if (mem.eql(u8, arg, "--verbose-air")) {
1807 verbose_air = true;
1808 } else if (mem.eql(u8, arg, "--verbose-intern-pool")) {
1809 verbose_intern_pool = true;
1810 } else if (mem.eql(u8, arg, "--verbose-generic-instances")) {
1811 verbose_generic_instances = true;
1812 } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) {
1813 verbose_llvm_ir = "-";
1814 } else if (mem.cutPrefix(u8, arg, "--verbose-llvm-ir=")) |rest| {
1815 verbose_llvm_ir = rest;
1816 } else if (mem.cutPrefix(u8, arg, "--verbose-llvm-bc=")) |rest| {
1817 verbose_llvm_bc = rest;
1818 } else if (mem.eql(u8, arg, "--verbose-llvm-cpu-features")) {
1819 verbose_llvm_cpu_features = true;
1820 } else if (mem.cutPrefix(u8, arg, "-T")) |rest| {
1821 linker_script = rest;
1822 } else if (mem.cutPrefix(u8, arg, "-L")) |rest| {
1823 try create_module.lib_dir_args.append(arena, rest);
1824 } else if (mem.cutPrefix(u8, arg, "-F")) |rest| {
1825 try create_module.framework_dirs.append(arena, rest);
1826 } else if (mem.cutPrefix(u8, arg, "-l")) |name| {
1827 // We don't know whether this library is part of libc
1828 // or libc++ until we resolve the target, so we append
1829 // to the list for now.
1830 try create_module.cli_link_inputs.append(arena, .{ .name_query = .{
1831 .name = name,
1832 .query = .{
1833 .needed = false,
1834 .weak = false,
1835 .preferred_mode = lib_preferred_mode,
1836 .search_strategy = lib_search_strategy,
1837 .allow_so_scripts = allow_so_scripts,
1838 },
1839 } });
1840 } else if (mem.cutPrefix(u8, arg, "-needed-l")) |name| {
1841 try create_module.cli_link_inputs.append(arena, .{ .name_query = .{
1842 .name = name,
1843 .query = .{
1844 .needed = true,
1845 .weak = false,
1846 .preferred_mode = lib_preferred_mode,
1847 .search_strategy = lib_search_strategy,
1848 .allow_so_scripts = allow_so_scripts,
1849 },
1850 } });
1851 } else if (mem.cutPrefix(u8, arg, "-weak-l")) |name| {
1852 try create_module.cli_link_inputs.append(arena, .{ .name_query = .{
1853 .name = name,
1854 .query = .{
1855 .needed = false,
1856 .weak = true,
1857 .preferred_mode = lib_preferred_mode,
1858 .search_strategy = lib_search_strategy,
1859 .allow_so_scripts = allow_so_scripts,
1860 },
1861 } });
1862 } else if (mem.startsWith(u8, arg, "-D")) {
1863 try cc_argv.append(arena, arg);
1864 } else if (mem.cutPrefix(u8, arg, "-I")) |rest| {
1865 try cssan.addIncludePath(arena, &cc_argv, .I, arg, rest, true);
1866 } else if (mem.cutPrefix(u8, arg, "-x")) |rest| {
1867 const lang = if (rest.len == 0) args_iter.nextOrFatal() else rest;
1868 if (mem.eql(u8, lang, "none")) {
1869 file_ext = null;
1870 } else if (Compilation.FileExt.from_lang.get(lang)) |got_ext| {
1871 file_ext = got_ext;
1872 } else {
1873 fatal("language not recognized: {s}", .{lang});
1874 }
1875 } else if (mem.cutPrefix(u8, arg, "-mexec-model=")) |rest| {
1876 create_module.opts.wasi_exec_model = parseWasiExecModel(rest);
1877 } else if (mem.eql(u8, arg, "-municode")) {
1878 mingw_unicode_entry_point = true;
1879 } else {
1880 fatal("unrecognized parameter: {s}", .{arg});
1881 }
1882 } else switch (file_ext orelse Compilation.classifyFileExt(arg)) {
1883 .shared_library, .object, .static_library => {
1884 try create_module.cli_link_inputs.append(arena, .{ .path_query = .{
1885 .path = Path.initCwd(arg),
1886 .query = .{
1887 .preferred_mode = lib_preferred_mode,
1888 .search_strategy = lib_search_strategy,
1889 .allow_so_scripts = allow_so_scripts,
1890 },
1891 } });
1892 // We do not set `any_dyn_libs` yet because a .so file
1893 // may actually resolve to a GNU ld script which ends
1894 // up being a static library.
1895 },
1896 .res => {
1897 try create_module.cli_link_inputs.append(arena, .{ .path_query = .{
1898 .path = Path.initCwd(arg),
1899 .query = .{
1900 .preferred_mode = lib_preferred_mode,
1901 .search_strategy = lib_search_strategy,
1902 .allow_so_scripts = allow_so_scripts,
1903 },
1904 } });
1905 contains_res_file = true;
1906 },
1907 .manifest => {
1908 if (manifest_file) |other| {
1909 fatal("only one manifest file can be specified, found {q} after {q}", .{ arg, other });
1910 } else manifest_file = arg;
1911 },
1912 .def => {
1913 linker_module_definition_file = arg;
1914 },
1915 .assembly, .assembly_with_cpp, .c, .cpp, .h, .hpp, .hm, .hmm, .ll, .bc, .m, .mm => {
1916 dev.check(.c_compiler);
1917 try create_module.c_source_files.append(arena, .{
1918 // Populated after module creation.
1919 .owner = undefined,
1920 .src_path = arg,
1921 .extra_flags = try arena.dupe([]const u8, extra_cflags.items),
1922 // duped when parsing the args.
1923 .ext = file_ext,
1924 });
1925 },
1926 .rc => {
1927 dev.check(.win32_resource);
1928 try create_module.rc_source_files.append(arena, .{
1929 // Populated after module creation.
1930 .owner = undefined,
1931 .src_path = arg,
1932 .extra_flags = try arena.dupe([]const u8, extra_rcflags.items),
1933 });
1934 },
1935 .zig => {
1936 if (root_src_file) |other| {
1937 fatal("found another zig file {q} after root source file {q}", .{ arg, other });
1938 } else root_src_file = arg;
1939 },
1940 .unknown => {
1941 if (std.ascii.eqlIgnoreCase(".xml", fs.path.extension(arg))) {
1942 warn("embedded manifest files must have the extension '.manifest'", .{});
1943 }
1944 fatal("unrecognized file extension of parameter {q}", .{arg});
1945 },
1946 }
1947 }
1948 },
1949 .cc, .cpp => {
1950 dev.check(.cc_command);
1951
1952 emit_h = .no;
1953 soname = .no;
1954 create_module.opts.ensure_libc_on_non_freestanding = true;
1955 create_module.opts.ensure_libcpp_on_non_freestanding = arg_mode == .cpp;
1956 create_module.want_native_include_dirs = true;
1957 // Clang's driver enables this switch unconditionally.
1958 // Disabling the emission of .eh_frame_hdr can unexpectedly break
1959 // some functionality that depend on it, such as C++ exceptions and
1960 // DWARF-based stack traces.
1961 link_eh_frame_hdr = true;
1962 allow_so_scripts = true;
1963
1964 const COutMode = enum {
1965 link,
1966 object,
1967 assembly,
1968 preprocessor,
1969 version,
1970 };
1971 var c_out_mode: ?COutMode = null;
1972 var out_path: ?[]const u8 = null;
1973 var is_shared_lib = false;
1974 var preprocessor_args = std.array_list.Managed([]const u8).init(arena);
1975 var linker_args = std.array_list.Managed([]const u8).init(arena);
1976 var it = ClangArgIterator.init(arena, all_args);
1977 var emit_llvm = false;
1978 var needed = false;
1979 var must_link = false;
1980 var file_ext: ?Compilation.FileExt = null;
1981 while (it.has_next) {
1982 it.next(io) catch |err| fatal("unable to parse command line parameters: {t}", .{err});
1983 switch (it.zig_equivalent) {
1984 .target => target_arch_os_abi = it.only_arg, // example: -target riscv64-linux-unknown
1985 .o => {
1986 // We handle -o /dev/null equivalent to -fno-emit-bin because
1987 // otherwise our atomic rename into place will fail. This also
1988 // makes Zig do less work, avoiding pointless file system operations.
1989 if (mem.eql(u8, it.only_arg, "/dev/null")) {
1990 emit_bin = .no;
1991 } else {
1992 out_path = it.only_arg;
1993 }
1994 },
1995 .c, .r => c_out_mode = .object, // -c or -r
1996 .asm_only => c_out_mode = .assembly, // -S
1997 .preprocess_only => c_out_mode = .preprocessor, // -E
1998 .version => {
1999 c_out_mode = .version; // --version
2000 disable_c_depfile = true;
2001 },
2002 .emit_llvm => emit_llvm = true,
2003 .x => {
2004 const lang = mem.sliceTo(it.only_arg, 0);
2005 if (mem.eql(u8, lang, "none")) {
2006 file_ext = null;
2007 } else if (Compilation.FileExt.from_lang.get(lang)) |got_ext| {
2008 file_ext = got_ext;
2009 } else {
2010 fatal("language not recognized: {q}", .{lang});
2011 }
2012 },
2013 .other => {
2014 try cc_argv.appendSlice(arena, it.other_args);
2015 },
2016 .positional => switch (file_ext orelse Compilation.classifyFileExt(mem.sliceTo(it.only_arg, 0))) {
2017 .assembly, .assembly_with_cpp, .c, .cpp, .ll, .bc, .h, .hpp, .hm, .hmm, .m, .mm => {
2018 try create_module.c_source_files.append(arena, .{
2019 // Populated after module creation.
2020 .owner = undefined,
2021 .src_path = it.only_arg,
2022 .ext = file_ext, // duped while parsing the args.
2023 });
2024 },
2025 .unknown, .object, .static_library, .shared_library => {
2026 try create_module.cli_link_inputs.append(arena, .{ .path_query = .{
2027 .path = Path.initCwd(it.only_arg),
2028 .query = .{
2029 .must_link = must_link,
2030 .needed = needed,
2031 .preferred_mode = lib_preferred_mode,
2032 .search_strategy = lib_search_strategy,
2033 .allow_so_scripts = allow_so_scripts,
2034 },
2035 } });
2036 // We do not set `any_dyn_libs` yet because a .so file
2037 // may actually resolve to a GNU ld script which ends
2038 // up being a static library.
2039 },
2040 .res => {
2041 try create_module.cli_link_inputs.append(arena, .{ .path_query = .{
2042 .path = Path.initCwd(it.only_arg),
2043 .query = .{
2044 .must_link = must_link,
2045 .needed = needed,
2046 .preferred_mode = lib_preferred_mode,
2047 .search_strategy = lib_search_strategy,
2048 .allow_so_scripts = allow_so_scripts,
2049 },
2050 } });
2051 contains_res_file = true;
2052 },
2053 .manifest => {
2054 if (manifest_file) |other| {
2055 fatal("only one manifest file can be specified, found {q} after previously specified manifest {q}", .{ it.only_arg, other });
2056 } else manifest_file = it.only_arg;
2057 },
2058 .def => {
2059 linker_module_definition_file = it.only_arg;
2060 },
2061 .rc => {
2062 try create_module.rc_source_files.append(arena, .{
2063 // Populated after module creation.
2064 .owner = undefined,
2065 .src_path = it.only_arg,
2066 });
2067 },
2068 .zig => {
2069 if (root_src_file) |other| {
2070 fatal("found another zig file {q} after root source file {q}", .{ it.only_arg, other });
2071 } else root_src_file = it.only_arg;
2072 },
2073 },
2074 .l => {
2075 // -l
2076 // We don't know whether this library is part of libc or libc++ until
2077 // we resolve the target, so we simply append to the list for now.
2078 if (mem.startsWith(u8, it.only_arg, ":")) {
2079 // -l :path/to/filename is used when callers need
2080 // more control over what's in the resulting
2081 // binary: no extra rpaths and DSO filename exactly
2082 // as provided. CGo compilation depends on this.
2083 try create_module.cli_link_inputs.append(arena, .{ .dso_exact = .{
2084 .name = it.only_arg,
2085 } });
2086 } else {
2087 const compiler_rt_classification = target_util.classifyCompilerRtLibName(it.only_arg);
2088 switch (compiler_rt_classification) {
2089 .only_compiler_rt, .both => {
2090 // We need this variable separately from `want_compiler_rt` because of
2091 // invocations such as `zig cc -lcompiler_rt -nostdlib`. If we just set
2092 // `want_compiler_rt = true` here, processing of the later `-nostdlib`
2093 // would undo that.
2094 zig_cc_explicitly_link_compiler_rt = true;
2095 },
2096 .none, .only_libunwind => {},
2097 }
2098 if (compiler_rt_classification != .only_compiler_rt) {
2099 // The case in which this arg wants to link libunwind is handled in createModule.
2100 try create_module.cli_link_inputs.append(arena, .{ .name_query = .{
2101 .name = it.only_arg,
2102 .query = .{
2103 .must_link = must_link,
2104 .needed = needed,
2105 .weak = false,
2106 .preferred_mode = lib_preferred_mode,
2107 .search_strategy = lib_search_strategy,
2108 .allow_so_scripts = allow_so_scripts,
2109 },
2110 } });
2111 }
2112 }
2113 },
2114 .ignore => {},
2115 .driver_punt => {
2116 // Never mind what we're doing, just pass the args directly. For example --help.
2117 return process.exit(try clangMain(arena, all_args));
2118 },
2119 .pic => mod_opts.pic = true,
2120 .no_pic => mod_opts.pic = false,
2121 .pie => create_module.opts.pie = true,
2122 .no_pie => create_module.opts.pie = false,
2123 .lto => {
2124 if (mem.eql(u8, it.only_arg, "flto") or
2125 mem.eql(u8, it.only_arg, "auto") or
2126 mem.eql(u8, it.only_arg, "full") or
2127 mem.eql(u8, it.only_arg, "jobserver"))
2128 {
2129 create_module.opts.lto = .full;
2130 } else if (mem.eql(u8, it.only_arg, "thin")) {
2131 create_module.opts.lto = .thin;
2132 } else {
2133 fatal("invalid -flto mode {q}; must be \"auto\", \"full\", \"thin\", or \"jobserver\"", .{it.only_arg});
2134 }
2135 },
2136 .no_lto => create_module.opts.lto = .none,
2137 .red_zone => mod_opts.red_zone = true,
2138 .no_red_zone => mod_opts.red_zone = false,
2139 .omit_frame_pointer => mod_opts.omit_frame_pointer = true,
2140 .no_omit_frame_pointer => mod_opts.omit_frame_pointer = false,
2141 .function_sections => function_sections = true,
2142 .no_function_sections => function_sections = false,
2143 .data_sections => data_sections = true,
2144 .no_data_sections => data_sections = false,
2145 .builtin => mod_opts.no_builtin = false,
2146 .no_builtin => mod_opts.no_builtin = true,
2147 .color_diagnostics => color = .on,
2148 .no_color_diagnostics => color = .off,
2149 .stack_check => mod_opts.stack_check = true,
2150 .no_stack_check => mod_opts.stack_check = false,
2151 .stack_protector => {
2152 if (mod_opts.stack_protector == null) {
2153 mod_opts.stack_protector = Compilation.default_stack_protector_buffer_size;
2154 }
2155 },
2156 .no_stack_protector => mod_opts.stack_protector = 0,
2157 // The way these unwind table options are processed in GCC and Clang is crazy
2158 // convoluted, and we also don't know the target triple here, so this is all
2159 // best-effort.
2160 .unwind_tables => if (mod_opts.unwind_tables) |uwt| switch (uwt) {
2161 .none => {
2162 mod_opts.unwind_tables = .sync;
2163 },
2164 .sync, .async => {},
2165 } else {
2166 mod_opts.unwind_tables = .sync;
2167 },
2168 .no_unwind_tables => mod_opts.unwind_tables = .none,
2169 .asynchronous_unwind_tables => mod_opts.unwind_tables = .async,
2170 .no_asynchronous_unwind_tables => if (mod_opts.unwind_tables) |uwt| switch (uwt) {
2171 .none, .sync => {},
2172 .async => {
2173 mod_opts.unwind_tables = .sync;
2174 },
2175 } else {
2176 mod_opts.unwind_tables = .sync;
2177 },
2178 .nostdlib => {
2179 create_module.opts.ensure_libc_on_non_freestanding = false;
2180 create_module.opts.ensure_libcpp_on_non_freestanding = false;
2181 want_compiler_rt = false;
2182 want_ubsan_rt = false;
2183 },
2184 .nostdlib_cpp => create_module.opts.ensure_libcpp_on_non_freestanding = false,
2185 .shared => {
2186 create_module.opts.link_mode = .dynamic;
2187 is_shared_lib = true;
2188 },
2189 .rdynamic => create_module.opts.rdynamic = true,
2190 .wp => {
2191 var split_it = mem.splitScalar(u8, it.only_arg, ',');
2192 while (split_it.next()) |preprocessor_arg| {
2193 if (preprocessor_arg.len >= 3 and
2194 preprocessor_arg[0] == '-' and
2195 preprocessor_arg[2] != '-')
2196 {
2197 if (mem.findScalar(u8, preprocessor_arg, '=')) |equals_pos| {
2198 const key = preprocessor_arg[0..equals_pos];
2199 const value = preprocessor_arg[equals_pos + 1 ..];
2200 try preprocessor_args.append(key);
2201 try preprocessor_args.append(value);
2202 continue;
2203 }
2204 }
2205 try preprocessor_args.append(preprocessor_arg);
2206 }
2207 },
2208 .wl => {
2209 var split_it = mem.splitScalar(u8, it.only_arg, ',');
2210 while (split_it.next()) |linker_arg| {
2211 // Unfortunately duplicated with the `for_linker` handling below.
2212
2213 // Handle nested-joined args like `-Wl,-rpath=foo`.
2214 // Must be prefixed with 1 or 2 dashes.
2215 if (linker_arg.len >= 3 and
2216 linker_arg[0] == '-' and
2217 linker_arg[2] != '-')
2218 {
2219 if (mem.findScalar(u8, linker_arg, '=')) |equals_pos| {
2220 const key = linker_arg[0..equals_pos];
2221 const value = linker_arg[equals_pos + 1 ..];
2222
2223 // We have to handle these here because they would be ambiguous
2224 // if split and added to `linker_args`, as there are argument-less
2225 // variants of them.
2226 if (mem.eql(u8, key, "--build-id")) {
2227 build_id = std.zig.BuildId.parse(value) catch |err| {
2228 fatal("unable to parse --build-id style {q}: {t}", .{ value, err });
2229 };
2230 continue;
2231 } else if (mem.eql(u8, key, "--sort-common")) {
2232 // this ignores --sort=common=<anything>; ignoring plain --sort-common
2233 // is done below.
2234 continue;
2235 }
2236
2237 try linker_args.append(key);
2238 try linker_args.append(value);
2239 continue;
2240 }
2241 }
2242
2243 // These options are handled inline because their order matters for
2244 // other non-linker options.
2245 if (mem.eql(u8, linker_arg, "--as-needed")) {
2246 needed = false;
2247 } else if (mem.eql(u8, linker_arg, "--no-as-needed")) {
2248 needed = true;
2249 } else if (mem.eql(u8, linker_arg, "--whole-archive") or
2250 mem.eql(u8, linker_arg, "-whole-archive"))
2251 {
2252 must_link = true;
2253 } else if (mem.eql(u8, linker_arg, "--no-whole-archive") or
2254 mem.eql(u8, linker_arg, "-no-whole-archive"))
2255 {
2256 must_link = false;
2257 } else if (mem.eql(u8, linker_arg, "-Bdynamic") or
2258 mem.eql(u8, linker_arg, "-dy") or
2259 mem.eql(u8, linker_arg, "-call_shared"))
2260 {
2261 lib_search_strategy = .no_fallback;
2262 lib_preferred_mode = .dynamic;
2263 } else if (mem.eql(u8, linker_arg, "-Bstatic") or
2264 mem.eql(u8, linker_arg, "-dn") or
2265 mem.eql(u8, linker_arg, "-non_shared") or
2266 mem.eql(u8, linker_arg, "-static"))
2267 {
2268 lib_search_strategy = .no_fallback;
2269 lib_preferred_mode = .static;
2270 } else if (mem.eql(u8, linker_arg, "-search_paths_first")) {
2271 lib_search_strategy = .paths_first;
2272 lib_preferred_mode = .dynamic;
2273 } else if (mem.eql(u8, linker_arg, "-search_dylibs_first")) {
2274 lib_search_strategy = .mode_first;
2275 lib_preferred_mode = .dynamic;
2276 } else {
2277 try linker_args.append(linker_arg);
2278 }
2279 }
2280 },
2281 .san_cov_trace_pc_guard => create_module.opts.san_cov_trace_pc_guard = true,
2282 .san_cov => {
2283 var split_it = mem.splitScalar(u8, it.only_arg, ',');
2284 while (split_it.next()) |san_arg| {
2285 if (std.mem.eql(u8, san_arg, "trace-pc-guard")) {
2286 create_module.opts.san_cov_trace_pc_guard = true;
2287 }
2288 }
2289 try cc_argv.appendSlice(arena, it.other_args);
2290 },
2291 .no_san_cov => {
2292 var split_it = mem.splitScalar(u8, it.only_arg, ',');
2293 while (split_it.next()) |san_arg| {
2294 if (std.mem.eql(u8, san_arg, "trace-pc-guard")) {
2295 create_module.opts.san_cov_trace_pc_guard = false;
2296 }
2297 }
2298 try cc_argv.appendSlice(arena, it.other_args);
2299 },
2300 .optimize => {
2301 // Alright, what release mode do they want?
2302 const level = if (it.only_arg.len >= 1 and it.only_arg[0] == 'O') it.only_arg[1..] else it.only_arg;
2303 if (mem.eql(u8, level, "s") or
2304 mem.eql(u8, level, "z"))
2305 {
2306 mod_opts.optimize_mode = .small;
2307 } else if (mem.eql(u8, level, "1") or
2308 mem.eql(u8, level, "2") or
2309 mem.eql(u8, level, "3") or
2310 mem.eql(u8, level, "4") or
2311 mem.eql(u8, level, "fast"))
2312 {
2313 mod_opts.optimize_mode = .fast;
2314 } else if (mem.eql(u8, level, "g") or
2315 mem.eql(u8, level, "0"))
2316 {
2317 mod_opts.optimize_mode = .debug;
2318 } else {
2319 try cc_argv.appendSlice(arena, it.other_args);
2320 }
2321 },
2322 .debug => {
2323 mod_opts.strip = false;
2324 if (mem.eql(u8, it.only_arg, "g")) {
2325 // We handled with strip = false above.
2326 } else if (mem.eql(u8, it.only_arg, "g1") or
2327 mem.eql(u8, it.only_arg, "gline-tables-only"))
2328 {
2329 // We handled with strip = false above. but we also want reduced debug info.
2330 try cc_argv.append(arena, "-gline-tables-only");
2331 } else {
2332 try cc_argv.appendSlice(arena, it.other_args);
2333 }
2334 },
2335 .gdwarf32 => {
2336 mod_opts.strip = false;
2337 create_module.opts.debug_format = .{ .dwarf = .@"32" };
2338 },
2339 .gdwarf64 => {
2340 mod_opts.strip = false;
2341 create_module.opts.debug_format = .{ .dwarf = .@"64" };
2342 },
2343 .sanitize, .no_sanitize => |t| {
2344 const enable = t == .sanitize;
2345 var san_it = std.mem.splitScalar(u8, it.only_arg, ',');
2346 var recognized_any = false;
2347 while (san_it.next()) |sub_arg| {
2348 if (mem.eql(u8, sub_arg, "undefined")) {
2349 mod_opts.sanitize_c = if (enable) .full else .off;
2350 recognized_any = true;
2351 } else if (mem.eql(u8, sub_arg, "thread")) {
2352 mod_opts.sanitize_thread = enable;
2353 recognized_any = true;
2354 } else if (mem.eql(u8, sub_arg, "fuzzer") or mem.eql(u8, sub_arg, "fuzzer-no-link")) {
2355 mod_opts.fuzz = enable;
2356 recognized_any = true;
2357 }
2358 }
2359 if (!recognized_any) {
2360 try cc_argv.appendSlice(arena, it.other_args);
2361 }
2362 },
2363 .sanitize_trap, .no_sanitize_trap => |t| {
2364 const enable = t == .sanitize_trap;
2365 var san_it = std.mem.splitScalar(u8, it.only_arg, ',');
2366 var recognized_any = false;
2367 while (san_it.next()) |sub_arg| {
2368 // This logic doesn't match Clang 1:1, but it's probably good enough, and avoids
2369 // significantly complicating the resolution of the options.
2370 if (mem.eql(u8, sub_arg, "undefined")) {
2371 if (mod_opts.sanitize_c) |sc| switch (sc) {
2372 .off => if (enable) {
2373 mod_opts.sanitize_c = .trap;
2374 },
2375 .trap => if (!enable) {
2376 mod_opts.sanitize_c = .full;
2377 },
2378 .full => if (enable) {
2379 mod_opts.sanitize_c = .trap;
2380 },
2381 } else {
2382 if (enable) {
2383 mod_opts.sanitize_c = .trap;
2384 } else {
2385 // This means we were passed `-fno-sanitize-trap=undefined` and nothing else. In
2386 // this case, ideally, we should use whatever value `sanitize_c` resolves to by
2387 // default, except change `trap` to `full`. However, we don't yet know what
2388 // `sanitize_c` will resolve to! So we either have to pick `off` or `full`.
2389 //
2390 // `full` has the potential to be problematic if `optimize_mode` turns out to
2391 // be `fast`/`small` because the user will get a slower and larger
2392 // binary than expected. On the other hand, if `optimize_mode` turns out to be
2393 // `debug`/`safe`, `off` would mean UBSan would unexpectedly be disabled.
2394 //
2395 // `off` seems very slightly less bad, so let's go with that.
2396 mod_opts.sanitize_c = .off;
2397 }
2398 }
2399 recognized_any = true;
2400 }
2401 }
2402 if (!recognized_any) {
2403 try cc_argv.appendSlice(arena, it.other_args);
2404 }
2405 },
2406 .linker_script => linker_script = it.only_arg,
2407 .verbose => {
2408 verbose_link = true;
2409 // Have Clang print more infos, some tools such as CMake
2410 // parse this to discover any implicit include and
2411 // library dir to look-up into.
2412 try cc_argv.append(arena, "-v");
2413 },
2414 .dry_run => {
2415 // This flag means "dry run". Clang will not actually output anything
2416 // to the file system.
2417 verbose_link = true;
2418 disable_c_depfile = true;
2419 try cc_argv.append(arena, "-###");
2420 },
2421 .for_linker => blk: {
2422 // Unfortunately duplicated with the `wl` handling above.
2423
2424 // Handle joined args like `--dependency-file=foo.d`.
2425 // Must be prefixed with 1 or 2 dashes.
2426 if (it.only_arg.len >= 3 and it.only_arg[0] == '-' and it.only_arg[2] != '-') {
2427 if (mem.findScalar(u8, it.only_arg, '=')) |equals_pos| {
2428 const key = it.only_arg[0..equals_pos];
2429 const value = it.only_arg[equals_pos + 1 ..];
2430
2431 // We have to handle these here because they would be ambiguous
2432 // if split and added to `linker_args`, as there are argument-less
2433 // variants of them.
2434 if (mem.eql(u8, key, "--build-id")) {
2435 build_id = std.zig.BuildId.parse(value) catch |err| {
2436 fatal("unable to parse --build-id style {q}: {t}", .{ value, err });
2437 };
2438 continue;
2439 } else if (mem.eql(u8, key, "--sort-common")) {
2440 // this ignores --sort-common=<anything>
2441 continue;
2442 }
2443
2444 try linker_args.append(key);
2445 try linker_args.append(value);
2446 break :blk;
2447 }
2448 }
2449
2450 // These options are handled inline because their order matters for
2451 // other non-linker options.
2452 if (mem.eql(u8, it.only_arg, "--as-needed")) {
2453 needed = false;
2454 } else if (mem.eql(u8, it.only_arg, "--no-as-needed")) {
2455 needed = true;
2456 } else if (mem.eql(u8, it.only_arg, "--whole-archive") or
2457 mem.eql(u8, it.only_arg, "-whole-archive"))
2458 {
2459 must_link = true;
2460 } else if (mem.eql(u8, it.only_arg, "--no-whole-archive") or
2461 mem.eql(u8, it.only_arg, "-no-whole-archive"))
2462 {
2463 must_link = false;
2464 } else if (mem.eql(u8, it.only_arg, "-Bdynamic") or
2465 mem.eql(u8, it.only_arg, "-dy") or
2466 mem.eql(u8, it.only_arg, "-call_shared"))
2467 {
2468 lib_search_strategy = .no_fallback;
2469 lib_preferred_mode = .dynamic;
2470 } else if (mem.eql(u8, it.only_arg, "-Bstatic") or
2471 mem.eql(u8, it.only_arg, "-dn") or
2472 mem.eql(u8, it.only_arg, "-non_shared") or
2473 mem.eql(u8, it.only_arg, "-static"))
2474 {
2475 lib_search_strategy = .no_fallback;
2476 lib_preferred_mode = .static;
2477 } else if (mem.eql(u8, it.only_arg, "-search_paths_first")) {
2478 lib_search_strategy = .paths_first;
2479 lib_preferred_mode = .dynamic;
2480 } else if (mem.eql(u8, it.only_arg, "-search_dylibs_first")) {
2481 lib_search_strategy = .mode_first;
2482 lib_preferred_mode = .dynamic;
2483 } else {
2484 try linker_args.append(it.only_arg);
2485 }
2486 },
2487 .linker_input_z => {
2488 try linker_args.append("-z");
2489 try linker_args.append(it.only_arg);
2490 },
2491 .lib_dir => try create_module.lib_dir_args.append(arena, it.only_arg),
2492 .mcpu => target_mcpu = it.only_arg,
2493 .m => try create_module.llvm_m_args.append(arena, it.only_arg),
2494 .dep_file => {
2495 disable_c_depfile = true;
2496 try cc_argv.appendSlice(arena, it.other_args);
2497 },
2498 .dep_file_to_stdout => { // -M, -MM
2499 // "Like -MD, but also implies -E and writes to stdout by default"
2500 // "Like -MMD, but also implies -E and writes to stdout by default"
2501 c_out_mode = .preprocessor;
2502 disable_c_depfile = true;
2503 try cc_argv.appendSlice(arena, it.other_args);
2504 },
2505 .framework_dir => try create_module.framework_dirs.append(arena, it.only_arg),
2506 .framework => try create_module.frameworks.put(arena, it.only_arg, .{}),
2507 .nostdlibinc => create_module.want_native_include_dirs = false,
2508 .strip => mod_opts.strip = true,
2509 .exec_model => {
2510 create_module.opts.wasi_exec_model = parseWasiExecModel(it.only_arg);
2511 },
2512 .sysroot => {
2513 create_module.sysroot = it.only_arg;
2514 },
2515 .entry => {
2516 entry = .{ .named = it.only_arg };
2517 },
2518 .force_undefined_symbol => {
2519 try force_undefined_symbols.put(arena, it.only_arg, {});
2520 },
2521 .force_load_objc => force_load_objc = true,
2522 .mingw_unicode_entry_point => mingw_unicode_entry_point = true,
2523 .weak_library => try create_module.cli_link_inputs.append(arena, .{ .name_query = .{
2524 .name = it.only_arg,
2525 .query = .{
2526 .needed = false,
2527 .weak = true,
2528 .preferred_mode = lib_preferred_mode,
2529 .search_strategy = lib_search_strategy,
2530 .allow_so_scripts = allow_so_scripts,
2531 },
2532 } }),
2533 .weak_framework => try create_module.frameworks.put(arena, it.only_arg, .{ .weak = true }),
2534 .headerpad_max_install_names => headerpad_max_install_names = true,
2535 .compress_debug_sections => {
2536 if (it.only_arg.len == 0) {
2537 linker_compress_debug_sections = .zlib;
2538 } else {
2539 linker_compress_debug_sections = stringToEnum(std.zig.CompressDebugSections, it.only_arg) orelse {
2540 fatal("expected [none|zlib|zstd] after --compress-debug-sections, found {q}", .{it.only_arg});
2541 };
2542 }
2543 },
2544 .install_name => {
2545 install_name = it.only_arg;
2546 },
2547 .undefined => {
2548 if (mem.eql(u8, "dynamic_lookup", it.only_arg)) {
2549 linker_allow_shlib_undefined = true;
2550 } else if (mem.eql(u8, "error", it.only_arg)) {
2551 linker_allow_shlib_undefined = false;
2552 } else {
2553 fatal("unsupported -undefined option {q}", .{it.only_arg});
2554 }
2555 },
2556 .rtlib => {
2557 // Unlike Clang, we support `none` for explicitly omitting compiler-rt.
2558 if (mem.eql(u8, "none", it.only_arg)) {
2559 want_compiler_rt = false;
2560 } else if (mem.eql(u8, "compiler-rt", it.only_arg) or
2561 mem.eql(u8, "libgcc", it.only_arg))
2562 {
2563 want_compiler_rt = true;
2564 } else {
2565 // Note that we don't support `platform`.
2566 fatal("unsupported -rtlib option {q}", .{it.only_arg});
2567 }
2568 },
2569 .static => {
2570 create_module.opts.link_mode = .static;
2571 lib_preferred_mode = .static;
2572 lib_search_strategy = .no_fallback;
2573 },
2574 .dynamic => {
2575 create_module.opts.link_mode = .dynamic;
2576 lib_preferred_mode = .dynamic;
2577 lib_search_strategy = .mode_first;
2578 },
2579 }
2580 }
2581 // Parse linker args.
2582 var linker_args_it = ArgsIterator{
2583 .args = linker_args.items,
2584 };
2585 while (linker_args_it.next()) |arg| {
2586 if (mem.eql(u8, arg, "-soname") or
2587 mem.eql(u8, arg, "--soname"))
2588 {
2589 const name = linker_args_it.nextOrFatal();
2590 soname = .{ .yes = name };
2591 // Use it as --name.
2592 // Example: libsoundio.so.2
2593 var prefix: usize = 0;
2594 if (mem.startsWith(u8, name, "lib")) {
2595 prefix = 3;
2596 }
2597 var end: usize = name.len;
2598 if (mem.endsWith(u8, name, ".so")) {
2599 end -= 3;
2600 } else {
2601 var found_digit = false;
2602 while (end > 0 and std.ascii.isDigit(name[end - 1])) {
2603 found_digit = true;
2604 end -= 1;
2605 }
2606 if (found_digit and end > 0 and name[end - 1] == '.') {
2607 end -= 1;
2608 } else {
2609 end = name.len;
2610 }
2611 if (mem.endsWith(u8, name[prefix..end], ".so")) {
2612 end -= 3;
2613 }
2614 }
2615 provided_name = name[prefix..end];
2616 } else if (mem.eql(u8, arg, "--build-id")) {
2617 build_id = .fast;
2618 } else if (mem.eql(u8, arg, "-no-pie")) {
2619 create_module.opts.pie = false;
2620 } else if (mem.eql(u8, arg, "--sort-common")) {
2621 // from ld.lld(1): --sort-common is ignored for GNU compatibility,
2622 // this ignores plain --sort-common
2623 } else if (mem.eql(u8, arg, "-rpath") or mem.eql(u8, arg, "--rpath") or mem.eql(u8, arg, "-R")) {
2624 try create_module.rpath_list.append(arena, linker_args_it.nextOrFatal());
2625 } else if (mem.eql(u8, arg, "-rpath-link") or mem.eql(u8, arg, "--rpath-link")) {
2626 _ = linker_args_it.nextOrFatal();
2627 warn("rpath-link option is unimplemented and ignored", .{});
2628 } else if (mem.eql(u8, arg, "--subsystem")) {
2629 subsystem = try parseSubsystem(linker_args_it.nextOrFatal());
2630 } else if (mem.eql(u8, arg, "-I") or
2631 mem.eql(u8, arg, "--dynamic-linker") or
2632 mem.eql(u8, arg, "-dynamic-linker"))
2633 {
2634 dynamic_linker = linker_args_it.nextOrFatal();
2635 } else if (mem.eql(u8, arg, "--no-dynamic-linker") or
2636 mem.eql(u8, arg, "-no-dynamic-linker"))
2637 {
2638 dynamic_linker = "";
2639 } else if (mem.eql(u8, arg, "-E") or
2640 mem.eql(u8, arg, "--export-dynamic") or
2641 mem.eql(u8, arg, "-export-dynamic"))
2642 {
2643 create_module.opts.rdynamic = true;
2644 } else if (mem.eql(u8, arg, "-version-script") or mem.eql(u8, arg, "--version-script")) {
2645 version_script = linker_args_it.nextOrFatal();
2646 } else if (mem.eql(u8, arg, "--undefined-version")) {
2647 linker_allow_undefined_version = true;
2648 } else if (mem.eql(u8, arg, "--no-undefined-version")) {
2649 linker_allow_undefined_version = false;
2650 } else if (mem.eql(u8, arg, "--enable-new-dtags")) {
2651 linker_enable_new_dtags = true;
2652 } else if (mem.eql(u8, arg, "--disable-new-dtags")) {
2653 linker_enable_new_dtags = false;
2654 } else if (mem.eql(u8, arg, "-O")) {
2655 linker_optimization = linker_args_it.nextOrFatal();
2656 } else if (mem.cutPrefix(u8, arg, "-O")) |rest| {
2657 linker_optimization = rest;
2658 } else if (mem.eql(u8, arg, "-pagezero_size")) {
2659 const next_arg = linker_args_it.nextOrFatal();
2660 pagezero_size = std.fmt.parseUnsigned(u64, eatIntPrefix(next_arg, 16), 16) catch |err| {
2661 fatal("unable to parse pagezero size {q}: {t}", .{ next_arg, err });
2662 };
2663 } else if (mem.eql(u8, arg, "-headerpad")) {
2664 const next_arg = linker_args_it.nextOrFatal();
2665 headerpad_size = std.fmt.parseUnsigned(u32, eatIntPrefix(next_arg, 16), 16) catch |err| {
2666 fatal("unable to parse headerpad size {q}: {t}", .{ next_arg, err });
2667 };
2668 } else if (mem.eql(u8, arg, "-headerpad_max_install_names")) {
2669 headerpad_max_install_names = true;
2670 } else if (mem.eql(u8, arg, "-dead_strip")) {
2671 linker_gc_sections = true;
2672 } else if (mem.eql(u8, arg, "-dead_strip_dylibs")) {
2673 dead_strip_dylibs = true;
2674 } else if (mem.eql(u8, arg, "-ObjC")) {
2675 force_load_objc = true;
2676 } else if (mem.eql(u8, arg, "--no-undefined")) {
2677 linker_z_defs = true;
2678 } else if (mem.eql(u8, arg, "--gc-sections")) {
2679 linker_gc_sections = true;
2680 } else if (mem.eql(u8, arg, "--no-gc-sections")) {
2681 linker_gc_sections = false;
2682 } else if (mem.eql(u8, arg, "--print-gc-sections")) {
2683 linker_print_gc_sections = true;
2684 } else if (mem.eql(u8, arg, "--print-icf-sections")) {
2685 linker_print_icf_sections = true;
2686 } else if (mem.eql(u8, arg, "--print-map")) {
2687 linker_print_map = true;
2688 } else if (mem.eql(u8, arg, "-n") or mem.eql(u8, arg, "--nmagic")) {
2689 linker_nmagic = true;
2690 } else if (mem.eql(u8, arg, "--fatal-warnings")) {
2691 linker_fatal_warnings = true;
2692 } else if (mem.eql(u8, arg, "--no-fatal-warnings")) {
2693 linker_fatal_warnings = false;
2694 } else if (mem.eql(u8, arg, "-m")) {
2695 _ = linker_args_it.nextOrFatal();
2696 warn("-m option is ignored; emulation is derived from target", .{});
2697 } else if (mem.eql(u8, arg, "--sort-section")) {
2698 const arg1 = linker_args_it.nextOrFatal();
2699 linker_sort_section = stringToEnum(link.File.Lld.Elf.SortSection, arg1) orelse {
2700 fatal("expected [name|alignment] after --sort-section, found {q}", .{arg1});
2701 };
2702 } else if (mem.eql(u8, arg, "--allow-shlib-undefined") or
2703 mem.eql(u8, arg, "-allow-shlib-undefined"))
2704 {
2705 linker_allow_shlib_undefined = true;
2706 } else if (mem.eql(u8, arg, "--no-allow-shlib-undefined") or
2707 mem.eql(u8, arg, "-no-allow-shlib-undefined"))
2708 {
2709 linker_allow_shlib_undefined = false;
2710 } else if (mem.eql(u8, arg, "-Bsymbolic")) {
2711 linker_bind_global_refs_locally = true;
2712 } else if (mem.eql(u8, arg, "--import-memory")) {
2713 create_module.opts.import_memory = true;
2714 } else if (mem.eql(u8, arg, "--export-memory")) {
2715 create_module.opts.export_memory = true;
2716 } else if (mem.eql(u8, arg, "--import-symbols")) {
2717 linker_import_symbols = true;
2718 } else if (mem.eql(u8, arg, "--import-table")) {
2719 linker_import_table = true;
2720 } else if (mem.eql(u8, arg, "--export-table")) {
2721 linker_export_table = true;
2722 } else if (mem.eql(u8, arg, "--growable-table")) {
2723 linker_growable_table = true;
2724 } else if (mem.eql(u8, arg, "--no-entry")) {
2725 entry = .disabled;
2726 } else if (mem.eql(u8, arg, "--initial-memory")) {
2727 const next_arg = linker_args_it.nextOrFatal();
2728 linker_initial_memory = std.fmt.parseUnsigned(u32, next_arg, 10) catch |err| {
2729 fatal("unable to parse initial memory size {q}: {t}", .{ next_arg, err });
2730 };
2731 } else if (mem.eql(u8, arg, "--max-memory")) {
2732 const next_arg = linker_args_it.nextOrFatal();
2733 linker_max_memory = std.fmt.parseUnsigned(u32, next_arg, 10) catch |err| {
2734 fatal("unable to parse max memory size {q}: {t}", .{ next_arg, err });
2735 };
2736 } else if (mem.eql(u8, arg, "--shared-memory")) {
2737 create_module.opts.shared_memory = true;
2738 } else if (mem.eql(u8, arg, "--global-base")) {
2739 const next_arg = linker_args_it.nextOrFatal();
2740 linker_global_base = std.fmt.parseUnsigned(u32, next_arg, 10) catch |err| {
2741 fatal("unable to parse global base {q}: {t}", .{ next_arg, err });
2742 };
2743 } else if (mem.eql(u8, arg, "--export")) {
2744 try linker_export_symbol_names.append(arena, linker_args_it.nextOrFatal());
2745 } else if (mem.eql(u8, arg, "-exported_symbols_list")) {
2746 const exported_symbols_list = linker_args_it.nextOrFatal();
2747 const content = Io.Dir.cwd().readFileAlloc(io, exported_symbols_list, arena, .limited(10 * 1024 * 1024)) catch |err| {
2748 fatal("unable to read exported symbols list {q}: {t}", .{ exported_symbols_list, err });
2749 };
2750 var symbols_it = mem.splitScalar(u8, content, '\n');
2751 while (symbols_it.next()) |line| {
2752 if (line.len == 0) continue;
2753 try linker_export_symbol_names.append(arena, line);
2754 }
2755 } else if (mem.eql(u8, arg, "--compress-debug-sections")) {
2756 const arg1 = linker_args_it.nextOrFatal();
2757 linker_compress_debug_sections = stringToEnum(std.zig.CompressDebugSections, arg1) orelse {
2758 fatal("expected [none|zlib|zstd] after --compress-debug-sections, found {q}", .{arg1});
2759 };
2760 } else if (mem.cutPrefix(u8, arg, "-z")) |z_rest| {
2761 const z_arg = if (z_rest.len == 0) linker_args_it.nextOrFatal() else z_rest;
2762 if (mem.eql(u8, z_arg, "nodelete")) {
2763 linker_z_nodelete = true;
2764 } else if (mem.eql(u8, z_arg, "notext")) {
2765 linker_z_notext = true;
2766 } else if (mem.eql(u8, z_arg, "defs")) {
2767 linker_z_defs = true;
2768 } else if (mem.eql(u8, z_arg, "undefs")) {
2769 linker_z_defs = false;
2770 } else if (mem.eql(u8, z_arg, "origin")) {
2771 linker_z_origin = true;
2772 } else if (mem.eql(u8, z_arg, "nocopyreloc")) {
2773 linker_z_nocopyreloc = true;
2774 } else if (mem.eql(u8, z_arg, "noexecstack")) {
2775 // noexecstack is the default when linking with LLD
2776 } else if (mem.eql(u8, z_arg, "now")) {
2777 linker_z_now = true;
2778 } else if (mem.eql(u8, z_arg, "lazy")) {
2779 linker_z_now = false;
2780 } else if (mem.eql(u8, z_arg, "relro")) {
2781 linker_z_relro = true;
2782 } else if (mem.eql(u8, z_arg, "norelro")) {
2783 linker_z_relro = false;
2784 } else if (mem.cutPrefix(u8, z_arg, "stack-size=")) |rest| {
2785 stack_size = parseStackSize(rest);
2786 } else if (prefixedIntArg(z_arg, "common-page-size=")) |int| {
2787 linker_z_common_page_size = int;
2788 } else if (prefixedIntArg(z_arg, "max-page-size=")) |int| {
2789 linker_z_max_page_size = int;
2790 } else {
2791 fatal("unsupported linker extension flag: -z {s}", .{z_arg});
2792 }
2793 } else if (mem.eql(u8, arg, "--major-image-version")) {
2794 const major = linker_args_it.nextOrFatal();
2795 version.major = std.fmt.parseUnsigned(u32, major, 10) catch |err| {
2796 fatal("unable to parse major image version {q}: {t}", .{ major, err });
2797 };
2798 have_version = true;
2799 } else if (mem.eql(u8, arg, "--minor-image-version")) {
2800 const minor = linker_args_it.nextOrFatal();
2801 version.minor = std.fmt.parseUnsigned(u32, minor, 10) catch |err| {
2802 fatal("unable to parse minor image version {q}: {t}", .{ minor, err });
2803 };
2804 have_version = true;
2805 } else if (mem.eql(u8, arg, "-e") or mem.eql(u8, arg, "--entry")) {
2806 entry = .{ .named = linker_args_it.nextOrFatal() };
2807 } else if (mem.eql(u8, arg, "-u")) {
2808 try force_undefined_symbols.put(arena, linker_args_it.nextOrFatal(), {});
2809 } else if (mem.eql(u8, arg, "-w")) {
2810 // This ignores the -w flag of ld64 and ld64.lld to suppress all linker warnings
2811 // since Zig doesn't emit linker warnings.
2812 } else if (mem.eql(u8, arg, "-x") or mem.eql(u8, arg, "--discard-all")) {
2813 discard_local_symbols = true;
2814 } else if (mem.eql(u8, arg, "--stack") or mem.eql(u8, arg, "-stack_size")) {
2815 stack_size = parseStackSize(linker_args_it.nextOrFatal());
2816 } else if (mem.eql(u8, arg, "--image-base")) {
2817 image_base = parseImageBase(linker_args_it.nextOrFatal());
2818 } else if (mem.eql(u8, arg, "--enable-auto-image-base") or
2819 mem.eql(u8, arg, "--disable-auto-image-base"))
2820 {
2821 // `--enable-auto-image-base` is a flag that binutils added in ~2000 for MinGW.
2822 // It does a hash of the file and uses that as part of the image base value.
2823 // Presumably the idea was to avoid DLLs needing to be relocated when loaded.
2824 // This is practically irrelevant today as all PEs produced since Windows Vista
2825 // have ASLR enabled by default anyway, and Windows 10+ has Mandatory ASLR which
2826 // doesn't even care what the PE file wants and relocates it anyway.
2827 //
2828 // Unfortunately, Libtool hardcodes usage of this archaic flag when targeting
2829 // MinGW, so to make `zig cc` for that use case work, accept and ignore the
2830 // flag, and warn the user that it has no effect.
2831 warn("auto-image-base options are unimplemented and ignored", .{});
2832 } else if (mem.eql(u8, arg, "-T") or mem.eql(u8, arg, "--script")) {
2833 linker_script = linker_args_it.nextOrFatal();
2834 } else if (mem.eql(u8, arg, "--eh-frame-hdr")) {
2835 link_eh_frame_hdr = true;
2836 } else if (mem.eql(u8, arg, "--no-eh-frame-hdr")) {
2837 link_eh_frame_hdr = false;
2838 } else if (mem.eql(u8, arg, "--tsaware")) {
2839 linker_tsaware = true;
2840 } else if (mem.eql(u8, arg, "--nxcompat")) {
2841 linker_nxcompat = true;
2842 } else if (mem.eql(u8, arg, "--dynamicbase")) {
2843 linker_dynamicbase = true;
2844 } else if (mem.eql(u8, arg, "--no-dynamicbase")) {
2845 linker_dynamicbase = false;
2846 } else if (mem.eql(u8, arg, "--high-entropy-va")) {
2847 // This option does not do anything.
2848 } else if (mem.eql(u8, arg, "--export-all-symbols")) {
2849 create_module.opts.rdynamic = true;
2850 } else if (mem.eql(u8, arg, "--color-diagnostics") or
2851 mem.eql(u8, arg, "--color-diagnostics=always"))
2852 {
2853 color = .on;
2854 } else if (mem.eql(u8, arg, "--no-color-diagnostics") or
2855 mem.eql(u8, arg, "--color-diagnostics=never"))
2856 {
2857 color = .off;
2858 } else if (mem.eql(u8, arg, "-s") or mem.eql(u8, arg, "--strip-all") or
2859 mem.eql(u8, arg, "-S") or mem.eql(u8, arg, "--strip-debug"))
2860 {
2861 // -s, --strip-all Strip all symbols
2862 // -S, --strip-debug Strip debugging symbols
2863 mod_opts.strip = true;
2864 } else if (mem.eql(u8, arg, "--start-group") or
2865 mem.eql(u8, arg, "--end-group"))
2866 {
2867 // We don't need to care about these because these args are
2868 // for resolving circular dependencies but our linker takes
2869 // care of this without explicit args.
2870 } else if (mem.eql(u8, arg, "--major-os-version") or
2871 mem.eql(u8, arg, "--minor-os-version"))
2872 {
2873 // This option does not do anything.
2874 _ = linker_args_it.nextOrFatal();
2875 } else if (mem.eql(u8, arg, "--major-subsystem-version")) {
2876 const major = linker_args_it.nextOrFatal();
2877 major_subsystem_version = std.fmt.parseUnsigned(u16, major, 10) catch |err| {
2878 fatal("unable to parse major subsystem version {q}: {t}", .{ major, err });
2879 };
2880 } else if (mem.eql(u8, arg, "--minor-subsystem-version")) {
2881 const minor = linker_args_it.nextOrFatal();
2882 minor_subsystem_version = std.fmt.parseUnsigned(u16, minor, 10) catch |err| {
2883 fatal("unable to parse minor subsystem version {q}: {t}", .{ minor, err });
2884 };
2885 } else if (mem.eql(u8, arg, "-framework")) {
2886 try create_module.frameworks.put(arena, linker_args_it.nextOrFatal(), .{});
2887 } else if (mem.eql(u8, arg, "-weak_framework")) {
2888 try create_module.frameworks.put(arena, linker_args_it.nextOrFatal(), .{ .weak = true });
2889 } else if (mem.eql(u8, arg, "-needed_framework")) {
2890 try create_module.frameworks.put(arena, linker_args_it.nextOrFatal(), .{ .needed = true });
2891 } else if (mem.eql(u8, arg, "-needed_library")) {
2892 try create_module.cli_link_inputs.append(arena, .{ .name_query = .{
2893 .name = linker_args_it.nextOrFatal(),
2894 .query = .{
2895 .weak = false,
2896 .needed = true,
2897 .preferred_mode = lib_preferred_mode,
2898 .search_strategy = lib_search_strategy,
2899 .allow_so_scripts = allow_so_scripts,
2900 },
2901 } });
2902 } else if (mem.cutPrefix(u8, arg, "-weak-l")) |rest| {
2903 try create_module.cli_link_inputs.append(arena, .{ .name_query = .{
2904 .name = rest,
2905 .query = .{
2906 .weak = true,
2907 .needed = false,
2908 .preferred_mode = lib_preferred_mode,
2909 .search_strategy = lib_search_strategy,
2910 .allow_so_scripts = allow_so_scripts,
2911 },
2912 } });
2913 } else if (mem.eql(u8, arg, "-weak_library")) {
2914 try create_module.cli_link_inputs.append(arena, .{ .name_query = .{
2915 .name = linker_args_it.nextOrFatal(),
2916 .query = .{
2917 .weak = true,
2918 .needed = false,
2919 .preferred_mode = lib_preferred_mode,
2920 .search_strategy = lib_search_strategy,
2921 .allow_so_scripts = allow_so_scripts,
2922 },
2923 } });
2924 } else if (mem.eql(u8, arg, "-compatibility_version")) {
2925 const compat_version = linker_args_it.nextOrFatal();
2926 compatibility_version = std.SemanticVersion.parse(compat_version) catch |err| {
2927 fatal("unable to parse -compatibility_version {q}: {t}", .{ compat_version, err });
2928 };
2929 } else if (mem.eql(u8, arg, "-current_version")) {
2930 const curr_version = linker_args_it.nextOrFatal();
2931 version = std.SemanticVersion.parse(curr_version) catch |err| {
2932 fatal("unable to parse -current_version {q}: {t}", .{ curr_version, err });
2933 };
2934 have_version = true;
2935 } else if (mem.eql(u8, arg, "--out-implib") or
2936 mem.eql(u8, arg, "-implib"))
2937 {
2938 emit_implib = .{ .yes = linker_args_it.nextOrFatal() };
2939 emit_implib_arg_provided = true;
2940 } else if (mem.eql(u8, arg, "--dependency-file")) {
2941 link_depfile = linker_args_it.nextOrFatal();
2942 } else if (mem.eql(u8, arg, "-Brepro") or mem.eql(u8, arg, "/Brepro")) {
2943 linker_repro = true;
2944 } else if (mem.eql(u8, arg, "-undefined")) {
2945 const lookup_type = linker_args_it.nextOrFatal();
2946 if (mem.eql(u8, "dynamic_lookup", lookup_type)) {
2947 linker_allow_shlib_undefined = true;
2948 } else if (mem.eql(u8, "error", lookup_type)) {
2949 linker_allow_shlib_undefined = false;
2950 } else {
2951 fatal("unsupported -undefined option {q}", .{lookup_type});
2952 }
2953 } else if (mem.eql(u8, arg, "-install_name")) {
2954 install_name = linker_args_it.nextOrFatal();
2955 } else if (mem.eql(u8, arg, "-force_load")) {
2956 try create_module.cli_link_inputs.append(arena, .{ .path_query = .{
2957 .path = Path.initCwd(linker_args_it.nextOrFatal()),
2958 .query = .{
2959 .must_link = true,
2960 .preferred_mode = .static,
2961 .search_strategy = .no_fallback,
2962 },
2963 } });
2964 } else if (mem.eql(u8, arg, "-hash-style") or
2965 mem.eql(u8, arg, "--hash-style"))
2966 {
2967 const next_arg = linker_args_it.nextOrFatal();
2968 hash_style = stringToEnum(link.File.Lld.Elf.HashStyle, next_arg) orelse {
2969 fatal("expected [sysv|gnu|both] after --hash-style, found {q}", .{next_arg});
2970 };
2971 } else if (mem.eql(u8, arg, "-wrap") or mem.eql(u8, arg, "--wrap")) {
2972 const next_arg = linker_args_it.nextOrFatal();
2973 try symbol_wrap_set.put(arena, next_arg, {});
2974 } else if (mem.cutPrefix(u8, arg, "--wrap=")) |symbol| {
2975 try symbol_wrap_set.put(arena, symbol, {});
2976 } else if (mem.startsWith(u8, arg, "/subsystem:")) {
2977 var split_it = mem.splitBackwardsScalar(u8, arg, ':');
2978 subsystem = try parseSubsystem(split_it.first());
2979 } else if (mem.startsWith(u8, arg, "/implib:")) {
2980 var split_it = mem.splitBackwardsScalar(u8, arg, ':');
2981 emit_implib = .{ .yes = split_it.first() };
2982 emit_implib_arg_provided = true;
2983 } else if (mem.startsWith(u8, arg, "/pdb:")) {
2984 var split_it = mem.splitBackwardsScalar(u8, arg, ':');
2985 pdb_out_path = split_it.first();
2986 } else if (mem.startsWith(u8, arg, "/version:")) {
2987 var split_it = mem.splitBackwardsScalar(u8, arg, ':');
2988 const version_arg = split_it.first();
2989 version = std.SemanticVersion.parse(version_arg) catch |err| {
2990 fatal("unable to parse /version {q}: {t}", .{ arg, err });
2991 };
2992 have_version = true;
2993 } else if (mem.eql(u8, arg, "-V")) {
2994 warn("ignoring request for supported emulations: unimplemented", .{});
2995 } else if (mem.eql(u8, arg, "-v")) {
2996 try Io.File.stdout().writeStreamingAll(io, "zig ld " ++ build_options.version ++ "\n");
2997 } else if (mem.eql(u8, arg, "--version")) {
2998 try Io.File.stdout().writeStreamingAll(io, "zig ld " ++ build_options.version ++ "\n");
2999 process.exit(0);
3000 } else {
3001 fatal("unsupported linker arg: {s}", .{arg});
3002 }
3003 }
3004
3005 // Parse preprocessor args.
3006 var preprocessor_args_it = ArgsIterator{
3007 .args = preprocessor_args.items,
3008 };
3009 while (preprocessor_args_it.next()) |arg| {
3010 if (mem.eql(u8, arg, "-MD") or mem.eql(u8, arg, "-MMD") or mem.eql(u8, arg, "-MT")) {
3011 disable_c_depfile = true;
3012 const cc_arg = try arena.print("-Wp,{s},{s}", .{ arg, preprocessor_args_it.nextOrFatal() });
3013 try cc_argv.append(arena, cc_arg);
3014 } else {
3015 fatal("unsupported preprocessor arg: {s}", .{arg});
3016 }
3017 }
3018
3019 if (mod_opts.sanitize_c) |wsc| {
3020 if (wsc != .off and mod_opts.optimize_mode == .fast) {
3021 mod_opts.optimize_mode = .safe;
3022 }
3023 }
3024
3025 // precompiled header syntax: "zig cc -x c-header test.h -o test.pch"
3026 const emit_pch = if (file_ext) |fe| switch (fe) {
3027 .h, .hpp, .hm, .hmm => c_out_mode == null,
3028 else => false,
3029 } else false;
3030 if (emit_pch) c_out_mode = .preprocessor;
3031
3032 switch (c_out_mode orelse .link) {
3033 .link => {
3034 create_module.opts.output_mode = if (is_shared_lib) .Lib else .Exe;
3035 if (emit_bin != .no) {
3036 emit_bin = if (out_path) |p| .{ .yes = p } else .yes_a_out;
3037 }
3038 if (emit_llvm) {
3039 fatal("-emit-llvm cannot be used when linking", .{});
3040 }
3041 },
3042 .object => {
3043 create_module.opts.output_mode = .Obj;
3044 if (emit_llvm) {
3045 emit_bin = .no;
3046 if (out_path) |p| {
3047 emit_llvm_bc = .{ .yes = p };
3048 } else {
3049 emit_llvm_bc = .yes_default_path;
3050 }
3051 } else {
3052 if (out_path) |p| {
3053 emit_bin = .{ .yes = p };
3054 } else {
3055 emit_bin = .yes_default_path;
3056 }
3057 }
3058 },
3059 .assembly => {
3060 create_module.opts.output_mode = .Obj;
3061 emit_bin = .no;
3062 if (emit_llvm) {
3063 if (out_path) |p| {
3064 emit_llvm_ir = .{ .yes = p };
3065 } else {
3066 emit_llvm_ir = .yes_default_path;
3067 }
3068 } else {
3069 if (out_path) |p| {
3070 emit_asm = .{ .yes = p };
3071 } else {
3072 emit_asm = .yes_default_path;
3073 }
3074 }
3075 },
3076 .preprocessor => {
3077 create_module.opts.output_mode = .Obj;
3078 // An error message is generated when there is more than 1 C source file.
3079 if (create_module.c_source_files.items.len != 1) {
3080 // For example `zig cc` and no args should print the "no input files" message.
3081 return process.exit(try clangMain(arena, all_args));
3082 }
3083 if (emit_pch) {
3084 emit_bin = if (out_path) |p| .{ .yes = p } else .yes_default_path;
3085 clang_preprocessor_mode = .pch;
3086 } else {
3087 // If the output path is "-" (stdout), then we need to emit the preprocessed output to stdout
3088 // like "clang -E main.c -o -" does.
3089 if (out_path != null and !mem.eql(u8, out_path.?, "-")) {
3090 emit_bin = .{ .yes = out_path.? };
3091 clang_preprocessor_mode = .yes;
3092 } else {
3093 emit_bin = .no;
3094 clang_preprocessor_mode = .stdout;
3095 }
3096 }
3097 },
3098 .version => {
3099 // We can't allow control flow to reach the simpler logic
3100 // below because the -target argument has to be lowered to
3101 // clang syntax in Compilation.
3102 create_module.opts.output_mode = .Obj;
3103 clang_preprocessor_mode = .version;
3104 if (create_module.c_source_files.items.len == 0) {
3105 try create_module.c_source_files.append(arena, .{
3106 .owner = undefined,
3107 .src_path = "a.c", // dummy name
3108 .ext = .c,
3109 });
3110 }
3111 },
3112 }
3113 if (create_module.c_source_files.items.len == 0 and
3114 !anyObjectLinkInputs(create_module.cli_link_inputs.items) and
3115 root_src_file == null)
3116 {
3117 // For example `zig cc` and no args should print the "no input files" message.
3118 // There could be other reasons to punt to clang, for example, --help.
3119 return process.exit(try clangMain(arena, all_args));
3120 }
3121 },
3122 }
3123
3124 if (arg_mode == .zig_test_obj and !test_no_exec and listen == .none) {
3125 fatal("test-obj requires --test-no-exec", .{});
3126 }
3127
3128 if (time_report and listen == .none) {
3129 fatal("--time-report requires --listen", .{});
3130 }
3131
3132 if (arg_mode == .translate_c and create_module.c_source_files.items.len != 1) {
3133 fatal("translate-c expects exactly 1 source file (found {d})", .{create_module.c_source_files.items.len});
3134 }
3135
3136 if (show_builtin and root_src_file == null) {
3137 // Without this, there will be no main module created and no zig
3138 // compilation unit, and therefore also no builtin.zig contents
3139 // created.
3140 root_src_file = "builtin.zig";
3141 }
3142
3143 implicit_root_mod: {
3144 const src_path = b: {
3145 if (root_src_file) |src_path| {
3146 if (create_module.modules.count() != 0) {
3147 fatal("main module provided both by '-M{s}={s}{c}{s}' and by positional argument {q}", .{
3148 create_module.modules.keys()[0],
3149 create_module.modules.values()[0].root_path,
3150 fs.path.sep,
3151 create_module.modules.values()[0].root_src_path,
3152 src_path,
3153 });
3154 }
3155 create_module.opts.have_zcu = true;
3156 break :b src_path;
3157 }
3158
3159 if (create_module.modules.count() != 0)
3160 break :implicit_root_mod;
3161
3162 if (create_module.c_source_files.items.len >= 1)
3163 break :b create_module.c_source_files.items[0].src_path;
3164
3165 for (create_module.cli_link_inputs.items) |unresolved_link_input| switch (unresolved_link_input) {
3166 // Intentionally includes dynamic libraries provided by file path.
3167 .path_query => |pq| break :b pq.path.sub_path,
3168 else => continue,
3169 };
3170
3171 if (emit_bin == .yes)
3172 break :b emit_bin.yes;
3173
3174 if (create_module.rc_source_files.items.len >= 1)
3175 break :b create_module.rc_source_files.items[0].src_path;
3176
3177 if (arg_mode == .run)
3178 fatal("`zig run` expects at least one positional argument", .{});
3179
3180 fatal("expected a positional argument, -femit-bin=[path], --show-builtin, or --name [name]", .{});
3181
3182 break :implicit_root_mod;
3183 };
3184
3185 // See duplicate logic: ModCreationGlobalFlags
3186 if (mod_opts.single_threaded == false)
3187 create_module.opts.any_non_single_threaded = true;
3188 if (mod_opts.sanitize_thread == true)
3189 create_module.opts.any_sanitize_thread = true;
3190 if (mod_opts.sanitize_c) |sc| switch (sc) {
3191 .off => {},
3192 .trap => if (create_module.opts.any_sanitize_c == .off) {
3193 create_module.opts.any_sanitize_c = .trap;
3194 },
3195 .full => create_module.opts.any_sanitize_c = .full,
3196 };
3197 if (mod_opts.fuzz == true)
3198 create_module.opts.any_fuzz = true;
3199 if (mod_opts.unwind_tables) |uwt| switch (uwt) {
3200 .none => {},
3201 .sync, .async => create_module.opts.any_unwind_tables = true,
3202 };
3203 if (mod_opts.strip == false)
3204 create_module.opts.any_non_stripped = true;
3205 if (mod_opts.error_tracing == true)
3206 create_module.opts.any_error_tracing = true;
3207
3208 const name = switch (arg_mode) {
3209 .zig_test => "test",
3210 .build, .cc, .cpp, .translate_c, .zig_test_obj, .run => fs.path.stem(fs.path.basename(src_path)),
3211 };
3212
3213 try create_module.modules.put(arena, name, .{
3214 .root_path = fs.path.dirname(src_path) orelse ".",
3215 .root_src_path = fs.path.basename(src_path),
3216 .cc_argv = try cc_argv.toOwnedSlice(arena),
3217 .inherited = mod_opts,
3218 .target_arch_os_abi = target_arch_os_abi,
3219 .target_mcpu = target_mcpu,
3220 .dynamic_linker = dynamic_linker,
3221 .deps = try deps.toOwnedSlice(arena),
3222 .resolved = null,
3223 .c_source_files_start = c_source_files_owner_index,
3224 .c_source_files_end = create_module.c_source_files.items.len,
3225 .rc_source_files_start = rc_source_files_owner_index,
3226 .rc_source_files_end = create_module.rc_source_files.items.len,
3227 });
3228 cssan.reset();
3229 mod_opts = .{};
3230 target_arch_os_abi = null;
3231 target_mcpu = null;
3232 c_source_files_owner_index = create_module.c_source_files.items.len;
3233 rc_source_files_owner_index = create_module.rc_source_files.items.len;
3234 }
3235
3236 if (!create_module.opts.have_zcu and create_module.opts.is_test) {
3237 fatal("`zig test` expects a zig source file argument", .{});
3238 }
3239
3240 if (c_source_files_owner_index != create_module.c_source_files.items.len) {
3241 fatal("C source file {q} has no parent module", .{
3242 create_module.c_source_files.items[c_source_files_owner_index].src_path,
3243 });
3244 }
3245
3246 if (rc_source_files_owner_index != create_module.rc_source_files.items.len) {
3247 fatal("resource file {q} has no parent module", .{
3248 create_module.rc_source_files.items[rc_source_files_owner_index].src_path,
3249 });
3250 }
3251
3252 const self_exe_path = switch (native_os) {
3253 .wasi => {},
3254 else => process.executablePathAlloc(io, arena) catch |err| fatal("unable to find zig self exe path: {t}", .{err}),
3255 };
3256
3257 const cwd_path = try std.zig.getResolvedCwd(io, arena);
3258
3259 // This `init` calls `fatal` on error.
3260 var dirs: std.zig.Directories = .init(arena, io, .{
3261 .override_zig_lib = override_lib_dir,
3262 .override_global_cache = override_global_cache_dir,
3263 .build_root = build_root_path,
3264 .local_cache_strat = s: {
3265 if (override_local_cache_dir) |p| break :s .{ .override = p };
3266 break :s switch (arg_mode) {
3267 .run => .global,
3268 else => .search,
3269 };
3270 },
3271 .preopens = preopens,
3272 .self_exe_path = self_exe_path,
3273 .environ_map = environ_map,
3274 .cwd = cwd_path,
3275 });
3276 defer dirs.deinit(io);
3277
3278 if (linker_optimization) |o| warn("ignoring deprecated linker optimization setting {q}", .{o});
3279
3280 create_module.dirs = dirs;
3281 create_module.opts.emit_llvm_ir = emit_llvm_ir != .no;
3282 create_module.opts.emit_llvm_bc = emit_llvm_bc != .no;
3283 create_module.opts.emit_bin = emit_bin != .no;
3284 create_module.opts.any_c_source_files = create_module.c_source_files.items.len != 0;
3285
3286 const main_mod = try createModule(gpa, arena, io, &create_module, 0, null, color, environ_map);
3287 for (create_module.modules.keys(), create_module.modules.values()) |key, cli_mod| {
3288 if (cli_mod.resolved == null)
3289 fatal("module {q} declared but not used", .{key});
3290 }
3291
3292 // When you're testing std, the main module is std, and we need to avoid duplicating the module.
3293 const main_mod_is_std = main_mod.root.root == .zig_lib and
3294 mem.eql(u8, main_mod.root.sub_path, "std") and
3295 mem.eql(u8, main_mod.root_src_path, "std.zig");
3296
3297 const std_mod = m: {
3298 if (main_mod_is_std) break :m main_mod;
3299 if (create_module.modules.get("std")) |cli_mod| break :m cli_mod.resolved.?;
3300 break :m null;
3301 };
3302
3303 const root_mod = switch (arg_mode) {
3304 .zig_test, .zig_test_obj => root_mod: {
3305 const test_mod = if (test_runner_path) |test_runner| test_mod: {
3306 const test_mod = try Module.create(arena, .{
3307 .paths = .{
3308 .root = try .fromUnresolved(arena, dirs, &.{fs.path.dirname(test_runner) orelse "."}),
3309 .root_src_path = fs.path.basename(test_runner),
3310 },
3311 .fully_qualified_name = "root",
3312 .cc_argv = &.{},
3313 .inherited = .{},
3314 .global = create_module.resolved_options,
3315 .parent = main_mod,
3316 });
3317 test_mod.deps = try main_mod.deps.clone(arena);
3318 break :test_mod test_mod;
3319 } else try Module.create(arena, .{
3320 .paths = .{
3321 .root = try .fromRoot(arena, dirs, .zig_lib, "compiler"),
3322 .root_src_path = "test_runner.zig",
3323 },
3324 .fully_qualified_name = "root",
3325 .cc_argv = &.{},
3326 .inherited = .{},
3327 .global = create_module.resolved_options,
3328 .parent = main_mod,
3329 });
3330
3331 break :root_mod test_mod;
3332 },
3333 else => main_mod,
3334 };
3335
3336 const target = &main_mod.resolved_target.result;
3337
3338 if (target.cpu.arch == .arc or target.cpu.arch.isNvptx()) {
3339 if (emit_bin != .no and create_module.resolved_options.use_llvm) {
3340 fatal("cannot emit {s} binary with the LLVM backend; only '-femit-asm' is supported", .{
3341 @tagName(target.cpu.arch),
3342 });
3343 }
3344 }
3345
3346 if (target.os.tag == .windows and major_subsystem_version == null and minor_subsystem_version == null) {
3347 major_subsystem_version, minor_subsystem_version = switch (target.os.version_range.windows.min) {
3348 .nt4 => .{ 4, 0 },
3349 .win2k => .{ 5, 0 },
3350 .xp => if (target.cpu.arch == .x86_64) .{ 5, 2 } else .{ 5, 1 },
3351 .ws2003 => .{ 5, 2 },
3352 else => .{ null, null },
3353 };
3354 }
3355
3356 if (target.ofmt != .coff) {
3357 if (manifest_file != null) {
3358 fatal("manifest file is not allowed unless the target object format is coff (Windows/UEFI)", .{});
3359 }
3360 if (create_module.rc_source_files.items.len != 0) {
3361 fatal("rc files are not allowed unless the target object format is coff (Windows/UEFI)", .{});
3362 }
3363 if (contains_res_file) {
3364 fatal("res files are not allowed unless the target object format is coff (Windows/UEFI)", .{});
3365 }
3366 }
3367
3368 var resolved_frameworks = std.array_list.Managed(Compilation.Framework).init(arena);
3369
3370 if (create_module.frameworks.keys().len > 0) {
3371 var test_path = std.array_list.Managed(u8).init(gpa);
3372 defer test_path.deinit();
3373
3374 var checked_paths = std.array_list.Managed(u8).init(gpa);
3375 defer checked_paths.deinit();
3376
3377 var failed_frameworks = std.array_list.Managed(struct {
3378 name: []const u8,
3379 checked_paths: []const u8,
3380 }).init(arena);
3381
3382 framework: for (create_module.frameworks.keys(), create_module.frameworks.values()) |framework_name, info| {
3383 checked_paths.clearRetainingCapacity();
3384
3385 for (create_module.framework_dirs.items) |framework_dir_path| {
3386 if (try accessFrameworkPath(
3387 io,
3388 &test_path,
3389 &checked_paths,
3390 framework_dir_path,
3391 framework_name,
3392 )) {
3393 const path = Path.initCwd(try arena.dupe(u8, test_path.items));
3394 try resolved_frameworks.append(.{
3395 .needed = info.needed,
3396 .weak = info.weak,
3397 .path = path,
3398 });
3399 continue :framework;
3400 }
3401 }
3402
3403 try failed_frameworks.append(.{
3404 .name = framework_name,
3405 .checked_paths = try arena.dupe(u8, checked_paths.items),
3406 });
3407 }
3408
3409 if (failed_frameworks.items.len > 0) {
3410 for (failed_frameworks.items) |f| {
3411 const searched_paths = if (f.checked_paths.len == 0) " none" else f.checked_paths;
3412 std.log.err("unable to find framework {q}. searched paths: {s}", .{
3413 f.name, searched_paths,
3414 });
3415 }
3416 process.exit(1);
3417 }
3418 }
3419 // After this point, resolved_frameworks is used instead of frameworks.
3420
3421 if (create_module.resolved_options.output_mode == .Obj and target.ofmt == .coff) {
3422 const total_obj_count = create_module.c_source_files.items.len +
3423 @intFromBool(root_src_file != null) +
3424 create_module.rc_source_files.items.len +
3425 link.countObjectInputs(create_module.link_inputs.items);
3426 if (total_obj_count > 1) {
3427 fatal("{s} does not support linking multiple objects into one", .{@tagName(target.ofmt)});
3428 }
3429 }
3430
3431 var cleanup_emit_bin_dir: ?Io.Dir = null;
3432 defer if (cleanup_emit_bin_dir) |*dir| dir.close(io);
3433
3434 // For `zig run` and `zig test`, we don't want to put the binary in the cwd by default. So, if
3435 // the binary is requested with no explicit path (as is the default), we emit to the cache.
3436 const output_to_cache: ?Emit.OutputToCacheReason = switch (listen) {
3437 .stdio, .ip4 => .listen,
3438 .none => if (arg_mode == .run and emit_bin == .yes_default_path)
3439 .@"zig run"
3440 else if (arg_mode == .zig_test and emit_bin == .yes_default_path)
3441 .@"zig test"
3442 else
3443 null,
3444 };
3445 const optional_version = if (have_version) version else null;
3446
3447 const root_name = if (provided_name) |n| n else main_mod.fully_qualified_name;
3448
3449 const resolved_soname: ?[]const u8 = switch (soname) {
3450 .yes => |explicit| explicit,
3451 .no => null,
3452 .yes_default_value => if (create_module.resolved_options.output_mode == .Lib and
3453 create_module.resolved_options.link_mode == .dynamic and target.ofmt == .elf)
3454 if (have_version)
3455 try arena.print("lib{s}.so.{d}", .{ root_name, version.major })
3456 else
3457 try arena.print("lib{s}.so", .{root_name})
3458 else
3459 null,
3460 };
3461
3462 const emit_bin_resolved: Compilation.CreateOptions.Emit = switch (emit_bin) {
3463 .no => .no,
3464 .yes_default_path => emit: {
3465 if (output_to_cache != null) break :emit .yes_cache;
3466 const name = switch (clang_preprocessor_mode) {
3467 .pch => try arena.print("{s}.pch", .{root_name}),
3468 else => try std.zig.binNameAlloc(arena, .{
3469 .root_name = root_name,
3470 .cpu_arch = target.cpu.arch,
3471 .os_tag = target.os.tag,
3472 .ofmt = target.ofmt,
3473 .abi = target.abi,
3474 .output_mode = create_module.resolved_options.output_mode,
3475 .link_mode = create_module.resolved_options.link_mode,
3476 .version = optional_version,
3477 }),
3478 };
3479 break :emit .{ .yes_path = name };
3480 },
3481 .yes => |path| if (output_to_cache != null) {
3482 assert(output_to_cache == .listen); // there was an explicit bin path
3483 fatal("--listen incompatible with explicit output path {q}", .{path});
3484 } else emit: {
3485 // If there's a dirname, check that dir exists. This will give a more descriptive error than `Compilation` otherwise would.
3486 if (fs.path.dirname(path)) |dir_path| {
3487 var dir = Io.Dir.cwd().openDir(io, dir_path, .{}) catch |err| {
3488 fatal("unable to open output directory {q}: {t}", .{ dir_path, err });
3489 };
3490 dir.close(io);
3491 }
3492 break :emit .{ .yes_path = path };
3493 },
3494 .yes_a_out => emit: {
3495 assert(output_to_cache == null);
3496 break :emit .{ .yes_path = switch (target.ofmt) {
3497 .coff => "a.exe",
3498 else => "a.out",
3499 } };
3500 },
3501 };
3502
3503 const default_h_basename = try arena.print("{s}.h", .{root_name});
3504 const emit_h_resolved = emit_h.resolve(io, default_h_basename, output_to_cache);
3505
3506 const default_asm_basename = try arena.print("{s}.s", .{root_name});
3507 const emit_asm_resolved = emit_asm.resolve(io, default_asm_basename, output_to_cache);
3508
3509 const default_llvm_ir_basename = try arena.print("{s}.ll", .{root_name});
3510 const emit_llvm_ir_resolved = emit_llvm_ir.resolve(io, default_llvm_ir_basename, output_to_cache);
3511
3512 const default_llvm_bc_basename = try arena.print("{s}.bc", .{root_name});
3513 const emit_llvm_bc_resolved = emit_llvm_bc.resolve(io, default_llvm_bc_basename, output_to_cache);
3514
3515 const emit_docs_resolved = emit_docs.resolve(io, "docs", output_to_cache);
3516
3517 const is_exe_or_dyn_lib = switch (create_module.resolved_options.output_mode) {
3518 .Obj => false,
3519 .Lib => create_module.resolved_options.link_mode == .dynamic,
3520 .Exe => true,
3521 };
3522 // Note that cmake when targeting Windows will try to execute
3523 // zig cc to make an executable and output an implib too.
3524 const implib_eligible = is_exe_or_dyn_lib and
3525 emit_bin_resolved != .no and target.os.tag == .windows;
3526 if (!implib_eligible) {
3527 if (!emit_implib_arg_provided) {
3528 emit_implib = .no;
3529 } else if (emit_implib != .no) {
3530 fatal("the argument -femit-implib is allowed only when building a Windows DLL", .{});
3531 }
3532 }
3533 const default_implib_basename = try arena.print("{s}.lib", .{root_name});
3534 const emit_implib_resolved: Compilation.CreateOptions.Emit = switch (emit_implib) {
3535 .no => .no,
3536 .yes => emit_implib.resolve(io, default_implib_basename, output_to_cache),
3537 .yes_default_path => emit: {
3538 if (output_to_cache != null) break :emit .yes_cache;
3539 const p = try fs.path.join(arena, &.{
3540 fs.path.dirname(emit_bin_resolved.yes_path) orelse ".",
3541 default_implib_basename,
3542 });
3543 break :emit .{ .yes_path = p };
3544 },
3545 };
3546
3547 const thread_limit = @min(
3548 @max(n_jobs orelse std.Thread.getCpuCount() catch 1, 1),
3549 std.math.maxInt(Zcu.PerThread.IdBacking),
3550 );
3551 try setThreadLimit(arena, thread_limit);
3552
3553 for (create_module.c_source_files.items) |*src| {
3554 dev.check(.c_compiler);
3555 if (!mem.eql(u8, src.src_path, "-")) continue;
3556
3557 const ext = src.ext orelse
3558 fatal("-E or -x is required when reading from a non-regular file", .{});
3559
3560 // "-" is stdin. Dump it to a real file.
3561 const sep = fs.path.sep_str;
3562 const dump_path = try arena.print("tmp" ++ sep ++ "{x}-dump-stdin{s}", .{
3563 randInt(io, u64), ext.canonicalName(target),
3564 });
3565 try dirs.local_cache.handle.createDirPath(io, "tmp");
3566
3567 // Note that in one of the happy paths, execve() is used to switch to
3568 // clang in which case any cleanup logic that exists for this temporary
3569 // file will not run and this temp file will be leaked. The filename
3570 // will be a hash of its contents — so multiple invocations of
3571 // `zig cc -` will result in the same temp file name.
3572 var f = try dirs.local_cache.handle.createFile(io, dump_path, .{});
3573 defer f.close(io);
3574
3575 // Re-using the hasher from Cache, since the functional requirements
3576 // for the hashing algorithm here and in the cache are the same.
3577 // We are providing our own cache key, because this file has nothing
3578 // to do with the cache manifest.
3579 var file_writer = f.writer(io, &.{});
3580 var buffer: [1000]u8 = undefined;
3581 var hasher = file_writer.interface.hashed(Cache.Hasher.init("0123456789abcdef"), &buffer);
3582 var stdin_reader = Io.File.stdin().readerStreaming(io, &.{});
3583 _ = hasher.writer.sendFileAll(&stdin_reader, .unlimited) catch |err| switch (err) {
3584 error.WriteFailed => fatal("failed to write {s}: {t}", .{ dump_path, file_writer.err.? }),
3585 else => fatal("failed to pipe stdin to {s}: {t}", .{ dump_path, err }),
3586 };
3587 try hasher.writer.flush();
3588
3589 const bin_digest: Cache.BinDigest = hasher.hasher.finalResult();
3590
3591 const sub_path = try arena.print("tmp" ++ sep ++ "{x}-stdin{s}", .{
3592 &bin_digest, ext.canonicalName(target),
3593 });
3594 try dirs.local_cache.handle.rename(dump_path, dirs.local_cache.handle, sub_path, io);
3595
3596 // Convert `sub_path` to be relative to current working directory.
3597 src.src_path = try dirs.local_cache.join(arena, &.{sub_path});
3598 }
3599
3600 if (build_options.have_llvm and emit_asm_resolved != .no) {
3601 // LLVM has no way to set this non-globally.
3602 const argv = [_][*:0]const u8{ "zig (LLVM option parsing)", "--x86-asm-syntax=intel" };
3603 @import("codegen/llvm/bindings.zig").ParseCommandLineOptions(argv.len, &argv);
3604 }
3605
3606 const clang_passthrough_mode = switch (arg_mode) {
3607 .cc, .cpp, .translate_c => true,
3608 else => false,
3609 };
3610
3611 const incremental = create_module.resolved_options.incremental;
3612 if (debug_incremental and !incremental) {
3613 fatal("--debug-incremental requires -fincremental", .{});
3614 }
3615
3616 const cache_mode: Compilation.CacheMode = b: {
3617 // Once incremental compilation is the default, we'll want some smarter logic here,
3618 // considering things like the backend in use and whether there's a ZCU.
3619 if (output_to_cache == null) break :b .none;
3620 if (incremental) break :b .incremental;
3621 break :b .whole;
3622 };
3623
3624 var file_system_inputs: std.ArrayList(u8) = .empty;
3625 defer file_system_inputs.deinit(gpa);
3626
3627 // Deduplicate rpath entries
3628 var rpath_dedup = std.array_hash_map.String(void){};
3629 for (create_module.rpath_list.items) |rpath| {
3630 try rpath_dedup.put(arena, rpath, {});
3631 }
3632 create_module.rpath_list.clearRetainingCapacity();
3633 try create_module.rpath_list.appendSlice(arena, rpath_dedup.keys());
3634
3635 var create_diag: Compilation.CreateDiagnostic = undefined;
3636 const comp = Compilation.create(gpa, arena, io, &create_diag, .{
3637 .dirs = dirs,
3638 .thread_limit = thread_limit,
3639 .self_exe_path = switch (native_os) {
3640 .wasi => null,
3641 else => self_exe_path,
3642 },
3643 .config = create_module.resolved_options,
3644 .root_name = root_name,
3645 .sysroot = create_module.sysroot,
3646 .main_mod = main_mod,
3647 .root_mod = root_mod,
3648 .std_mod = std_mod,
3649 .emit_bin = emit_bin_resolved,
3650 .emit_h = emit_h_resolved,
3651 .emit_asm = emit_asm_resolved,
3652 .emit_llvm_ir = emit_llvm_ir_resolved,
3653 .emit_llvm_bc = emit_llvm_bc_resolved,
3654 .emit_docs = emit_docs_resolved,
3655 .emit_implib = emit_implib_resolved,
3656 .lib_directories = create_module.lib_directories.items,
3657 .rpath_list = create_module.rpath_list.items,
3658 .symbol_wrap_set = symbol_wrap_set,
3659 .c_source_files = create_module.c_source_files.items,
3660 .rc_source_files = create_module.rc_source_files.items,
3661 .manifest_file = manifest_file,
3662 .rc_includes = rc_includes,
3663 .mingw_unicode_entry_point = mingw_unicode_entry_point,
3664 .link_inputs = create_module.link_inputs.items,
3665 .framework_dirs = create_module.framework_dirs.items,
3666 .frameworks = resolved_frameworks.items,
3667 .windows_lib_names = create_module.windows_libs.keys(),
3668 .want_compiler_rt = if (zig_cc_explicitly_link_compiler_rt) true else want_compiler_rt,
3669 .want_ubsan_rt = want_ubsan_rt,
3670 .hash_style = hash_style,
3671 .linker_script = if (linker_script) |p| .initCwd(p) else null,
3672 .version_script = if (version_script) |p| .initCwd(p) else null,
3673 .linker_allow_undefined_version = linker_allow_undefined_version,
3674 .linker_enable_new_dtags = linker_enable_new_dtags,
3675 .disable_c_depfile = disable_c_depfile,
3676 .soname = resolved_soname,
3677 .linker_sort_section = linker_sort_section,
3678 .linker_gc_sections = linker_gc_sections,
3679 .linker_repro = linker_repro,
3680 .linker_allow_shlib_undefined = linker_allow_shlib_undefined,
3681 .linker_bind_global_refs_locally = linker_bind_global_refs_locally,
3682 .linker_import_symbols = linker_import_symbols,
3683 .linker_import_table = linker_import_table,
3684 .linker_export_table = linker_export_table,
3685 .linker_growable_table = linker_growable_table,
3686 .linker_initial_memory = linker_initial_memory,
3687 .linker_max_memory = linker_max_memory,
3688 .linker_print_gc_sections = linker_print_gc_sections,
3689 .linker_print_icf_sections = linker_print_icf_sections,
3690 .linker_print_map = linker_print_map,
3691 .linker_nmagic = linker_nmagic,
3692 .linker_fatal_warnings = linker_fatal_warnings,
3693 .llvm_opt_bisect_limit = llvm_opt_bisect_limit,
3694 .linker_global_base = linker_global_base,
3695 .linker_export_symbol_names = linker_export_symbol_names.items,
3696 .linker_z_nocopyreloc = linker_z_nocopyreloc,
3697 .linker_z_nodelete = linker_z_nodelete,
3698 .linker_z_notext = linker_z_notext,
3699 .linker_z_defs = linker_z_defs,
3700 .linker_z_origin = linker_z_origin,
3701 .linker_z_now = linker_z_now,
3702 .linker_z_relro = linker_z_relro,
3703 .linker_z_common_page_size = linker_z_common_page_size,
3704 .linker_z_max_page_size = linker_z_max_page_size,
3705 .linker_tsaware = linker_tsaware,
3706 .linker_nxcompat = linker_nxcompat,
3707 .linker_dynamicbase = linker_dynamicbase,
3708 .linker_compress_debug_sections = linker_compress_debug_sections,
3709 .linker_module_definition_file = linker_module_definition_file,
3710 .major_subsystem_version = major_subsystem_version,
3711 .minor_subsystem_version = minor_subsystem_version,
3712 .link_eh_frame_hdr = link_eh_frame_hdr,
3713 .link_emit_relocs = link_emit_relocs,
3714 .entry = entry,
3715 .force_undefined_symbols = force_undefined_symbols,
3716 .stack_size = stack_size,
3717 .image_base = image_base,
3718 .function_sections = function_sections,
3719 .data_sections = data_sections,
3720 .clang_passthrough_mode = clang_passthrough_mode,
3721 .clang_preprocessor_mode = clang_preprocessor_mode,
3722 .version = optional_version,
3723 .compatibility_version = compatibility_version,
3724 .libc_installation = if (create_module.libc_installation) |*lci| lci else null,
3725 .verbose_cc = verbose_cc,
3726 .verbose_link = verbose_link,
3727 .verbose_air = verbose_air,
3728 .verbose_intern_pool = verbose_intern_pool,
3729 .verbose_generic_instances = verbose_generic_instances,
3730 .verbose_llvm_ir = verbose_llvm_ir,
3731 .verbose_llvm_bc = verbose_llvm_bc,
3732 .link_depfile = link_depfile,
3733 .verbose_llvm_cpu_features = verbose_llvm_cpu_features,
3734 .time_report = time_report,
3735 .stack_report = stack_report,
3736 .build_id = build_id,
3737 .test_filters = test_filters.items,
3738 .test_runner_path = test_runner_path,
3739 .cache_mode = cache_mode,
3740 .subsystem = subsystem,
3741 .debug_compile_errors = debug_compile_errors,
3742 .debug_incremental = debug_incremental,
3743 .enable_link_snapshots = enable_link_snapshots,
3744 .install_name = install_name,
3745 .entitlements = if (entitlements) |p| .initCwd(p) else null,
3746 .pagezero_size = pagezero_size,
3747 .headerpad_size = headerpad_size,
3748 .headerpad_max_install_names = headerpad_max_install_names,
3749 .dead_strip_dylibs = dead_strip_dylibs,
3750 .force_load_objc = force_load_objc,
3751 .discard_local_symbols = discard_local_symbols,
3752 .reference_trace = reference_trace,
3753 .pdb_out_path = pdb_out_path,
3754 .error_limit = error_limit,
3755 .native_system_include_paths = create_module.native_system_include_paths,
3756 // Any leftover C compilation args (such as -I) apply globally rather
3757 // than to any particular module. This feature can greatly reduce CLI
3758 // noise when --search-prefix and -M are combined.
3759 .global_cc_argv = try cc_argv.toOwnedSlice(arena),
3760 .file_system_inputs = &file_system_inputs,
3761 .debug_compiler_runtime_libs = debug_compiler_runtime_libs,
3762 .environ_map = environ_map,
3763 }) catch |err| switch (err) {
3764 error.CreateFail => switch (create_diag) {
3765 .cross_libc_unavailable => {
3766 // We can emit a more informative error for this.
3767 const triple_name = try target.zigTriple(arena);
3768 std.log.err("unable to provide libc for target {q}", .{triple_name});
3769
3770 for (std.zig.target.available_libcs) |t| {
3771 if (t.arch == target.cpu.arch and t.os == target.os.tag) {
3772 // If there's a `glibc_min`, there's also an `os_ver`.
3773 if (t.glibc_min) |glibc_min| {
3774 std.log.info("zig can provide libc for related target {t}-{t}.{f}-{t}.{d}.{d}", .{
3775 t.arch, t.os, t.os_ver.?, t.abi, glibc_min.major, glibc_min.minor,
3776 });
3777 } else if (t.os_ver) |os_ver| {
3778 std.log.info("zig can provide libc for related target {t}-{t}.{f}-{t}", .{
3779 t.arch, t.os, os_ver, t.abi,
3780 });
3781 } else {
3782 std.log.info("zig can provide libc for related target {t}-{t}-{t}", .{
3783 t.arch, t.os, t.abi,
3784 });
3785 }
3786 }
3787 }
3788 process.exit(1);
3789 },
3790 else => fatal("{f}", .{create_diag}),
3791 },
3792 else => fatal("failed to create compilation: {t}", .{err}),
3793 };
3794 var comp_destroyed = false;
3795 defer if (!comp_destroyed) comp.destroy();
3796
3797 if (show_builtin) {
3798 const builtin_opts = comp.root_mod.getBuiltinOptions(comp.config);
3799 const source = try builtin_opts.generate(arena);
3800 return Io.File.stdout().writeStreamingAll(io, source);
3801 }
3802 switch (listen) {
3803 .none => {},
3804 .stdio => {
3805 var stdin_reader = Io.File.stdin().reader(io, &stdin_buffer);
3806 var stdout_writer = Io.File.stdout().writer(io, &stdout_buffer);
3807 try serve(
3808 comp,
3809 &stdin_reader.interface,
3810 &stdout_writer.interface,
3811 test_exec_args.items,
3812 self_exe_path,
3813 arg_mode,
3814 all_args,
3815 runtime_args_start,
3816 environ_map,
3817 );
3818 return cleanExit(io);
3819 },
3820 .ip4 => |ip4_addr| {
3821 const addr: Io.net.IpAddress = .{ .ip4 = ip4_addr };
3822
3823 var server = try addr.listen(io, .{
3824 .reuse_address = true,
3825 });
3826 defer server.deinit(io);
3827
3828 var stream = try server.accept(io);
3829 defer stream.close(io);
3830
3831 var input = stream.reader(io, &stdin_buffer);
3832 var output = stream.writer(io, &stdout_buffer);
3833
3834 try serve(
3835 comp,
3836 &input.interface,
3837 &output.interface,
3838 test_exec_args.items,
3839 self_exe_path,
3840 arg_mode,
3841 all_args,
3842 runtime_args_start,
3843 environ_map,
3844 );
3845 return cleanExit(io);
3846 },
3847 }
3848
3849 {
3850 const root_prog_node = std.Progress.start(io, .{
3851 .disable_printing = (color == .off),
3852 });
3853 defer root_prog_node.end();
3854
3855 if (arg_mode == .translate_c) {
3856 return cmdTranslateC(comp, arena, null, null, root_prog_node, environ_map);
3857 }
3858
3859 updateModule(comp, color, root_prog_node) catch |err| switch (err) {
3860 error.CompileErrorsReported => {
3861 assert(listen == .none);
3862 saveState(comp, incremental);
3863 process.exit(1);
3864 },
3865 else => |e| return e,
3866 };
3867 }
3868 try comp.makeBinFileExecutable();
3869 saveState(comp, incremental);
3870
3871 if (switch (arg_mode) {
3872 .run => true,
3873 .zig_test => !test_no_exec,
3874 else => false,
3875 }) {
3876 dev.checkAny(&.{ .run_command, .test_command });
3877
3878 const self_exe_path_or_argv0 = switch (native_os) {
3879 .wasi => all_args[0], // Will error because of `!process.can_spawn`
3880 else => self_exe_path,
3881 };
3882
3883 if (test_exec_args.items.len == 0 and target.ofmt == .c and emit_bin_resolved != .no) {
3884 // Default to using `zig run` to execute the produced .c code from `zig test`.
3885 try test_exec_args.appendSlice(arena, &.{ self_exe_path_or_argv0, "run" });
3886 // Skip passing `-ofmt`, we want the default for the target, not `.c` anymore.
3887
3888 var prev_has_cflags = false;
3889 var prev_has_rcflags = false;
3890 {
3891 if (dirs.zig_lib.path) |zig_lib_path| {
3892 try test_exec_args.appendSlice(arena, &.{ "-cflags", "-I", zig_lib_path, "--" });
3893 prev_has_cflags = true;
3894 }
3895 const emit_ext: Compilation.FileExt = .c;
3896 const need_lang = if (comp.emit_bin) |comp_emit_bin| Compilation.classifyFileExt(comp_emit_bin) != emit_ext else true;
3897 if (need_lang) try test_exec_args.appendSlice(arena, &.{ "-x", emit_ext.toLang() });
3898 try test_exec_args.append(arena, null);
3899 if (need_lang) try test_exec_args.appendSlice(arena, &.{ "-x", "none" });
3900 }
3901 for (create_module.modules.keys(), create_module.modules.values()) |mod_name, mod| {
3902 for (create_module.c_source_files.items[mod.c_source_files_start..mod.c_source_files_end]) |c_source_file| {
3903 const cflags_len = c_source_file.extra_flags.len + c_source_file.cache_exempt_flags.len;
3904 if (prev_has_cflags or cflags_len > 0) {
3905 try test_exec_args.ensureUnusedCapacity(arena, 1 + cflags_len + 1);
3906 test_exec_args.appendAssumeCapacity("-cflags");
3907 for (c_source_file.extra_flags) |extra_flag| test_exec_args.appendAssumeCapacity(extra_flag);
3908 for (c_source_file.cache_exempt_flags) |cache_exempt_flag| test_exec_args.appendAssumeCapacity(cache_exempt_flag);
3909 test_exec_args.appendAssumeCapacity("--");
3910 }
3911 prev_has_cflags = cflags_len > 0;
3912 if (c_source_file.ext) |ext| try test_exec_args.appendSlice(arena, &.{ "-x", ext.toLang() });
3913 try test_exec_args.append(arena, c_source_file.src_path);
3914 if (c_source_file.ext) |_| try test_exec_args.appendSlice(arena, &.{ "-x", "none" });
3915 }
3916 for (create_module.rc_source_files.items[mod.rc_source_files_start..mod.rc_source_files_end]) |rc_source_file| {
3917 const rcflags_len = rc_source_file.extra_flags.len;
3918 if (prev_has_rcflags or rcflags_len > 0) {
3919 try test_exec_args.ensureUnusedCapacity(arena, 1 + rcflags_len + 1);
3920 test_exec_args.appendAssumeCapacity("-rcflags");
3921 for (rc_source_file.extra_flags) |extra_flag| test_exec_args.appendAssumeCapacity(extra_flag);
3922 test_exec_args.appendAssumeCapacity("--");
3923 }
3924 prev_has_rcflags = rcflags_len > 0;
3925 try test_exec_args.append(arena, rc_source_file.src_path);
3926 }
3927 if (mod.target_arch_os_abi) |triple| try test_exec_args.appendSlice(arena, &.{ "-target", triple });
3928 if (mod.target_mcpu) |mcpu| try test_exec_args.appendSlice(arena, &.{ "-mcpu", mcpu });
3929 if (mod.dynamic_linker) |dl| if (dl.len > 0)
3930 try test_exec_args.appendSlice(arena, &.{ "--dynamic-linker", dl })
3931 else
3932 try test_exec_args.append(arena, "--no-dynamic-linker");
3933 try test_exec_args.ensureUnusedCapacity(arena, mod.cc_argv.len);
3934 for (mod.cc_argv) |cc_arg| test_exec_args.appendAssumeCapacity(cc_arg);
3935 for (mod.deps) |dep| try test_exec_args.appendSlice(arena, &.{
3936 "--dep",
3937 if (std.mem.eql(u8, dep.key, dep.value)) dep.value else try arena.print("{s}={s}", .{ dep.key, dep.value }),
3938 });
3939 try test_exec_args.append(arena, try arena.print("-M{s}", .{mod_name}));
3940 }
3941
3942 try test_exec_args.ensureUnusedCapacity(arena, comp.global_cc_argv.len);
3943 for (comp.global_cc_argv) |global_cc_arg| test_exec_args.appendAssumeCapacity(global_cc_arg);
3944 if (create_module.resolved_options.link_libcpp) try test_exec_args.append(arena, "-lc++");
3945 if (create_module.resolved_options.link_libc) {
3946 try test_exec_args.append(arena, "-lc");
3947 } else if (target.os.tag == .windows) {
3948 try test_exec_args.appendSlice(arena, &.{
3949 "--subsystem", "console",
3950 "-lkernel32", "-lntdll",
3951 });
3952 }
3953
3954 try test_exec_args.ensureUnusedCapacity(arena, 2 * log_scopes.items.len + @intFromBool(verbose_link) + @intFromBool(verbose_cc));
3955 for (log_scopes.items) |log_scope| test_exec_args.appendSliceAssumeCapacity(&.{ "--debug-log", log_scope });
3956 if (verbose_link) test_exec_args.appendAssumeCapacity("--verbose-link");
3957 if (verbose_cc) test_exec_args.appendAssumeCapacity("--verbose-cc");
3958 }
3959
3960 try runOrTest(
3961 comp,
3962 gpa,
3963 arena,
3964 io,
3965 test_exec_args.items,
3966 self_exe_path_or_argv0,
3967 arg_mode,
3968 target,
3969 &comp_destroyed,
3970 all_args,
3971 runtime_args_start,
3972 create_module.resolved_options.link_libc,
3973 test_execve,
3974 environ_map,
3975 );
3976 }
3977
3978 // Skip resource deallocation in release builds; let the OS do it.
3979 return cleanExit(io);
3980}
3981
3982const CreateModule = struct {
3983 dirs: std.zig.Directories,
3984 modules: std.array_hash_map.String(CliModule),
3985 opts: Compilation.Config.Options,
3986 object_format: ?[]const u8,
3987 /// undefined until createModule() for the root module is called.
3988 resolved_options: Compilation.Config,
3989
3990 /// This one is used while collecting CLI options. The set of libs is used
3991 /// directly after computing the target and used to compute link_libc,
3992 /// link_libcpp, and then the libraries are filtered into
3993 /// `unresolved_link_inputs` and `windows_libs`.
3994 cli_link_inputs: std.ArrayList(link.UnresolvedInput),
3995 windows_libs: std.array_hash_map.String(void),
3996 /// The local variable `unresolved_link_inputs` is fed into library
3997 /// resolution, mutating the input array, and producing this data as
3998 /// output. Allocated with gpa.
3999 link_inputs: std.ArrayList(link.Input),
4000
4001 c_source_files: std.ArrayList(Compilation.CSourceFile),
4002 rc_source_files: std.ArrayList(Compilation.RcSourceFile),
4003
4004 /// e.g. -m3dnow or -mno-outline-atomics. They correspond to std.Target llvm cpu feature names.
4005 /// This array is populated by zig cc frontend and then has to be converted to zig-style
4006 /// CPU features.
4007 llvm_m_args: std.ArrayList([]const u8),
4008 sysroot: ?[]const u8,
4009 lib_directories: std.ArrayList(Directory),
4010 lib_dir_args: std.ArrayList([]const u8),
4011 libc_installation: ?LibCInstallation,
4012 want_native_include_dirs: bool,
4013 frameworks: std.array_hash_map.String(Framework),
4014 native_system_include_paths: []const []const u8,
4015 framework_dirs: std.ArrayList([]const u8),
4016 rpath_list: std.ArrayList([]const u8),
4017 each_lib_rpath: ?bool,
4018 libc_paths_file: ?[]const u8,
4019};
4020
4021fn createModule(
4022 gpa: Allocator,
4023 arena: Allocator,
4024 io: Io,
4025 create_module: *CreateModule,
4026 index: usize,
4027 parent: ?*Module,
4028 color: std.zig.Color,
4029 environ_map: *process.Environ.Map,
4030) Allocator.Error!*Module {
4031 const cli_mod = &create_module.modules.values()[index];
4032 if (cli_mod.resolved) |m| return m;
4033
4034 const name = create_module.modules.keys()[index];
4035
4036 cli_mod.inherited.resolved_target = t: {
4037 // If the target is not overridden, use the parent's target. Of course,
4038 // if this is the root module then we need to proceed to resolve the
4039 // target.
4040 if (cli_mod.target_arch_os_abi == null and cli_mod.target_mcpu == null) {
4041 if (parent) |p| break :t p.resolved_target;
4042 }
4043
4044 var target_parse_options: std.Target.Query.ParseOptions = .{
4045 .arch_os_abi = cli_mod.target_arch_os_abi orelse "native",
4046 .cpu_features = cli_mod.target_mcpu,
4047 .dynamic_linker = cli_mod.dynamic_linker,
4048 .object_format = create_module.object_format,
4049 };
4050
4051 // Before passing the mcpu string in for parsing, we convert any -m flags that were
4052 // passed in via zig cc to zig-style.
4053 if (create_module.llvm_m_args.items.len != 0) {
4054 // If this returns null, we let it fall through to the case below which will
4055 // run the full parse function and do proper error handling.
4056 if (std.Target.Query.parseCpuArch(target_parse_options)) |cpu_arch| {
4057 var llvm_to_zig_name = std.StringHashMap([]const u8).init(gpa);
4058 defer llvm_to_zig_name.deinit();
4059
4060 for (cpu_arch.allFeaturesList()) |feature| {
4061 const llvm_name = feature.llvm_name orelse continue;
4062 try llvm_to_zig_name.put(llvm_name, feature.name);
4063 }
4064
4065 var mcpu_buffer = std.array_list.Managed(u8).init(gpa);
4066 defer mcpu_buffer.deinit();
4067
4068 try mcpu_buffer.appendSlice(cli_mod.target_mcpu orelse "baseline");
4069
4070 for (create_module.llvm_m_args.items) |llvm_m_arg| {
4071 if (mem.cutPrefix(u8, llvm_m_arg, "mno-")) |llvm_name| {
4072 const zig_name = llvm_to_zig_name.get(llvm_name) orelse {
4073 fatal("target architecture {t} has no LLVM CPU feature named {q}", .{
4074 cpu_arch, llvm_name,
4075 });
4076 };
4077 try mcpu_buffer.append('-');
4078 try mcpu_buffer.appendSlice(zig_name);
4079 } else if (mem.cutPrefix(u8, llvm_m_arg, "m")) |llvm_name| {
4080 const zig_name = llvm_to_zig_name.get(llvm_name) orelse {
4081 fatal("target architecture {t} has no LLVM CPU feature named {q}", .{
4082 cpu_arch, llvm_name,
4083 });
4084 };
4085 try mcpu_buffer.append('+');
4086 try mcpu_buffer.appendSlice(zig_name);
4087 } else {
4088 unreachable;
4089 }
4090 }
4091
4092 const adjusted_target_mcpu = try arena.dupe(u8, mcpu_buffer.items);
4093 std.log.debug("adjusted target_mcpu: {s}", .{adjusted_target_mcpu});
4094 target_parse_options.cpu_features = adjusted_target_mcpu;
4095 }
4096 }
4097
4098 const target_query = std.zig.parseTargetQueryOrReportFatalError(arena, target_parse_options);
4099 const target = std.zig.resolveTargetQueryOrFatal(io, target_query);
4100 break :t .{
4101 .result = target,
4102 .is_native_os = target_query.isNativeOs(),
4103 .is_native_abi = target_query.isNativeAbi(),
4104 .is_explicit_dynamic_linker = target_query.dynamic_linker != null,
4105 };
4106 };
4107
4108 if (parent == null) {
4109 // This block is for initializing the fields of
4110 // `Compilation.Config.Options` that require knowledge of the
4111 // target (which was just now resolved for the root module above).
4112 const resolved_target = &cli_mod.inherited.resolved_target.?;
4113 create_module.opts.resolved_target = resolved_target.*;
4114 create_module.opts.root_optimize_mode = cli_mod.inherited.optimize_mode;
4115 create_module.opts.root_strip = cli_mod.inherited.strip;
4116 create_module.opts.root_error_tracing = cli_mod.inherited.error_tracing;
4117 const target = &resolved_target.result;
4118
4119 // First, remove libc, libc++, and compiler_rt libraries from the system libraries list.
4120 // We need to know whether the set of system libraries contains anything besides these
4121 // to decide whether to trigger native path detection logic.
4122 // Preserves linker input order.
4123 var unresolved_link_inputs: std.ArrayList(link.UnresolvedInput) = .empty;
4124 defer unresolved_link_inputs.deinit(gpa);
4125 try unresolved_link_inputs.ensureUnusedCapacity(gpa, create_module.cli_link_inputs.items.len);
4126 var any_name_queries_remaining = false;
4127 for (create_module.cli_link_inputs.items) |cli_link_input| switch (cli_link_input) {
4128 .name_query => |nq| {
4129 const lib_name = nq.name;
4130
4131 if (std.zig.target.isLibCLibName(target, lib_name)) {
4132 create_module.opts.link_libc = true;
4133 continue;
4134 }
4135 if (std.zig.target.isLibCxxLibName(target, lib_name)) {
4136 create_module.opts.link_libcpp = true;
4137 continue;
4138 }
4139
4140 switch (target_util.classifyCompilerRtLibName(lib_name)) {
4141 .none => {},
4142 .only_libunwind, .both => {
4143 create_module.opts.link_libunwind = true;
4144 continue;
4145 },
4146 .only_compiler_rt => continue,
4147 }
4148
4149 if (target.isMinGW()) {
4150 const exists = mingw.libExists(arena, io, target, create_module.dirs.zig_lib, lib_name) catch |err|
4151 fatal("failed to check zig installation for DLL import libs: {t}", .{err});
4152 if (exists) {
4153 try create_module.windows_libs.put(arena, lib_name, {});
4154 continue;
4155 }
4156 }
4157
4158 if (fs.path.isAbsolute(lib_name)) {
4159 fatal("cannot use absolute path as a system library: {s}", .{lib_name});
4160 }
4161
4162 unresolved_link_inputs.appendAssumeCapacity(cli_link_input);
4163 any_name_queries_remaining = true;
4164 },
4165 else => {
4166 unresolved_link_inputs.appendAssumeCapacity(cli_link_input);
4167 },
4168 }; // After this point, unresolved_link_inputs is used instead of cli_link_inputs.
4169
4170 if (any_name_queries_remaining) create_module.want_native_include_dirs = true;
4171
4172 // Resolve the library path arguments with respect to sysroot.
4173 try create_module.lib_directories.ensureUnusedCapacity(arena, create_module.lib_dir_args.items.len);
4174 if (create_module.sysroot) |root| {
4175 for (create_module.lib_dir_args.items) |lib_dir_arg| {
4176 if (fs.path.isAbsolute(lib_dir_arg)) {
4177 const stripped_dir = lib_dir_arg[fs.path.parsePath(lib_dir_arg).root.len..];
4178 const full_path = try fs.path.join(arena, &[_][]const u8{ root, stripped_dir });
4179 addLibDirectoryWarn(io, &create_module.lib_directories, full_path);
4180 } else {
4181 addLibDirectoryWarn(io, &create_module.lib_directories, lib_dir_arg);
4182 }
4183 }
4184 } else {
4185 for (create_module.lib_dir_args.items) |lib_dir_arg| {
4186 addLibDirectoryWarn(io, &create_module.lib_directories, lib_dir_arg);
4187 }
4188 }
4189 create_module.lib_dir_args = undefined; // From here we use lib_directories instead.
4190
4191 if (resolved_target.is_native_os and target.os.tag.isDarwin()) {
4192 // If we want to link against frameworks, we need system headers.
4193 if (create_module.frameworks.count() > 0)
4194 create_module.want_native_include_dirs = true;
4195 }
4196
4197 if (create_module.each_lib_rpath orelse resolved_target.is_native_os) {
4198 try create_module.rpath_list.ensureUnusedCapacity(arena, create_module.lib_directories.items.len);
4199 for (create_module.lib_directories.items) |lib_directory| {
4200 create_module.rpath_list.appendAssumeCapacity(lib_directory.path.?);
4201 }
4202 }
4203
4204 // Trigger native system library path detection if necessary.
4205 if (create_module.sysroot == null and
4206 resolved_target.is_native_os and resolved_target.is_native_abi and
4207 create_module.want_native_include_dirs)
4208 {
4209 var paths = std.zig.system.NativePaths.detect(arena, io, target, environ_map) catch |err|
4210 fatal("unable to detect native system paths: {t}", .{err});
4211 for (paths.warnings.items) |warning| {
4212 warn("{s}", .{warning});
4213 }
4214
4215 create_module.native_system_include_paths = try paths.include_dirs.toOwnedSlice(arena);
4216
4217 try create_module.framework_dirs.appendSlice(arena, paths.framework_dirs.items);
4218 try create_module.rpath_list.appendSlice(arena, paths.rpaths.items);
4219
4220 try create_module.lib_directories.ensureUnusedCapacity(arena, paths.lib_dirs.items.len);
4221 for (paths.lib_dirs.items) |path| addLibDirectoryWarn2(io, &create_module.lib_directories, path, true);
4222 }
4223
4224 if (create_module.libc_paths_file) |paths_file| {
4225 create_module.libc_installation = LibCInstallation.parse(arena, io, paths_file, target) catch |err|
4226 fatal("unable to parse libc paths file at path {s}: {t}", .{ paths_file, err });
4227 }
4228
4229 if (target.os.tag == .windows and (target.abi == .msvc or target.abi == .itanium) and
4230 any_name_queries_remaining)
4231 {
4232 if (create_module.libc_installation == null) {
4233 create_module.libc_installation = LibCInstallation.findNative(arena, io, .{
4234 .verbose = true,
4235 .target = target,
4236 .environ_map = environ_map,
4237 }) catch |err| {
4238 fatal("unable to find native libc installation: {t}", .{err});
4239 };
4240 }
4241 try create_module.lib_directories.ensureUnusedCapacity(arena, 2);
4242 addLibDirectoryWarn(io, &create_module.lib_directories, create_module.libc_installation.?.msvc_lib_dir.?);
4243 addLibDirectoryWarn(io, &create_module.lib_directories, create_module.libc_installation.?.kernel32_lib_dir.?);
4244 }
4245
4246 // Destructively mutates but does not transfer ownership of `unresolved_link_inputs`.
4247 link.resolveInputs(
4248 gpa,
4249 arena,
4250 io,
4251 target,
4252 &unresolved_link_inputs,
4253 &create_module.link_inputs,
4254 create_module.lib_directories.items,
4255 color,
4256 ) catch |err| fatal("failed to resolve link inputs: {s}", .{@errorName(err)});
4257
4258 if (!create_module.opts.any_dyn_libs) for (create_module.link_inputs.items) |item| switch (item) {
4259 .dso, .dso_exact => {
4260 create_module.opts.any_dyn_libs = true;
4261 break;
4262 },
4263 else => {},
4264 };
4265
4266 create_module.resolved_options = Compilation.Config.resolve(create_module.opts) catch |err| switch (err) {
4267 error.WasiExecModelRequiresWasi => fatal("only WASI OS targets support execution model", .{}),
4268 error.SharedMemoryIsWasmOnly => fatal("only WebAssembly CPU targets support shared memory", .{}),
4269 error.ObjectFilesCannotShareMemory => fatal("object files cannot share memory", .{}),
4270 error.SharedMemoryRequiresAtomicsAndBulkMemory => fatal("shared memory requires atomics and bulk_memory CPU features", .{}),
4271 error.ThreadsRequireSharedMemory => fatal("threads require shared memory", .{}),
4272 error.EmittingLlvmModuleRequiresLlvmBackend => fatal("emitting an LLVM module requires using the LLVM backend", .{}),
4273 error.LlvmLacksTargetSupport => fatal("LLVM lacks support for the specified target", .{}),
4274 error.ZigLacksTargetSupport => fatal("compiler backend unavailable for the specified target", .{}),
4275 error.EmittingBinaryRequiresLlvmLibrary => fatal("producing machine code via LLVM requires using the LLVM library", .{}),
4276 error.LldIncompatibleObjectFormat => fatal("using LLD to link {s} files is unsupported", .{@tagName(target.ofmt)}),
4277 error.LldIncompatibleWithSelfHostedBackend => fatal("self-hosted backends do not support linking with LLD", .{}),
4278 error.LtoRequiresLld => fatal("LTO requires using LLD", .{}),
4279 error.SanitizeThreadRequiresLibCpp => fatal("thread sanitization is (for now) implemented in C++, so it requires linking libc++", .{}),
4280 error.LibCRequiresLibUnwind => fatal("libc of the specified target requires linking libunwind", .{}),
4281 error.LibCppRequiresLibUnwind => fatal("libc++ requires linking libunwind", .{}),
4282 error.LibCppRequiresLibC => fatal("libc++ requires linking libc", .{}),
4283 error.LibUnwindRequiresLibC => fatal("libunwind requires linking libc", .{}),
4284 error.TargetCannotDynamicLink => fatal("dynamic linking unavailable on the specified target", .{}),
4285 error.TargetCannotStaticLinkExecutables => fatal("static linking of executables unavailable on the specified target", .{}),
4286 error.LibCRequiresDynamicLinking => fatal("libc of the specified target requires dynamic linking", .{}),
4287 error.SharedLibrariesRequireDynamicLinking => fatal("using shared libraries requires dynamic linking", .{}),
4288 error.DynamicLinkingWithLldRequiresSharedLibraries => fatal("dynamic linking with lld requires at least one shared library", .{}),
4289 error.ExportMemoryAndDynamicIncompatible => fatal("exporting memory is incompatible with dynamic linking", .{}),
4290 error.DynamicLibraryPrecludesPie => fatal("dynamic libraries cannot be position independent executables", .{}),
4291 error.TargetRequiresPie => fatal("the specified target requires position independent executables", .{}),
4292 error.SanitizeThreadRequiresPie => fatal("thread sanitization requires position independent executables", .{}),
4293 error.SanitizeThreadRequiresLlvmBackend => fatal("thread sanitization requires the LLVM backend", .{}),
4294 error.BackendLacksErrorTracing => fatal("the selected backend has not yet implemented error return tracing", .{}),
4295 error.LlvmLibraryUnavailable => fatal("zig was compiled without LLVM libraries", .{}),
4296 error.LldUnavailable => fatal("zig was compiled without LLD libraries", .{}),
4297 error.ClangUnavailable => fatal("zig was compiled without Clang libraries", .{}),
4298 error.DllExportFnsRequiresWindows => fatal("only Windows OS targets support DLLs", .{}),
4299 error.NewLinkerIncompatibleWithLld => fatal("using the new linker is incompatible with using lld", .{}),
4300 error.NewLinkerIncompatibleObjectFormat => fatal("no new linker available for '{t}' files", .{target.ofmt}),
4301 };
4302 }
4303
4304 const root: Compilation.Path = try .fromUnresolved(arena, create_module.dirs, &.{cli_mod.root_path});
4305
4306 const mod = Module.create(arena, .{
4307 .paths = .{
4308 .root = root,
4309 .root_src_path = cli_mod.root_src_path,
4310 },
4311 .fully_qualified_name = name,
4312
4313 .cc_argv = cli_mod.cc_argv,
4314 .inherited = cli_mod.inherited,
4315 .global = create_module.resolved_options,
4316 .parent = parent,
4317 }) catch |err| switch (err) {
4318 error.ValgrindUnsupportedOnTarget => fatal("unable to create module {q}: valgrind does not support the selected target CPU architecture", .{name}),
4319 error.TargetRequiresSingleThreaded => fatal("unable to create module {q}: the selected target does not support multithreading", .{name}),
4320 error.BackendRequiresSingleThreaded => fatal("unable to create module {q}: the selected machine code backend is limited to single-threaded applications", .{name}),
4321 error.TargetRequiresPic => fatal("unable to create module {q}: the selected target requires position independent code", .{name}),
4322 error.PieRequiresPic => fatal("unable to create module {q}: making a Position Independent Executable requires enabling Position Independent Code", .{name}),
4323 error.DynamicLinkingRequiresPic => fatal("unable to create module {q}: dynamic linking requires enabling Position Independent Code", .{name}),
4324 error.TargetHasNoRedZone => fatal("unable to create module {q}: the selected target does not have a red zone", .{name}),
4325 error.StackCheckUnsupportedByTarget => fatal("unable to create module {q}: the selected target does not support stack checking", .{name}),
4326 error.StackProtectorUnsupportedByTarget => fatal("unable to create module {q}: the selected target does not support stack protection", .{name}),
4327 error.StackProtectorUnavailableWithoutLibC => fatal("unable to create module {q}: enabling stack protection requires libc", .{name}),
4328 error.OutOfMemory => |e| return e,
4329 };
4330 cli_mod.resolved = mod;
4331
4332 for (create_module.c_source_files.items[cli_mod.c_source_files_start..cli_mod.c_source_files_end]) |*item| item.owner = mod;
4333
4334 for (create_module.rc_source_files.items[cli_mod.rc_source_files_start..cli_mod.rc_source_files_end]) |*item| item.owner = mod;
4335
4336 for (cli_mod.deps) |dep| {
4337 const dep_index = create_module.modules.getIndex(dep.value) orelse
4338 fatal("module {q} depends on non-existent module {q}", .{ name, dep.key });
4339 const dep_mod = try createModule(gpa, arena, io, create_module, dep_index, mod, color, environ_map);
4340 try mod.deps.put(arena, dep.key, dep_mod);
4341 }
4342
4343 return mod;
4344}
4345
4346fn saveState(comp: *Compilation, incremental: bool) void {
4347 if (incremental) {
4348 comp.saveState() catch |err| warn("unable to save incremental compilation state: {t}", .{err});
4349 }
4350}
4351
4352fn serve(
4353 comp: *Compilation,
4354 in: *Io.Reader,
4355 out: *Io.Writer,
4356 test_exec_args: []const ?[]const u8,
4357 self_exe_path: switch (native_os) {
4358 .wasi => void,
4359 else => []const u8,
4360 },
4361 arg_mode: ArgMode,
4362 all_args: []const []const u8,
4363 runtime_args_start: ?usize,
4364 environ_map: *process.Environ.Map,
4365) !void {
4366 const gpa = comp.gpa;
4367 const io = comp.io;
4368
4369 var server: Server = .{ .in = in, .out = out };
4370 try server.serveStringMessage(.zig_version, build_options.version);
4371
4372 var child_pid: ?std.process.Child.Id = null;
4373
4374 const main_progress_node = std.Progress.start(io, .{});
4375 defer main_progress_node.end();
4376
4377 const file_system_inputs = comp.file_system_inputs.?;
4378
4379 const IncrementalDebugServer = if (build_options.enable_debug_extensions and !builtin.single_threaded)
4380 @import("IncrementalDebugServer.zig")
4381 else
4382 void;
4383
4384 var ids: IncrementalDebugServer = if (comp.debugIncremental()) ids: {
4385 break :ids .init(comp.zcu orelse @panic("--debug-incremental requires a ZCU"));
4386 } else undefined;
4387 defer if (comp.debugIncremental()) ids.deinit();
4388
4389 if (comp.debugIncremental()) ids.spawn();
4390
4391 while (true) {
4392 const hdr = try server.receiveMessage();
4393
4394 // Lock the debug server while handling the message.
4395 if (comp.debugIncremental()) try ids.mutex.lock(io);
4396 defer if (comp.debugIncremental()) ids.mutex.unlock(io);
4397
4398 switch (hdr.tag) {
4399 .exit => return cleanExit(io),
4400 .update => {
4401 file_system_inputs.clearRetainingCapacity();
4402
4403 if (arg_mode == .translate_c) {
4404 var arena_instance = std.heap.ArenaAllocator.init(gpa);
4405 defer arena_instance.deinit();
4406 const arena = arena_instance.allocator();
4407 var output: Compilation.TranslateCResult = undefined;
4408 try cmdTranslateC(comp, arena, &output, file_system_inputs, main_progress_node, environ_map);
4409 defer output.deinit(gpa);
4410
4411 if (file_system_inputs.items.len != 0) {
4412 try server.serveStringMessage(.file_system_inputs, file_system_inputs.items);
4413 }
4414
4415 if (output.errors.errorMessageCount() != 0) {
4416 try server.serveErrorBundle(output.errors);
4417 } else {
4418 try server.serveEmitDigest(&output.digest, .{
4419 .flags = .{ .cache_hit = output.cache_hit },
4420 });
4421 }
4422
4423 continue;
4424 }
4425
4426 if (comp.config.output_mode == .Exe) {
4427 try comp.makeBinFileWritable();
4428 }
4429
4430 try comp.update(main_progress_node);
4431
4432 try comp.makeBinFileExecutable();
4433 try serveUpdateResults(&server, comp);
4434 },
4435 .run => {
4436 if (child_pid != null) {
4437 @panic("TODO block until the child exits");
4438 }
4439 @panic("TODO call runOrTest");
4440 //try runOrTest(
4441 // comp,
4442 // gpa,
4443 // arena,
4444 // io,
4445 // test_exec_args,
4446 // self_exe_path.?,
4447 // arg_mode,
4448 // target,
4449 // true,
4450 // &comp_destroyed,
4451 // all_args,
4452 // runtime_args_start,
4453 // link_libc,
4454 //);
4455 },
4456 .hot_update => {
4457 file_system_inputs.clearRetainingCapacity();
4458 if (child_pid) |pid| {
4459 try comp.hotCodeSwap(main_progress_node, pid);
4460 try serveUpdateResults(&server, comp);
4461 } else {
4462 if (comp.config.output_mode == .Exe) {
4463 try comp.makeBinFileWritable();
4464 }
4465 try comp.update(main_progress_node);
4466 try comp.makeBinFileExecutable();
4467 try serveUpdateResults(&server, comp);
4468
4469 child_pid = try runOrTestHotSwap(
4470 comp,
4471 gpa,
4472 test_exec_args,
4473 self_exe_path,
4474 arg_mode,
4475 all_args,
4476 runtime_args_start,
4477 );
4478 }
4479 },
4480 else => {
4481 fatal("unrecognized message from client: 0x{x}", .{@backingInt(hdr.tag)});
4482 },
4483 }
4484 }
4485}
4486
4487fn serveUpdateResults(s: *Server, comp: *Compilation) !void {
4488 const gpa = comp.gpa;
4489
4490 var error_bundle = try comp.getAllErrorsAlloc();
4491 defer error_bundle.deinit(gpa);
4492
4493 if (comp.file_system_inputs) |file_system_inputs| {
4494 if (file_system_inputs.items.len == 0) {
4495 assert(error_bundle.errorMessageCount() > 0);
4496 } else {
4497 try s.serveStringMessage(.file_system_inputs, file_system_inputs.items);
4498 }
4499 }
4500
4501 if (comp.time_report) |*tr| {
4502 var decls_len: u32 = 0;
4503
4504 var file_name_bytes: std.ArrayList(u8) = .empty;
4505 defer file_name_bytes.deinit(gpa);
4506 var files: std.array_hash_map.Auto(Zcu.File.Index, void) = .empty;
4507 defer files.deinit(gpa);
4508 var decl_data: std.ArrayList(u8) = .empty;
4509 defer decl_data.deinit(gpa);
4510
4511 // Each decl needs at least 34 bytes:
4512 // * 2 for 1-byte name plus null terminator
4513 // * 4 for `file`
4514 // * 4 for `sema_count`
4515 // * 8 for `sema_ns`
4516 // * 8 for `codegen_ns`
4517 // * 8 for `link_ns`
4518 // Most, if not all, decls in `tr.decl_sema_ns` are valid, so we have a good size estimate.
4519 try decl_data.ensureUnusedCapacity(gpa, tr.decl_sema_info.count() * 34);
4520
4521 for (tr.decl_sema_info.keys(), tr.decl_sema_info.values()) |tracked_inst, sema_info| {
4522 const resolved = tracked_inst.resolveFull(&comp.zcu.?.intern_pool) orelse continue;
4523 const file = comp.zcu.?.fileByIndex(resolved.file);
4524 const zir = file.zir orelse continue;
4525 const decl_name = zir.nullTerminatedString(zir.getDeclaration(resolved.inst).name);
4526
4527 const gop = try files.getOrPut(gpa, resolved.file);
4528 if (!gop.found_existing) try file_name_bytes.print(gpa, "{f}\x00", .{file.path.fmt(comp)});
4529
4530 const codegen_ns = tr.decl_codegen_ns.get(tracked_inst) orelse 0;
4531 const link_ns = tr.decl_link_ns.get(tracked_inst) orelse 0;
4532
4533 decls_len += 1;
4534
4535 try decl_data.ensureUnusedCapacity(gpa, 33 + decl_name.len);
4536 decl_data.appendSliceAssumeCapacity(decl_name);
4537 decl_data.appendAssumeCapacity(0);
4538
4539 const out_file = decl_data.addManyAsArrayAssumeCapacity(4);
4540 const out_sema_count = decl_data.addManyAsArrayAssumeCapacity(4);
4541 const out_sema_ns = decl_data.addManyAsArrayAssumeCapacity(8);
4542 const out_codegen_ns = decl_data.addManyAsArrayAssumeCapacity(8);
4543 const out_link_ns = decl_data.addManyAsArrayAssumeCapacity(8);
4544 std.mem.writeInt(u32, out_file, @intCast(gop.index), .little);
4545 std.mem.writeInt(u32, out_sema_count, sema_info.count, .little);
4546 std.mem.writeInt(u64, out_sema_ns, sema_info.ns, .little);
4547 std.mem.writeInt(u64, out_codegen_ns, codegen_ns, .little);
4548 std.mem.writeInt(u64, out_link_ns, link_ns, .little);
4549 }
4550
4551 const header: std.zig.Server.Message.TimeReport = .{
4552 .stats = tr.stats,
4553 .llvm_pass_timings_len = @intCast(tr.llvm_pass_timings.len),
4554 .files_len = @intCast(files.count()),
4555 .decls_len = decls_len,
4556 .flags = .{
4557 .use_llvm = comp.zcu != null and comp.zcu.?.llvm_object != null,
4558 },
4559 };
4560
4561 var slices: [4][]const u8 = .{
4562 @ptrCast(&header),
4563 tr.llvm_pass_timings,
4564 file_name_bytes.items,
4565 decl_data.items,
4566 };
4567 try s.serveMessageHeader(.{
4568 .tag = .time_report,
4569 .bytes_len = len: {
4570 var len: u32 = 0;
4571 for (slices) |slice| len += @intCast(slice.len);
4572 break :len len;
4573 },
4574 });
4575 try s.out.writeVecAll(&slices);
4576 try s.out.flush();
4577 }
4578
4579 if (error_bundle.errorMessageCount() > 0) {
4580 try s.serveErrorBundle(error_bundle);
4581 return;
4582 }
4583
4584 if (comp.digest) |digest| {
4585 try s.serveEmitDigest(&digest, .{
4586 .flags = .{ .cache_hit = comp.last_update_was_cache_hit },
4587 });
4588 }
4589
4590 // Serve empty error bundle to indicate the update is done.
4591 try s.serveErrorBundle(std.zig.ErrorBundle.empty);
4592}
4593
4594fn runOrTest(
4595 comp: *Compilation,
4596 gpa: Allocator,
4597 arena: Allocator,
4598 io: Io,
4599 test_exec_args: []const ?[]const u8,
4600 self_exe_path: []const u8,
4601 arg_mode: ArgMode,
4602 target: *const std.Target,
4603 comp_destroyed: *bool,
4604 all_args: []const []const u8,
4605 runtime_args_start: ?usize,
4606 link_libc: bool,
4607 test_execve: bool,
4608 environ_map: *process.Environ.Map,
4609) !void {
4610 const raw_emit_bin = comp.emit_bin orelse return;
4611 const exe_path = switch (comp.cache_use) {
4612 .none => p: {
4613 if (fs.path.isAbsolute(raw_emit_bin)) break :p raw_emit_bin;
4614 // Use `fs.path.join` to make a file in the cwd is still executed properly.
4615 break :p try fs.path.join(arena, &.{
4616 ".",
4617 raw_emit_bin,
4618 });
4619 },
4620 .whole, .incremental => try comp.dirs.local_cache.join(arena, &.{
4621 "o",
4622 &Cache.binToHex(comp.digest.?),
4623 raw_emit_bin,
4624 }),
4625 };
4626
4627 var argv = std.array_list.Managed([]const u8).init(gpa);
4628 defer argv.deinit();
4629
4630 if (test_exec_args.len == 0) {
4631 try argv.append(exe_path);
4632 if (arg_mode == .zig_test) {
4633 try argv.append(
4634 try arena.print("--seed=0x{x}", .{randInt(io, u32)}),
4635 );
4636 }
4637 } else {
4638 for (test_exec_args) |arg| {
4639 try argv.append(arg orelse exe_path);
4640 }
4641 }
4642 if (runtime_args_start) |i| {
4643 try argv.appendSlice(all_args[i..]);
4644 }
4645 try environ_map.put("ZIG_EXE", self_exe_path);
4646
4647 // We do not execve for tests because if the test fails we want to print
4648 // the error message and invocation below.
4649 if (process.can_replace and (arg_mode == .run or (arg_mode == .zig_test and test_execve))) {
4650 // process replacement releases the locks; no need to destroy the Compilation here.
4651 _ = try io.lockStderr(&.{}, .no_color);
4652 const err = process.replace(io, .{ .argv = argv.items, .environ_map = environ_map });
4653 io.unlockStderr();
4654 try warnAboutForeignBinaries(io, arena, arg_mode, target, link_libc);
4655 const cmd = try std.mem.join(arena, " ", argv.items);
4656 fatal("the following command failed to execve with '{t}':\n{s}", .{ err, cmd });
4657 } else if (!process.can_spawn) {
4658 fatal("the following command cannot be executed ({t} does not support spawning a child process):\n{f}", .{
4659 native_os, std.zig.SubprocessCommand{ .argv = argv.items },
4660 });
4661 }
4662 const term_result = (term: {
4663 // Here we release all the locks associated with the Compilation so
4664 // that whatever this child process wants to do won't deadlock.
4665 comp.destroy();
4666 comp_destroyed.* = true;
4667
4668 _ = try io.lockStderr(&.{}, .no_color);
4669 defer io.unlockStderr();
4670
4671 var child = std.process.spawn(io, .{
4672 .argv = argv.items,
4673 .environ_map = environ_map,
4674 .stdin = .inherit,
4675 .stdout = .inherit,
4676 .stderr = .inherit,
4677 }) catch |err| break :term err;
4678 defer child.kill(io);
4679
4680 break :term child.wait(io);
4681 });
4682
4683 const term = term_result catch |err| {
4684 try warnAboutForeignBinaries(io, arena, arg_mode, target, link_libc);
4685 const cmd = try std.mem.join(arena, " ", argv.items);
4686 fatal("the following command failed with {t}:\n{s}", .{ err, cmd });
4687 };
4688 switch (arg_mode) {
4689 .run, .build => {
4690 switch (term) {
4691 .exited => |code| {
4692 if (code == 0) {
4693 return cleanExit(io);
4694 } else {
4695 process.exit(code);
4696 }
4697 },
4698 .signal => |sig| {
4699 const cmd = try std.mem.join(arena, " ", argv.items);
4700 fatal("the following command terminated with signal {t}:\n{s}", .{ sig, cmd });
4701 },
4702 .stopped => |sig| {
4703 const cmd = try std.mem.join(arena, " ", argv.items);
4704 fatal("the following command stopped with signal {t}:\n{s}", .{ sig, cmd });
4705 },
4706 .unknown => {
4707 process.exit(1);
4708 },
4709 }
4710 },
4711 .zig_test => {
4712 switch (term) {
4713 .exited => |code| {
4714 if (code == 0) {
4715 return cleanExit(io);
4716 } else {
4717 const cmd = try std.mem.join(arena, " ", argv.items);
4718 fatal("the following test command failed with exit code {d}:\n{s}", .{ code, cmd });
4719 }
4720 },
4721 .signal => |sig| {
4722 const cmd = try std.mem.join(arena, " ", argv.items);
4723 fatal("the following test command terminated with signal {t}:\n{s}", .{ sig, cmd });
4724 },
4725 else => {
4726 const cmd = try std.mem.join(arena, " ", argv.items);
4727 fatal("the following test command crashed:\n{s}", .{cmd});
4728 },
4729 }
4730 },
4731 else => unreachable,
4732 }
4733}
4734
4735fn runOrTestHotSwap(
4736 comp: *Compilation,
4737 gpa: Allocator,
4738 test_exec_args: []const ?[]const u8,
4739 self_exe_path: switch (native_os) {
4740 .wasi => void,
4741 else => []const u8,
4742 },
4743 arg_mode: ArgMode,
4744 all_args: []const []const u8,
4745 runtime_args_start: ?usize,
4746) !std.process.Child.Id {
4747 const io = comp.io;
4748 const lf = comp.bin_file.?;
4749
4750 const self_exe_path_or_argv0 = switch (native_os) {
4751 .wasi => all_args[0], // Will error because of `!process.can_spawn`
4752 else => self_exe_path,
4753 };
4754
4755 const exe_path = switch (builtin.target.os.tag) {
4756 // On Windows it seems impossible to perform an atomic rename of a file that is currently
4757 // running in a process. Therefore, we do the opposite. We create a copy of the file in
4758 // tmp zig-cache and use it to spawn the child process. This way we are free to update
4759 // the binary with each requested hot update.
4760 .windows => blk: {
4761 try lf.emit.root_dir.handle.copyFile(lf.emit.sub_path, comp.dirs.local_cache.handle, lf.emit.sub_path, io, .{});
4762 break :blk try fs.path.join(gpa, &.{ comp.dirs.local_cache.path orelse ".", lf.emit.sub_path });
4763 },
4764
4765 // A naive `directory.join` here will indeed get the correct path to the binary,
4766 // however, in the case of cwd, we actually want `./foo` so that the path can be executed.
4767 else => try fs.path.join(gpa, &.{
4768 lf.emit.root_dir.path orelse ".", lf.emit.sub_path,
4769 }),
4770 };
4771 defer gpa.free(exe_path);
4772
4773 var argv = std.array_list.Managed([]const u8).init(gpa);
4774 defer argv.deinit();
4775
4776 if (test_exec_args.len == 0) {
4777 // when testing pass the zig_exe_path to argv
4778 if (arg_mode == .zig_test)
4779 try argv.appendSlice(&[_][]const u8{
4780 exe_path, self_exe_path_or_argv0,
4781 })
4782 // when running just pass the current exe
4783 else
4784 try argv.appendSlice(&[_][]const u8{
4785 exe_path,
4786 });
4787 } else {
4788 for (test_exec_args) |arg| {
4789 if (arg) |a| {
4790 try argv.append(a);
4791 } else {
4792 try argv.appendSlice(&[_][]const u8{
4793 exe_path, self_exe_path_or_argv0,
4794 });
4795 }
4796 }
4797 }
4798 if (runtime_args_start) |i| {
4799 try argv.appendSlice(all_args[i..]);
4800 }
4801
4802 if (!process.can_spawn) {
4803 fatal("the following command cannot be executed ({t} does not support spawning a child process):\n{f}", .{
4804 native_os, std.zig.SubprocessCommand{ .argv = argv.items },
4805 });
4806 }
4807
4808 const child = try std.process.spawn(io, .{
4809 .argv = argv.items,
4810 .stdin = .inherit,
4811 .stdout = .inherit,
4812 .stderr = .inherit,
4813 });
4814 return child.id.?;
4815}
4816
4817const UpdateModuleError = Compilation.UpdateError || error{
4818 /// The update caused compile errors. The error bundle has already been
4819 /// reported to the user by being rendered to stderr.
4820 CompileErrorsReported,
4821 /// Error occurred printing compilation errors to stderr.
4822 PrintingErrorsFailed,
4823};
4824fn updateModule(comp: *Compilation, color: Color, prog_node: std.Progress.Node) UpdateModuleError!void {
4825 try comp.update(prog_node);
4826
4827 var errors = try comp.getAllErrorsAlloc();
4828 defer errors.deinit(comp.gpa);
4829
4830 if (errors.errorMessageCount() > 0) {
4831 const io = comp.io;
4832 errors.renderToStderr(io, .{}, color) catch |err| switch (err) {
4833 error.Canceled => |e| return e,
4834 else => return error.PrintingErrorsFailed,
4835 };
4836 return error.CompileErrorsReported;
4837 }
4838}
4839
4840fn cmdTranslateC(
4841 comp: *Compilation,
4842 arena: Allocator,
4843 fancy_output: ?*Compilation.TranslateCResult,
4844 file_system_inputs: ?*std.ArrayList(u8),
4845 prog_node: std.Progress.Node,
4846 environ_map: *process.Environ.Map,
4847) !void {
4848 dev.check(.translate_c_command);
4849
4850 const io = comp.io;
4851
4852 assert(comp.c_source_files.len == 1);
4853 const c_source_file = comp.c_source_files[0];
4854
4855 const translated_basename = try arena.print("{s}.zig", .{comp.root_name});
4856
4857 var man: Cache.Manifest = comp.obtainCObjectCacheManifest(comp.root_mod);
4858 man.want_shared_lock = false;
4859 defer man.deinit();
4860
4861 man.hash.add(@as(u16, 0xb945)); // Random number to distinguish translate-c from compiling C objects
4862 Compilation.cache_helpers.hashCSource(&man, c_source_file) catch |err|
4863 fatal("unable to process {q}: {t}", .{ c_source_file.src_path, err });
4864
4865 const result: Compilation.TranslateCResult = if (try man.hit(prog_node)) .{
4866 .digest = man.finalBin(),
4867 .cache_hit = true,
4868 .errors = std.zig.ErrorBundle.empty,
4869 } else result: {
4870 const result = try comp.translateC(
4871 arena,
4872 &man,
4873 Compilation.classifyFileExt(c_source_file.src_path),
4874 c_source_file.src_path,
4875 translated_basename,
4876 comp.root_mod,
4877 prog_node,
4878 environ_map,
4879 );
4880
4881 if (result.errors.errorMessageCount() != 0) {
4882 if (fancy_output) |p| {
4883 if (file_system_inputs) |buf| try man.populateFileSystemInputs(buf);
4884 p.* = result;
4885 return;
4886 } else {
4887 const color: Color = Color.settingFromEnvironment(environ_map);
4888 result.errors.renderToStderr(io, .{}, color) catch {};
4889 process.exit(1);
4890 }
4891 }
4892
4893 man.writeManifest() catch |err| warn("failed to write cache manifest: {t}", .{err});
4894 break :result result;
4895 };
4896
4897 if (file_system_inputs) |buf| try man.populateFileSystemInputs(buf);
4898 if (fancy_output) |p| {
4899 p.* = result;
4900 } else {
4901 const hex_digest = Cache.binToHex(result.digest);
4902 const out_zig_path = try fs.path.join(arena, &.{ "o", &hex_digest, translated_basename });
4903 const zig_file = comp.dirs.local_cache.handle.openFile(io, out_zig_path, .{}) catch |err| {
4904 const path = comp.dirs.local_cache.path orelse ".";
4905 fatal("unable to open cached translated zig file '{s}{s}{s}': {t}", .{
4906 path, fs.path.sep_str, out_zig_path, err,
4907 });
4908 };
4909 defer zig_file.close(io);
4910 var stdout_writer = Io.File.stdout().writer(io, &stdout_buffer);
4911 var file_reader = zig_file.reader(io, &.{});
4912 _ = try stdout_writer.interface.sendFileAll(&file_reader, .unlimited);
4913 try stdout_writer.interface.flush();
4914 return cleanExit(io);
4915 }
4916}
4917
4918pub fn translateC(
4919 gpa: Allocator,
4920 arena: Allocator,
4921 io: Io,
4922 argv: []const []const u8,
4923 environ_map: *const process.Environ.Map,
4924 prog_node: std.Progress.Node,
4925 thread_limit: usize,
4926 capture: ?*[]u8,
4927) !void {
4928 try jitCmdInner(gpa, arena, io, argv, environ_map, prog_node, thread_limit, .{
4929 .cmd_name = "translate-c",
4930 .root_src_path = "translate-c/main.zig",
4931 .depend_on_aro = true,
4932 .capture = capture,
4933 });
4934}
4935
4936const JitCmdOptions = struct {
4937 cmd_name: []const u8,
4938 root_src_path: []const u8,
4939 prepend_cmd: ?[]const u8 = null,
4940 prepend_zig_lib_dir_path: bool = false,
4941 prepend_global_cache_path: bool = false,
4942 prepend_zig_exe_path: bool = false,
4943 prepend_seed: bool = false,
4944 depend_on_aro: bool = false,
4945 capture: ?*[]u8 = null,
4946 /// Send error bundles via std.zig.Server over stdout
4947 server: bool = false,
4948 release_mode: std.lang.Optimize = .fast,
4949};
4950
4951fn jitCmd(
4952 gpa: Allocator,
4953 arena: Allocator,
4954 io: Io,
4955 args: []const []const u8,
4956 environ_map: *const process.Environ.Map,
4957 options: JitCmdOptions,
4958) !void {
4959 dev.check(.jit_command);
4960
4961 const color = Color.settingFromEnvironment(environ_map);
4962
4963 const root_prog_node = std.Progress.start(io, .{
4964 .disable_printing = (color == .off),
4965 .root_name = try arena.print("Compiling {s} (first time setup)", .{options.cmd_name}),
4966 });
4967 defer root_prog_node.end();
4968
4969 const thread_limit = @min(
4970 @max(std.Thread.getCpuCount() catch 1, 1),
4971 std.math.maxInt(Zcu.PerThread.IdBacking),
4972 );
4973 try setThreadLimit(arena, thread_limit);
4974
4975 return jitCmdInner(gpa, arena, io, args, environ_map, root_prog_node, thread_limit, options);
4976}
4977
4978fn jitCmdInner(
4979 gpa: Allocator,
4980 arena: Allocator,
4981 io: Io,
4982 args: []const []const u8,
4983 environ_map: *const process.Environ.Map,
4984 root_prog_node: std.Progress.Node,
4985 thread_limit: usize,
4986 options: JitCmdOptions,
4987) !void {
4988 if (!std.process.can_spawn) {
4989 fatal("The {s} command cannot be executed ({t} does not support spawning a child process)", .{
4990 options.cmd_name, native_os,
4991 });
4992 }
4993
4994 const target_query: std.Target.Query = .{};
4995 const resolved_target: Module.ResolvedTarget = .{
4996 .result = std.zig.resolveTargetQueryOrFatal(io, target_query),
4997 .is_native_os = true,
4998 .is_native_abi = true,
4999 .is_explicit_dynamic_linker = false,
5000 };
5001
5002 const self_exe_path = process.executablePathAlloc(io, arena) catch |err|
5003 fatal("unable to find self exe path: {t}", .{err});
5004
5005 const optimize_mode: std.lang.Optimize = if (EnvVar.ZIG_DEBUG_CMD.isSet(environ_map))
5006 .debug
5007 else
5008 options.release_mode;
5009 const strip = optimize_mode != .debug;
5010 var override_lib_dir: ?[]const u8 = EnvVar.ZIG_LIB_DIR.get(environ_map);
5011 const override_global_cache_dir: ?[]const u8 = EnvVar.ZIG_GLOBAL_CACHE_DIR.get(environ_map);
5012
5013 // Special case: if first arg starts with --zig-lib= then it is handled here.
5014 var args_i: usize = 0;
5015 if (args.len - args_i != 0) {
5016 if (mem.cutPrefix(u8, args[args_i], "--zig-lib=")) |rest| {
5017 override_lib_dir = rest;
5018 args_i += 1;
5019 }
5020 }
5021
5022 const cwd_path = try std.zig.getResolvedCwd(io, arena);
5023
5024 // This `init` calls `fatal` on error.
5025 var dirs: std.zig.Directories = .init(arena, io, .{
5026 .override_zig_lib = override_lib_dir,
5027 .override_global_cache = override_global_cache_dir,
5028 .build_root = null,
5029 .local_cache_strat = .global,
5030 .preopens = preopens,
5031 .self_exe_path = self_exe_path,
5032 .environ_map = environ_map,
5033 .cwd = cwd_path,
5034 });
5035 defer dirs.deinit(io);
5036
5037 var child_argv: std.ArrayList([]const u8) = .empty;
5038 try child_argv.ensureUnusedCapacity(arena, (args.len - args_i) + 6);
5039
5040 // We want to release all the locks before executing the child process, so we make a nice
5041 // big block here to ensure the cleanup gets run when we extract out our argv.
5042 {
5043 const main_mod_paths: Module.CreateOptions.Paths = .{
5044 .root = try .fromRoot(arena, dirs, .zig_lib, "compiler"),
5045 .root_src_path = options.root_src_path,
5046 };
5047
5048 const config = try Compilation.Config.resolve(.{
5049 .output_mode = .Exe,
5050 .root_strip = strip,
5051 .root_optimize_mode = optimize_mode,
5052 .resolved_target = resolved_target,
5053 .have_zcu = true,
5054 .emit_bin = true,
5055 .is_test = false,
5056 });
5057
5058 const root_mod = try Module.create(arena, .{
5059 .paths = main_mod_paths,
5060 .fully_qualified_name = "root",
5061 .cc_argv = &.{},
5062 .inherited = .{
5063 .resolved_target = resolved_target,
5064 .optimize_mode = optimize_mode,
5065 .strip = strip,
5066 },
5067 .global = config,
5068 .parent = null,
5069 });
5070
5071 if (options.depend_on_aro) {
5072 const aro_mod = try Module.create(arena, .{
5073 .paths = .{
5074 .root = try .fromRoot(arena, dirs, .zig_lib, "compiler/aro"),
5075 .root_src_path = "aro.zig",
5076 },
5077 .fully_qualified_name = "aro",
5078 .cc_argv = &.{},
5079 .inherited = .{
5080 .resolved_target = resolved_target,
5081 .optimize_mode = optimize_mode,
5082 .strip = strip,
5083 },
5084 .global = config,
5085 .parent = null,
5086 });
5087 try root_mod.deps.put(arena, "aro", aro_mod);
5088 }
5089
5090 var create_diag: Compilation.CreateDiagnostic = undefined;
5091 const comp = Compilation.create(gpa, arena, io, &create_diag, .{
5092 .dirs = dirs,
5093 .root_name = options.cmd_name,
5094 .config = config,
5095 .root_mod = root_mod,
5096 .main_mod = root_mod,
5097 .emit_bin = .yes_cache,
5098 .self_exe_path = self_exe_path,
5099 .thread_limit = thread_limit,
5100 .cache_mode = .whole,
5101 .environ_map = environ_map,
5102 }) catch |err| switch (err) {
5103 error.CreateFail => fatal("failed to create compilation: {f}", .{create_diag}),
5104 else => fatal("failed to create compilation: {t}", .{err}),
5105 };
5106 defer comp.destroy();
5107
5108 if (options.server) {
5109 var stdout_writer = Io.File.stdout().writer(io, &stdout_buffer);
5110 var server: std.zig.Server = .{
5111 .out = &stdout_writer.interface,
5112 .in = undefined, // won't be receiving messages
5113 };
5114
5115 try comp.update(root_prog_node);
5116
5117 var error_bundle = try comp.getAllErrorsAlloc();
5118 defer error_bundle.deinit(comp.gpa);
5119 if (error_bundle.errorMessageCount() > 0) {
5120 try server.serveErrorBundle(error_bundle);
5121 process.exit(2);
5122 }
5123 } else {
5124 const color = Color.settingFromEnvironment(environ_map);
5125 updateModule(comp, color, root_prog_node) catch |err| switch (err) {
5126 error.CompileErrorsReported => process.exit(2),
5127 else => |e| return e,
5128 };
5129 }
5130
5131 const exe_path = try dirs.global_cache.join(arena, &.{
5132 "o",
5133 &Cache.binToHex(comp.digest.?),
5134 comp.emit_bin.?,
5135 });
5136 child_argv.appendAssumeCapacity(exe_path);
5137 }
5138
5139 if (options.prepend_cmd) |cmd|
5140 child_argv.appendAssumeCapacity(cmd);
5141 if (options.prepend_zig_lib_dir_path)
5142 child_argv.appendAssumeCapacity(try arena.print("--zig-lib={s}", .{dirs.zig_lib.path orelse "."}));
5143 if (options.prepend_zig_exe_path)
5144 child_argv.appendAssumeCapacity(try arena.print("--zig={s}", .{self_exe_path}));
5145 if (options.prepend_global_cache_path)
5146 child_argv.appendAssumeCapacity(try arena.print("--global-cache={s}", .{dirs.global_cache.path orelse "."}));
5147 if (options.prepend_seed)
5148 child_argv.appendAssumeCapacity(try arena.print("--seed=0x{x}", .{randInt(io, u32)}));
5149
5150 child_argv.appendSliceAssumeCapacity(args[args_i..]);
5151
5152 if (EnvVar.ZIG_VERBOSE_CMD.isSet(environ_map)) {
5153 const cmd: std.zig.SubprocessCommand = .{
5154 .argv = child_argv.items,
5155 };
5156 std.log.info("{f}", .{cmd});
5157 }
5158
5159 if (process.can_replace and options.capture == null) {
5160 _ = try io.lockStderr(&.{}, .no_color);
5161 const err = process.replace(io, .{ .argv = child_argv.items, .environ_map = environ_map });
5162 const cmd = try std.mem.join(arena, " ", child_argv.items);
5163 fatal("the following command failed to execve with {t}:\n{s}", .{ err, cmd });
5164 }
5165
5166 const term = t: {
5167 _ = try io.lockStderr(&.{}, .no_color);
5168 defer io.unlockStderr();
5169
5170 var child = std.process.spawn(io, .{
5171 .argv = child_argv.items,
5172 .stdin = .inherit,
5173 .stdout = if (options.capture == null) .inherit else .pipe,
5174 .stderr = .inherit,
5175 }) catch |err| fatal("failed to spawn {s}: {t}", .{ child_argv.items[0], err });
5176 defer child.kill(io);
5177
5178 if (options.capture) |ptr| {
5179 var stdout_reader = child.stdout.?.readerStreaming(io, &.{});
5180 ptr.* = try stdout_reader.interface.allocRemaining(arena, .limited(std.math.maxInt(u32)));
5181 }
5182
5183 break :t try child.wait(io);
5184 };
5185 if (term.success()) {
5186 if (options.capture != null) return;
5187 return cleanExit(io);
5188 }
5189 const cmd = try std.mem.join(arena, " ", child_argv.items);
5190 fatal("the following build command {f}:\n{s}", .{ term, cmd });
5191}
5192
5193const info_zen =
5194 \\
5195 \\ * Communicate intent precisely.
5196 \\ * Edge cases matter.
5197 \\ * Favor reading code over writing code.
5198 \\ * There is an idiomatic way to do it.
5199 \\ * Runtime crashes are better than bugs.
5200 \\ * Compile errors are better than runtime crashes.
5201 \\ * Incremental improvements.
5202 \\ * Avoid local maximums.
5203 \\ * Reduce the amount one must remember.
5204 \\ * Focus on logic, not style.
5205 \\ * Resource allocation may fail.
5206 \\ * Resource deallocation must succeed.
5207 \\
5208 \\Together, we serve the users!
5209 \\
5210 \\
5211;
5212
5213extern fn ZigClangIsLLVMUsingSeparateLibcxx() bool;
5214
5215extern "c" fn ZigClang_main(argc: c_int, argv: [*:null]?[*:0]u8) c_int;
5216extern "c" fn ZigLlvmAr_main(argc: c_int, argv: [*:null]?[*:0]u8) c_int;
5217
5218fn argsCopyZ(alloc: Allocator, args: []const []const u8) ![:null]?[*:0]u8 {
5219 var argv = try alloc.allocSentinel(?[*:0]u8, args.len, null);
5220 for (args, 0..) |arg, i| {
5221 argv[i] = try alloc.dupeSentinel(u8, arg, 0); // TODO If there was an argsAllocZ we could avoid this allocation.
5222 }
5223 return argv;
5224}
5225
5226pub fn clangMain(alloc: Allocator, args: []const []const u8) error{OutOfMemory}!u8 {
5227 if (!build_options.have_llvm)
5228 fatal("`zig cc` and `zig c++` unavailable: compiler built without LLVM extensions", .{});
5229
5230 var arena_instance = std.heap.ArenaAllocator.init(alloc);
5231 defer arena_instance.deinit();
5232 const arena = arena_instance.allocator();
5233
5234 // Convert the args to the null-terminated format Clang expects.
5235 const argv = try argsCopyZ(arena, args);
5236 const exit_code = ZigClang_main(@as(c_int, @intCast(argv.len)), argv.ptr);
5237 return @as(u8, @bitCast(@as(i8, @truncate(exit_code))));
5238}
5239
5240pub fn llvmArMain(alloc: Allocator, args: []const []const u8) error{OutOfMemory}!u8 {
5241 if (!build_options.have_llvm)
5242 fatal("`zig ar`, `zig dlltool`, `zig ranlib', and `zig lib` unavailable: compiler built without LLVM extensions", .{});
5243
5244 var arena_instance = std.heap.ArenaAllocator.init(alloc);
5245 defer arena_instance.deinit();
5246 const arena = arena_instance.allocator();
5247
5248 // Convert the args to the format llvm-ar expects.
5249 // We intentionally shave off the zig binary at args[0].
5250 const argv = try argsCopyZ(arena, args[1..]);
5251 const exit_code = ZigLlvmAr_main(@as(c_int, @intCast(argv.len)), argv.ptr);
5252 return @as(u8, @bitCast(@as(i8, @truncate(exit_code))));
5253}
5254
5255/// The first argument determines which backend is invoked. The options are:
5256/// * `ld.lld` - ELF
5257/// * `lld-link` - COFF
5258/// * `wasm-ld` - WebAssembly
5259pub fn lldMain(
5260 alloc: Allocator,
5261 args: []const []const u8,
5262 can_exit_early: bool,
5263) error{OutOfMemory}!u8 {
5264 if (!build_options.have_llvm)
5265 fatal("`zig {s}` unavailable: compiler built without LLVM extensions", .{args[0]});
5266
5267 // Print a warning if lld is called multiple times in the same process,
5268 // since it may misbehave
5269 // https://github.com/ziglang/zig/issues/3825
5270 const CallCounter = struct {
5271 var count: usize = 0;
5272 };
5273 if (CallCounter.count == 1) { // Issue the warning on the first repeat call
5274 warn("invoking LLD for the second time within the same process because the host OS ({s}) does not support spawning child processes. This sometimes activates LLD bugs", .{@tagName(native_os)});
5275 }
5276 CallCounter.count += 1;
5277
5278 var arena_instance = std.heap.ArenaAllocator.init(alloc);
5279 defer arena_instance.deinit();
5280 const arena = arena_instance.allocator();
5281
5282 // Convert the args to the format LLD expects.
5283 // We intentionally shave off the zig binary at args[0].
5284 const argv = try argsCopyZ(arena, args[1..]);
5285 // "If an error occurs, false will be returned."
5286 const ok = rc: {
5287 const llvm = @import("codegen/llvm/bindings.zig");
5288 const argc = @as(c_int, @intCast(argv.len));
5289 if (mem.eql(u8, args[1], "ld.lld")) {
5290 break :rc llvm.LinkELF(argc, argv.ptr, can_exit_early, false);
5291 } else if (mem.eql(u8, args[1], "lld-link")) {
5292 break :rc llvm.LinkCOFF(argc, argv.ptr, can_exit_early, false);
5293 } else if (mem.eql(u8, args[1], "wasm-ld")) {
5294 break :rc llvm.LinkWasm(argc, argv.ptr, can_exit_early, false);
5295 } else {
5296 unreachable;
5297 }
5298 };
5299 return @intFromBool(!ok);
5300}
5301
5302const ArgIteratorResponseFile = process.Args.IteratorGeneral(.{ .comments = true, .single_quotes = true });
5303
5304/// Initialize the arguments from a Response File. "*.rsp"
5305fn initArgIteratorResponseFile(allocator: Allocator, io: Io, resp_file_path: []const u8) !ArgIteratorResponseFile {
5306 const max_bytes = 10 * 1024 * 1024; // 10 MiB of command line arguments is a reasonable limit
5307 const cmd_line = try Io.Dir.cwd().readFileAlloc(io, resp_file_path, allocator, .limited(max_bytes));
5308 errdefer allocator.free(cmd_line);
5309
5310 return ArgIteratorResponseFile.initTakeOwnership(allocator, cmd_line);
5311}
5312
5313pub const ClangArgIterator = struct {
5314 has_next: bool,
5315 zig_equivalent: std.zig.ClangCliParam.ZigEquivalent,
5316 only_arg: []const u8,
5317 second_arg: []const u8,
5318 other_args: []const []const u8,
5319 argv: []const []const u8,
5320 next_index: usize,
5321 root_args: ?*Args,
5322 arg_iterator_response_file: ArgIteratorResponseFile,
5323 arena: Allocator,
5324
5325 const Args = struct {
5326 next_index: usize,
5327 argv: []const []const u8,
5328 };
5329
5330 fn init(arena: Allocator, argv: []const []const u8) ClangArgIterator {
5331 return .{
5332 .next_index = 2, // `zig cc foo` this points to `foo`
5333 .has_next = argv.len > 2,
5334 .zig_equivalent = undefined,
5335 .only_arg = undefined,
5336 .second_arg = undefined,
5337 .other_args = undefined,
5338 .argv = argv,
5339 .root_args = null,
5340 .arg_iterator_response_file = undefined,
5341 .arena = arena,
5342 };
5343 }
5344
5345 fn next(self: *ClangArgIterator, io: Io) !void {
5346 assert(self.has_next);
5347 assert(self.next_index < self.argv.len);
5348 // In this state we know that the parameter we are looking at is a root parameter
5349 // rather than an argument to a parameter.
5350 // We adjust the len below when necessary.
5351 self.other_args = (self.argv.ptr + self.next_index)[0..1];
5352 var arg = self.argv[self.next_index];
5353 self.incrementArgIndex();
5354
5355 if (mem.startsWith(u8, arg, "@")) {
5356 if (self.root_args != null) return error.NestedResponseFile;
5357
5358 // This is a "compiler response file". We must parse the file and treat its
5359 // contents as command line parameters.
5360 const arena = self.arena;
5361 const resp_file_path = arg[1..];
5362
5363 self.arg_iterator_response_file = initArgIteratorResponseFile(arena, io, resp_file_path) catch |err|
5364 fatal("unable to read response file {q}: {t}", .{ resp_file_path, err });
5365 // NOTE: The ArgIteratorResponseFile returns tokens from next() that are slices of an
5366 // internal buffer. This internal buffer is arena allocated, so it is not cleaned up here.
5367
5368 var resp_arg_list = std.array_list.Managed([]const u8).init(arena);
5369 defer resp_arg_list.deinit();
5370 {
5371 while (self.arg_iterator_response_file.next()) |token| {
5372 try resp_arg_list.append(token);
5373 }
5374
5375 const args = try arena.create(Args);
5376 errdefer arena.destroy(args);
5377 args.* = .{
5378 .next_index = self.next_index,
5379 .argv = self.argv,
5380 };
5381 self.root_args = args;
5382 }
5383 const resp_arg_slice = try resp_arg_list.toOwnedSlice();
5384 self.next_index = 0;
5385 self.argv = resp_arg_slice;
5386
5387 if (resp_arg_slice.len == 0) {
5388 self.resolveRespFileArgs();
5389 return;
5390 }
5391
5392 self.has_next = true;
5393 self.other_args = (self.argv.ptr + self.next_index)[0..1]; // We adjust len below when necessary.
5394 arg = self.argv[self.next_index];
5395 self.incrementArgIndex();
5396 }
5397
5398 if (mem.eql(u8, arg, "-") or !mem.startsWith(u8, arg, "-")) {
5399 self.zig_equivalent = .positional;
5400 self.only_arg = arg;
5401 return;
5402 }
5403
5404 const clang_args: []const std.zig.ClangCliParam = @import("clang_options.zon");
5405
5406 find_clang_arg: for (clang_args) |clang_arg| switch (clang_arg.syntax) {
5407 .flag => {
5408 const prefix_len = clang_arg.matchEql(arg);
5409 if (prefix_len > 0) {
5410 self.zig_equivalent = clang_arg.ze;
5411 self.only_arg = arg[prefix_len..];
5412
5413 break :find_clang_arg;
5414 }
5415 },
5416 .joined, .comma_joined => {
5417 // joined example: --target=foo
5418 // comma_joined example: -Wl,-soname,libsoundio.so.2
5419 const prefix_len = clang_arg.matchStartsWith(arg);
5420 if (prefix_len != 0) {
5421 self.zig_equivalent = clang_arg.ze;
5422 self.only_arg = arg[prefix_len..]; // This will skip over the "--target=" part.
5423
5424 break :find_clang_arg;
5425 }
5426 },
5427 .joined_or_separate => {
5428 // Examples: `-lfoo`, `-l foo`
5429 const prefix_len = clang_arg.matchStartsWith(arg);
5430 if (prefix_len == arg.len) {
5431 if (self.next_index >= self.argv.len) {
5432 fatal("Expected parameter after {q}", .{arg});
5433 }
5434 self.only_arg = self.argv[self.next_index];
5435 self.incrementArgIndex();
5436 self.other_args.len += 1;
5437 self.zig_equivalent = clang_arg.ze;
5438
5439 break :find_clang_arg;
5440 } else if (prefix_len != 0) {
5441 self.zig_equivalent = clang_arg.ze;
5442 self.only_arg = arg[prefix_len..];
5443
5444 break :find_clang_arg;
5445 }
5446 },
5447 .joined_and_separate => {
5448 // Example: `-Xopenmp-target=riscv64-linux-unknown foo`
5449 const prefix_len = clang_arg.matchStartsWith(arg);
5450 if (prefix_len != 0) {
5451 self.only_arg = arg[prefix_len..];
5452 if (self.next_index >= self.argv.len) {
5453 fatal("Expected parameter after {q}", .{arg});
5454 }
5455 self.second_arg = self.argv[self.next_index];
5456 self.incrementArgIndex();
5457 self.other_args.len += 1;
5458 self.zig_equivalent = clang_arg.ze;
5459 break :find_clang_arg;
5460 }
5461 },
5462 .separate => if (clang_arg.matchEql(arg) > 0) {
5463 if (self.next_index >= self.argv.len) {
5464 fatal("expected parameter after {q}", .{arg});
5465 }
5466 self.only_arg = self.argv[self.next_index];
5467 self.incrementArgIndex();
5468 self.other_args.len += 1;
5469 self.zig_equivalent = clang_arg.ze;
5470 break :find_clang_arg;
5471 },
5472 .remaining_args_joined => {
5473 const prefix_len = clang_arg.matchStartsWith(arg);
5474 if (prefix_len != 0) {
5475 @panic("TODO");
5476 }
5477 },
5478 .multi_arg => |num_args| if (clang_arg.matchEql(arg) > 0) {
5479 // Example `-sectcreate <arg1> <arg2> <arg3>`.
5480 var i: usize = 0;
5481 while (i < num_args) : (i += 1) {
5482 self.incrementArgIndex();
5483 self.other_args.len += 1;
5484 }
5485 self.zig_equivalent = clang_arg.ze;
5486 break :find_clang_arg;
5487 },
5488 } else {
5489 fatal("unknown clang option: {q}", .{arg});
5490 }
5491 }
5492
5493 fn incrementArgIndex(self: *ClangArgIterator) void {
5494 self.next_index += 1;
5495 self.resolveRespFileArgs();
5496 }
5497
5498 fn resolveRespFileArgs(self: *ClangArgIterator) void {
5499 const arena = self.arena;
5500 if (self.next_index >= self.argv.len) {
5501 if (self.root_args) |root_args| {
5502 self.next_index = root_args.next_index;
5503 self.argv = root_args.argv;
5504
5505 arena.destroy(root_args);
5506 self.root_args = null;
5507 }
5508 if (self.next_index >= self.argv.len) {
5509 self.has_next = false;
5510 }
5511 }
5512 }
5513};
5514
5515fn parseCodeModel(arg: []const u8) std.lang.CodeModel {
5516 return stringToEnum(std.lang.CodeModel, arg) orelse
5517 fatal("unsupported machine code model: {q}", .{arg});
5518}
5519
5520const usage_ast_check =
5521 \\Usage: zig ast-check [file]
5522 \\
5523 \\ Given a .zig source file or .zon file, reports any compile errors
5524 \\ that can be ascertained on the basis of the source code alone,
5525 \\ without target information or type checking.
5526 \\
5527 \\ If [file] is omitted, stdin is used.
5528 \\
5529 \\Options:
5530 \\ -h, --help Print this help and exit
5531 \\ --color [auto|off|on] Enable or disable colored error messages
5532 \\ --zon Treat the input file as ZON, regardless of file extension
5533 \\ -t (debug option) Output ZIR in text form to stdout
5534 \\
5535 \\
5536;
5537
5538fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8, environ_map: *const std.process.Environ.Map) !void {
5539 const Zir = std.zig.Zir;
5540
5541 var color: Color = Color.settingFromEnvironment(environ_map);
5542 var want_output_text = false;
5543 var force_zon = false;
5544 var zig_source_path: ?[]const u8 = null;
5545
5546 var i: usize = 0;
5547 while (i < args.len) : (i += 1) {
5548 const arg = args[i];
5549 if (mem.startsWith(u8, arg, "-")) {
5550 if (mem.eql(u8, arg, "-h") or mem.eql(u8, arg, "--help")) {
5551 try Io.File.stdout().writeStreamingAll(io, usage_ast_check);
5552 return cleanExit(io);
5553 } else if (mem.eql(u8, arg, "-t")) {
5554 want_output_text = true;
5555 } else if (mem.eql(u8, arg, "--zon")) {
5556 force_zon = true;
5557 } else if (mem.eql(u8, arg, "--color")) {
5558 if (i + 1 >= args.len) {
5559 fatal("expected [auto|on|off] after --color", .{});
5560 }
5561 i += 1;
5562 const next_arg = args[i];
5563 color = stringToEnum(Color, next_arg) orelse {
5564 fatal("expected [auto|on|off] after --color, found {q}", .{next_arg});
5565 };
5566 } else {
5567 fatal("unrecognized parameter: {q}", .{arg});
5568 }
5569 } else if (zig_source_path == null) {
5570 zig_source_path = arg;
5571 } else {
5572 fatal("extra positional parameter: {q}", .{arg});
5573 }
5574 }
5575
5576 const display_path = zig_source_path orelse "<stdin>";
5577 const source: [:0]const u8 = s: {
5578 var f = if (zig_source_path) |p| file: {
5579 break :file Io.Dir.cwd().openFile(io, p, .{}) catch |err| {
5580 fatal("unable to open file {q} for ast-check: {t}", .{ display_path, err });
5581 };
5582 } else Io.File.stdin();
5583 defer if (zig_source_path != null) f.close(io);
5584 var file_reader: Io.File.Reader = f.reader(io, &stdin_buffer);
5585 break :s std.zig.readSourceFileToEndAlloc(arena, &file_reader) catch |err| {
5586 fatal("unable to load file {q} for ast-check: {t}", .{ display_path, err });
5587 };
5588 };
5589
5590 const mode: Ast.Mode = mode: {
5591 if (force_zon) break :mode .zon;
5592 if (zig_source_path) |path| {
5593 if (mem.endsWith(u8, path, ".zon")) {
5594 break :mode .zon;
5595 }
5596 }
5597 break :mode .zig;
5598 };
5599
5600 const tree = try Ast.parse(arena, source, .{ .mode = mode });
5601
5602 var stdout_writer = Io.File.stdout().writerStreaming(io, &stdout_buffer);
5603 const stdout_bw = &stdout_writer.interface;
5604 switch (mode) {
5605 .zig => {
5606 const zir = try AstGen.generate(arena, tree);
5607
5608 if (zir.hasCompileErrors()) {
5609 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
5610 try wip_errors.init(arena);
5611 try wip_errors.addZirErrorMessages(zir, tree, source, display_path);
5612 var error_bundle = try wip_errors.toOwnedBundle("");
5613 try error_bundle.renderToStderr(io, .{}, color);
5614 if (zir.loweringFailed()) {
5615 process.exit(1);
5616 }
5617 }
5618
5619 if (!want_output_text) {
5620 if (zir.hasCompileErrors()) {
5621 process.exit(1);
5622 } else {
5623 return cleanExit(io);
5624 }
5625 }
5626 if (!build_options.enable_debug_extensions) {
5627 fatal("-t option only available in builds of zig with debug extensions", .{});
5628 }
5629
5630 {
5631 const token_bytes = @sizeOf(Ast.TokenList) +
5632 tree.tokens.len * (@sizeOf(std.zig.Token.Tag) + @sizeOf(Ast.ByteOffset));
5633 const tree_bytes = @sizeOf(Ast) + tree.nodes.len *
5634 (@sizeOf(Ast.Node.Tag) +
5635 @sizeOf(Ast.TokenIndex) +
5636 // Here we don't use @sizeOf(Ast.Node.Data) because it would include
5637 // the debug safety tag but we want to measure release size.
5638 8);
5639 const instruction_bytes = zir.instructions.len *
5640 // Here we don't use @sizeOf(Zir.Inst.Data) because it would include
5641 // the debug safety tag but we want to measure release size.
5642 (@sizeOf(Zir.Inst.Tag) + 8);
5643 const extra_bytes = zir.extra.len * @sizeOf(u32);
5644 const total_bytes = @sizeOf(Zir) + instruction_bytes + extra_bytes +
5645 zir.string_bytes.len * @sizeOf(u8);
5646 // zig fmt: off
5647 try stdout_bw.print(
5648 \\# Source bytes: {Bi}
5649 \\# Tokens: {} ({Bi})
5650 \\# AST Nodes: {} ({Bi})
5651 \\# Total ZIR bytes: {Bi}
5652 \\# Instructions: {d} ({Bi})
5653 \\# String Table Bytes: {}
5654 \\# Extra Data Items: {d} ({Bi})
5655 \\
5656 , .{
5657 source.len,
5658 tree.tokens.len, token_bytes,
5659 tree.nodes.len, tree_bytes,
5660 total_bytes,
5661 zir.instructions.len, instruction_bytes,
5662 zir.string_bytes.len,
5663 zir.extra.len, extra_bytes,
5664 });
5665 // zig fmt: on
5666 }
5667
5668 try @import("print_zir.zig").renderAsText(arena, tree, zir, stdout_bw);
5669 try stdout_bw.flush();
5670
5671 if (zir.hasCompileErrors()) {
5672 process.exit(1);
5673 } else {
5674 return cleanExit(io);
5675 }
5676 },
5677 .zon => {
5678 const zoir = try ZonGen.generate(arena, tree, .{});
5679 if (zoir.hasCompileErrors()) {
5680 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
5681 try wip_errors.init(arena);
5682 try wip_errors.addZoirErrorMessages(zoir, tree, source, display_path);
5683 var error_bundle = try wip_errors.toOwnedBundle("");
5684 error_bundle.renderToStderr(io, .{}, color) catch {};
5685 process.exit(1);
5686 }
5687
5688 if (!want_output_text) {
5689 return cleanExit(io);
5690 }
5691
5692 if (!build_options.enable_debug_extensions) {
5693 fatal("-t option only available in builds of zig with debug extensions", .{});
5694 }
5695
5696 try @import("print_zoir.zig").renderToWriter(zoir, arena, stdout_bw);
5697 try stdout_bw.flush();
5698 return cleanExit(io);
5699 },
5700 }
5701}
5702
5703/// This is only enabled for debug builds.
5704fn cmdDumpZir(arena: Allocator, io: Io, args: []const []const u8) !void {
5705 const Zir = std.zig.Zir;
5706
5707 const cache_file = args[0];
5708
5709 var f = Io.Dir.cwd().openFile(io, cache_file, .{}) catch |err| {
5710 fatal("unable to open zir cache file for dumping {q}: {t}", .{ cache_file, err });
5711 };
5712 defer f.close(io);
5713
5714 const zir = try Zcu.loadZirCache(arena, io, f);
5715 var stdout_writer = Io.File.stdout().writerStreaming(io, &stdout_buffer);
5716 const stdout_bw = &stdout_writer.interface;
5717 {
5718 const instruction_bytes = zir.instructions.len *
5719 // Here we don't use @sizeOf(Zir.Inst.Data) because it would include
5720 // the debug safety tag but we want to measure release size.
5721 (@sizeOf(Zir.Inst.Tag) + 8);
5722 const extra_bytes = zir.extra.len * @sizeOf(u32);
5723 const total_bytes = @sizeOf(Zir) + instruction_bytes + extra_bytes +
5724 zir.string_bytes.len * @sizeOf(u8);
5725 // zig fmt: off
5726 try stdout_bw.print(
5727 \\# Total ZIR bytes: {Bi}
5728 \\# Instructions: {d} ({Bi})
5729 \\# String Table Bytes: {Bi}
5730 \\# Extra Data Items: {d} ({Bi})
5731 \\
5732 , .{
5733 total_bytes,
5734 zir.instructions.len, instruction_bytes,
5735 zir.string_bytes.len,
5736 zir.extra.len, extra_bytes,
5737 });
5738 // zig fmt: on
5739 }
5740
5741 try @import("print_zir.zig").renderAsText(arena, null, zir, stdout_bw);
5742 try stdout_bw.flush();
5743}
5744
5745/// This is only enabled for debug builds.
5746fn cmdChangelist(arena: Allocator, io: Io, args: []const []const u8, environ_map: *const std.process.Environ.Map) !void {
5747 const color: Color = Color.settingFromEnvironment(environ_map);
5748 const Zir = std.zig.Zir;
5749
5750 const old_source_path = args[0];
5751 const new_source_path = args[1];
5752
5753 const old_source = source: {
5754 var f = Io.Dir.cwd().openFile(io, old_source_path, .{}) catch |err|
5755 fatal("unable to open old source file {q}: {t}", .{ old_source_path, err });
5756 defer f.close(io);
5757 var file_reader: Io.File.Reader = f.reader(io, &stdin_buffer);
5758 break :source std.zig.readSourceFileToEndAlloc(arena, &file_reader) catch |err|
5759 fatal("unable to read old source file {q}: {t}", .{ old_source_path, err });
5760 };
5761 const new_source = source: {
5762 var f = Io.Dir.cwd().openFile(io, new_source_path, .{}) catch |err|
5763 fatal("unable to open new source file {q}: {t}", .{ new_source_path, err });
5764 defer f.close(io);
5765 var file_reader: Io.File.Reader = f.reader(io, &stdin_buffer);
5766 break :source std.zig.readSourceFileToEndAlloc(arena, &file_reader) catch |err|
5767 fatal("unable to read new source file {q}: {t}", .{ new_source_path, err });
5768 };
5769
5770 const old_tree = try Ast.parse(arena, old_source, .{});
5771 const old_zir = try AstGen.generate(arena, old_tree);
5772
5773 if (old_zir.loweringFailed()) {
5774 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
5775 try wip_errors.init(arena);
5776 try wip_errors.addZirErrorMessages(old_zir, old_tree, old_source, old_source_path);
5777 var error_bundle = try wip_errors.toOwnedBundle("");
5778 error_bundle.renderToStderr(io, .{}, color) catch {};
5779 process.exit(1);
5780 }
5781
5782 const new_tree = try Ast.parse(arena, new_source, .{});
5783 const new_zir = try AstGen.generate(arena, new_tree);
5784
5785 if (new_zir.loweringFailed()) {
5786 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
5787 try wip_errors.init(arena);
5788 try wip_errors.addZirErrorMessages(new_zir, new_tree, new_source, new_source_path);
5789 var error_bundle = try wip_errors.toOwnedBundle("");
5790 error_bundle.renderToStderr(io, .{}, color) catch {};
5791 process.exit(1);
5792 }
5793
5794 var inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .empty;
5795 try Zcu.mapOldZirToNew(arena, old_zir, new_zir, &inst_map);
5796
5797 var stdout_writer = Io.File.stdout().writerStreaming(io, &stdout_buffer);
5798 const stdout_bw = &stdout_writer.interface;
5799 {
5800 try stdout_bw.print("Instruction mappings:\n", .{});
5801 var it = inst_map.iterator();
5802 while (it.next()) |entry| {
5803 try stdout_bw.print(" %{d} => %{d}\n", .{
5804 @backingInt(entry.key_ptr.*),
5805 @backingInt(entry.value_ptr.*),
5806 });
5807 }
5808 }
5809 try stdout_bw.flush();
5810}
5811
5812fn eatIntPrefix(arg: []const u8, base: u8) []const u8 {
5813 if (arg.len > 2 and arg[0] == '0') {
5814 switch (std.ascii.toLower(arg[1])) {
5815 'b' => if (base == 2) return arg[2..],
5816 'o' => if (base == 8) return arg[2..],
5817 'x' => if (base == 16) return arg[2..],
5818 else => {},
5819 }
5820 }
5821 return arg;
5822}
5823
5824fn prefixedIntArg(arg: []const u8, prefix: []const u8) ?u64 {
5825 const number = mem.cutPrefix(u8, arg, prefix) orelse return null;
5826 return std.fmt.parseUnsigned(u64, number, 0) catch |err| fatal("unable to parse {q}: {t}", .{ arg, err });
5827}
5828
5829fn warnAboutForeignBinaries(
5830 io: Io,
5831 arena: Allocator,
5832 arg_mode: ArgMode,
5833 target: *const std.Target,
5834 link_libc: bool,
5835) !void {
5836 const host_query: std.Target.Query = .{};
5837 const host_target = std.zig.resolveTargetQueryOrFatal(io, host_query);
5838
5839 switch (std.zig.system.getExternalExecutor(io, target, .{
5840 .host_cpu_arch = host_target.cpu.arch,
5841 .host_os_tag = host_target.os.tag,
5842 .link_libc = link_libc,
5843 })) {
5844 .native => return,
5845 .rosetta => {
5846 const host_name = try host_target.zigTriple(arena);
5847 const foreign_name = try target.zigTriple(arena);
5848 warn("the host system ({s}) does not appear to be capable of executing binaries from the target ({s}). Consider installing Rosetta.", .{
5849 host_name, foreign_name,
5850 });
5851 },
5852 .qemu => |qemu| {
5853 const host_name = try host_target.zigTriple(arena);
5854 const foreign_name = try target.zigTriple(arena);
5855 switch (arg_mode) {
5856 .zig_test => warn(
5857 "the host system ({s}) does not appear to be capable of executing binaries " ++
5858 "from the target ({s}). Consider using '--test-cmd {s} --test-cmd-bin' " ++
5859 "to run the tests",
5860 .{ host_name, foreign_name, qemu },
5861 ),
5862 else => warn(
5863 "the host system ({s}) does not appear to be capable of executing binaries " ++
5864 "from the target ({s}). Consider using {q} to run the binary",
5865 .{ host_name, foreign_name, qemu },
5866 ),
5867 }
5868 },
5869 .wine => |wine| {
5870 const host_name = try host_target.zigTriple(arena);
5871 const foreign_name = try target.zigTriple(arena);
5872 switch (arg_mode) {
5873 .zig_test => warn(
5874 "the host system ({s}) does not appear to be capable of executing binaries " ++
5875 "from the target ({s}). Consider using '--test-cmd {s} --test-cmd-bin' " ++
5876 "to run the tests",
5877 .{ host_name, foreign_name, wine },
5878 ),
5879 else => warn(
5880 "the host system ({s}) does not appear to be capable of executing binaries " ++
5881 "from the target ({s}). Consider using {q} to run the binary",
5882 .{ host_name, foreign_name, wine },
5883 ),
5884 }
5885 },
5886 .wasmtime => |wasmtime| {
5887 const host_name = try host_target.zigTriple(arena);
5888 const foreign_name = try target.zigTriple(arena);
5889 switch (arg_mode) {
5890 .zig_test => warn(
5891 "the host system ({s}) does not appear to be capable of executing binaries " ++
5892 "from the target ({s}). Consider using '--test-cmd {s} --test-cmd-bin' " ++
5893 "to run the tests",
5894 .{ host_name, foreign_name, wasmtime },
5895 ),
5896 else => warn(
5897 "the host system ({s}) does not appear to be capable of executing binaries " ++
5898 "from the target ({s}). Consider using {q} to run the binary",
5899 .{ host_name, foreign_name, wasmtime },
5900 ),
5901 }
5902 },
5903 .darling => |darling| {
5904 const host_name = try host_target.zigTriple(arena);
5905 const foreign_name = try target.zigTriple(arena);
5906 switch (arg_mode) {
5907 .zig_test => warn(
5908 "the host system ({s}) does not appear to be capable of executing binaries " ++
5909 "from the target ({s}). Consider using '--test-cmd {s} --test-cmd-bin' " ++
5910 "to run the tests",
5911 .{ host_name, foreign_name, darling },
5912 ),
5913 else => warn(
5914 "the host system ({s}) does not appear to be capable of executing binaries " ++
5915 "from the target ({s}). Consider using {q} to run the binary",
5916 .{ host_name, foreign_name, darling },
5917 ),
5918 }
5919 },
5920 .bad_dl => |foreign_dl| {
5921 const host_dl = host_target.dynamic_linker.get() orelse "(none)";
5922 const tip_suffix = switch (arg_mode) {
5923 .zig_test => ", '--test-no-exec', or '--test-cmd'",
5924 else => "",
5925 };
5926 warn("the host system does not appear to be capable of executing binaries from the target because the host dynamic linker is {q}, while the target dynamic linker is {q}. Consider using '--dynamic-linker'{s}", .{
5927 host_dl, foreign_dl, tip_suffix,
5928 });
5929 },
5930 .bad_os_or_cpu => {
5931 const host_name = try host_target.zigTriple(arena);
5932 const foreign_name = try target.zigTriple(arena);
5933 const tip_suffix = switch (arg_mode) {
5934 .zig_test => ". Consider using '--test-no-exec' or '--test-cmd'",
5935 else => "",
5936 };
5937 warn("the host system ({s}) does not appear to be capable of executing binaries from the target ({s}){s}", .{
5938 host_name, foreign_name, tip_suffix,
5939 });
5940 },
5941 }
5942}
5943
5944fn parseSubsystem(arg: []const u8) !std.zig.Subsystem {
5945 return stringToEnum(std.zig.Subsystem, arg) orelse
5946 fatal("invalid: --subsystem: {q}. Options are:\n{s}", .{
5947 arg,
5948 \\ console
5949 \\ windows
5950 \\ posix
5951 \\ native
5952 \\ efi_application
5953 \\ efi_boot_service_driver
5954 \\ efi_rom
5955 \\ efi_runtime_driver
5956 \\
5957 });
5958}
5959
5960/// Model a header searchlist as a group.
5961/// Silently ignore superfluous search dirs.
5962/// Warn when a dir is added to multiple searchlists.
5963const ClangSearchSanitizer = struct {
5964 map: std.StringHashMapUnmanaged(Membership) = .empty,
5965
5966 fn reset(self: *@This()) void {
5967 self.map.clearRetainingCapacity();
5968 }
5969
5970 fn addIncludePath(
5971 self: *@This(),
5972 ally: Allocator,
5973 argv: *std.ArrayList([]const u8),
5974 group: Group,
5975 arg: []const u8,
5976 dir: []const u8,
5977 joined: bool,
5978 ) !void {
5979 const gopr = try self.map.getOrPut(ally, dir);
5980 const m = gopr.value_ptr;
5981 if (!gopr.found_existing) {
5982 // init empty membership
5983 m.* = .{};
5984 }
5985 const wtxt = "add {q} to header searchlist '-{s}' conflicts with '-{s}'";
5986 switch (group) {
5987 .I => {
5988 if (m.I) return;
5989 m.I = true;
5990 if (m.isystem) warn(wtxt, .{ dir, "I", "isystem" });
5991 if (m.idirafter) warn(wtxt, .{ dir, "I", "idirafter" });
5992 if (m.iframework) warn(wtxt, .{ dir, "I", "iframework" });
5993 },
5994 .isystem => {
5995 if (m.isystem) return;
5996 m.isystem = true;
5997 if (m.I) warn(wtxt, .{ dir, "isystem", "I" });
5998 if (m.idirafter) warn(wtxt, .{ dir, "isystem", "idirafter" });
5999 if (m.iframework) warn(wtxt, .{ dir, "isystem", "iframework" });
6000 },
6001 .iwithsysroot => {
6002 if (m.iwithsysroot) return;
6003 m.iwithsysroot = true;
6004 if (m.iframeworkwithsysroot) warn(wtxt, .{ dir, "iwithsysroot", "iframeworkwithsysroot" });
6005 },
6006 .idirafter => {
6007 if (m.idirafter) return;
6008 m.idirafter = true;
6009 if (m.I) warn(wtxt, .{ dir, "idirafter", "I" });
6010 if (m.isystem) warn(wtxt, .{ dir, "idirafter", "isystem" });
6011 if (m.iframework) warn(wtxt, .{ dir, "idirafter", "iframework" });
6012 },
6013 .iframework => {
6014 if (m.iframework) return;
6015 m.iframework = true;
6016 if (m.I) warn(wtxt, .{ dir, "iframework", "I" });
6017 if (m.isystem) warn(wtxt, .{ dir, "iframework", "isystem" });
6018 if (m.idirafter) warn(wtxt, .{ dir, "iframework", "idirafter" });
6019 },
6020 .iframeworkwithsysroot => {
6021 if (m.iframeworkwithsysroot) return;
6022 m.iframeworkwithsysroot = true;
6023 if (m.iwithsysroot) warn(wtxt, .{ dir, "iframeworkwithsysroot", "iwithsysroot" });
6024 },
6025 .embed_dir => {
6026 if (m.embed_dir) return;
6027 m.embed_dir = true;
6028 },
6029 }
6030 try argv.ensureUnusedCapacity(ally, 2);
6031 argv.appendAssumeCapacity(arg);
6032 if (!joined) argv.appendAssumeCapacity(dir);
6033 }
6034
6035 const Group = enum { I, isystem, iwithsysroot, idirafter, iframework, iframeworkwithsysroot, embed_dir };
6036
6037 const Membership = packed struct {
6038 I: bool = false,
6039 isystem: bool = false,
6040 iwithsysroot: bool = false,
6041 idirafter: bool = false,
6042 iframework: bool = false,
6043 iframeworkwithsysroot: bool = false,
6044 embed_dir: bool = false,
6045 };
6046};
6047
6048fn accessFrameworkPath(
6049 io: Io,
6050 test_path: *std.array_list.Managed(u8),
6051 checked_paths: *std.array_list.Managed(u8),
6052 framework_dir_path: []const u8,
6053 framework_name: []const u8,
6054) !bool {
6055 const sep = fs.path.sep_str;
6056
6057 for (&[_][]const u8{ ".tbd", ".dylib", "" }) |ext| {
6058 test_path.clearRetainingCapacity();
6059 try test_path.print("{s}" ++ sep ++ "{s}.framework" ++ sep ++ "{s}{s}", .{
6060 framework_dir_path, framework_name, framework_name, ext,
6061 });
6062 try checked_paths.print("\n {s}", .{test_path.items});
6063 Io.Dir.cwd().access(io, test_path.items, .{}) catch |err| switch (err) {
6064 error.FileNotFound => continue,
6065 else => |e| fatal("unable to search for {s} framework {q}: {t}", .{
6066 ext, test_path.items, e,
6067 }),
6068 };
6069 return true;
6070 }
6071
6072 return false;
6073}
6074
6075fn parseRcIncludes(arg: []const u8) std.zig.RcIncludes {
6076 return stringToEnum(std.zig.RcIncludes, arg) orelse
6077 fatal("unsupported rc includes type: {q}", .{arg});
6078}
6079
6080fn parseOptimizeMode(s: []const u8) std.lang.Optimize {
6081 return std.lang.Optimize.fromString(s) orelse fatal("unrecognized optimization mode: {q}", .{s});
6082}
6083
6084fn parseWasiExecModel(s: []const u8) std.lang.WasiExecModel {
6085 return stringToEnum(std.lang.WasiExecModel, s) orelse
6086 fatal("expected [command|reactor] for -mexec-mode=[value], found {q}", .{s});
6087}
6088
6089fn parseStackSize(s: []const u8) u64 {
6090 return std.fmt.parseUnsigned(u64, s, 0) catch |err|
6091 fatal("unable to parse stack size {q}: {t}", .{ s, err });
6092}
6093
6094fn parseImageBase(s: []const u8) u64 {
6095 return std.fmt.parseUnsigned(u64, s, 0) catch |err|
6096 fatal("unable to parse image base {q}: {t}", .{ s, err });
6097}
6098
6099fn handleModArg(
6100 arena: Allocator,
6101 mod_name: []const u8,
6102 opt_root_src_orig: ?[]const u8,
6103 create_module: *CreateModule,
6104 mod_opts: *Module.CreateOptions.Inherited,
6105 cc_argv: *std.ArrayList([]const u8),
6106 target_arch_os_abi: *?[]const u8,
6107 target_mcpu: *?[]const u8,
6108 dynamic_linker: *?[]const u8,
6109 deps: *std.ArrayList(CliModule.Dep),
6110 c_source_files_owner_index: *usize,
6111 rc_source_files_owner_index: *usize,
6112 cssan: *ClangSearchSanitizer,
6113) !void {
6114 const gop = try create_module.modules.getOrPut(arena, mod_name);
6115
6116 if (gop.found_existing) {
6117 fatal("unable to add module {q}: already exists as '{s}{c}{s}'", .{
6118 mod_name, gop.value_ptr.root_path, fs.path.sep, gop.value_ptr.root_src_path,
6119 });
6120 }
6121
6122 // See duplicate logic: ModCreationGlobalFlags
6123 if (mod_opts.single_threaded == false)
6124 create_module.opts.any_non_single_threaded = true;
6125 if (mod_opts.sanitize_thread == true)
6126 create_module.opts.any_sanitize_thread = true;
6127 if (mod_opts.sanitize_c) |sc| switch (sc) {
6128 .off => {},
6129 .trap => if (create_module.opts.any_sanitize_c == .off) {
6130 create_module.opts.any_sanitize_c = .trap;
6131 },
6132 .full => create_module.opts.any_sanitize_c = .full,
6133 };
6134 if (mod_opts.fuzz == true)
6135 create_module.opts.any_fuzz = true;
6136 if (mod_opts.unwind_tables) |uwt| switch (uwt) {
6137 .none => {},
6138 .sync, .async => create_module.opts.any_unwind_tables = true,
6139 };
6140 if (mod_opts.strip == false)
6141 create_module.opts.any_non_stripped = true;
6142 if (mod_opts.error_tracing == true)
6143 create_module.opts.any_error_tracing = true;
6144
6145 const root_path: []const u8, const root_src_path: []const u8 = if (opt_root_src_orig) |path| root: {
6146 create_module.opts.have_zcu = true;
6147 break :root .{ fs.path.dirname(path) orelse ".", fs.path.basename(path) };
6148 } else .{ ".", "" };
6149
6150 gop.value_ptr.* = .{
6151 .root_path = root_path,
6152 .root_src_path = root_src_path,
6153 .cc_argv = try cc_argv.toOwnedSlice(arena),
6154 .inherited = mod_opts.*,
6155 .target_arch_os_abi = target_arch_os_abi.*,
6156 .target_mcpu = target_mcpu.*,
6157 .dynamic_linker = dynamic_linker.*,
6158 .deps = try deps.toOwnedSlice(arena),
6159 .resolved = null,
6160 .c_source_files_start = c_source_files_owner_index.*,
6161 .c_source_files_end = create_module.c_source_files.items.len,
6162 .rc_source_files_start = rc_source_files_owner_index.*,
6163 .rc_source_files_end = create_module.rc_source_files.items.len,
6164 };
6165 cssan.reset();
6166 mod_opts.* = .{};
6167 target_arch_os_abi.* = null;
6168 target_mcpu.* = null;
6169 dynamic_linker.* = null;
6170 c_source_files_owner_index.* = create_module.c_source_files.items.len;
6171 rc_source_files_owner_index.* = create_module.rc_source_files.items.len;
6172}
6173
6174fn anyObjectLinkInputs(link_inputs: []const link.UnresolvedInput) bool {
6175 for (link_inputs) |link_input| switch (link_input) {
6176 .path_query => |pq| switch (Compilation.classifyFileExt(pq.path.sub_path)) {
6177 .object, .static_library, .res => return true,
6178 else => continue,
6179 },
6180 else => continue,
6181 };
6182 return false;
6183}
6184
6185fn addLibDirectoryWarn(io: Io, lib_directories: *std.ArrayList(Directory), path: []const u8) void {
6186 return addLibDirectoryWarn2(io, lib_directories, path, false);
6187}
6188
6189fn addLibDirectoryWarn2(
6190 io: Io,
6191 lib_directories: *std.ArrayList(Directory),
6192 path: []const u8,
6193 ignore_not_found: bool,
6194) void {
6195 lib_directories.appendAssumeCapacity(.{
6196 .handle = Io.Dir.cwd().openDir(io, path, .{}) catch |err| {
6197 if (err == error.FileNotFound and ignore_not_found) return;
6198 warn("unable to open library directory {q}: {t}", .{ path, err });
6199 return;
6200 },
6201 .path = path,
6202 });
6203}
6204
6205const IoImpl = switch (build_options.io_mode) {
6206 .threaded => Io.Threaded,
6207 .evented => Io.Evented,
6208};
6209var io_impl_ptr: *IoImpl = undefined;
6210fn setThreadLimit(arena: std.mem.Allocator, n: usize) Allocator.Error!void {
6211 switch (build_options.io_mode) {
6212 .threaded => {
6213 // We want a maximum of n total threads to keep the InternPool happy, but
6214 // the main thread doesn't count towards the limits, so use n-1. Also, the
6215 // linker can run concurrently, so we need to set both the async *and* the
6216 // concurrency limit.
6217 const limit: Io.Limit = .limited(n - 1);
6218 io_impl_ptr.setAsyncLimit(limit);
6219 io_impl_ptr.concurrent_limit = limit;
6220 },
6221 .evented => {},
6222 }
6223 try Zcu.PerThread.Id.allocate(arena, @max(n, 2));
6224}
6225
6226fn randInt(io: Io, comptime T: type) T {
6227 var x: T = undefined;
6228 io.random(@ptrCast(&x));
6229 return x;
6230}
6231
6232fn addDebugLog(arena: Allocator, scope_name: []const u8) error{OutOfMemory}!void {
6233 if (!build_options.enable_logging) {
6234 warn("Zig was compiled without logging enabled (-Dlog). --debug-log has no effect.", .{});
6235 } else {
6236 try log_scopes.append(arena, scope_name);
6237 }
6238}