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