1const Compilation = @This(); 2 3const std = @import("std"); 4const builtin = @import("builtin"); 5const mem = std.mem; 6const Allocator = std.mem.Allocator; 7const assert = std.debug.assert; 8const log = std.log.scoped(.compilation); 9const Target = std.Target; 10 11const Value = @import("value.zig").Value; 12const Type = @import("type.zig").Type; 13const target_util = @import("target.zig"); 14const Package = @import("Package.zig"); 15const link = @import("link.zig"); 16const tracy = @import("tracy.zig"); 17const trace = tracy.trace; 18const Liveness = @import("Liveness.zig"); 19const build_options = @import("build_options"); 20const LibCInstallation = @import("libc_installation.zig").LibCInstallation; 21const glibc = @import("glibc.zig"); 22const musl = @import("musl.zig"); 23const mingw = @import("mingw.zig"); 24const libunwind = @import("libunwind.zig"); 25const libcxx = @import("libcxx.zig"); 26const wasi_libc = @import("wasi_libc.zig"); 27const fatal = @import("main.zig").fatal; 28const Module = @import("Module.zig"); 29const Cache = @import("Cache.zig"); 30const stage1 = @import("stage1.zig"); 31const translate_c = @import("translate_c.zig"); 32const c_codegen = @import("codegen/c.zig"); 33const ThreadPool = @import("ThreadPool.zig"); 34const WaitGroup = @import("WaitGroup.zig"); 35const libtsan = @import("libtsan.zig"); 36const Zir = @import("Zir.zig"); 37 38/// General-purpose allocator. Used for both temporary and long-term storage. 39gpa: Allocator, 40/// Arena-allocated memory used during initialization. Should be untouched until deinit. 41arena_state: std.heap.ArenaAllocator.State, 42bin_file: *link.File, 43c_object_table: std.AutoArrayHashMapUnmanaged(*CObject, void) = .{}, 44stage1_lock: ?Cache.Lock = null, 45stage1_cache_manifest: *Cache.Manifest = undefined, 46 47link_error_flags: link.File.ErrorFlags = .{}, 48 49work_queue: std.fifo.LinearFifo(Job, .Dynamic), 50anon_work_queue: std.fifo.LinearFifo(Job, .Dynamic), 51 52/// These jobs are to invoke the Clang compiler to create an object file, which 53/// gets linked with the Compilation. 54c_object_work_queue: std.fifo.LinearFifo(*CObject, .Dynamic), 55 56/// These jobs are to tokenize, parse, and astgen files, which may be outdated 57/// since the last compilation, as well as scan for `@import` and queue up 58/// additional jobs corresponding to those new files. 59astgen_work_queue: std.fifo.LinearFifo(*Module.File, .Dynamic), 60/// These jobs are to inspect the file system stat() and if the embedded file has changed 61/// on disk, mark the corresponding Decl outdated and queue up an `analyze_decl` 62/// task for it. 63embed_file_work_queue: std.fifo.LinearFifo(*Module.EmbedFile, .Dynamic), 64 65/// The ErrorMsg memory is owned by the `CObject`, using Compilation's general purpose allocator. 66/// This data is accessed by multiple threads and is protected by `mutex`. 67failed_c_objects: std.AutoArrayHashMapUnmanaged(*CObject, *CObject.ErrorMsg) = .{}, 68 69/// Miscellaneous things that can fail. 70misc_failures: std.AutoArrayHashMapUnmanaged(MiscTask, MiscError) = .{}, 71 72keep_source_files_loaded: bool, 73use_clang: bool, 74sanitize_c: bool, 75/// When this is `true` it means invoking clang as a sub-process is expected to inherit 76/// stdin, stdout, stderr, and if it returns non success, to forward the exit code. 77/// Otherwise we attempt to parse the error messages and expose them via the Compilation API. 78/// This is `true` for `zig cc`, `zig c++`, and `zig translate-c`. 79clang_passthrough_mode: bool, 80clang_preprocessor_mode: ClangPreprocessorMode, 81/// Whether to print clang argvs to stdout. 82verbose_cc: bool, 83verbose_air: bool, 84verbose_mir: bool, 85verbose_llvm_ir: bool, 86verbose_cimport: bool, 87verbose_llvm_cpu_features: bool, 88disable_c_depfile: bool, 89time_report: bool, 90stack_report: bool, 91unwind_tables: bool, 92test_evented_io: bool, 93debug_compiler_runtime_libs: bool, 94debug_compile_errors: bool, 95 96c_source_files: []const CSourceFile, 97clang_argv: []const []const u8, 98cache_parent: *Cache, 99/// Path to own executable for invoking `zig clang`. 100self_exe_path: ?[]const u8, 101zig_lib_directory: Directory, 102local_cache_directory: Directory, 103global_cache_directory: Directory, 104libc_include_dir_list: []const []const u8, 105thread_pool: *ThreadPool, 106 107/// Populated when we build the libc++ static library. A Job to build this is placed in the queue 108/// and resolved before calling linker.flush(). 109libcxx_static_lib: ?CRTFile = null, 110/// Populated when we build the libc++abi static library. A Job to build this is placed in the queue 111/// and resolved before calling linker.flush(). 112libcxxabi_static_lib: ?CRTFile = null, 113/// Populated when we build the libunwind static library. A Job to build this is placed in the queue 114/// and resolved before calling linker.flush(). 115libunwind_static_lib: ?CRTFile = null, 116/// Populated when we build the TSAN static library. A Job to build this is placed in the queue 117/// and resolved before calling linker.flush(). 118tsan_static_lib: ?CRTFile = null, 119/// Populated when we build the libssp static library. A Job to build this is placed in the queue 120/// and resolved before calling linker.flush(). 121libssp_static_lib: ?CRTFile = null, 122/// Populated when we build the libc static library. A Job to build this is placed in the queue 123/// and resolved before calling linker.flush(). 124libc_static_lib: ?CRTFile = null, 125/// Populated when we build the libcompiler_rt static library. A Job to build this is placed in the queue 126/// and resolved before calling linker.flush(). 127compiler_rt_static_lib: ?CRTFile = null, 128/// Populated when we build the compiler_rt_obj object. A Job to build this is placed in the queue 129/// and resolved before calling linker.flush(). 130compiler_rt_obj: ?CRTFile = null, 131 132glibc_so_files: ?glibc.BuiltSharedObjects = null, 133 134/// For example `Scrt1.o` and `libc_nonshared.a`. These are populated after building libc from source, 135/// The set of needed CRT (C runtime) files differs depending on the target and compilation settings. 136/// The key is the basename, and the value is the absolute path to the completed build artifact. 137crt_files: std.StringHashMapUnmanaged(CRTFile) = .{}, 138 139/// Keeping track of this possibly open resource so we can close it later. 140owned_link_dir: ?std.fs.Dir, 141 142/// This is for stage1 and should be deleted upon completion of self-hosting. 143/// Don't use this for anything other than stage1 compatibility. 144color: @import("main.zig").Color = .auto, 145 146/// This mutex guards all `Compilation` mutable state. 147mutex: std.Thread.Mutex = .{}, 148 149test_filter: ?[]const u8, 150test_name_prefix: ?[]const u8, 151 152emit_asm: ?EmitLoc, 153emit_llvm_ir: ?EmitLoc, 154emit_llvm_bc: ?EmitLoc, 155emit_analysis: ?EmitLoc, 156emit_docs: ?EmitLoc, 157 158work_queue_wait_group: WaitGroup, 159astgen_wait_group: WaitGroup, 160 161pub const SemaError = Module.SemaError; 162 163pub const CRTFile = struct { 164 lock: Cache.Lock, 165 full_object_path: []const u8, 166 167 fn deinit(self: *CRTFile, gpa: Allocator) void { 168 self.lock.release(); 169 gpa.free(self.full_object_path); 170 self.* = undefined; 171 } 172}; 173 174/// For passing to a C compiler. 175pub const CSourceFile = struct { 176 src_path: []const u8, 177 extra_flags: []const []const u8 = &[0][]const u8{}, 178}; 179 180const Job = union(enum) { 181 /// Write the constant value for a Decl to the output file. 182 codegen_decl: *Module.Decl, 183 /// Write the machine code for a function to the output file. 184 codegen_func: *Module.Fn, 185 /// Render the .h file snippet for the Decl. 186 emit_h_decl: *Module.Decl, 187 /// The Decl needs to be analyzed and possibly export itself. 188 /// It may have already be analyzed, or it may have been determined 189 /// to be outdated; in this case perform semantic analysis again. 190 analyze_decl: *Module.Decl, 191 /// The file that was loaded with `@embedFile` has changed on disk 192 /// and has been re-loaded into memory. All Decls that depend on it 193 /// need to be re-analyzed. 194 update_embed_file: *Module.EmbedFile, 195 /// The source file containing the Decl has been updated, and so the 196 /// Decl may need its line number information updated in the debug info. 197 update_line_number: *Module.Decl, 198 /// The main source file for the package needs to be analyzed. 199 analyze_pkg: *Package, 200 201 /// one of the glibc static objects 202 glibc_crt_file: glibc.CRTFile, 203 /// all of the glibc shared objects 204 glibc_shared_objects, 205 /// one of the musl static objects 206 musl_crt_file: musl.CRTFile, 207 /// one of the mingw-w64 static objects 208 mingw_crt_file: mingw.CRTFile, 209 /// libunwind.a, usually needed when linking libc 210 libunwind: void, 211 libcxx: void, 212 libcxxabi: void, 213 libtsan: void, 214 libssp: void, 215 compiler_rt_lib: void, 216 compiler_rt_obj: void, 217 /// needed when not linking libc and using LLVM for code generation because it generates 218 /// calls to, for example, memcpy and memset. 219 zig_libc: void, 220 /// one of WASI libc static objects 221 wasi_libc_crt_file: wasi_libc.CRTFile, 222 223 /// Use stage1 C++ code to compile zig code into an object file. 224 stage1_module: void, 225 226 /// The value is the index into `link.File.Options.system_libs`. 227 windows_import_lib: usize, 228}; 229 230pub const CObject = struct { 231 /// Relative to cwd. Owned by arena. 232 src: CSourceFile, 233 status: union(enum) { 234 new, 235 success: struct { 236 /// The outputted result. Owned by gpa. 237 object_path: []u8, 238 /// This is a file system lock on the cache hash manifest representing this 239 /// object. It prevents other invocations of the Zig compiler from interfering 240 /// with this object until released. 241 lock: Cache.Lock, 242 }, 243 /// There will be a corresponding ErrorMsg in Compilation.failed_c_objects. 244 failure, 245 /// A transient failure happened when trying to compile the C Object; it may 246 /// succeed if we try again. There may be a corresponding ErrorMsg in 247 /// Compilation.failed_c_objects. If there is not, the failure is out of memory. 248 failure_retryable, 249 }, 250 251 pub const ErrorMsg = struct { 252 msg: []const u8, 253 line: u32, 254 column: u32, 255 256 pub fn destroy(em: *ErrorMsg, gpa: Allocator) void { 257 gpa.free(em.msg); 258 gpa.destroy(em); 259 } 260 }; 261 262 /// Returns if there was failure. 263 pub fn clearStatus(self: *CObject, gpa: Allocator) bool { 264 switch (self.status) { 265 .new => return false, 266 .failure, .failure_retryable => { 267 self.status = .new; 268 return true; 269 }, 270 .success => |*success| { 271 gpa.free(success.object_path); 272 success.lock.release(); 273 self.status = .new; 274 return false; 275 }, 276 } 277 } 278 279 pub fn destroy(self: *CObject, gpa: Allocator) void { 280 _ = self.clearStatus(gpa); 281 gpa.destroy(self); 282 } 283}; 284 285pub const MiscTask = enum { 286 write_builtin_zig, 287 glibc_crt_file, 288 glibc_shared_objects, 289 musl_crt_file, 290 mingw_crt_file, 291 windows_import_lib, 292 libunwind, 293 libcxx, 294 libcxxabi, 295 libtsan, 296 wasi_libc_crt_file, 297 compiler_rt, 298 libssp, 299 zig_libc, 300 analyze_pkg, 301}; 302 303pub const MiscError = struct { 304 /// Allocated with gpa. 305 msg: []u8, 306 children: ?AllErrors = null, 307 308 pub fn deinit(misc_err: *MiscError, gpa: Allocator) void { 309 gpa.free(misc_err.msg); 310 if (misc_err.children) |*children| { 311 children.deinit(gpa); 312 } 313 misc_err.* = undefined; 314 } 315}; 316 317/// To support incremental compilation, errors are stored in various places 318/// so that they can be created and destroyed appropriately. This structure 319/// is used to collect all the errors from the various places into one 320/// convenient place for API users to consume. It is allocated into 1 arena 321/// and freed all at once. 322pub const AllErrors = struct { 323 arena: std.heap.ArenaAllocator.State, 324 list: []const Message, 325 326 pub const Message = union(enum) { 327 src: struct { 328 msg: []const u8, 329 src_path: []const u8, 330 line: u32, 331 column: u32, 332 byte_offset: u32, 333 /// Does not include the trailing newline. 334 source_line: ?[]const u8, 335 notes: []Message = &.{}, 336 }, 337 plain: struct { 338 msg: []const u8, 339 notes: []Message = &.{}, 340 }, 341 342 pub fn renderToStdErr(msg: Message, ttyconf: std.debug.TTY.Config) void { 343 std.debug.getStderrMutex().lock(); 344 defer std.debug.getStderrMutex().unlock(); 345 const stderr = std.io.getStdErr(); 346 return msg.renderToStdErrInner(ttyconf, stderr, "error:", .Red, 0) catch return; 347 } 348 349 fn renderToStdErrInner( 350 msg: Message, 351 ttyconf: std.debug.TTY.Config, 352 stderr_file: std.fs.File, 353 kind: []const u8, 354 color: std.debug.TTY.Color, 355 indent: usize, 356 ) anyerror!void { 357 const stderr = stderr_file.writer(); 358 switch (msg) { 359 .src => |src| { 360 try stderr.writeByteNTimes(' ', indent); 361 ttyconf.setColor(stderr, .Bold); 362 try stderr.print("{s}:{d}:{d}: ", .{ 363 src.src_path, 364 src.line + 1, 365 src.column + 1, 366 }); 367 ttyconf.setColor(stderr, color); 368 try stderr.writeAll(kind); 369 ttyconf.setColor(stderr, .Reset); 370 ttyconf.setColor(stderr, .Bold); 371 try stderr.print(" {s}\n", .{src.msg}); 372 ttyconf.setColor(stderr, .Reset); 373 if (ttyconf != .no_color) { 374 if (src.source_line) |line| { 375 for (line) |b| switch (b) { 376 '\t' => try stderr.writeByte(' '), 377 else => try stderr.writeByte(b), 378 }; 379 try stderr.writeByte('\n'); 380 try stderr.writeByteNTimes(' ', src.column); 381 ttyconf.setColor(stderr, .Green); 382 try stderr.writeAll("^\n"); 383 ttyconf.setColor(stderr, .Reset); 384 } 385 } 386 for (src.notes) |note| { 387 try note.renderToStdErrInner(ttyconf, stderr_file, "note:", .Cyan, indent); 388 } 389 }, 390 .plain => |plain| { 391 ttyconf.setColor(stderr, color); 392 try stderr.writeByteNTimes(' ', indent); 393 try stderr.writeAll(kind); 394 ttyconf.setColor(stderr, .Reset); 395 try stderr.print(" {s}\n", .{plain.msg}); 396 ttyconf.setColor(stderr, .Reset); 397 for (plain.notes) |note| { 398 try note.renderToStdErrInner(ttyconf, stderr_file, "error:", .Red, indent + 4); 399 } 400 }, 401 } 402 } 403 }; 404 405 pub fn deinit(self: *AllErrors, gpa: Allocator) void { 406 self.arena.promote(gpa).deinit(); 407 } 408 409 fn add( 410 module: *Module, 411 arena: *std.heap.ArenaAllocator, 412 errors: *std.ArrayList(Message), 413 module_err_msg: Module.ErrorMsg, 414 ) !void { 415 const allocator = arena.allocator(); 416 const notes = try allocator.alloc(Message, module_err_msg.notes.len); 417 for (notes) |*note, i| { 418 const module_note = module_err_msg.notes[i]; 419 const source = try module_note.src_loc.file_scope.getSource(module.gpa); 420 const byte_offset = try module_note.src_loc.byteOffset(module.gpa); 421 const loc = std.zig.findLineColumn(source, byte_offset); 422 const file_path = try module_note.src_loc.file_scope.fullPath(allocator); 423 note.* = .{ 424 .src = .{ 425 .src_path = file_path, 426 .msg = try allocator.dupe(u8, module_note.msg), 427 .byte_offset = byte_offset, 428 .line = @intCast(u32, loc.line), 429 .column = @intCast(u32, loc.column), 430 .source_line = try allocator.dupe(u8, loc.source_line), 431 }, 432 }; 433 } 434 if (module_err_msg.src_loc.lazy == .entire_file) { 435 try errors.append(.{ 436 .plain = .{ 437 .msg = try allocator.dupe(u8, module_err_msg.msg), 438 }, 439 }); 440 return; 441 } 442 const source = try module_err_msg.src_loc.file_scope.getSource(module.gpa); 443 const byte_offset = try module_err_msg.src_loc.byteOffset(module.gpa); 444 const loc = std.zig.findLineColumn(source, byte_offset); 445 const file_path = try module_err_msg.src_loc.file_scope.fullPath(allocator); 446 try errors.append(.{ 447 .src = .{ 448 .src_path = file_path, 449 .msg = try allocator.dupe(u8, module_err_msg.msg), 450 .byte_offset = byte_offset, 451 .line = @intCast(u32, loc.line), 452 .column = @intCast(u32, loc.column), 453 .notes = notes, 454 .source_line = try allocator.dupe(u8, loc.source_line), 455 }, 456 }); 457 } 458 459 pub fn addZir( 460 arena: Allocator, 461 errors: *std.ArrayList(Message), 462 file: *Module.File, 463 ) !void { 464 assert(file.zir_loaded); 465 assert(file.tree_loaded); 466 assert(file.source_loaded); 467 const payload_index = file.zir.extra[@enumToInt(Zir.ExtraIndex.compile_errors)]; 468 assert(payload_index != 0); 469 470 const header = file.zir.extraData(Zir.Inst.CompileErrors, payload_index); 471 const items_len = header.data.items_len; 472 var extra_index = header.end; 473 var item_i: usize = 0; 474 while (item_i < items_len) : (item_i += 1) { 475 const item = file.zir.extraData(Zir.Inst.CompileErrors.Item, extra_index); 476 extra_index = item.end; 477 478 var notes: []Message = &[0]Message{}; 479 if (item.data.notes != 0) { 480 const block = file.zir.extraData(Zir.Inst.Block, item.data.notes); 481 const body = file.zir.extra[block.end..][0..block.data.body_len]; 482 notes = try arena.alloc(Message, body.len); 483 for (notes) |*note, i| { 484 const note_item = file.zir.extraData(Zir.Inst.CompileErrors.Item, body[i]); 485 const msg = file.zir.nullTerminatedString(note_item.data.msg); 486 const byte_offset = blk: { 487 const token_starts = file.tree.tokens.items(.start); 488 if (note_item.data.node != 0) { 489 const main_tokens = file.tree.nodes.items(.main_token); 490 const main_token = main_tokens[note_item.data.node]; 491 break :blk token_starts[main_token]; 492 } 493 break :blk token_starts[note_item.data.token] + note_item.data.byte_offset; 494 }; 495 const loc = std.zig.findLineColumn(file.source, byte_offset); 496 497 note.* = .{ 498 .src = .{ 499 .src_path = try file.fullPath(arena), 500 .msg = try arena.dupe(u8, msg), 501 .byte_offset = byte_offset, 502 .line = @intCast(u32, loc.line), 503 .column = @intCast(u32, loc.column), 504 .notes = &.{}, // TODO rework this function to be recursive 505 .source_line = try arena.dupe(u8, loc.source_line), 506 }, 507 }; 508 } 509 } 510 511 const msg = file.zir.nullTerminatedString(item.data.msg); 512 const byte_offset = blk: { 513 const token_starts = file.tree.tokens.items(.start); 514 if (item.data.node != 0) { 515 const main_tokens = file.tree.nodes.items(.main_token); 516 const main_token = main_tokens[item.data.node]; 517 break :blk token_starts[main_token]; 518 } 519 break :blk token_starts[item.data.token] + item.data.byte_offset; 520 }; 521 const loc = std.zig.findLineColumn(file.source, byte_offset); 522 523 try errors.append(.{ 524 .src = .{ 525 .src_path = try file.fullPath(arena), 526 .msg = try arena.dupe(u8, msg), 527 .byte_offset = byte_offset, 528 .line = @intCast(u32, loc.line), 529 .column = @intCast(u32, loc.column), 530 .notes = notes, 531 .source_line = try arena.dupe(u8, loc.source_line), 532 }, 533 }); 534 } 535 } 536 537 fn addPlain( 538 arena: *std.heap.ArenaAllocator, 539 errors: *std.ArrayList(Message), 540 msg: []const u8, 541 ) !void { 542 _ = arena; 543 try errors.append(.{ .plain = .{ .msg = msg } }); 544 } 545 546 fn addPlainWithChildren( 547 arena: *std.heap.ArenaAllocator, 548 errors: *std.ArrayList(Message), 549 msg: []const u8, 550 optional_children: ?AllErrors, 551 ) !void { 552 const allocator = arena.allocator(); 553 const duped_msg = try allocator.dupe(u8, msg); 554 if (optional_children) |*children| { 555 try errors.append(.{ .plain = .{ 556 .msg = duped_msg, 557 .notes = try dupeList(children.list, allocator), 558 } }); 559 } else { 560 try errors.append(.{ .plain = .{ .msg = duped_msg } }); 561 } 562 } 563 564 fn dupeList(list: []const Message, arena: Allocator) Allocator.Error![]Message { 565 const duped_list = try arena.alloc(Message, list.len); 566 for (list) |item, i| { 567 duped_list[i] = switch (item) { 568 .src => |src| .{ .src = .{ 569 .msg = try arena.dupe(u8, src.msg), 570 .src_path = try arena.dupe(u8, src.src_path), 571 .line = src.line, 572 .column = src.column, 573 .byte_offset = src.byte_offset, 574 .source_line = if (src.source_line) |s| try arena.dupe(u8, s) else null, 575 .notes = try dupeList(src.notes, arena), 576 } }, 577 .plain => |plain| .{ .plain = .{ 578 .msg = try arena.dupe(u8, plain.msg), 579 .notes = try dupeList(plain.notes, arena), 580 } }, 581 }; 582 } 583 return duped_list; 584 } 585}; 586 587pub const Directory = struct { 588 /// This field is redundant for operations that can act on the open directory handle 589 /// directly, but it is needed when passing the directory to a child process. 590 /// `null` means cwd. 591 path: ?[]const u8, 592 handle: std.fs.Dir, 593 594 pub fn join(self: Directory, allocator: Allocator, paths: []const []const u8) ![]u8 { 595 if (self.path) |p| { 596 // TODO clean way to do this with only 1 allocation 597 const part2 = try std.fs.path.join(allocator, paths); 598 defer allocator.free(part2); 599 return std.fs.path.join(allocator, &[_][]const u8{ p, part2 }); 600 } else { 601 return std.fs.path.join(allocator, paths); 602 } 603 } 604 605 pub fn joinZ(self: Directory, allocator: Allocator, paths: []const []const u8) ![:0]u8 { 606 if (self.path) |p| { 607 // TODO clean way to do this with only 1 allocation 608 const part2 = try std.fs.path.join(allocator, paths); 609 defer allocator.free(part2); 610 return std.fs.path.joinZ(allocator, &[_][]const u8{ p, part2 }); 611 } else { 612 return std.fs.path.joinZ(allocator, paths); 613 } 614 } 615}; 616 617pub const EmitLoc = struct { 618 /// If this is `null` it means the file will be output to the cache directory. 619 /// When provided, both the open file handle and the path name must outlive the `Compilation`. 620 directory: ?Compilation.Directory, 621 /// This may not have sub-directories in it. 622 basename: []const u8, 623}; 624 625pub const ClangPreprocessorMode = enum { 626 no, 627 /// This means we are doing `zig cc -E -o <path>`. 628 yes, 629 /// This means we are doing `zig cc -E`. 630 stdout, 631}; 632 633pub const SystemLib = link.SystemLib; 634 635pub const InitOptions = struct { 636 zig_lib_directory: Directory, 637 local_cache_directory: Directory, 638 global_cache_directory: Directory, 639 target: Target, 640 root_name: []const u8, 641 main_pkg: ?*Package, 642 output_mode: std.builtin.OutputMode, 643 thread_pool: *ThreadPool, 644 dynamic_linker: ?[]const u8 = null, 645 sysroot: ?[]const u8 = null, 646 /// `null` means to not emit a binary file. 647 emit_bin: ?EmitLoc, 648 /// `null` means to not emit a C header file. 649 emit_h: ?EmitLoc = null, 650 /// `null` means to not emit assembly. 651 emit_asm: ?EmitLoc = null, 652 /// `null` means to not emit LLVM IR. 653 emit_llvm_ir: ?EmitLoc = null, 654 /// `null` means to not emit LLVM module bitcode. 655 emit_llvm_bc: ?EmitLoc = null, 656 /// `null` means to not emit semantic analysis JSON. 657 emit_analysis: ?EmitLoc = null, 658 /// `null` means to not emit docs. 659 emit_docs: ?EmitLoc = null, 660 /// `null` means to not emit an import lib. 661 emit_implib: ?EmitLoc = null, 662 link_mode: ?std.builtin.LinkMode = null, 663 dll_export_fns: ?bool = false, 664 /// Normally when using LLD to link, Zig uses a file named "lld.id" in the 665 /// same directory as the output binary which contains the hash of the link 666 /// operation, allowing Zig to skip linking when the hash would be unchanged. 667 /// In the case that the output binary is being emitted into a directory which 668 /// is externally modified - essentially anything other than zig-cache - then 669 /// this flag would be set to disable this machinery to avoid false positives. 670 disable_lld_caching: bool = false, 671 object_format: ?std.Target.ObjectFormat = null, 672 optimize_mode: std.builtin.Mode = .Debug, 673 keep_source_files_loaded: bool = false, 674 clang_argv: []const []const u8 = &[0][]const u8{}, 675 lib_dirs: []const []const u8 = &[0][]const u8{}, 676 rpath_list: []const []const u8 = &[0][]const u8{}, 677 c_source_files: []const CSourceFile = &[0]CSourceFile{}, 678 link_objects: []const []const u8 = &[0][]const u8{}, 679 framework_dirs: []const []const u8 = &[0][]const u8{}, 680 frameworks: []const []const u8 = &[0][]const u8{}, 681 system_lib_names: []const []const u8 = &.{}, 682 system_lib_infos: []const SystemLib = &.{}, 683 /// These correspond to the WASI libc emulated subcomponents including: 684 /// * process clocks 685 /// * getpid 686 /// * mman 687 /// * signal 688 wasi_emulated_libs: []const wasi_libc.CRTFile = &[0]wasi_libc.CRTFile{}, 689 link_libc: bool = false, 690 link_libcpp: bool = false, 691 link_libunwind: bool = false, 692 want_pic: ?bool = null, 693 /// This means that if the output mode is an executable it will be a 694 /// Position Independent Executable. If the output mode is not an 695 /// executable this field is ignored. 696 want_pie: ?bool = null, 697 want_sanitize_c: ?bool = null, 698 want_stack_check: ?bool = null, 699 want_red_zone: ?bool = null, 700 omit_frame_pointer: ?bool = null, 701 want_valgrind: ?bool = null, 702 want_tsan: ?bool = null, 703 want_compiler_rt: ?bool = null, 704 want_lto: ?bool = null, 705 want_unwind_tables: ?bool = null, 706 use_llvm: ?bool = null, 707 use_lld: ?bool = null, 708 use_clang: ?bool = null, 709 use_stage1: ?bool = null, 710 single_threaded: ?bool = null, 711 rdynamic: bool = false, 712 strip: bool = false, 713 function_sections: bool = false, 714 is_native_os: bool, 715 is_native_abi: bool, 716 time_report: bool = false, 717 stack_report: bool = false, 718 link_eh_frame_hdr: bool = false, 719 link_emit_relocs: bool = false, 720 linker_script: ?[]const u8 = null, 721 version_script: ?[]const u8 = null, 722 soname: ?[]const u8 = null, 723 linker_gc_sections: ?bool = null, 724 linker_allow_shlib_undefined: ?bool = null, 725 linker_bind_global_refs_locally: ?bool = null, 726 linker_import_memory: ?bool = null, 727 linker_initial_memory: ?u64 = null, 728 linker_max_memory: ?u64 = null, 729 linker_global_base: ?u64 = null, 730 linker_export_symbol_names: []const []const u8 = &.{}, 731 each_lib_rpath: ?bool = null, 732 disable_c_depfile: bool = false, 733 linker_z_nodelete: bool = false, 734 linker_z_notext: bool = false, 735 linker_z_defs: bool = false, 736 linker_z_origin: bool = false, 737 linker_z_noexecstack: bool = false, 738 linker_z_now: bool = false, 739 linker_z_relro: bool = false, 740 linker_tsaware: bool = false, 741 linker_nxcompat: bool = false, 742 linker_dynamicbase: bool = false, 743 linker_optimization: ?u8 = null, 744 major_subsystem_version: ?u32 = null, 745 minor_subsystem_version: ?u32 = null, 746 clang_passthrough_mode: bool = false, 747 verbose_cc: bool = false, 748 verbose_link: bool = false, 749 verbose_air: bool = false, 750 verbose_mir: bool = false, 751 verbose_llvm_ir: bool = false, 752 verbose_cimport: bool = false, 753 verbose_llvm_cpu_features: bool = false, 754 is_test: bool = false, 755 test_evented_io: bool = false, 756 debug_compiler_runtime_libs: bool = false, 757 debug_compile_errors: bool = false, 758 /// Normally when you create a `Compilation`, Zig will automatically build 759 /// and link in required dependencies, such as compiler-rt and libc. When 760 /// building such dependencies themselves, this flag must be set to avoid 761 /// infinite recursion. 762 skip_linker_dependencies: bool = false, 763 parent_compilation_link_libc: bool = false, 764 stack_size_override: ?u64 = null, 765 image_base_override: ?u64 = null, 766 self_exe_path: ?[]const u8 = null, 767 version: ?std.builtin.Version = null, 768 compatibility_version: ?std.builtin.Version = null, 769 libc_installation: ?*const LibCInstallation = null, 770 machine_code_model: std.builtin.CodeModel = .default, 771 clang_preprocessor_mode: ClangPreprocessorMode = .no, 772 /// This is for stage1 and should be deleted upon completion of self-hosting. 773 color: @import("main.zig").Color = .auto, 774 test_filter: ?[]const u8 = null, 775 test_name_prefix: ?[]const u8 = null, 776 subsystem: ?std.Target.SubSystem = null, 777 /// WASI-only. Type of WASI execution model ("command" or "reactor"). 778 wasi_exec_model: ?std.builtin.WasiExecModel = null, 779 /// (Zig compiler development) Enable dumping linker's state as JSON. 780 enable_link_snapshots: bool = false, 781 /// (Darwin) Path and version of the native SDK if detected. 782 native_darwin_sdk: ?std.zig.system.darwin.DarwinSDK = null, 783 /// (Darwin) Install name of the dylib 784 install_name: ?[]const u8 = null, 785}; 786 787fn addPackageTableToCacheHash( 788 hash: *Cache.HashHelper, 789 arena: *std.heap.ArenaAllocator, 790 pkg_table: Package.Table, 791 seen_table: *std.AutoHashMap(*Package, void), 792 hash_type: union(enum) { path_bytes, files: *Cache.Manifest }, 793) (error{OutOfMemory} || std.os.GetCwdError)!void { 794 const allocator = arena.allocator(); 795 796 const packages = try allocator.alloc(Package.Table.KV, pkg_table.count()); 797 { 798 // Copy over the hashmap entries to our slice 799 var table_it = pkg_table.iterator(); 800 var idx: usize = 0; 801 while (table_it.next()) |entry| : (idx += 1) { 802 packages[idx] = .{ 803 .key = entry.key_ptr.*, 804 .value = entry.value_ptr.*, 805 }; 806 } 807 } 808 // Sort the slice by package name 809 std.sort.sort(Package.Table.KV, packages, {}, struct { 810 fn lessThan(_: void, lhs: Package.Table.KV, rhs: Package.Table.KV) bool { 811 return std.mem.lessThan(u8, lhs.key, rhs.key); 812 } 813 }.lessThan); 814 815 for (packages) |pkg| { 816 if ((try seen_table.getOrPut(pkg.value)).found_existing) continue; 817 818 // Finally insert the package name and path to the cache hash. 819 hash.addBytes(pkg.key); 820 switch (hash_type) { 821 .path_bytes => { 822 hash.addBytes(pkg.value.root_src_path); 823 hash.addOptionalBytes(pkg.value.root_src_directory.path); 824 }, 825 .files => |man| { 826 const pkg_zig_file = try pkg.value.root_src_directory.join(allocator, &[_][]const u8{ 827 pkg.value.root_src_path, 828 }); 829 _ = try man.addFile(pkg_zig_file, null); 830 }, 831 } 832 // Recurse to handle the package's dependencies 833 try addPackageTableToCacheHash(hash, arena, pkg.value.table, seen_table, hash_type); 834 } 835} 836 837pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { 838 const is_dyn_lib = switch (options.output_mode) { 839 .Obj, .Exe => false, 840 .Lib => (options.link_mode orelse .Static) == .Dynamic, 841 }; 842 const is_exe_or_dyn_lib = switch (options.output_mode) { 843 .Obj => false, 844 .Lib => is_dyn_lib, 845 .Exe => true, 846 }; 847 848 const needs_c_symbols = !options.skip_linker_dependencies and is_exe_or_dyn_lib; 849 850 // WASI-only. Resolve the optional exec-model option, defaults to command. 851 const wasi_exec_model = if (options.target.os.tag != .wasi) undefined else options.wasi_exec_model orelse .command; 852 853 const comp: *Compilation = comp: { 854 // For allocations that have the same lifetime as Compilation. This arena is used only during this 855 // initialization and then is freed in deinit(). 856 var arena_allocator = std.heap.ArenaAllocator.init(gpa); 857 errdefer arena_allocator.deinit(); 858 const arena = arena_allocator.allocator(); 859 860 // We put the `Compilation` itself in the arena. Freeing the arena will free the module. 861 // It's initialized later after we prepare the initialization options. 862 const comp = try arena.create(Compilation); 863 const root_name = try arena.dupe(u8, options.root_name); 864 865 const ofmt = options.object_format orelse options.target.getObjectFormat(); 866 867 const use_stage1 = options.use_stage1 orelse blk: { 868 // Even though we may have no Zig code to compile (depending on `options.main_pkg`), 869 // we may need to use stage1 for building compiler-rt and other dependencies. 870 871 if (build_options.omit_stage2) 872 break :blk true; 873 if (options.use_llvm) |use_llvm| { 874 if (!use_llvm) { 875 break :blk false; 876 } 877 } 878 879 break :blk build_options.is_stage1; 880 }; 881 882 // Make a decision on whether to use LLVM or our own backend. 883 const use_llvm = build_options.have_llvm and blk: { 884 if (options.use_llvm) |explicit| 885 break :blk explicit; 886 887 // If we are outputting .c code we must use Zig backend. 888 if (ofmt == .c) 889 break :blk false; 890 891 // If emitting to LLVM bitcode object format, must use LLVM backend. 892 if (options.emit_llvm_ir != null or options.emit_llvm_bc != null) 893 break :blk true; 894 895 // If we have no zig code to compile, no need for LLVM. 896 if (options.main_pkg == null) 897 break :blk false; 898 899 // The stage1 compiler depends on the stage1 C++ LLVM backend 900 // to compile zig code. 901 if (use_stage1) 902 break :blk true; 903 904 // Prefer LLVM for release builds as long as it supports the target architecture. 905 if (options.optimize_mode != .Debug and target_util.hasLlvmSupport(options.target)) 906 break :blk true; 907 908 break :blk false; 909 }; 910 if (!use_llvm) { 911 if (options.use_llvm == true) { 912 return error.ZigCompilerNotBuiltWithLLVMExtensions; 913 } 914 if (options.emit_llvm_ir != null or options.emit_llvm_bc != null) { 915 return error.EmittingLlvmModuleRequiresUsingLlvmBackend; 916 } 917 } 918 919 const tsan = options.want_tsan orelse false; 920 // TSAN is implemented in C++ so it requires linking libc++. 921 const link_libcpp = options.link_libcpp or tsan; 922 const link_libc = link_libcpp or options.link_libc or 923 target_util.osRequiresLibC(options.target); 924 925 const link_libunwind = options.link_libunwind or 926 (link_libcpp and target_util.libcNeedsLibUnwind(options.target)); 927 const unwind_tables = options.want_unwind_tables orelse 928 (link_libunwind or target_util.needUnwindTables(options.target)); 929 const link_eh_frame_hdr = options.link_eh_frame_hdr or unwind_tables; 930 931 // Make a decision on whether to use LLD or our own linker. 932 const use_lld = options.use_lld orelse blk: { 933 if (options.target.isDarwin()) { 934 break :blk false; 935 } 936 937 if (!build_options.have_llvm) 938 break :blk false; 939 940 if (ofmt == .c) 941 break :blk false; 942 943 if (options.want_lto) |lto| { 944 if (lto) { 945 break :blk true; 946 } 947 } 948 949 // Our linker can't handle objects or most advanced options yet. 950 if (options.link_objects.len != 0 or 951 options.c_source_files.len != 0 or 952 options.frameworks.len != 0 or 953 options.system_lib_names.len != 0 or 954 options.link_libc or options.link_libcpp or 955 link_eh_frame_hdr or 956 options.link_emit_relocs or 957 options.output_mode == .Lib or 958 options.image_base_override != null or 959 options.linker_script != null or options.version_script != null or 960 options.emit_implib != null) 961 { 962 break :blk true; 963 } 964 965 if (use_llvm) { 966 // If stage1 generates an object file, self-hosted linker is not 967 // yet sophisticated enough to handle that. 968 break :blk options.main_pkg != null; 969 } 970 971 break :blk false; 972 }; 973 974 const sysroot = blk: { 975 if (options.sysroot) |sysroot| { 976 break :blk sysroot; 977 } else if (options.native_darwin_sdk) |sdk| { 978 break :blk sdk.path; 979 } else { 980 break :blk null; 981 } 982 }; 983 984 const lto = blk: { 985 if (options.want_lto) |explicit| { 986 if (!use_lld and !options.target.isDarwin()) 987 return error.LtoUnavailableWithoutLld; 988 break :blk explicit; 989 } else if (!use_lld) { 990 // TODO zig ld LTO support 991 // See https://github.com/ziglang/zig/issues/8680 992 break :blk false; 993 } else if (options.c_source_files.len == 0) { 994 break :blk false; 995 } else if (options.target.os.tag == .windows and link_libcpp) { 996 // https://github.com/ziglang/zig/issues/8531 997 break :blk false; 998 } else if (options.target.cpu.arch.isRISCV()) { 999 // Clang and LLVM currently don't support RISC-V target-abi for LTO. 1000 // Compiling with LTO may fail or produce undesired results. 1001 // See https://reviews.llvm.org/D71387 1002 // See https://reviews.llvm.org/D102582 1003 break :blk false; 1004 } else switch (options.output_mode) { 1005 .Lib, .Obj => break :blk false, 1006 .Exe => switch (options.optimize_mode) { 1007 .Debug => break :blk false, 1008 .ReleaseSafe, .ReleaseFast, .ReleaseSmall => break :blk true, 1009 }, 1010 } 1011 }; 1012 1013 const must_dynamic_link = dl: { 1014 if (target_util.cannotDynamicLink(options.target)) 1015 break :dl false; 1016 if (is_exe_or_dyn_lib and link_libc and 1017 (options.target.isGnuLibC() or target_util.osRequiresLibC(options.target))) 1018 { 1019 break :dl true; 1020 } 1021 const any_dyn_libs: bool = x: { 1022 if (options.system_lib_names.len != 0) 1023 break :x true; 1024 for (options.link_objects) |obj| { 1025 switch (classifyFileExt(obj)) { 1026 .shared_library => break :x true, 1027 else => continue, 1028 } 1029 } 1030 break :x false; 1031 }; 1032 if (any_dyn_libs) { 1033 // When creating a executable that links to system libraries, 1034 // we require dynamic linking, but we must not link static libraries 1035 // or object files dynamically! 1036 break :dl (options.output_mode == .Exe); 1037 } 1038 1039 break :dl false; 1040 }; 1041 const default_link_mode: std.builtin.LinkMode = blk: { 1042 if (must_dynamic_link) { 1043 break :blk .Dynamic; 1044 } else if (is_exe_or_dyn_lib and link_libc and 1045 options.is_native_abi and options.target.abi.isMusl()) 1046 { 1047 // If targeting the system's native ABI and the system's 1048 // libc is musl, link dynamically by default. 1049 break :blk .Dynamic; 1050 } else { 1051 break :blk .Static; 1052 } 1053 }; 1054 const link_mode: std.builtin.LinkMode = if (options.link_mode) |lm| blk: { 1055 if (lm == .Static and must_dynamic_link) { 1056 return error.UnableToStaticLink; 1057 } 1058 break :blk lm; 1059 } else default_link_mode; 1060 1061 const dll_export_fns = if (options.dll_export_fns) |explicit| explicit else is_dyn_lib or options.rdynamic; 1062 1063 const libc_dirs = try detectLibCIncludeDirs( 1064 arena, 1065 options.zig_lib_directory.path.?, 1066 options.target, 1067 options.is_native_abi, 1068 link_libc, 1069 options.system_lib_names.len != 0 or options.frameworks.len != 0, 1070 options.libc_installation, 1071 options.native_darwin_sdk != null, 1072 ); 1073 1074 const must_pie = target_util.requiresPIE(options.target); 1075 const pie: bool = if (options.want_pie) |explicit| pie: { 1076 if (!explicit and must_pie) { 1077 return error.TargetRequiresPIE; 1078 } 1079 break :pie explicit; 1080 } else must_pie or tsan; 1081 1082 const must_pic: bool = b: { 1083 if (target_util.requiresPIC(options.target, link_libc)) 1084 break :b true; 1085 break :b link_mode == .Dynamic; 1086 }; 1087 const pic = if (options.want_pic) |explicit| pic: { 1088 if (!explicit) { 1089 if (must_pic) { 1090 return error.TargetRequiresPIC; 1091 } 1092 if (pie) { 1093 return error.PIERequiresPIC; 1094 } 1095 } 1096 break :pic explicit; 1097 } else pie or must_pic; 1098 1099 // Make a decision on whether to use Clang for translate-c and compiling C files. 1100 const use_clang = if (options.use_clang) |explicit| explicit else blk: { 1101 if (build_options.have_llvm) { 1102 // Can't use it if we don't have it! 1103 break :blk false; 1104 } 1105 // It's not planned to do our own translate-c or C compilation. 1106 break :blk true; 1107 }; 1108 1109 const is_safe_mode = switch (options.optimize_mode) { 1110 .Debug, .ReleaseSafe => true, 1111 .ReleaseFast, .ReleaseSmall => false, 1112 }; 1113 1114 const sanitize_c = options.want_sanitize_c orelse is_safe_mode; 1115 1116 const stack_check: bool = b: { 1117 if (!target_util.supportsStackProbing(options.target)) 1118 break :b false; 1119 break :b options.want_stack_check orelse is_safe_mode; 1120 }; 1121 1122 const valgrind: bool = b: { 1123 if (!target_util.hasValgrindSupport(options.target)) 1124 break :b false; 1125 break :b options.want_valgrind orelse (options.optimize_mode == .Debug); 1126 }; 1127 1128 const include_compiler_rt = options.want_compiler_rt orelse needs_c_symbols; 1129 1130 const must_single_thread = target_util.isSingleThreaded(options.target); 1131 const single_threaded = options.single_threaded orelse must_single_thread; 1132 if (must_single_thread and !single_threaded) { 1133 return error.TargetRequiresSingleThreaded; 1134 } 1135 1136 const llvm_cpu_features: ?[*:0]const u8 = if (build_options.have_llvm and use_llvm) blk: { 1137 var buf = std.ArrayList(u8).init(arena); 1138 for (options.target.cpu.arch.allFeaturesList()) |feature, index_usize| { 1139 const index = @intCast(Target.Cpu.Feature.Set.Index, index_usize); 1140 const is_enabled = options.target.cpu.features.isEnabled(index); 1141 1142 if (feature.llvm_name) |llvm_name| { 1143 const plus_or_minus = "-+"[@boolToInt(is_enabled)]; 1144 try buf.ensureUnusedCapacity(2 + llvm_name.len); 1145 buf.appendAssumeCapacity(plus_or_minus); 1146 buf.appendSliceAssumeCapacity(llvm_name); 1147 buf.appendSliceAssumeCapacity(","); 1148 } 1149 } 1150 assert(mem.endsWith(u8, buf.items, ",")); 1151 buf.items[buf.items.len - 1] = 0; 1152 buf.shrinkAndFree(buf.items.len); 1153 break :blk buf.items[0 .. buf.items.len - 1 :0].ptr; 1154 } else null; 1155 1156 const strip = options.strip or !target_util.hasDebugInfo(options.target); 1157 const red_zone = options.want_red_zone orelse target_util.hasRedZone(options.target); 1158 const omit_frame_pointer = options.omit_frame_pointer orelse (options.optimize_mode != .Debug); 1159 const linker_optimization: u8 = options.linker_optimization orelse switch (options.optimize_mode) { 1160 .Debug => @as(u8, 0), 1161 else => @as(u8, 3), 1162 }; 1163 1164 // We put everything into the cache hash that *cannot be modified during an incremental update*. 1165 // For example, one cannot change the target between updates, but one can change source files, 1166 // so the target goes into the cache hash, but source files do not. This is so that we can 1167 // find the same binary and incrementally update it even if there are modified source files. 1168 // We do this even if outputting to the current directory because we need somewhere to store 1169 // incremental compilation metadata. 1170 const cache = try arena.create(Cache); 1171 cache.* = .{ 1172 .gpa = gpa, 1173 .manifest_dir = try options.local_cache_directory.handle.makeOpenPath("h", .{}), 1174 }; 1175 errdefer cache.manifest_dir.close(); 1176 1177 // This is shared hasher state common to zig source and all C source files. 1178 cache.hash.addBytes(build_options.version); 1179 cache.hash.addBytes(options.zig_lib_directory.path orelse "."); 1180 cache.hash.add(options.optimize_mode); 1181 cache.hash.add(options.target.cpu.arch); 1182 cache.hash.addBytes(options.target.cpu.model.name); 1183 cache.hash.add(options.target.cpu.features.ints); 1184 cache.hash.add(options.target.os.tag); 1185 cache.hash.add(options.target.os.getVersionRange()); 1186 cache.hash.add(options.is_native_os); 1187 cache.hash.add(options.target.abi); 1188 cache.hash.add(ofmt); 1189 cache.hash.add(pic); 1190 cache.hash.add(pie); 1191 cache.hash.add(lto); 1192 cache.hash.add(unwind_tables); 1193 cache.hash.add(tsan); 1194 cache.hash.add(stack_check); 1195 cache.hash.add(red_zone); 1196 cache.hash.add(omit_frame_pointer); 1197 cache.hash.add(link_mode); 1198 cache.hash.add(options.function_sections); 1199 cache.hash.add(strip); 1200 cache.hash.add(link_libc); 1201 cache.hash.add(link_libcpp); 1202 cache.hash.add(link_libunwind); 1203 cache.hash.add(options.output_mode); 1204 cache.hash.add(options.machine_code_model); 1205 cache.hash.addOptionalEmitLoc(options.emit_bin); 1206 cache.hash.addOptionalEmitLoc(options.emit_implib); 1207 cache.hash.addBytes(options.root_name); 1208 if (options.target.os.tag == .wasi) cache.hash.add(wasi_exec_model); 1209 // TODO audit this and make sure everything is in it 1210 1211 const module: ?*Module = if (options.main_pkg) |main_pkg| blk: { 1212 // Options that are specific to zig source files, that cannot be 1213 // modified between incremental updates. 1214 var hash = cache.hash; 1215 1216 // Here we put the root source file path name, but *not* with addFile. We want the 1217 // hash to be the same regardless of the contents of the source file, because 1218 // incremental compilation will handle it, but we do want to namespace different 1219 // source file names because they are likely different compilations and therefore this 1220 // would be likely to cause cache hits. 1221 hash.addBytes(main_pkg.root_src_path); 1222 hash.addOptionalBytes(main_pkg.root_src_directory.path); 1223 { 1224 var local_arena = std.heap.ArenaAllocator.init(gpa); 1225 defer local_arena.deinit(); 1226 var seen_table = std.AutoHashMap(*Package, void).init(local_arena.allocator()); 1227 try addPackageTableToCacheHash(&hash, &local_arena, main_pkg.table, &seen_table, .path_bytes); 1228 } 1229 hash.add(valgrind); 1230 hash.add(single_threaded); 1231 hash.add(use_stage1); 1232 hash.add(use_llvm); 1233 hash.add(dll_export_fns); 1234 hash.add(options.is_test); 1235 hash.add(options.skip_linker_dependencies); 1236 hash.add(options.parent_compilation_link_libc); 1237 1238 const digest = hash.final(); 1239 const artifact_sub_dir = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest }); 1240 var artifact_dir = try options.local_cache_directory.handle.makeOpenPath(artifact_sub_dir, .{}); 1241 errdefer artifact_dir.close(); 1242 const zig_cache_artifact_directory: Directory = .{ 1243 .handle = artifact_dir, 1244 .path = if (options.local_cache_directory.path) |p| 1245 try std.fs.path.join(arena, &[_][]const u8{ p, artifact_sub_dir }) 1246 else 1247 artifact_sub_dir, 1248 }; 1249 1250 const builtin_pkg = try Package.createWithDir( 1251 gpa, 1252 zig_cache_artifact_directory, 1253 null, 1254 "builtin.zig", 1255 ); 1256 errdefer builtin_pkg.destroy(gpa); 1257 1258 const std_pkg = try Package.createWithDir( 1259 gpa, 1260 options.zig_lib_directory, 1261 "std", 1262 "std.zig", 1263 ); 1264 errdefer std_pkg.destroy(gpa); 1265 1266 const root_pkg = if (options.is_test) root_pkg: { 1267 const test_pkg = try Package.createWithDir( 1268 gpa, 1269 options.zig_lib_directory, 1270 "std" ++ std.fs.path.sep_str ++ "special", 1271 "test_runner.zig", 1272 ); 1273 errdefer test_pkg.destroy(gpa); 1274 1275 try test_pkg.add(gpa, "builtin", builtin_pkg); 1276 try test_pkg.add(gpa, "root", test_pkg); 1277 try test_pkg.add(gpa, "std", std_pkg); 1278 1279 break :root_pkg test_pkg; 1280 } else main_pkg; 1281 errdefer if (options.is_test) root_pkg.destroy(gpa); 1282 1283 var other_pkg_iter = main_pkg.table.valueIterator(); 1284 while (other_pkg_iter.next()) |pkg| { 1285 try pkg.*.add(gpa, "builtin", builtin_pkg); 1286 try pkg.*.add(gpa, "std", std_pkg); 1287 } 1288 1289 try main_pkg.addAndAdopt(gpa, "builtin", builtin_pkg); 1290 try main_pkg.add(gpa, "root", root_pkg); 1291 try main_pkg.addAndAdopt(gpa, "std", std_pkg); 1292 1293 try std_pkg.add(gpa, "builtin", builtin_pkg); 1294 try std_pkg.add(gpa, "root", root_pkg); 1295 try std_pkg.add(gpa, "std", std_pkg); 1296 1297 try builtin_pkg.add(gpa, "std", std_pkg); 1298 try builtin_pkg.add(gpa, "builtin", builtin_pkg); 1299 1300 // Pre-open the directory handles for cached ZIR code so that it does not need 1301 // to redundantly happen for each AstGen operation. 1302 const zir_sub_dir = "z"; 1303 1304 var local_zir_dir = try options.local_cache_directory.handle.makeOpenPath(zir_sub_dir, .{}); 1305 errdefer local_zir_dir.close(); 1306 const local_zir_cache: Directory = .{ 1307 .handle = local_zir_dir, 1308 .path = try options.local_cache_directory.join(arena, &[_][]const u8{zir_sub_dir}), 1309 }; 1310 var global_zir_dir = try options.global_cache_directory.handle.makeOpenPath(zir_sub_dir, .{}); 1311 errdefer global_zir_dir.close(); 1312 const global_zir_cache: Directory = .{ 1313 .handle = global_zir_dir, 1314 .path = try options.global_cache_directory.join(arena, &[_][]const u8{zir_sub_dir}), 1315 }; 1316 1317 const emit_h: ?*Module.GlobalEmitH = if (options.emit_h) |loc| eh: { 1318 const eh = try gpa.create(Module.GlobalEmitH); 1319 eh.* = .{ .loc = loc }; 1320 break :eh eh; 1321 } else null; 1322 errdefer if (emit_h) |eh| gpa.destroy(eh); 1323 1324 // TODO when we implement serialization and deserialization of incremental 1325 // compilation metadata, this is where we would load it. We have open a handle 1326 // to the directory where the output either already is, or will be. 1327 // However we currently do not have serialization of such metadata, so for now 1328 // we set up an empty Module that does the entire compilation fresh. 1329 1330 const module = try arena.create(Module); 1331 errdefer module.deinit(); 1332 module.* = .{ 1333 .gpa = gpa, 1334 .comp = comp, 1335 .main_pkg = main_pkg, 1336 .root_pkg = root_pkg, 1337 .zig_cache_artifact_directory = zig_cache_artifact_directory, 1338 .global_zir_cache = global_zir_cache, 1339 .local_zir_cache = local_zir_cache, 1340 .emit_h = emit_h, 1341 .error_name_list = try std.ArrayListUnmanaged([]const u8).initCapacity(gpa, 1), 1342 }; 1343 module.error_name_list.appendAssumeCapacity("(no error)"); 1344 1345 break :blk module; 1346 } else blk: { 1347 if (options.emit_h != null) return error.NoZigModuleForCHeader; 1348 break :blk null; 1349 }; 1350 errdefer if (module) |zm| zm.deinit(); 1351 1352 const error_return_tracing = !strip and switch (options.optimize_mode) { 1353 .Debug, .ReleaseSafe => true, 1354 .ReleaseFast, .ReleaseSmall => false, 1355 }; 1356 1357 // For resource management purposes. 1358 var owned_link_dir: ?std.fs.Dir = null; 1359 errdefer if (owned_link_dir) |*dir| dir.close(); 1360 1361 const bin_file_emit: ?link.Emit = blk: { 1362 const emit_bin = options.emit_bin orelse break :blk null; 1363 1364 if (emit_bin.directory) |directory| { 1365 break :blk link.Emit{ 1366 .directory = directory, 1367 .sub_path = emit_bin.basename, 1368 }; 1369 } 1370 1371 if (module) |zm| { 1372 break :blk link.Emit{ 1373 .directory = zm.zig_cache_artifact_directory, 1374 .sub_path = emit_bin.basename, 1375 }; 1376 } 1377 1378 // We could use the cache hash as is no problem, however, we increase 1379 // the likelihood of cache hits by adding the first C source file 1380 // path name (not contents) to the hash. This way if the user is compiling 1381 // foo.c and bar.c as separate compilations, they get different cache 1382 // directories. 1383 var hash = cache.hash; 1384 if (options.c_source_files.len >= 1) { 1385 hash.addBytes(options.c_source_files[0].src_path); 1386 } else if (options.link_objects.len >= 1) { 1387 hash.addBytes(options.link_objects[0]); 1388 } 1389 1390 const digest = hash.final(); 1391 const artifact_sub_dir = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest }); 1392 var artifact_dir = try options.local_cache_directory.handle.makeOpenPath(artifact_sub_dir, .{}); 1393 owned_link_dir = artifact_dir; 1394 const link_artifact_directory: Directory = .{ 1395 .handle = artifact_dir, 1396 .path = try options.local_cache_directory.join(arena, &[_][]const u8{artifact_sub_dir}), 1397 }; 1398 break :blk link.Emit{ 1399 .directory = link_artifact_directory, 1400 .sub_path = emit_bin.basename, 1401 }; 1402 }; 1403 1404 const implib_emit: ?link.Emit = blk: { 1405 const emit_implib = options.emit_implib orelse break :blk null; 1406 1407 if (emit_implib.directory) |directory| { 1408 break :blk link.Emit{ 1409 .directory = directory, 1410 .sub_path = emit_implib.basename, 1411 }; 1412 } 1413 1414 // Use the same directory as the bin. The CLI already emits an 1415 // error if -fno-emit-bin is combined with -femit-implib. 1416 break :blk link.Emit{ 1417 .directory = bin_file_emit.?.directory, 1418 .sub_path = emit_implib.basename, 1419 }; 1420 }; 1421 1422 var system_libs: std.StringArrayHashMapUnmanaged(SystemLib) = .{}; 1423 errdefer system_libs.deinit(gpa); 1424 try system_libs.ensureTotalCapacity(gpa, options.system_lib_names.len); 1425 for (options.system_lib_names) |lib_name, i| { 1426 system_libs.putAssumeCapacity(lib_name, options.system_lib_infos[i]); 1427 } 1428 1429 const bin_file = try link.File.openPath(gpa, .{ 1430 .emit = bin_file_emit, 1431 .implib_emit = implib_emit, 1432 .root_name = root_name, 1433 .module = module, 1434 .target = options.target, 1435 .dynamic_linker = options.dynamic_linker, 1436 .sysroot = sysroot, 1437 .output_mode = options.output_mode, 1438 .link_mode = link_mode, 1439 .object_format = ofmt, 1440 .optimize_mode = options.optimize_mode, 1441 .use_lld = use_lld, 1442 .use_llvm = use_llvm, 1443 .link_libc = link_libc, 1444 .link_libcpp = link_libcpp, 1445 .link_libunwind = link_libunwind, 1446 .objects = options.link_objects, 1447 .frameworks = options.frameworks, 1448 .framework_dirs = options.framework_dirs, 1449 .system_libs = system_libs, 1450 .wasi_emulated_libs = options.wasi_emulated_libs, 1451 .lib_dirs = options.lib_dirs, 1452 .rpath_list = options.rpath_list, 1453 .strip = strip, 1454 .is_native_os = options.is_native_os, 1455 .is_native_abi = options.is_native_abi, 1456 .function_sections = options.function_sections, 1457 .allow_shlib_undefined = options.linker_allow_shlib_undefined, 1458 .bind_global_refs_locally = options.linker_bind_global_refs_locally orelse false, 1459 .import_memory = options.linker_import_memory orelse false, 1460 .initial_memory = options.linker_initial_memory, 1461 .max_memory = options.linker_max_memory, 1462 .global_base = options.linker_global_base, 1463 .export_symbol_names = options.linker_export_symbol_names, 1464 .z_nodelete = options.linker_z_nodelete, 1465 .z_notext = options.linker_z_notext, 1466 .z_defs = options.linker_z_defs, 1467 .z_origin = options.linker_z_origin, 1468 .z_noexecstack = options.linker_z_noexecstack, 1469 .z_now = options.linker_z_now, 1470 .z_relro = options.linker_z_relro, 1471 .tsaware = options.linker_tsaware, 1472 .nxcompat = options.linker_nxcompat, 1473 .dynamicbase = options.linker_dynamicbase, 1474 .linker_optimization = linker_optimization, 1475 .major_subsystem_version = options.major_subsystem_version, 1476 .minor_subsystem_version = options.minor_subsystem_version, 1477 .stack_size_override = options.stack_size_override, 1478 .image_base_override = options.image_base_override, 1479 .include_compiler_rt = include_compiler_rt, 1480 .linker_script = options.linker_script, 1481 .version_script = options.version_script, 1482 .gc_sections = options.linker_gc_sections, 1483 .eh_frame_hdr = link_eh_frame_hdr, 1484 .emit_relocs = options.link_emit_relocs, 1485 .rdynamic = options.rdynamic, 1486 .soname = options.soname, 1487 .version = options.version, 1488 .compatibility_version = options.compatibility_version, 1489 .libc_installation = libc_dirs.libc_installation, 1490 .pic = pic, 1491 .pie = pie, 1492 .lto = lto, 1493 .valgrind = valgrind, 1494 .tsan = tsan, 1495 .stack_check = stack_check, 1496 .red_zone = red_zone, 1497 .omit_frame_pointer = omit_frame_pointer, 1498 .single_threaded = single_threaded, 1499 .verbose_link = options.verbose_link, 1500 .machine_code_model = options.machine_code_model, 1501 .dll_export_fns = dll_export_fns, 1502 .error_return_tracing = error_return_tracing, 1503 .llvm_cpu_features = llvm_cpu_features, 1504 .skip_linker_dependencies = options.skip_linker_dependencies, 1505 .parent_compilation_link_libc = options.parent_compilation_link_libc, 1506 .each_lib_rpath = options.each_lib_rpath orelse options.is_native_os, 1507 .disable_lld_caching = options.disable_lld_caching, 1508 .subsystem = options.subsystem, 1509 .is_test = options.is_test, 1510 .wasi_exec_model = wasi_exec_model, 1511 .use_stage1 = use_stage1, 1512 .enable_link_snapshots = options.enable_link_snapshots, 1513 .native_darwin_sdk = options.native_darwin_sdk, 1514 .install_name = options.install_name, 1515 }); 1516 errdefer bin_file.destroy(); 1517 comp.* = .{ 1518 .gpa = gpa, 1519 .arena_state = arena_allocator.state, 1520 .zig_lib_directory = options.zig_lib_directory, 1521 .local_cache_directory = options.local_cache_directory, 1522 .global_cache_directory = options.global_cache_directory, 1523 .bin_file = bin_file, 1524 .emit_asm = options.emit_asm, 1525 .emit_llvm_ir = options.emit_llvm_ir, 1526 .emit_llvm_bc = options.emit_llvm_bc, 1527 .emit_analysis = options.emit_analysis, 1528 .emit_docs = options.emit_docs, 1529 .work_queue = std.fifo.LinearFifo(Job, .Dynamic).init(gpa), 1530 .anon_work_queue = std.fifo.LinearFifo(Job, .Dynamic).init(gpa), 1531 .c_object_work_queue = std.fifo.LinearFifo(*CObject, .Dynamic).init(gpa), 1532 .astgen_work_queue = std.fifo.LinearFifo(*Module.File, .Dynamic).init(gpa), 1533 .embed_file_work_queue = std.fifo.LinearFifo(*Module.EmbedFile, .Dynamic).init(gpa), 1534 .keep_source_files_loaded = options.keep_source_files_loaded, 1535 .use_clang = use_clang, 1536 .clang_argv = options.clang_argv, 1537 .c_source_files = options.c_source_files, 1538 .cache_parent = cache, 1539 .self_exe_path = options.self_exe_path, 1540 .libc_include_dir_list = libc_dirs.libc_include_dir_list, 1541 .sanitize_c = sanitize_c, 1542 .thread_pool = options.thread_pool, 1543 .clang_passthrough_mode = options.clang_passthrough_mode, 1544 .clang_preprocessor_mode = options.clang_preprocessor_mode, 1545 .verbose_cc = options.verbose_cc, 1546 .verbose_air = options.verbose_air, 1547 .verbose_mir = options.verbose_mir, 1548 .verbose_llvm_ir = options.verbose_llvm_ir, 1549 .verbose_cimport = options.verbose_cimport, 1550 .verbose_llvm_cpu_features = options.verbose_llvm_cpu_features, 1551 .disable_c_depfile = options.disable_c_depfile, 1552 .owned_link_dir = owned_link_dir, 1553 .color = options.color, 1554 .time_report = options.time_report, 1555 .stack_report = options.stack_report, 1556 .unwind_tables = unwind_tables, 1557 .test_filter = options.test_filter, 1558 .test_name_prefix = options.test_name_prefix, 1559 .test_evented_io = options.test_evented_io, 1560 .debug_compiler_runtime_libs = options.debug_compiler_runtime_libs, 1561 .debug_compile_errors = options.debug_compile_errors, 1562 .work_queue_wait_group = undefined, 1563 .astgen_wait_group = undefined, 1564 }; 1565 break :comp comp; 1566 }; 1567 errdefer comp.destroy(); 1568 1569 try comp.work_queue_wait_group.init(); 1570 errdefer comp.work_queue_wait_group.deinit(); 1571 1572 try comp.astgen_wait_group.init(); 1573 errdefer comp.astgen_wait_group.deinit(); 1574 1575 // Add a `CObject` for each `c_source_files`. 1576 try comp.c_object_table.ensureTotalCapacity(gpa, options.c_source_files.len); 1577 for (options.c_source_files) |c_source_file| { 1578 const c_object = try gpa.create(CObject); 1579 errdefer gpa.destroy(c_object); 1580 1581 c_object.* = .{ 1582 .status = .{ .new = {} }, 1583 .src = c_source_file, 1584 }; 1585 comp.c_object_table.putAssumeCapacityNoClobber(c_object, {}); 1586 } 1587 1588 if (comp.bin_file.options.emit != null and !comp.bin_file.options.skip_linker_dependencies) { 1589 // If we need to build glibc for the target, add work items for it. 1590 // We go through the work queue so that building can be done in parallel. 1591 if (comp.wantBuildGLibCFromSource()) { 1592 if (!target_util.canBuildLibC(comp.getTarget())) return error.LibCUnavailable; 1593 1594 if (glibc.needsCrtiCrtn(comp.getTarget())) { 1595 try comp.work_queue.write(&[_]Job{ 1596 .{ .glibc_crt_file = .crti_o }, 1597 .{ .glibc_crt_file = .crtn_o }, 1598 }); 1599 } 1600 try comp.work_queue.write(&[_]Job{ 1601 .{ .glibc_crt_file = .scrt1_o }, 1602 .{ .glibc_crt_file = .libc_nonshared_a }, 1603 .{ .glibc_shared_objects = {} }, 1604 }); 1605 } 1606 if (comp.wantBuildMuslFromSource()) { 1607 if (!target_util.canBuildLibC(comp.getTarget())) return error.LibCUnavailable; 1608 1609 try comp.work_queue.ensureUnusedCapacity(6); 1610 if (musl.needsCrtiCrtn(comp.getTarget())) { 1611 comp.work_queue.writeAssumeCapacity(&[_]Job{ 1612 .{ .musl_crt_file = .crti_o }, 1613 .{ .musl_crt_file = .crtn_o }, 1614 }); 1615 } 1616 comp.work_queue.writeAssumeCapacity(&[_]Job{ 1617 .{ .musl_crt_file = .crt1_o }, 1618 .{ .musl_crt_file = .scrt1_o }, 1619 .{ .musl_crt_file = .rcrt1_o }, 1620 switch (comp.bin_file.options.link_mode) { 1621 .Static => .{ .musl_crt_file = .libc_a }, 1622 .Dynamic => .{ .musl_crt_file = .libc_so }, 1623 }, 1624 }); 1625 } 1626 if (comp.wantBuildWasiLibcFromSource()) { 1627 if (!target_util.canBuildLibC(comp.getTarget())) return error.LibCUnavailable; 1628 1629 const wasi_emulated_libs = comp.bin_file.options.wasi_emulated_libs; 1630 try comp.work_queue.ensureUnusedCapacity(wasi_emulated_libs.len + 2); // worst-case we need all components 1631 for (wasi_emulated_libs) |crt_file| { 1632 comp.work_queue.writeItemAssumeCapacity(.{ 1633 .wasi_libc_crt_file = crt_file, 1634 }); 1635 } 1636 comp.work_queue.writeAssumeCapacity(&[_]Job{ 1637 .{ .wasi_libc_crt_file = wasi_libc.execModelCrtFile(wasi_exec_model) }, 1638 .{ .wasi_libc_crt_file = .libc_a }, 1639 }); 1640 } 1641 if (comp.wantBuildMinGWFromSource()) { 1642 if (!target_util.canBuildLibC(comp.getTarget())) return error.LibCUnavailable; 1643 1644 const static_lib_jobs = [_]Job{ 1645 .{ .mingw_crt_file = .mingw32_lib }, 1646 .{ .mingw_crt_file = .msvcrt_os_lib }, 1647 .{ .mingw_crt_file = .mingwex_lib }, 1648 .{ .mingw_crt_file = .uuid_lib }, 1649 }; 1650 const crt_job: Job = .{ .mingw_crt_file = if (is_dyn_lib) .dllcrt2_o else .crt2_o }; 1651 try comp.work_queue.ensureUnusedCapacity(static_lib_jobs.len + 1); 1652 comp.work_queue.writeAssumeCapacity(&static_lib_jobs); 1653 comp.work_queue.writeItemAssumeCapacity(crt_job); 1654 1655 // When linking mingw-w64 there are some import libs we always need. 1656 for (mingw.always_link_libs) |name| { 1657 try comp.bin_file.options.system_libs.put(comp.gpa, name, .{}); 1658 } 1659 } 1660 // Generate Windows import libs. 1661 if (comp.getTarget().os.tag == .windows) { 1662 const count = comp.bin_file.options.system_libs.count(); 1663 try comp.work_queue.ensureUnusedCapacity(count); 1664 var i: usize = 0; 1665 while (i < count) : (i += 1) { 1666 comp.work_queue.writeItemAssumeCapacity(.{ .windows_import_lib = i }); 1667 } 1668 } 1669 if (comp.wantBuildLibUnwindFromSource()) { 1670 try comp.work_queue.writeItem(.{ .libunwind = {} }); 1671 } 1672 if (build_options.have_llvm and is_exe_or_dyn_lib and comp.bin_file.options.link_libcpp) { 1673 try comp.work_queue.writeItem(.libcxx); 1674 try comp.work_queue.writeItem(.libcxxabi); 1675 } 1676 if (build_options.have_llvm and comp.bin_file.options.tsan) { 1677 try comp.work_queue.writeItem(.libtsan); 1678 } 1679 1680 // The `use_stage1` condition is here only because stage2 cannot yet build compiler-rt. 1681 // Once it is capable this condition should be removed. When removing this condition, 1682 // also test the use case of `build-obj -fcompiler-rt` with the self-hosted compiler 1683 // and make sure the compiler-rt symbols are emitted. Currently this is hooked up for 1684 // stage1 but not stage2. 1685 const capable_of_building_compiler_rt = comp.bin_file.options.use_stage1 or 1686 comp.bin_file.options.use_llvm; 1687 const capable_of_building_zig_libc = comp.bin_file.options.use_stage1 or 1688 comp.bin_file.options.use_llvm; 1689 const capable_of_building_ssp = comp.bin_file.options.use_stage1; 1690 1691 if (comp.bin_file.options.include_compiler_rt and capable_of_building_compiler_rt) { 1692 if (is_exe_or_dyn_lib) { 1693 try comp.work_queue.writeItem(.{ .compiler_rt_lib = {} }); 1694 } else if (options.output_mode != .Obj) { 1695 // If build-obj with -fcompiler-rt is requested, that is handled specially 1696 // elsewhere. In this case we are making a static library, so we ask 1697 // for a compiler-rt object to put in it. 1698 try comp.work_queue.writeItem(.{ .compiler_rt_obj = {} }); 1699 } 1700 } 1701 if (needs_c_symbols) { 1702 // MinGW provides no libssp, use our own implementation. 1703 if (comp.getTarget().isMinGW() and capable_of_building_ssp) { 1704 try comp.work_queue.writeItem(.{ .libssp = {} }); 1705 } 1706 1707 if (!comp.bin_file.options.link_libc and capable_of_building_zig_libc) { 1708 try comp.work_queue.writeItem(.{ .zig_libc = {} }); 1709 } 1710 } 1711 } 1712 1713 if (comp.bin_file.options.use_stage1 and comp.bin_file.options.module != null) { 1714 try comp.work_queue.writeItem(.{ .stage1_module = {} }); 1715 } 1716 1717 return comp; 1718} 1719 1720fn releaseStage1Lock(comp: *Compilation) void { 1721 if (comp.stage1_lock) |*lock| { 1722 lock.release(); 1723 comp.stage1_lock = null; 1724 } 1725} 1726 1727pub fn destroy(self: *Compilation) void { 1728 const optional_module = self.bin_file.options.module; 1729 self.bin_file.destroy(); 1730 if (optional_module) |module| module.deinit(); 1731 1732 self.releaseStage1Lock(); 1733 1734 const gpa = self.gpa; 1735 self.work_queue.deinit(); 1736 self.anon_work_queue.deinit(); 1737 self.c_object_work_queue.deinit(); 1738 self.astgen_work_queue.deinit(); 1739 self.embed_file_work_queue.deinit(); 1740 1741 { 1742 var it = self.crt_files.iterator(); 1743 while (it.next()) |entry| { 1744 gpa.free(entry.key_ptr.*); 1745 entry.value_ptr.deinit(gpa); 1746 } 1747 self.crt_files.deinit(gpa); 1748 } 1749 1750 if (self.libunwind_static_lib) |*crt_file| { 1751 crt_file.deinit(gpa); 1752 } 1753 if (self.libcxx_static_lib) |*crt_file| { 1754 crt_file.deinit(gpa); 1755 } 1756 if (self.libcxxabi_static_lib) |*crt_file| { 1757 crt_file.deinit(gpa); 1758 } 1759 if (self.compiler_rt_static_lib) |*crt_file| { 1760 crt_file.deinit(gpa); 1761 } 1762 if (self.compiler_rt_obj) |*crt_file| { 1763 crt_file.deinit(gpa); 1764 } 1765 if (self.libssp_static_lib) |*crt_file| { 1766 crt_file.deinit(gpa); 1767 } 1768 if (self.libc_static_lib) |*crt_file| { 1769 crt_file.deinit(gpa); 1770 } 1771 1772 if (self.glibc_so_files) |*glibc_file| { 1773 glibc_file.deinit(gpa); 1774 } 1775 1776 for (self.c_object_table.keys()) |key| { 1777 key.destroy(gpa); 1778 } 1779 self.c_object_table.deinit(gpa); 1780 1781 for (self.failed_c_objects.values()) |value| { 1782 value.destroy(gpa); 1783 } 1784 self.failed_c_objects.deinit(gpa); 1785 1786 self.clearMiscFailures(); 1787 1788 self.cache_parent.manifest_dir.close(); 1789 if (self.owned_link_dir) |*dir| dir.close(); 1790 1791 self.work_queue_wait_group.deinit(); 1792 self.astgen_wait_group.deinit(); 1793 1794 // This destroys `self`. 1795 self.arena_state.promote(gpa).deinit(); 1796} 1797 1798pub fn clearMiscFailures(comp: *Compilation) void { 1799 for (comp.misc_failures.values()) |*value| { 1800 value.deinit(comp.gpa); 1801 } 1802 comp.misc_failures.deinit(comp.gpa); 1803 comp.misc_failures = .{}; 1804} 1805 1806pub fn getTarget(self: Compilation) Target { 1807 return self.bin_file.options.target; 1808} 1809 1810/// Detect changes to source files, perform semantic analysis, and update the output files. 1811pub fn update(self: *Compilation) !void { 1812 const tracy_trace = trace(@src()); 1813 defer tracy_trace.end(); 1814 1815 self.clearMiscFailures(); 1816 1817 // For compiling C objects, we rely on the cache hash system to avoid duplicating work. 1818 // Add a Job for each C object. 1819 try self.c_object_work_queue.ensureUnusedCapacity(self.c_object_table.count()); 1820 for (self.c_object_table.keys()) |key| { 1821 self.c_object_work_queue.writeItemAssumeCapacity(key); 1822 } 1823 1824 const use_stage1 = build_options.is_stage1 and self.bin_file.options.use_stage1; 1825 if (self.bin_file.options.module) |module| { 1826 module.compile_log_text.shrinkAndFree(module.gpa, 0); 1827 module.generation += 1; 1828 1829 // Make sure std.zig is inside the import_table. We unconditionally need 1830 // it for start.zig. 1831 const std_pkg = module.main_pkg.table.get("std").?; 1832 _ = try module.importPkg(std_pkg); 1833 1834 // Normally we rely on importing std to in turn import the root source file 1835 // in the start code, but when using the stage1 backend that won't happen, 1836 // so in order to run AstGen on the root source file we put it into the 1837 // import_table here. 1838 // Likewise, in the case of `zig test`, the test runner is the root source file, 1839 // and so there is nothing to import the main file. 1840 if (use_stage1 or self.bin_file.options.is_test) { 1841 _ = try module.importPkg(module.main_pkg); 1842 } 1843 1844 // Put a work item in for every known source file to detect if 1845 // it changed, and, if so, re-compute ZIR and then queue the job 1846 // to update it. 1847 // We still want AstGen work items for stage1 so that we expose compile errors 1848 // that are implemented in stage2 but not stage1. 1849 try self.astgen_work_queue.ensureUnusedCapacity(module.import_table.count()); 1850 for (module.import_table.values()) |value| { 1851 self.astgen_work_queue.writeItemAssumeCapacity(value); 1852 } 1853 1854 if (!use_stage1) { 1855 // Put a work item in for checking if any files used with `@embedFile` changed. 1856 { 1857 try self.embed_file_work_queue.ensureUnusedCapacity(module.embed_table.count()); 1858 var it = module.embed_table.iterator(); 1859 while (it.next()) |entry| { 1860 const embed_file = entry.value_ptr.*; 1861 self.embed_file_work_queue.writeItemAssumeCapacity(embed_file); 1862 } 1863 } 1864 1865 try self.work_queue.writeItem(.{ .analyze_pkg = std_pkg }); 1866 if (self.bin_file.options.is_test) { 1867 try self.work_queue.writeItem(.{ .analyze_pkg = module.main_pkg }); 1868 } 1869 } 1870 } 1871 1872 try self.performAllTheWork(); 1873 1874 if (!use_stage1) { 1875 if (self.bin_file.options.module) |module| { 1876 if (self.bin_file.options.is_test and self.totalErrorCount() == 0) { 1877 // The `test_functions` decl has been intentionally postponed until now, 1878 // at which point we must populate it with the list of test functions that 1879 // have been discovered and not filtered out. 1880 try module.populateTestFunctions(); 1881 } 1882 1883 // Process the deletion set. We use a while loop here because the 1884 // deletion set may grow as we call `clearDecl` within this loop, 1885 // and more unreferenced Decls are revealed. 1886 while (module.deletion_set.count() != 0) { 1887 const decl = module.deletion_set.keys()[0]; 1888 assert(decl.deletion_flag); 1889 assert(decl.dependants.count() == 0); 1890 const is_anon = if (decl.zir_decl_index == 0) blk: { 1891 break :blk decl.src_namespace.anon_decls.swapRemove(decl); 1892 } else false; 1893 1894 try module.clearDecl(decl, null); 1895 1896 if (is_anon) { 1897 decl.destroy(module); 1898 } 1899 } 1900 1901 try module.processExports(); 1902 } 1903 } 1904 1905 if (self.totalErrorCount() != 0) { 1906 // Skip flushing. 1907 self.link_error_flags = .{}; 1908 return; 1909 } 1910 1911 // This is needed before reading the error flags. 1912 try self.bin_file.flush(self); 1913 self.link_error_flags = self.bin_file.errorFlags(); 1914 1915 if (!use_stage1) { 1916 if (self.bin_file.options.module) |module| { 1917 try link.File.C.flushEmitH(module); 1918 } 1919 } 1920 1921 // Flush takes care of -femit-bin, but we still have -femit-llvm-ir, -femit-llvm-bc, and 1922 // -femit-asm to handle, in the case of C objects. 1923 self.emitOthers(); 1924 1925 // If there are any errors, we anticipate the source files being loaded 1926 // to report error messages. Otherwise we unload all source files to save memory. 1927 // The ZIR needs to stay loaded in memory because (1) Decl objects contain references 1928 // to it, and (2) generic instantiations, comptime calls, inline calls will need 1929 // to reference the ZIR. 1930 if (self.totalErrorCount() == 0 and !self.keep_source_files_loaded) { 1931 if (self.bin_file.options.module) |module| { 1932 for (module.import_table.values()) |file| { 1933 file.unloadTree(self.gpa); 1934 file.unloadSource(self.gpa); 1935 } 1936 } 1937 } 1938} 1939 1940fn emitOthers(comp: *Compilation) void { 1941 if (comp.bin_file.options.output_mode != .Obj or comp.bin_file.options.module != null or 1942 comp.c_object_table.count() == 0) 1943 { 1944 return; 1945 } 1946 const obj_path = comp.c_object_table.keys()[0].status.success.object_path; 1947 const cwd = std.fs.cwd(); 1948 const ext = std.fs.path.extension(obj_path); 1949 const basename = obj_path[0 .. obj_path.len - ext.len]; 1950 // This obj path always ends with the object file extension, but if we change the 1951 // extension to .ll, .bc, or .s, then it will be the path to those things. 1952 const outs = [_]struct { 1953 emit: ?EmitLoc, 1954 ext: []const u8, 1955 }{ 1956 .{ .emit = comp.emit_asm, .ext = ".s" }, 1957 .{ .emit = comp.emit_llvm_ir, .ext = ".ll" }, 1958 .{ .emit = comp.emit_llvm_bc, .ext = ".bc" }, 1959 }; 1960 for (outs) |out| { 1961 if (out.emit) |loc| { 1962 if (loc.directory) |directory| { 1963 const src_path = std.fmt.allocPrint(comp.gpa, "{s}{s}", .{ 1964 basename, out.ext, 1965 }) catch |err| { 1966 log.err("unable to copy {s}{s}: {s}", .{ basename, out.ext, @errorName(err) }); 1967 continue; 1968 }; 1969 defer comp.gpa.free(src_path); 1970 cwd.copyFile(src_path, directory.handle, loc.basename, .{}) catch |err| { 1971 log.err("unable to copy {s}: {s}", .{ src_path, @errorName(err) }); 1972 }; 1973 } 1974 } 1975 } 1976} 1977 1978/// Having the file open for writing is problematic as far as executing the 1979/// binary is concerned. This will remove the write flag, or close the file, 1980/// or whatever is needed so that it can be executed. 1981/// After this, one must call` makeFileWritable` before calling `update`. 1982pub fn makeBinFileExecutable(self: *Compilation) !void { 1983 return self.bin_file.makeExecutable(); 1984} 1985 1986pub fn makeBinFileWritable(self: *Compilation) !void { 1987 return self.bin_file.makeWritable(); 1988} 1989 1990pub fn totalErrorCount(self: *Compilation) usize { 1991 var total: usize = self.failed_c_objects.count() + self.misc_failures.count(); 1992 1993 if (self.bin_file.options.module) |module| { 1994 total += module.failed_exports.count(); 1995 total += module.failed_embed_files.count(); 1996 1997 { 1998 var it = module.failed_files.iterator(); 1999 while (it.next()) |entry| { 2000 if (entry.value_ptr.*) |_| { 2001 total += 1; 2002 } else { 2003 const file = entry.key_ptr.*; 2004 assert(file.zir_loaded); 2005 const payload_index = file.zir.extra[@enumToInt(Zir.ExtraIndex.compile_errors)]; 2006 assert(payload_index != 0); 2007 const header = file.zir.extraData(Zir.Inst.CompileErrors, payload_index); 2008 total += header.data.items_len; 2009 } 2010 } 2011 } 2012 2013 // Skip errors for Decls within files that failed parsing. 2014 // When a parse error is introduced, we keep all the semantic analysis for 2015 // the previous parse success, including compile errors, but we cannot 2016 // emit them until the file succeeds parsing. 2017 for (module.failed_decls.keys()) |key| { 2018 if (key.getFileScope().okToReportErrors()) { 2019 total += 1; 2020 } 2021 } 2022 if (module.emit_h) |emit_h| { 2023 for (emit_h.failed_decls.keys()) |key| { 2024 if (key.getFileScope().okToReportErrors()) { 2025 total += 1; 2026 } 2027 } 2028 } 2029 } 2030 2031 // The "no entry point found" error only counts if there are no other errors. 2032 if (total == 0) { 2033 total += @boolToInt(self.link_error_flags.no_entry_point_found); 2034 } 2035 2036 // Compile log errors only count if there are no other errors. 2037 if (total == 0) { 2038 if (self.bin_file.options.module) |module| { 2039 total += @boolToInt(module.compile_log_decls.count() != 0); 2040 } 2041 } 2042 2043 return total; 2044} 2045 2046pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors { 2047 var arena = std.heap.ArenaAllocator.init(self.gpa); 2048 errdefer arena.deinit(); 2049 const arena_allocator = arena.allocator(); 2050 2051 var errors = std.ArrayList(AllErrors.Message).init(self.gpa); 2052 defer errors.deinit(); 2053 2054 { 2055 var it = self.failed_c_objects.iterator(); 2056 while (it.next()) |entry| { 2057 const c_object = entry.key_ptr.*; 2058 const err_msg = entry.value_ptr.*; 2059 // TODO these fields will need to be adjusted when we have proper 2060 // C error reporting bubbling up. 2061 try errors.append(.{ 2062 .src = .{ 2063 .src_path = try arena_allocator.dupe(u8, c_object.src.src_path), 2064 .msg = try std.fmt.allocPrint(arena_allocator, "unable to build C object: {s}", .{ 2065 err_msg.msg, 2066 }), 2067 .byte_offset = 0, 2068 .line = err_msg.line, 2069 .column = err_msg.column, 2070 .source_line = null, // TODO 2071 }, 2072 }); 2073 } 2074 } 2075 for (self.misc_failures.values()) |*value| { 2076 try AllErrors.addPlainWithChildren(&arena, &errors, value.msg, value.children); 2077 } 2078 if (self.bin_file.options.module) |module| { 2079 { 2080 var it = module.failed_files.iterator(); 2081 while (it.next()) |entry| { 2082 if (entry.value_ptr.*) |msg| { 2083 try AllErrors.add(module, &arena, &errors, msg.*); 2084 } else { 2085 // Must be ZIR errors. In order for ZIR errors to exist, the parsing 2086 // must have completed successfully. 2087 const tree = try entry.key_ptr.*.getTree(module.gpa); 2088 assert(tree.errors.len == 0); 2089 try AllErrors.addZir(arena_allocator, &errors, entry.key_ptr.*); 2090 } 2091 } 2092 } 2093 { 2094 var it = module.failed_embed_files.iterator(); 2095 while (it.next()) |entry| { 2096 const msg = entry.value_ptr.*; 2097 try AllErrors.add(module, &arena, &errors, msg.*); 2098 } 2099 } 2100 { 2101 var it = module.failed_decls.iterator(); 2102 while (it.next()) |entry| { 2103 // Skip errors for Decls within files that had a parse failure. 2104 // We'll try again once parsing succeeds. 2105 if (entry.key_ptr.*.getFileScope().okToReportErrors()) { 2106 try AllErrors.add(module, &arena, &errors, entry.value_ptr.*.*); 2107 } 2108 } 2109 } 2110 if (module.emit_h) |emit_h| { 2111 var it = emit_h.failed_decls.iterator(); 2112 while (it.next()) |entry| { 2113 // Skip errors for Decls within files that had a parse failure. 2114 // We'll try again once parsing succeeds. 2115 if (entry.key_ptr.*.getFileScope().okToReportErrors()) { 2116 try AllErrors.add(module, &arena, &errors, entry.value_ptr.*.*); 2117 } 2118 } 2119 } 2120 for (module.failed_exports.values()) |value| { 2121 try AllErrors.add(module, &arena, &errors, value.*); 2122 } 2123 } 2124 2125 if (errors.items.len == 0 and self.link_error_flags.no_entry_point_found) { 2126 try errors.append(.{ 2127 .plain = .{ 2128 .msg = try std.fmt.allocPrint(arena_allocator, "no entry point found", .{}), 2129 }, 2130 }); 2131 } 2132 2133 if (self.bin_file.options.module) |module| { 2134 if (errors.items.len == 0 and module.compile_log_decls.count() != 0) { 2135 const keys = module.compile_log_decls.keys(); 2136 const values = module.compile_log_decls.values(); 2137 // First one will be the error; subsequent ones will be notes. 2138 const src_loc = keys[0].nodeOffsetSrcLoc(values[0]); 2139 const err_msg = Module.ErrorMsg{ 2140 .src_loc = src_loc, 2141 .msg = "found compile log statement", 2142 .notes = try self.gpa.alloc(Module.ErrorMsg, module.compile_log_decls.count() - 1), 2143 }; 2144 defer self.gpa.free(err_msg.notes); 2145 2146 for (keys[1..]) |key, i| { 2147 err_msg.notes[i] = .{ 2148 .src_loc = key.nodeOffsetSrcLoc(values[i + 1]), 2149 .msg = "also here", 2150 }; 2151 } 2152 2153 try AllErrors.add(module, &arena, &errors, err_msg); 2154 } 2155 } 2156 2157 assert(errors.items.len == self.totalErrorCount()); 2158 2159 return AllErrors{ 2160 .list = try arena_allocator.dupe(AllErrors.Message, errors.items), 2161 .arena = arena.state, 2162 }; 2163} 2164 2165pub fn getCompileLogOutput(self: *Compilation) []const u8 { 2166 const module = self.bin_file.options.module orelse return &[0]u8{}; 2167 return module.compile_log_text.items; 2168} 2169 2170pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemory }!void { 2171 // If the terminal is dumb, we dont want to show the user all the 2172 // output. 2173 var progress: std.Progress = .{ .dont_print_on_dumb = true }; 2174 var main_progress_node = try progress.start("", 0); 2175 defer main_progress_node.end(); 2176 if (self.color == .off) progress.terminal = null; 2177 2178 // Here we queue up all the AstGen tasks first, followed by C object compilation. 2179 // We wait until the AstGen tasks are all completed before proceeding to the 2180 // (at least for now) single-threaded main work queue. However, C object compilation 2181 // only needs to be finished by the end of this function. 2182 2183 var zir_prog_node = main_progress_node.start("AST Lowering", 0); 2184 defer zir_prog_node.end(); 2185 2186 var c_obj_prog_node = main_progress_node.start("Compile C Objects", self.c_source_files.len); 2187 defer c_obj_prog_node.end(); 2188 2189 var embed_file_prog_node = main_progress_node.start("Detect @embedFile updates", self.embed_file_work_queue.count); 2190 defer embed_file_prog_node.end(); 2191 2192 self.work_queue_wait_group.reset(); 2193 defer self.work_queue_wait_group.wait(); 2194 2195 { 2196 const astgen_frame = tracy.namedFrame("astgen"); 2197 defer astgen_frame.end(); 2198 2199 self.astgen_wait_group.reset(); 2200 defer self.astgen_wait_group.wait(); 2201 2202 // builtin.zig is handled specially for two reasons: 2203 // 1. to avoid race condition of zig processes truncating each other's builtin.zig files 2204 // 2. optimization; in the hot path it only incurs a stat() syscall, which happens 2205 // in the `astgen_wait_group`. 2206 if (self.bin_file.options.module) |mod| { 2207 if (mod.job_queued_update_builtin_zig) { 2208 mod.job_queued_update_builtin_zig = false; 2209 2210 self.astgen_wait_group.start(); 2211 try self.thread_pool.spawn(workerUpdateBuiltinZigFile, .{ 2212 self, mod, &self.astgen_wait_group, 2213 }); 2214 } 2215 } 2216 2217 while (self.astgen_work_queue.readItem()) |file| { 2218 self.astgen_wait_group.start(); 2219 try self.thread_pool.spawn(workerAstGenFile, .{ 2220 self, file, &zir_prog_node, &self.astgen_wait_group, .root, 2221 }); 2222 } 2223 2224 while (self.embed_file_work_queue.readItem()) |embed_file| { 2225 self.astgen_wait_group.start(); 2226 try self.thread_pool.spawn(workerCheckEmbedFile, .{ 2227 self, embed_file, &embed_file_prog_node, &self.astgen_wait_group, 2228 }); 2229 } 2230 2231 while (self.c_object_work_queue.readItem()) |c_object| { 2232 self.work_queue_wait_group.start(); 2233 try self.thread_pool.spawn(workerUpdateCObject, .{ 2234 self, c_object, &c_obj_prog_node, &self.work_queue_wait_group, 2235 }); 2236 } 2237 } 2238 2239 const use_stage1 = build_options.is_stage1 and self.bin_file.options.use_stage1; 2240 if (!use_stage1) { 2241 const outdated_and_deleted_decls_frame = tracy.namedFrame("outdated_and_deleted_decls"); 2242 defer outdated_and_deleted_decls_frame.end(); 2243 2244 // Iterate over all the files and look for outdated and deleted declarations. 2245 if (self.bin_file.options.module) |mod| { 2246 try mod.processOutdatedAndDeletedDecls(); 2247 } 2248 } else if (self.bin_file.options.module) |mod| { 2249 // If there are any AstGen compile errors, report them now to avoid 2250 // hitting stage1 bugs. 2251 if (mod.failed_files.count() != 0) { 2252 return; 2253 } 2254 } 2255 2256 // In this main loop we give priority to non-anonymous Decls in the work queue, so 2257 // that they can establish references to anonymous Decls, setting alive=true in the 2258 // backend, preventing anonymous Decls from being prematurely destroyed. 2259 while (true) { 2260 if (self.work_queue.readItem()) |work_item| { 2261 try processOneJob(self, work_item, main_progress_node); 2262 continue; 2263 } 2264 if (self.anon_work_queue.readItem()) |work_item| { 2265 try processOneJob(self, work_item, main_progress_node); 2266 continue; 2267 } 2268 break; 2269 } 2270} 2271 2272fn processOneJob(comp: *Compilation, job: Job, main_progress_node: *std.Progress.Node) !void { 2273 switch (job) { 2274 .codegen_decl => |decl| switch (decl.analysis) { 2275 .unreferenced => unreachable, 2276 .in_progress => unreachable, 2277 .outdated => unreachable, 2278 2279 .file_failure, 2280 .sema_failure, 2281 .codegen_failure, 2282 .dependency_failure, 2283 .sema_failure_retryable, 2284 => return, 2285 2286 .complete, .codegen_failure_retryable => { 2287 const named_frame = tracy.namedFrame("codegen_decl"); 2288 defer named_frame.end(); 2289 2290 if (build_options.omit_stage2) 2291 @panic("sadly stage2 is omitted from this build to save memory on the CI server"); 2292 2293 const module = comp.bin_file.options.module.?; 2294 assert(decl.has_tv); 2295 assert(decl.ty.hasCodeGenBits()); 2296 2297 if (decl.alive) { 2298 try module.linkerUpdateDecl(decl); 2299 return; 2300 } 2301 2302 // Instead of sending this decl to the linker, we actually will delete it 2303 // because we found out that it in fact was never referenced. 2304 module.deleteUnusedDecl(decl); 2305 return; 2306 }, 2307 }, 2308 .codegen_func => |func| switch (func.owner_decl.analysis) { 2309 .unreferenced => unreachable, 2310 .in_progress => unreachable, 2311 .outdated => unreachable, 2312 2313 .file_failure, 2314 .sema_failure, 2315 .codegen_failure, 2316 .dependency_failure, 2317 .sema_failure_retryable, 2318 => return, 2319 2320 .complete, .codegen_failure_retryable => { 2321 if (build_options.omit_stage2) 2322 @panic("sadly stage2 is omitted from this build to save memory on the CI server"); 2323 switch (func.state) { 2324 .sema_failure, .dependency_failure => return, 2325 .queued => {}, 2326 .in_progress => unreachable, 2327 .inline_only => unreachable, // don't queue work for this 2328 .success => unreachable, // don't queue it twice 2329 } 2330 2331 const gpa = comp.gpa; 2332 const module = comp.bin_file.options.module.?; 2333 const decl = func.owner_decl; 2334 2335 var tmp_arena = std.heap.ArenaAllocator.init(gpa); 2336 defer tmp_arena.deinit(); 2337 const sema_arena = tmp_arena.allocator(); 2338 2339 const sema_frame = tracy.namedFrame("sema"); 2340 var sema_frame_ended = false; 2341 errdefer if (!sema_frame_ended) sema_frame.end(); 2342 2343 var air = module.analyzeFnBody(decl, func, sema_arena) catch |err| switch (err) { 2344 error.AnalysisFail => { 2345 assert(func.state != .in_progress); 2346 return; 2347 }, 2348 error.OutOfMemory => return error.OutOfMemory, 2349 }; 2350 defer air.deinit(gpa); 2351 2352 sema_frame.end(); 2353 sema_frame_ended = true; 2354 2355 const liveness_frame = tracy.namedFrame("liveness"); 2356 var liveness_frame_ended = false; 2357 errdefer if (!liveness_frame_ended) liveness_frame.end(); 2358 2359 log.debug("analyze liveness of {s}", .{decl.name}); 2360 var liveness = try Liveness.analyze(gpa, air, decl.getFileScope().zir); 2361 defer liveness.deinit(gpa); 2362 2363 liveness_frame.end(); 2364 liveness_frame_ended = true; 2365 2366 if (builtin.mode == .Debug and comp.verbose_air) { 2367 std.debug.print("# Begin Function AIR: {s}:\n", .{decl.name}); 2368 @import("print_air.zig").dump(gpa, air, decl.getFileScope().zir, liveness); 2369 std.debug.print("# End Function AIR: {s}\n\n", .{decl.name}); 2370 } 2371 2372 const named_frame = tracy.namedFrame("codegen"); 2373 defer named_frame.end(); 2374 2375 comp.bin_file.updateFunc(module, func, air, liveness) catch |err| switch (err) { 2376 error.OutOfMemory => return error.OutOfMemory, 2377 error.AnalysisFail => { 2378 decl.analysis = .codegen_failure; 2379 return; 2380 }, 2381 else => { 2382 try module.failed_decls.ensureUnusedCapacity(gpa, 1); 2383 module.failed_decls.putAssumeCapacityNoClobber(decl, try Module.ErrorMsg.create( 2384 gpa, 2385 decl.srcLoc(), 2386 "unable to codegen: {s}", 2387 .{@errorName(err)}, 2388 )); 2389 decl.analysis = .codegen_failure_retryable; 2390 return; 2391 }, 2392 }; 2393 return; 2394 }, 2395 }, 2396 .emit_h_decl => |decl| switch (decl.analysis) { 2397 .unreferenced => unreachable, 2398 .in_progress => unreachable, 2399 .outdated => unreachable, 2400 2401 .file_failure, 2402 .sema_failure, 2403 .dependency_failure, 2404 .sema_failure_retryable, 2405 => return, 2406 2407 // emit-h only requires semantic analysis of the Decl to be complete, 2408 // it does not depend on machine code generation to succeed. 2409 .codegen_failure, .codegen_failure_retryable, .complete => { 2410 const named_frame = tracy.namedFrame("emit_h_decl"); 2411 defer named_frame.end(); 2412 2413 if (build_options.omit_stage2) 2414 @panic("sadly stage2 is omitted from this build to save memory on the CI server"); 2415 const gpa = comp.gpa; 2416 const module = comp.bin_file.options.module.?; 2417 const emit_h = module.emit_h.?; 2418 _ = try emit_h.decl_table.getOrPut(gpa, decl); 2419 const decl_emit_h = decl.getEmitH(module); 2420 const fwd_decl = &decl_emit_h.fwd_decl; 2421 fwd_decl.shrinkRetainingCapacity(0); 2422 var typedefs_arena = std.heap.ArenaAllocator.init(gpa); 2423 defer typedefs_arena.deinit(); 2424 2425 var dg: c_codegen.DeclGen = .{ 2426 .gpa = gpa, 2427 .module = module, 2428 .error_msg = null, 2429 .decl = decl, 2430 .fwd_decl = fwd_decl.toManaged(gpa), 2431 .typedefs = c_codegen.TypedefMap.init(gpa), 2432 .typedefs_arena = typedefs_arena.allocator(), 2433 }; 2434 defer dg.fwd_decl.deinit(); 2435 defer dg.typedefs.deinit(); 2436 2437 c_codegen.genHeader(&dg) catch |err| switch (err) { 2438 error.AnalysisFail => { 2439 try emit_h.failed_decls.put(gpa, decl, dg.error_msg.?); 2440 return; 2441 }, 2442 else => |e| return e, 2443 }; 2444 2445 fwd_decl.* = dg.fwd_decl.moveToUnmanaged(); 2446 fwd_decl.shrinkAndFree(gpa, fwd_decl.items.len); 2447 }, 2448 }, 2449 .analyze_decl => |decl| { 2450 const named_frame = tracy.namedFrame("analyze_decl"); 2451 defer named_frame.end(); 2452 2453 if (build_options.omit_stage2) 2454 @panic("sadly stage2 is omitted from this build to save memory on the CI server"); 2455 const module = comp.bin_file.options.module.?; 2456 module.ensureDeclAnalyzed(decl) catch |err| switch (err) { 2457 error.OutOfMemory => return error.OutOfMemory, 2458 error.AnalysisFail => return, 2459 }; 2460 }, 2461 .update_embed_file => |embed_file| { 2462 const named_frame = tracy.namedFrame("update_embed_file"); 2463 defer named_frame.end(); 2464 2465 if (build_options.omit_stage2) 2466 @panic("sadly stage2 is omitted from this build to save memory on the CI server"); 2467 const module = comp.bin_file.options.module.?; 2468 module.updateEmbedFile(embed_file) catch |err| switch (err) { 2469 error.OutOfMemory => return error.OutOfMemory, 2470 error.AnalysisFail => return, 2471 }; 2472 }, 2473 .update_line_number => |decl| { 2474 const named_frame = tracy.namedFrame("update_line_number"); 2475 defer named_frame.end(); 2476 2477 if (build_options.omit_stage2) 2478 @panic("sadly stage2 is omitted from this build to save memory on the CI server"); 2479 const gpa = comp.gpa; 2480 const module = comp.bin_file.options.module.?; 2481 comp.bin_file.updateDeclLineNumber(module, decl) catch |err| { 2482 try module.failed_decls.ensureUnusedCapacity(gpa, 1); 2483 module.failed_decls.putAssumeCapacityNoClobber(decl, try Module.ErrorMsg.create( 2484 gpa, 2485 decl.srcLoc(), 2486 "unable to update line number: {s}", 2487 .{@errorName(err)}, 2488 )); 2489 decl.analysis = .codegen_failure_retryable; 2490 }; 2491 }, 2492 .analyze_pkg => |pkg| { 2493 const named_frame = tracy.namedFrame("analyze_pkg"); 2494 defer named_frame.end(); 2495 2496 if (build_options.omit_stage2) 2497 @panic("sadly stage2 is omitted from this build to save memory on the CI server"); 2498 const module = comp.bin_file.options.module.?; 2499 module.semaPkg(pkg) catch |err| switch (err) { 2500 error.CurrentWorkingDirectoryUnlinked, 2501 error.Unexpected, 2502 => try comp.setMiscFailure( 2503 .analyze_pkg, 2504 "unexpected problem analyzing package '{s}'", 2505 .{pkg.root_src_path}, 2506 ), 2507 error.OutOfMemory => return error.OutOfMemory, 2508 error.AnalysisFail => return, 2509 }; 2510 }, 2511 .glibc_crt_file => |crt_file| { 2512 const named_frame = tracy.namedFrame("glibc_crt_file"); 2513 defer named_frame.end(); 2514 2515 glibc.buildCRTFile(comp, crt_file) catch |err| { 2516 // TODO Surface more error details. 2517 try comp.setMiscFailure(.glibc_crt_file, "unable to build glibc CRT file: {s}", .{ 2518 @errorName(err), 2519 }); 2520 }; 2521 }, 2522 .glibc_shared_objects => { 2523 const named_frame = tracy.namedFrame("glibc_shared_objects"); 2524 defer named_frame.end(); 2525 2526 glibc.buildSharedObjects(comp) catch |err| { 2527 // TODO Surface more error details. 2528 try comp.setMiscFailure( 2529 .glibc_shared_objects, 2530 "unable to build glibc shared objects: {s}", 2531 .{@errorName(err)}, 2532 ); 2533 }; 2534 }, 2535 .musl_crt_file => |crt_file| { 2536 const named_frame = tracy.namedFrame("musl_crt_file"); 2537 defer named_frame.end(); 2538 2539 musl.buildCRTFile(comp, crt_file) catch |err| { 2540 // TODO Surface more error details. 2541 try comp.setMiscFailure( 2542 .musl_crt_file, 2543 "unable to build musl CRT file: {s}", 2544 .{@errorName(err)}, 2545 ); 2546 }; 2547 }, 2548 .mingw_crt_file => |crt_file| { 2549 const named_frame = tracy.namedFrame("mingw_crt_file"); 2550 defer named_frame.end(); 2551 2552 mingw.buildCRTFile(comp, crt_file) catch |err| { 2553 // TODO Surface more error details. 2554 try comp.setMiscFailure( 2555 .mingw_crt_file, 2556 "unable to build mingw-w64 CRT file: {s}", 2557 .{@errorName(err)}, 2558 ); 2559 }; 2560 }, 2561 .windows_import_lib => |index| { 2562 const named_frame = tracy.namedFrame("windows_import_lib"); 2563 defer named_frame.end(); 2564 2565 const link_lib = comp.bin_file.options.system_libs.keys()[index]; 2566 mingw.buildImportLib(comp, link_lib) catch |err| { 2567 // TODO Surface more error details. 2568 try comp.setMiscFailure( 2569 .windows_import_lib, 2570 "unable to generate DLL import .lib file: {s}", 2571 .{@errorName(err)}, 2572 ); 2573 }; 2574 }, 2575 .libunwind => { 2576 const named_frame = tracy.namedFrame("libunwind"); 2577 defer named_frame.end(); 2578 2579 libunwind.buildStaticLib(comp) catch |err| { 2580 // TODO Surface more error details. 2581 try comp.setMiscFailure( 2582 .libunwind, 2583 "unable to build libunwind: {s}", 2584 .{@errorName(err)}, 2585 ); 2586 }; 2587 }, 2588 .libcxx => { 2589 const named_frame = tracy.namedFrame("libcxx"); 2590 defer named_frame.end(); 2591 2592 libcxx.buildLibCXX(comp) catch |err| { 2593 // TODO Surface more error details. 2594 try comp.setMiscFailure( 2595 .libcxx, 2596 "unable to build libcxx: {s}", 2597 .{@errorName(err)}, 2598 ); 2599 }; 2600 }, 2601 .libcxxabi => { 2602 const named_frame = tracy.namedFrame("libcxxabi"); 2603 defer named_frame.end(); 2604 2605 libcxx.buildLibCXXABI(comp) catch |err| { 2606 // TODO Surface more error details. 2607 try comp.setMiscFailure( 2608 .libcxxabi, 2609 "unable to build libcxxabi: {s}", 2610 .{@errorName(err)}, 2611 ); 2612 }; 2613 }, 2614 .libtsan => { 2615 const named_frame = tracy.namedFrame("libtsan"); 2616 defer named_frame.end(); 2617 2618 libtsan.buildTsan(comp) catch |err| { 2619 // TODO Surface more error details. 2620 try comp.setMiscFailure( 2621 .libtsan, 2622 "unable to build TSAN library: {s}", 2623 .{@errorName(err)}, 2624 ); 2625 }; 2626 }, 2627 .wasi_libc_crt_file => |crt_file| { 2628 const named_frame = tracy.namedFrame("wasi_libc_crt_file"); 2629 defer named_frame.end(); 2630 2631 wasi_libc.buildCRTFile(comp, crt_file) catch |err| { 2632 // TODO Surface more error details. 2633 try comp.setMiscFailure( 2634 .wasi_libc_crt_file, 2635 "unable to build WASI libc CRT file: {s}", 2636 .{@errorName(err)}, 2637 ); 2638 }; 2639 }, 2640 .compiler_rt_lib => { 2641 const named_frame = tracy.namedFrame("compiler_rt_lib"); 2642 defer named_frame.end(); 2643 2644 comp.buildOutputFromZig( 2645 "compiler_rt.zig", 2646 .Lib, 2647 &comp.compiler_rt_static_lib, 2648 .compiler_rt, 2649 ) catch |err| switch (err) { 2650 error.OutOfMemory => return error.OutOfMemory, 2651 error.SubCompilationFailed => return, // error reported already 2652 else => try comp.setMiscFailure( 2653 .compiler_rt, 2654 "unable to build compiler_rt: {s}", 2655 .{@errorName(err)}, 2656 ), 2657 }; 2658 }, 2659 .compiler_rt_obj => { 2660 const named_frame = tracy.namedFrame("compiler_rt_obj"); 2661 defer named_frame.end(); 2662 2663 comp.buildOutputFromZig( 2664 "compiler_rt.zig", 2665 .Obj, 2666 &comp.compiler_rt_obj, 2667 .compiler_rt, 2668 ) catch |err| switch (err) { 2669 error.OutOfMemory => return error.OutOfMemory, 2670 error.SubCompilationFailed => return, // error reported already 2671 else => try comp.setMiscFailure( 2672 .compiler_rt, 2673 "unable to build compiler_rt: {s}", 2674 .{@errorName(err)}, 2675 ), 2676 }; 2677 }, 2678 .libssp => { 2679 const named_frame = tracy.namedFrame("libssp"); 2680 defer named_frame.end(); 2681 2682 comp.buildOutputFromZig( 2683 "ssp.zig", 2684 .Lib, 2685 &comp.libssp_static_lib, 2686 .libssp, 2687 ) catch |err| switch (err) { 2688 error.OutOfMemory => return error.OutOfMemory, 2689 error.SubCompilationFailed => return, // error reported already 2690 else => try comp.setMiscFailure( 2691 .libssp, 2692 "unable to build libssp: {s}", 2693 .{@errorName(err)}, 2694 ), 2695 }; 2696 }, 2697 .zig_libc => { 2698 const named_frame = tracy.namedFrame("zig_libc"); 2699 defer named_frame.end(); 2700 2701 comp.buildOutputFromZig( 2702 "c.zig", 2703 .Lib, 2704 &comp.libc_static_lib, 2705 .zig_libc, 2706 ) catch |err| switch (err) { 2707 error.OutOfMemory => return error.OutOfMemory, 2708 error.SubCompilationFailed => return, // error reported already 2709 else => try comp.setMiscFailure( 2710 .zig_libc, 2711 "unable to build zig's multitarget libc: {s}", 2712 .{@errorName(err)}, 2713 ), 2714 }; 2715 }, 2716 .stage1_module => { 2717 const named_frame = tracy.namedFrame("stage1_module"); 2718 defer named_frame.end(); 2719 2720 if (!build_options.is_stage1) 2721 unreachable; 2722 2723 comp.updateStage1Module(main_progress_node) catch |err| { 2724 fatal("unable to build stage1 zig object: {s}", .{@errorName(err)}); 2725 }; 2726 }, 2727 } 2728} 2729 2730const AstGenSrc = union(enum) { 2731 root, 2732 import: struct { 2733 importing_file: *Module.File, 2734 import_tok: std.zig.Ast.TokenIndex, 2735 }, 2736}; 2737 2738fn workerAstGenFile( 2739 comp: *Compilation, 2740 file: *Module.File, 2741 prog_node: *std.Progress.Node, 2742 wg: *WaitGroup, 2743 src: AstGenSrc, 2744) void { 2745 defer wg.finish(); 2746 2747 var child_prog_node = prog_node.start(file.sub_file_path, 0); 2748 child_prog_node.activate(); 2749 defer child_prog_node.end(); 2750 2751 const mod = comp.bin_file.options.module.?; 2752 mod.astGenFile(file) catch |err| switch (err) { 2753 error.AnalysisFail => return, 2754 else => { 2755 file.status = .retryable_failure; 2756 comp.reportRetryableAstGenError(src, file, err) catch |oom| switch (oom) { 2757 // Swallowing this error is OK because it's implied to be OOM when 2758 // there is a missing `failed_files` error message. 2759 error.OutOfMemory => {}, 2760 }; 2761 return; 2762 }, 2763 }; 2764 2765 // Pre-emptively look for `@import` paths and queue them up. 2766 // If we experience an error preemptively fetching the 2767 // file, just ignore it and let it happen again later during Sema. 2768 assert(file.zir_loaded); 2769 const imports_index = file.zir.extra[@enumToInt(Zir.ExtraIndex.imports)]; 2770 if (imports_index != 0) { 2771 const extra = file.zir.extraData(Zir.Inst.Imports, imports_index); 2772 var import_i: u32 = 0; 2773 var extra_index = extra.end; 2774 2775 while (import_i < extra.data.imports_len) : (import_i += 1) { 2776 const item = file.zir.extraData(Zir.Inst.Imports.Item, extra_index); 2777 extra_index = item.end; 2778 2779 const import_path = file.zir.nullTerminatedString(item.data.name); 2780 // `@import("builtin")` is handled specially. 2781 if (mem.eql(u8, import_path, "builtin")) continue; 2782 2783 const import_result = blk: { 2784 comp.mutex.lock(); 2785 defer comp.mutex.unlock(); 2786 2787 break :blk mod.importFile(file, import_path) catch continue; 2788 }; 2789 if (import_result.is_new) { 2790 log.debug("AstGen of {s} has import '{s}'; queuing AstGen of {s}", .{ 2791 file.sub_file_path, import_path, import_result.file.sub_file_path, 2792 }); 2793 const sub_src: AstGenSrc = .{ .import = .{ 2794 .importing_file = file, 2795 .import_tok = item.data.token, 2796 } }; 2797 wg.start(); 2798 comp.thread_pool.spawn(workerAstGenFile, .{ 2799 comp, import_result.file, prog_node, wg, sub_src, 2800 }) catch { 2801 wg.finish(); 2802 continue; 2803 }; 2804 } 2805 } 2806 } 2807} 2808 2809fn workerUpdateBuiltinZigFile( 2810 comp: *Compilation, 2811 mod: *Module, 2812 wg: *WaitGroup, 2813) void { 2814 defer wg.finish(); 2815 2816 mod.populateBuiltinFile() catch |err| { 2817 const dir_path: []const u8 = mod.zig_cache_artifact_directory.path orelse "."; 2818 2819 comp.mutex.lock(); 2820 defer comp.mutex.unlock(); 2821 2822 comp.setMiscFailure(.write_builtin_zig, "unable to write builtin.zig to {s}: {s}", .{ 2823 dir_path, @errorName(err), 2824 }) catch |oom| switch (oom) { 2825 error.OutOfMemory => log.err("unable to write builtin.zig to {s}: {s}", .{ 2826 dir_path, @errorName(err), 2827 }), 2828 }; 2829 }; 2830} 2831 2832fn workerCheckEmbedFile( 2833 comp: *Compilation, 2834 embed_file: *Module.EmbedFile, 2835 prog_node: *std.Progress.Node, 2836 wg: *WaitGroup, 2837) void { 2838 defer wg.finish(); 2839 2840 var child_prog_node = prog_node.start(embed_file.sub_file_path, 0); 2841 child_prog_node.activate(); 2842 defer child_prog_node.end(); 2843 2844 const mod = comp.bin_file.options.module.?; 2845 mod.detectEmbedFileUpdate(embed_file) catch |err| { 2846 comp.reportRetryableEmbedFileError(embed_file, err) catch |oom| switch (oom) { 2847 // Swallowing this error is OK because it's implied to be OOM when 2848 // there is a missing `failed_embed_files` error message. 2849 error.OutOfMemory => {}, 2850 }; 2851 return; 2852 }; 2853} 2854 2855pub fn obtainCObjectCacheManifest(comp: *const Compilation) Cache.Manifest { 2856 var man = comp.cache_parent.obtain(); 2857 2858 // Only things that need to be added on top of the base hash, and only things 2859 // that apply both to @cImport and compiling C objects. No linking stuff here! 2860 // Also nothing that applies only to compiling .zig code. 2861 man.hash.add(comp.sanitize_c); 2862 man.hash.addListOfBytes(comp.clang_argv); 2863 man.hash.add(comp.bin_file.options.link_libcpp); 2864 man.hash.addListOfBytes(comp.libc_include_dir_list); 2865 2866 return man; 2867} 2868 2869test "cImport" { 2870 _ = cImport; 2871} 2872 2873const CImportResult = struct { 2874 out_zig_path: []u8, 2875 errors: []translate_c.ClangErrMsg, 2876}; 2877 2878/// Caller owns returned memory. 2879/// This API is currently coupled pretty tightly to stage1's needs; it will need to be reworked 2880/// a bit when we want to start using it from self-hosted. 2881pub fn cImport(comp: *Compilation, c_src: []const u8) !CImportResult { 2882 if (!build_options.have_llvm) 2883 return error.ZigCompilerNotBuiltWithLLVMExtensions; 2884 2885 const tracy_trace = trace(@src()); 2886 defer tracy_trace.end(); 2887 2888 const cimport_zig_basename = "cimport.zig"; 2889 2890 var man = comp.obtainCObjectCacheManifest(); 2891 defer man.deinit(); 2892 2893 man.hash.add(@as(u16, 0xb945)); // Random number to distinguish translate-c from compiling C objects 2894 man.hash.addBytes(c_src); 2895 2896 // If the previous invocation resulted in clang errors, we will see a hit 2897 // here with 0 files in the manifest, in which case it is actually a miss. 2898 // We need to "unhit" in this case, to keep the digests matching. 2899 const prev_hash_state = man.hash.peekBin(); 2900 const actual_hit = hit: { 2901 _ = try man.hit(); 2902 if (man.files.items.len == 0) { 2903 man.unhit(prev_hash_state, 0); 2904 break :hit false; 2905 } 2906 break :hit true; 2907 }; 2908 const digest = if (!actual_hit) digest: { 2909 var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa); 2910 defer arena_allocator.deinit(); 2911 const arena = arena_allocator.allocator(); 2912 2913 const tmp_digest = man.hash.peek(); 2914 const tmp_dir_sub_path = try std.fs.path.join(arena, &[_][]const u8{ "o", &tmp_digest }); 2915 var zig_cache_tmp_dir = try comp.local_cache_directory.handle.makeOpenPath(tmp_dir_sub_path, .{}); 2916 defer zig_cache_tmp_dir.close(); 2917 const cimport_basename = "cimport.h"; 2918 const out_h_path = try comp.local_cache_directory.join(arena, &[_][]const u8{ 2919 tmp_dir_sub_path, cimport_basename, 2920 }); 2921 const out_dep_path = try std.fmt.allocPrint(arena, "{s}.d", .{out_h_path}); 2922 2923 try zig_cache_tmp_dir.writeFile(cimport_basename, c_src); 2924 if (comp.verbose_cimport) { 2925 log.info("C import source: {s}", .{out_h_path}); 2926 } 2927 2928 var argv = std.ArrayList([]const u8).init(comp.gpa); 2929 defer argv.deinit(); 2930 2931 try argv.append(""); // argv[0] is program name, actual args start at [1] 2932 try comp.addTranslateCCArgs(arena, &argv, .c, out_dep_path); 2933 2934 try argv.append(out_h_path); 2935 2936 if (comp.verbose_cc) { 2937 dump_argv(argv.items); 2938 } 2939 2940 // Convert to null terminated args. 2941 const new_argv_with_sentinel = try arena.alloc(?[*:0]const u8, argv.items.len + 1); 2942 new_argv_with_sentinel[argv.items.len] = null; 2943 const new_argv = new_argv_with_sentinel[0..argv.items.len :null]; 2944 for (argv.items) |arg, i| { 2945 new_argv[i] = try arena.dupeZ(u8, arg); 2946 } 2947 2948 const c_headers_dir_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{"include"}); 2949 const c_headers_dir_path_z = try arena.dupeZ(u8, c_headers_dir_path); 2950 var clang_errors: []translate_c.ClangErrMsg = &[0]translate_c.ClangErrMsg{}; 2951 var tree = translate_c.translate( 2952 comp.gpa, 2953 new_argv.ptr, 2954 new_argv.ptr + new_argv.len, 2955 &clang_errors, 2956 c_headers_dir_path_z, 2957 ) catch |err| switch (err) { 2958 error.OutOfMemory => return error.OutOfMemory, 2959 error.ASTUnitFailure => { 2960 log.warn("clang API returned errors but due to a clang bug, it is not exposing the errors for zig to see. For more details: https://github.com/ziglang/zig/issues/4455", .{}); 2961 return error.ASTUnitFailure; 2962 }, 2963 error.SemanticAnalyzeFail => { 2964 return CImportResult{ 2965 .out_zig_path = "", 2966 .errors = clang_errors, 2967 }; 2968 }, 2969 }; 2970 defer tree.deinit(comp.gpa); 2971 2972 if (comp.verbose_cimport) { 2973 log.info("C import .d file: {s}", .{out_dep_path}); 2974 } 2975 2976 const dep_basename = std.fs.path.basename(out_dep_path); 2977 try man.addDepFilePost(zig_cache_tmp_dir, dep_basename); 2978 if (build_options.is_stage1 and comp.bin_file.options.use_stage1) try comp.stage1_cache_manifest.addDepFilePost(zig_cache_tmp_dir, dep_basename); 2979 2980 const digest = man.final(); 2981 const o_sub_path = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest }); 2982 var o_dir = try comp.local_cache_directory.handle.makeOpenPath(o_sub_path, .{}); 2983 defer o_dir.close(); 2984 2985 var out_zig_file = try o_dir.createFile(cimport_zig_basename, .{}); 2986 defer out_zig_file.close(); 2987 2988 const formatted = try tree.render(comp.gpa); 2989 defer comp.gpa.free(formatted); 2990 2991 try out_zig_file.writeAll(formatted); 2992 2993 break :digest digest; 2994 } else man.final(); 2995 2996 // Write the updated manifest. This is a no-op if the manifest is not dirty. Note that it is 2997 // possible we had a hit and the manifest is dirty, for example if the file mtime changed but 2998 // the contents were the same, we hit the cache but the manifest is dirty and we need to update 2999 // it to prevent doing a full file content comparison the next time around. 3000 man.writeManifest() catch |err| { 3001 log.warn("failed to write cache manifest for C import: {s}", .{@errorName(err)}); 3002 }; 3003 3004 const out_zig_path = try comp.local_cache_directory.join(comp.gpa, &[_][]const u8{ 3005 "o", &digest, cimport_zig_basename, 3006 }); 3007 if (comp.verbose_cimport) { 3008 log.info("C import output: {s}", .{out_zig_path}); 3009 } 3010 return CImportResult{ 3011 .out_zig_path = out_zig_path, 3012 .errors = &[0]translate_c.ClangErrMsg{}, 3013 }; 3014} 3015 3016fn workerUpdateCObject( 3017 comp: *Compilation, 3018 c_object: *CObject, 3019 progress_node: *std.Progress.Node, 3020 wg: *WaitGroup, 3021) void { 3022 defer wg.finish(); 3023 3024 comp.updateCObject(c_object, progress_node) catch |err| switch (err) { 3025 error.AnalysisFail => return, 3026 else => { 3027 comp.reportRetryableCObjectError(c_object, err) catch |oom| switch (oom) { 3028 // Swallowing this error is OK because it's implied to be OOM when 3029 // there is a missing failed_c_objects error message. 3030 error.OutOfMemory => {}, 3031 }; 3032 }, 3033 }; 3034} 3035 3036fn reportRetryableCObjectError( 3037 comp: *Compilation, 3038 c_object: *CObject, 3039 err: anyerror, 3040) error{OutOfMemory}!void { 3041 c_object.status = .failure_retryable; 3042 3043 const c_obj_err_msg = try comp.gpa.create(CObject.ErrorMsg); 3044 errdefer comp.gpa.destroy(c_obj_err_msg); 3045 const msg = try std.fmt.allocPrint(comp.gpa, "{s}", .{@errorName(err)}); 3046 errdefer comp.gpa.free(msg); 3047 c_obj_err_msg.* = .{ 3048 .msg = msg, 3049 .line = 0, 3050 .column = 0, 3051 }; 3052 { 3053 comp.mutex.lock(); 3054 defer comp.mutex.unlock(); 3055 try comp.failed_c_objects.putNoClobber(comp.gpa, c_object, c_obj_err_msg); 3056 } 3057} 3058 3059fn reportRetryableAstGenError( 3060 comp: *Compilation, 3061 src: AstGenSrc, 3062 file: *Module.File, 3063 err: anyerror, 3064) error{OutOfMemory}!void { 3065 const mod = comp.bin_file.options.module.?; 3066 const gpa = mod.gpa; 3067 3068 file.status = .retryable_failure; 3069 3070 const src_loc: Module.SrcLoc = switch (src) { 3071 .root => .{ 3072 .file_scope = file, 3073 .parent_decl_node = 0, 3074 .lazy = .entire_file, 3075 }, 3076 .import => |info| blk: { 3077 const importing_file = info.importing_file; 3078 3079 break :blk .{ 3080 .file_scope = importing_file, 3081 .parent_decl_node = 0, 3082 .lazy = .{ .token_abs = info.import_tok }, 3083 }; 3084 }, 3085 }; 3086 3087 const err_msg = if (file.pkg.root_src_directory.path) |dir_path| 3088 try Module.ErrorMsg.create( 3089 gpa, 3090 src_loc, 3091 "unable to load '{s}" ++ std.fs.path.sep_str ++ "{s}': {s}", 3092 .{ dir_path, file.sub_file_path, @errorName(err) }, 3093 ) 3094 else 3095 try Module.ErrorMsg.create(gpa, src_loc, "unable to load '{s}': {s}", .{ 3096 file.sub_file_path, @errorName(err), 3097 }); 3098 errdefer err_msg.destroy(gpa); 3099 3100 { 3101 comp.mutex.lock(); 3102 defer comp.mutex.unlock(); 3103 try mod.failed_files.putNoClobber(gpa, file, err_msg); 3104 } 3105} 3106 3107fn reportRetryableEmbedFileError( 3108 comp: *Compilation, 3109 embed_file: *Module.EmbedFile, 3110 err: anyerror, 3111) error{OutOfMemory}!void { 3112 const mod = comp.bin_file.options.module.?; 3113 const gpa = mod.gpa; 3114 3115 const src_loc: Module.SrcLoc = embed_file.owner_decl.srcLoc(); 3116 3117 const err_msg = if (embed_file.pkg.root_src_directory.path) |dir_path| 3118 try Module.ErrorMsg.create( 3119 gpa, 3120 src_loc, 3121 "unable to load '{s}" ++ std.fs.path.sep_str ++ "{s}': {s}", 3122 .{ dir_path, embed_file.sub_file_path, @errorName(err) }, 3123 ) 3124 else 3125 try Module.ErrorMsg.create(gpa, src_loc, "unable to load '{s}': {s}", .{ 3126 embed_file.sub_file_path, @errorName(err), 3127 }); 3128 errdefer err_msg.destroy(gpa); 3129 3130 { 3131 comp.mutex.lock(); 3132 defer comp.mutex.unlock(); 3133 try mod.failed_embed_files.putNoClobber(gpa, embed_file, err_msg); 3134 } 3135} 3136 3137fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.Progress.Node) !void { 3138 if (!build_options.have_llvm) { 3139 return comp.failCObj(c_object, "clang not available: compiler built without LLVM extensions", .{}); 3140 } 3141 const self_exe_path = comp.self_exe_path orelse 3142 return comp.failCObj(c_object, "clang compilation disabled", .{}); 3143 3144 const tracy_trace = trace(@src()); 3145 defer tracy_trace.end(); 3146 3147 log.debug("updating C object: {s}", .{c_object.src.src_path}); 3148 3149 if (c_object.clearStatus(comp.gpa)) { 3150 // There was previous failure. 3151 comp.mutex.lock(); 3152 defer comp.mutex.unlock(); 3153 // If the failure was OOM, there will not be an entry here, so we do 3154 // not assert discard. 3155 _ = comp.failed_c_objects.swapRemove(c_object); 3156 } 3157 3158 var man = comp.obtainCObjectCacheManifest(); 3159 defer man.deinit(); 3160 3161 man.hash.add(comp.clang_preprocessor_mode); 3162 man.hash.addOptionalEmitLoc(comp.emit_asm); 3163 man.hash.addOptionalEmitLoc(comp.emit_llvm_ir); 3164 man.hash.addOptionalEmitLoc(comp.emit_llvm_bc); 3165 3166 try man.hashCSource(c_object.src); 3167 3168 var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa); 3169 defer arena_allocator.deinit(); 3170 const arena = arena_allocator.allocator(); 3171 3172 const c_source_basename = std.fs.path.basename(c_object.src.src_path); 3173 3174 c_obj_prog_node.activate(); 3175 var child_progress_node = c_obj_prog_node.start(c_source_basename, 0); 3176 child_progress_node.activate(); 3177 defer child_progress_node.end(); 3178 3179 // Special case when doing build-obj for just one C file. When there are more than one object 3180 // file and building an object we need to link them together, but with just one it should go 3181 // directly to the output file. 3182 const direct_o = comp.c_source_files.len == 1 and comp.bin_file.options.module == null and 3183 comp.bin_file.options.output_mode == .Obj and comp.bin_file.options.objects.len == 0; 3184 const o_basename_noext = if (direct_o) 3185 comp.bin_file.options.root_name 3186 else 3187 c_source_basename[0 .. c_source_basename.len - std.fs.path.extension(c_source_basename).len]; 3188 3189 const o_ext = comp.bin_file.options.object_format.fileExt(comp.bin_file.options.target.cpu.arch); 3190 const digest = if (!comp.disable_c_depfile and try man.hit()) man.final() else blk: { 3191 var argv = std.ArrayList([]const u8).init(comp.gpa); 3192 defer argv.deinit(); 3193 3194 // In case we are doing passthrough mode, we need to detect -S and -emit-llvm. 3195 const out_ext = e: { 3196 if (!comp.clang_passthrough_mode) 3197 break :e o_ext; 3198 if (comp.emit_asm != null) 3199 break :e ".s"; 3200 if (comp.emit_llvm_ir != null) 3201 break :e ".ll"; 3202 if (comp.emit_llvm_bc != null) 3203 break :e ".bc"; 3204 3205 break :e o_ext; 3206 }; 3207 const o_basename = try std.fmt.allocPrint(arena, "{s}{s}", .{ o_basename_noext, out_ext }); 3208 3209 // We can't know the digest until we do the C compiler invocation, 3210 // so we need a temporary filename. 3211 const out_obj_path = try comp.tmpFilePath(arena, o_basename); 3212 var zig_cache_tmp_dir = try comp.local_cache_directory.handle.makeOpenPath("tmp", .{}); 3213 defer zig_cache_tmp_dir.close(); 3214 3215 try argv.appendSlice(&[_][]const u8{ self_exe_path, "clang" }); 3216 3217 const ext = classifyFileExt(c_object.src.src_path); 3218 const out_dep_path: ?[]const u8 = if (comp.disable_c_depfile or !ext.clangSupportsDepFile()) 3219 null 3220 else 3221 try std.fmt.allocPrint(arena, "{s}.d", .{out_obj_path}); 3222 try comp.addCCArgs(arena, &argv, ext, out_dep_path); 3223 3224 try argv.ensureUnusedCapacity(6 + c_object.src.extra_flags.len); 3225 switch (comp.clang_preprocessor_mode) { 3226 .no => argv.appendSliceAssumeCapacity(&[_][]const u8{ "-c", "-o", out_obj_path }), 3227 .yes => argv.appendSliceAssumeCapacity(&[_][]const u8{ "-E", "-o", out_obj_path }), 3228 .stdout => argv.appendAssumeCapacity("-E"), 3229 } 3230 if (comp.clang_passthrough_mode) { 3231 if (comp.emit_asm != null) { 3232 argv.appendAssumeCapacity("-S"); 3233 } else if (comp.emit_llvm_ir != null) { 3234 argv.appendSliceAssumeCapacity(&[_][]const u8{ "-emit-llvm", "-S" }); 3235 } else if (comp.emit_llvm_bc != null) { 3236 argv.appendAssumeCapacity("-emit-llvm"); 3237 } 3238 } 3239 argv.appendAssumeCapacity(c_object.src.src_path); 3240 argv.appendSliceAssumeCapacity(c_object.src.extra_flags); 3241 3242 if (comp.verbose_cc) { 3243 dump_argv(argv.items); 3244 } 3245 3246 const child = try std.ChildProcess.init(argv.items, arena); 3247 defer child.deinit(); 3248 3249 if (comp.clang_passthrough_mode) { 3250 child.stdin_behavior = .Inherit; 3251 child.stdout_behavior = .Inherit; 3252 child.stderr_behavior = .Inherit; 3253 3254 const term = child.spawnAndWait() catch |err| { 3255 return comp.failCObj(c_object, "unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); 3256 }; 3257 switch (term) { 3258 .Exited => |code| { 3259 if (code != 0) { 3260 std.process.exit(code); 3261 } 3262 if (comp.clang_preprocessor_mode == .stdout) 3263 std.process.exit(0); 3264 }, 3265 else => std.process.abort(), 3266 } 3267 } else { 3268 child.stdin_behavior = .Ignore; 3269 child.stdout_behavior = .Ignore; 3270 child.stderr_behavior = .Pipe; 3271 3272 try child.spawn(); 3273 3274 const stderr_reader = child.stderr.?.reader(); 3275 3276 const stderr = try stderr_reader.readAllAlloc(arena, 10 * 1024 * 1024); 3277 3278 const term = child.wait() catch |err| { 3279 return comp.failCObj(c_object, "unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) }); 3280 }; 3281 3282 switch (term) { 3283 .Exited => |code| { 3284 if (code != 0) { 3285 // TODO parse clang stderr and turn it into an error message 3286 // and then call failCObjWithOwnedErrorMsg 3287 log.err("clang failed with stderr: {s}", .{stderr}); 3288 return comp.failCObj(c_object, "clang exited with code {d}", .{code}); 3289 } 3290 }, 3291 else => { 3292 log.err("clang terminated with stderr: {s}", .{stderr}); 3293 return comp.failCObj(c_object, "clang terminated unexpectedly", .{}); 3294 }, 3295 } 3296 } 3297 3298 if (out_dep_path) |dep_file_path| { 3299 const dep_basename = std.fs.path.basename(dep_file_path); 3300 // Add the files depended on to the cache system. 3301 try man.addDepFilePost(zig_cache_tmp_dir, dep_basename); 3302 // Just to save disk space, we delete the file because it is never needed again. 3303 zig_cache_tmp_dir.deleteFile(dep_basename) catch |err| { 3304 log.warn("failed to delete '{s}': {s}", .{ dep_file_path, @errorName(err) }); 3305 }; 3306 } 3307 3308 // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock. 3309 if (comp.disable_c_depfile) _ = try man.hit(); 3310 3311 // Rename into place. 3312 const digest = man.final(); 3313 const o_sub_path = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest }); 3314 var o_dir = try comp.local_cache_directory.handle.makeOpenPath(o_sub_path, .{}); 3315 defer o_dir.close(); 3316 const tmp_basename = std.fs.path.basename(out_obj_path); 3317 try std.fs.rename(zig_cache_tmp_dir, tmp_basename, o_dir, o_basename); 3318 break :blk digest; 3319 }; 3320 3321 // Write the updated manifest. This is a no-op if the manifest is not dirty. Note that it is 3322 // possible we had a hit and the manifest is dirty, for example if the file mtime changed but 3323 // the contents were the same, we hit the cache but the manifest is dirty and we need to update 3324 // it to prevent doing a full file content comparison the next time around. 3325 man.writeManifest() catch |err| { 3326 log.warn("failed to write cache manifest when compiling '{s}': {s}", .{ c_object.src.src_path, @errorName(err) }); 3327 }; 3328 3329 const o_basename = try std.fmt.allocPrint(arena, "{s}{s}", .{ o_basename_noext, o_ext }); 3330 3331 c_object.status = .{ 3332 .success = .{ 3333 .object_path = try comp.local_cache_directory.join(comp.gpa, &[_][]const u8{ 3334 "o", &digest, o_basename, 3335 }), 3336 .lock = man.toOwnedLock(), 3337 }, 3338 }; 3339} 3340 3341pub fn tmpFilePath(comp: *Compilation, arena: Allocator, suffix: []const u8) error{OutOfMemory}![]const u8 { 3342 const s = std.fs.path.sep_str; 3343 const rand_int = std.crypto.random.int(u64); 3344 if (comp.local_cache_directory.path) |p| { 3345 return std.fmt.allocPrint(arena, "{s}" ++ s ++ "tmp" ++ s ++ "{x}-{s}", .{ p, rand_int, suffix }); 3346 } else { 3347 return std.fmt.allocPrint(arena, "tmp" ++ s ++ "{x}-{s}", .{ rand_int, suffix }); 3348 } 3349} 3350 3351pub fn addTranslateCCArgs( 3352 comp: *Compilation, 3353 arena: Allocator, 3354 argv: *std.ArrayList([]const u8), 3355 ext: FileExt, 3356 out_dep_path: ?[]const u8, 3357) !void { 3358 try argv.appendSlice(&[_][]const u8{ "-x", "c" }); 3359 try comp.addCCArgs(arena, argv, ext, out_dep_path); 3360 // This gives us access to preprocessing entities, presumably at the cost of performance. 3361 try argv.appendSlice(&[_][]const u8{ "-Xclang", "-detailed-preprocessing-record" }); 3362} 3363 3364/// Add common C compiler args between translate-c and C object compilation. 3365pub fn addCCArgs( 3366 comp: *const Compilation, 3367 arena: Allocator, 3368 argv: *std.ArrayList([]const u8), 3369 ext: FileExt, 3370 out_dep_path: ?[]const u8, 3371) !void { 3372 const target = comp.getTarget(); 3373 3374 if (ext == .cpp) { 3375 try argv.append("-nostdinc++"); 3376 } 3377 3378 // We don't ever put `-fcolor-diagnostics` or `-fno-color-diagnostics` because in passthrough mode 3379 // we want Clang to infer it, and in normal mode we always want it off, which will be true since 3380 // clang will detect stderr as a pipe rather than a terminal. 3381 if (!comp.clang_passthrough_mode) { 3382 // Make stderr more easily parseable. 3383 try argv.append("-fno-caret-diagnostics"); 3384 } 3385 3386 if (comp.bin_file.options.function_sections) { 3387 try argv.append("-ffunction-sections"); 3388 } 3389 3390 if (comp.bin_file.options.link_libcpp) { 3391 const libcxx_include_path = try std.fs.path.join(arena, &[_][]const u8{ 3392 comp.zig_lib_directory.path.?, "libcxx", "include", 3393 }); 3394 const libcxxabi_include_path = try std.fs.path.join(arena, &[_][]const u8{ 3395 comp.zig_lib_directory.path.?, "libcxxabi", "include", 3396 }); 3397 3398 try argv.append("-isystem"); 3399 try argv.append(libcxx_include_path); 3400 3401 try argv.append("-isystem"); 3402 try argv.append(libcxxabi_include_path); 3403 3404 if (target.abi.isMusl()) { 3405 try argv.append("-D_LIBCPP_HAS_MUSL_LIBC"); 3406 } 3407 try argv.append("-D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS"); 3408 try argv.append("-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS"); 3409 try argv.append("-D_LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS"); 3410 } 3411 3412 if (comp.bin_file.options.link_libunwind) { 3413 const libunwind_include_path = try std.fs.path.join(arena, &[_][]const u8{ 3414 comp.zig_lib_directory.path.?, "libunwind", "include", 3415 }); 3416 3417 try argv.append("-isystem"); 3418 try argv.append(libunwind_include_path); 3419 } 3420 3421 if (comp.bin_file.options.link_libc and target.isGnuLibC()) { 3422 const target_version = target.os.version_range.linux.glibc; 3423 const glibc_minor_define = try std.fmt.allocPrint(arena, "-D__GLIBC_MINOR__={d}", .{ 3424 target_version.minor, 3425 }); 3426 try argv.append(glibc_minor_define); 3427 } 3428 3429 const llvm_triple = try @import("codegen/llvm.zig").targetTriple(arena, target); 3430 try argv.appendSlice(&[_][]const u8{ "-target", llvm_triple }); 3431 3432 switch (ext) { 3433 .c, .cpp, .m, .mm, .h => { 3434 try argv.appendSlice(&[_][]const u8{ 3435 "-nostdinc", 3436 "-fno-spell-checking", 3437 }); 3438 if (comp.bin_file.options.lto) { 3439 try argv.append("-flto"); 3440 } 3441 3442 if (ext == .mm) { 3443 try argv.append("-ObjC++"); 3444 } 3445 3446 // According to Rich Felker libc headers are supposed to go before C language headers. 3447 // However as noted by @dimenus, appending libc headers before c_headers breaks intrinsics 3448 // and other compiler specific items. 3449 const c_headers_dir = try std.fs.path.join(arena, &[_][]const u8{ comp.zig_lib_directory.path.?, "include" }); 3450 try argv.append("-isystem"); 3451 try argv.append(c_headers_dir); 3452 3453 for (comp.libc_include_dir_list) |include_dir| { 3454 try argv.append("-isystem"); 3455 try argv.append(include_dir); 3456 } 3457 3458 if (target.cpu.model.llvm_name) |llvm_name| { 3459 try argv.appendSlice(&[_][]const u8{ 3460 "-Xclang", "-target-cpu", "-Xclang", llvm_name, 3461 }); 3462 } 3463 3464 // It would be really nice if there was a more compact way to communicate this info to Clang. 3465 const all_features_list = target.cpu.arch.allFeaturesList(); 3466 try argv.ensureUnusedCapacity(all_features_list.len * 4); 3467 for (all_features_list) |feature, index_usize| { 3468 const index = @intCast(std.Target.Cpu.Feature.Set.Index, index_usize); 3469 const is_enabled = target.cpu.features.isEnabled(index); 3470 3471 if (feature.llvm_name) |llvm_name| { 3472 argv.appendSliceAssumeCapacity(&[_][]const u8{ "-Xclang", "-target-feature", "-Xclang" }); 3473 const plus_or_minus = "-+"[@boolToInt(is_enabled)]; 3474 const arg = try std.fmt.allocPrint(arena, "{c}{s}", .{ plus_or_minus, llvm_name }); 3475 argv.appendAssumeCapacity(arg); 3476 } 3477 } 3478 const mcmodel = comp.bin_file.options.machine_code_model; 3479 if (mcmodel != .default) { 3480 try argv.append(try std.fmt.allocPrint(arena, "-mcmodel={s}", .{@tagName(mcmodel)})); 3481 } 3482 3483 switch (target.os.tag) { 3484 .windows => { 3485 // windows.h has files such as pshpack1.h which do #pragma packing, 3486 // triggering a clang warning. So for this target, we disable this warning. 3487 if (target.abi.isGnu()) { 3488 try argv.append("-Wno-pragma-pack"); 3489 } 3490 }, 3491 .macos => { 3492 // Pass the proper -m<os>-version-min argument for darwin. 3493 const ver = target.os.version_range.semver.min; 3494 try argv.append(try std.fmt.allocPrint(arena, "-mmacos-version-min={d}.{d}.{d}", .{ 3495 ver.major, ver.minor, ver.patch, 3496 })); 3497 }, 3498 .ios, .tvos, .watchos => switch (target.cpu.arch) { 3499 // Pass the proper -m<os>-version-min argument for darwin. 3500 .i386, .x86_64 => { 3501 const ver = target.os.version_range.semver.min; 3502 try argv.append(try std.fmt.allocPrint( 3503 arena, 3504 "-m{s}-simulator-version-min={d}.{d}.{d}", 3505 .{ @tagName(target.os.tag), ver.major, ver.minor, ver.patch }, 3506 )); 3507 }, 3508 else => { 3509 const ver = target.os.version_range.semver.min; 3510 try argv.append(try std.fmt.allocPrint(arena, "-m{s}-version-min={d}.{d}.{d}", .{ 3511 @tagName(target.os.tag), ver.major, ver.minor, ver.patch, 3512 })); 3513 }, 3514 }, 3515 else => {}, 3516 } 3517 3518 if (!comp.bin_file.options.strip) { 3519 try argv.append("-g"); 3520 switch (comp.bin_file.options.object_format) { 3521 .coff => try argv.append("-gcodeview"), 3522 else => {}, 3523 } 3524 } 3525 3526 if (target.cpu.arch.isThumb()) { 3527 try argv.append("-mthumb"); 3528 } 3529 3530 if (comp.sanitize_c and !comp.bin_file.options.tsan) { 3531 try argv.append("-fsanitize=undefined"); 3532 try argv.append("-fsanitize-trap=undefined"); 3533 } else if (comp.sanitize_c and comp.bin_file.options.tsan) { 3534 try argv.append("-fsanitize=undefined,thread"); 3535 try argv.append("-fsanitize-trap=undefined"); 3536 } else if (!comp.sanitize_c and comp.bin_file.options.tsan) { 3537 try argv.append("-fsanitize=thread"); 3538 } 3539 3540 if (comp.bin_file.options.red_zone) { 3541 try argv.append("-mred-zone"); 3542 } else if (target_util.hasRedZone(target)) { 3543 try argv.append("-mno-red-zone"); 3544 } 3545 3546 if (comp.bin_file.options.omit_frame_pointer) { 3547 try argv.append("-fomit-frame-pointer"); 3548 } else { 3549 try argv.append("-fno-omit-frame-pointer"); 3550 } 3551 3552 switch (comp.bin_file.options.optimize_mode) { 3553 .Debug => { 3554 // windows c runtime requires -D_DEBUG if using debug libraries 3555 try argv.append("-D_DEBUG"); 3556 try argv.append("-Og"); 3557 3558 if (comp.bin_file.options.link_libc and target.os.tag != .wasi) { 3559 try argv.append("-fstack-protector-strong"); 3560 try argv.append("--param"); 3561 try argv.append("ssp-buffer-size=4"); 3562 } else { 3563 try argv.append("-fno-stack-protector"); 3564 } 3565 }, 3566 .ReleaseSafe => { 3567 // See the comment in the BuildModeFastRelease case for why we pass -O2 rather 3568 // than -O3 here. 3569 try argv.append("-O2"); 3570 if (comp.bin_file.options.link_libc and target.os.tag != .wasi) { 3571 try argv.append("-D_FORTIFY_SOURCE=2"); 3572 try argv.append("-fstack-protector-strong"); 3573 try argv.append("--param"); 3574 try argv.append("ssp-buffer-size=4"); 3575 } else { 3576 try argv.append("-fno-stack-protector"); 3577 } 3578 }, 3579 .ReleaseFast => { 3580 try argv.append("-DNDEBUG"); 3581 // Here we pass -O2 rather than -O3 because, although we do the equivalent of 3582 // -O3 in Zig code, the justification for the difference here is that Zig 3583 // has better detection and prevention of undefined behavior, so -O3 is safer for 3584 // Zig code than it is for C code. Also, C programmers are used to their code 3585 // running in -O2 and thus the -O3 path has been tested less. 3586 try argv.append("-O2"); 3587 try argv.append("-fno-stack-protector"); 3588 }, 3589 .ReleaseSmall => { 3590 try argv.append("-DNDEBUG"); 3591 try argv.append("-Os"); 3592 try argv.append("-fno-stack-protector"); 3593 }, 3594 } 3595 3596 if (target_util.supports_fpic(target) and comp.bin_file.options.pic) { 3597 try argv.append("-fPIC"); 3598 } 3599 3600 if (comp.unwind_tables) { 3601 try argv.append("-funwind-tables"); 3602 } else { 3603 try argv.append("-fno-unwind-tables"); 3604 } 3605 }, 3606 .shared_library, .ll, .bc, .unknown, .static_library, .object, .zig => {}, 3607 .assembly => { 3608 // The Clang assembler does not accept the list of CPU features like the 3609 // compiler frontend does. Therefore we must hard-code the -m flags for 3610 // all CPU features here. 3611 switch (target.cpu.arch) { 3612 .riscv32, .riscv64 => { 3613 const RvArchFeat = struct { char: u8, feat: std.Target.riscv.Feature }; 3614 const letters = [_]RvArchFeat{ 3615 .{ .char = 'm', .feat = .m }, 3616 .{ .char = 'a', .feat = .a }, 3617 .{ .char = 'f', .feat = .f }, 3618 .{ .char = 'd', .feat = .d }, 3619 .{ .char = 'c', .feat = .c }, 3620 }; 3621 const prefix: []const u8 = if (target.cpu.arch == .riscv64) "rv64" else "rv32"; 3622 const prefix_len = 4; 3623 assert(prefix.len == prefix_len); 3624 var march_buf: [prefix_len + letters.len + 1]u8 = undefined; 3625 var march_index: usize = prefix_len; 3626 mem.copy(u8, &march_buf, prefix); 3627 3628 if (std.Target.riscv.featureSetHas(target.cpu.features, .e)) { 3629 march_buf[march_index] = 'e'; 3630 } else { 3631 march_buf[march_index] = 'i'; 3632 } 3633 march_index += 1; 3634 3635 for (letters) |letter| { 3636 if (std.Target.riscv.featureSetHas(target.cpu.features, letter.feat)) { 3637 march_buf[march_index] = letter.char; 3638 march_index += 1; 3639 } 3640 } 3641 3642 const march_arg = try std.fmt.allocPrint(arena, "-march={s}", .{ 3643 march_buf[0..march_index], 3644 }); 3645 try argv.append(march_arg); 3646 3647 if (std.Target.riscv.featureSetHas(target.cpu.features, .relax)) { 3648 try argv.append("-mrelax"); 3649 } else { 3650 try argv.append("-mno-relax"); 3651 } 3652 if (std.Target.riscv.featureSetHas(target.cpu.features, .save_restore)) { 3653 try argv.append("-msave-restore"); 3654 } else { 3655 try argv.append("-mno-save-restore"); 3656 } 3657 }, 3658 else => { 3659 // TODO 3660 }, 3661 } 3662 if (target_util.clangAssemblerSupportsMcpuArg(target)) { 3663 if (target.cpu.model.llvm_name) |llvm_name| { 3664 try argv.append(try std.fmt.allocPrint(arena, "-mcpu={s}", .{llvm_name})); 3665 } 3666 } 3667 }, 3668 } 3669 3670 if (target_util.llvmMachineAbi(target)) |mabi| { 3671 try argv.append(try std.fmt.allocPrint(arena, "-mabi={s}", .{mabi})); 3672 } 3673 3674 if (out_dep_path) |p| { 3675 try argv.appendSlice(&[_][]const u8{ "-MD", "-MV", "-MF", p }); 3676 } 3677 3678 // We never want clang to invoke the system assembler for anything. So we would want 3679 // this option always enabled. However, it only matters for some targets. To avoid 3680 // "unused parameter" warnings, and to keep CLI spam to a minimum, we only put this 3681 // flag on the command line if it is necessary. 3682 if (target_util.clangMightShellOutForAssembly(target)) { 3683 try argv.append("-integrated-as"); 3684 } 3685 3686 if (target.os.tag == .freestanding) { 3687 try argv.append("-ffreestanding"); 3688 } 3689 3690 try argv.appendSlice(comp.clang_argv); 3691} 3692 3693fn failCObj(comp: *Compilation, c_object: *CObject, comptime format: []const u8, args: anytype) SemaError { 3694 @setCold(true); 3695 const err_msg = blk: { 3696 const msg = try std.fmt.allocPrint(comp.gpa, format, args); 3697 errdefer comp.gpa.free(msg); 3698 const err_msg = try comp.gpa.create(CObject.ErrorMsg); 3699 errdefer comp.gpa.destroy(err_msg); 3700 err_msg.* = .{ 3701 .msg = msg, 3702 .line = 0, 3703 .column = 0, 3704 }; 3705 break :blk err_msg; 3706 }; 3707 return comp.failCObjWithOwnedErrorMsg(c_object, err_msg); 3708} 3709 3710fn failCObjWithOwnedErrorMsg( 3711 comp: *Compilation, 3712 c_object: *CObject, 3713 err_msg: *CObject.ErrorMsg, 3714) SemaError { 3715 @setCold(true); 3716 { 3717 comp.mutex.lock(); 3718 defer comp.mutex.unlock(); 3719 { 3720 errdefer err_msg.destroy(comp.gpa); 3721 try comp.failed_c_objects.ensureUnusedCapacity(comp.gpa, 1); 3722 } 3723 comp.failed_c_objects.putAssumeCapacityNoClobber(c_object, err_msg); 3724 } 3725 c_object.status = .failure; 3726 return error.AnalysisFail; 3727} 3728 3729pub const FileExt = enum { 3730 c, 3731 cpp, 3732 h, 3733 m, 3734 mm, 3735 ll, 3736 bc, 3737 assembly, 3738 shared_library, 3739 object, 3740 static_library, 3741 zig, 3742 unknown, 3743 3744 pub fn clangSupportsDepFile(ext: FileExt) bool { 3745 return switch (ext) { 3746 .c, .cpp, .h, .m, .mm => true, 3747 3748 .ll, 3749 .bc, 3750 .assembly, 3751 .shared_library, 3752 .object, 3753 .static_library, 3754 .zig, 3755 .unknown, 3756 => false, 3757 }; 3758 } 3759}; 3760 3761pub fn hasObjectExt(filename: []const u8) bool { 3762 return mem.endsWith(u8, filename, ".o") or mem.endsWith(u8, filename, ".obj"); 3763} 3764 3765pub fn hasStaticLibraryExt(filename: []const u8) bool { 3766 return mem.endsWith(u8, filename, ".a") or mem.endsWith(u8, filename, ".lib"); 3767} 3768 3769pub fn hasCExt(filename: []const u8) bool { 3770 return mem.endsWith(u8, filename, ".c"); 3771} 3772 3773pub fn hasCppExt(filename: []const u8) bool { 3774 return mem.endsWith(u8, filename, ".C") or 3775 mem.endsWith(u8, filename, ".cc") or 3776 mem.endsWith(u8, filename, ".cpp") or 3777 mem.endsWith(u8, filename, ".cxx"); 3778} 3779 3780pub fn hasObjCExt(filename: []const u8) bool { 3781 return mem.endsWith(u8, filename, ".m"); 3782} 3783 3784pub fn hasObjCppExt(filename: []const u8) bool { 3785 return mem.endsWith(u8, filename, ".mm"); 3786} 3787 3788pub fn hasAsmExt(filename: []const u8) bool { 3789 return mem.endsWith(u8, filename, ".s") or mem.endsWith(u8, filename, ".S"); 3790} 3791 3792pub fn hasSharedLibraryExt(filename: []const u8) bool { 3793 if (mem.endsWith(u8, filename, ".so") or 3794 mem.endsWith(u8, filename, ".dll") or 3795 mem.endsWith(u8, filename, ".dylib") or 3796 mem.endsWith(u8, filename, ".tbd")) 3797 { 3798 return true; 3799 } 3800 // Look for .so.X, .so.X.Y, .so.X.Y.Z 3801 var it = mem.split(u8, filename, "."); 3802 _ = it.next().?; 3803 var so_txt = it.next() orelse return false; 3804 while (!mem.eql(u8, so_txt, "so")) { 3805 so_txt = it.next() orelse return false; 3806 } 3807 const n1 = it.next() orelse return false; 3808 const n2 = it.next(); 3809 const n3 = it.next(); 3810 3811 _ = std.fmt.parseInt(u32, n1, 10) catch return false; 3812 if (n2) |x| _ = std.fmt.parseInt(u32, x, 10) catch return false; 3813 if (n3) |x| _ = std.fmt.parseInt(u32, x, 10) catch return false; 3814 if (it.next() != null) return false; 3815 3816 return true; 3817} 3818 3819pub fn classifyFileExt(filename: []const u8) FileExt { 3820 if (hasCExt(filename)) { 3821 return .c; 3822 } else if (hasCppExt(filename)) { 3823 return .cpp; 3824 } else if (hasObjCExt(filename)) { 3825 return .m; 3826 } else if (hasObjCppExt(filename)) { 3827 return .mm; 3828 } else if (mem.endsWith(u8, filename, ".ll")) { 3829 return .ll; 3830 } else if (mem.endsWith(u8, filename, ".bc")) { 3831 return .bc; 3832 } else if (hasAsmExt(filename)) { 3833 return .assembly; 3834 } else if (mem.endsWith(u8, filename, ".h")) { 3835 return .h; 3836 } else if (mem.endsWith(u8, filename, ".zig")) { 3837 return .zig; 3838 } else if (hasSharedLibraryExt(filename)) { 3839 return .shared_library; 3840 } else if (hasStaticLibraryExt(filename)) { 3841 return .static_library; 3842 } else if (hasObjectExt(filename)) { 3843 return .object; 3844 } else { 3845 return .unknown; 3846 } 3847} 3848 3849test "classifyFileExt" { 3850 try std.testing.expectEqual(FileExt.cpp, classifyFileExt("foo.cc")); 3851 try std.testing.expectEqual(FileExt.m, classifyFileExt("foo.m")); 3852 try std.testing.expectEqual(FileExt.mm, classifyFileExt("foo.mm")); 3853 try std.testing.expectEqual(FileExt.unknown, classifyFileExt("foo.nim")); 3854 try std.testing.expectEqual(FileExt.shared_library, classifyFileExt("foo.so")); 3855 try std.testing.expectEqual(FileExt.shared_library, classifyFileExt("foo.so.1")); 3856 try std.testing.expectEqual(FileExt.shared_library, classifyFileExt("foo.so.1.2")); 3857 try std.testing.expectEqual(FileExt.shared_library, classifyFileExt("foo.so.1.2.3")); 3858 try std.testing.expectEqual(FileExt.unknown, classifyFileExt("foo.so.1.2.3~")); 3859 try std.testing.expectEqual(FileExt.zig, classifyFileExt("foo.zig")); 3860} 3861 3862const LibCDirs = struct { 3863 libc_include_dir_list: []const []const u8, 3864 libc_installation: ?*const LibCInstallation, 3865}; 3866 3867fn getZigShippedLibCIncludeDirsDarwin(arena: Allocator, zig_lib_dir: []const u8, target: Target) !LibCDirs { 3868 const arch_name = @tagName(target.cpu.arch); 3869 const os_name = try std.fmt.allocPrint(arena, "{s}.{d}", .{ 3870 @tagName(target.os.tag), 3871 target.os.version_range.semver.min.major, 3872 }); 3873 const s = std.fs.path.sep_str; 3874 const list = try arena.alloc([]const u8, 3); 3875 3876 list[0] = try std.fmt.allocPrint( 3877 arena, 3878 "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "{s}-{s}-gnu", 3879 .{ zig_lib_dir, arch_name, os_name }, 3880 ); 3881 list[1] = try std.fmt.allocPrint( 3882 arena, 3883 "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "any-{s}-any", 3884 .{ zig_lib_dir, os_name }, 3885 ); 3886 list[2] = try std.fmt.allocPrint( 3887 arena, 3888 "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "any-macos-any", 3889 .{zig_lib_dir}, 3890 ); 3891 3892 return LibCDirs{ 3893 .libc_include_dir_list = list, 3894 .libc_installation = null, 3895 }; 3896} 3897 3898fn detectLibCIncludeDirs( 3899 arena: Allocator, 3900 zig_lib_dir: []const u8, 3901 target: Target, 3902 is_native_abi: bool, 3903 link_libc: bool, 3904 link_system_libs: bool, 3905 libc_installation: ?*const LibCInstallation, 3906 has_macos_sdk: bool, 3907) !LibCDirs { 3908 if (!link_libc) { 3909 return LibCDirs{ 3910 .libc_include_dir_list = &[0][]u8{}, 3911 .libc_installation = null, 3912 }; 3913 } 3914 3915 if (libc_installation) |lci| { 3916 return detectLibCFromLibCInstallation(arena, target, lci); 3917 } 3918 3919 // If linking system libraries and targeting the native abi, default to 3920 // using the system libc installation. 3921 if (link_system_libs and is_native_abi and !target.isMinGW()) { 3922 if (target.isDarwin()) { 3923 return if (has_macos_sdk) 3924 // For Darwin/macOS, we are all set with getDarwinSDK found earlier. 3925 LibCDirs{ 3926 .libc_include_dir_list = &[0][]u8{}, 3927 .libc_installation = null, 3928 } 3929 else 3930 getZigShippedLibCIncludeDirsDarwin(arena, zig_lib_dir, target); 3931 } 3932 const libc = try arena.create(LibCInstallation); 3933 libc.* = try LibCInstallation.findNative(.{ .allocator = arena, .verbose = true }); 3934 return detectLibCFromLibCInstallation(arena, target, libc); 3935 } 3936 3937 // If not linking system libraries, build and provide our own libc by 3938 // default if possible. 3939 if (target_util.canBuildLibC(target)) { 3940 switch (target.os.tag) { 3941 .macos => return if (has_macos_sdk) 3942 // For Darwin/macOS, we are all set with getDarwinSDK found earlier. 3943 LibCDirs{ 3944 .libc_include_dir_list = &[0][]u8{}, 3945 .libc_installation = null, 3946 } 3947 else 3948 getZigShippedLibCIncludeDirsDarwin(arena, zig_lib_dir, target), 3949 else => { 3950 const generic_name = target_util.libCGenericName(target); 3951 // Some architectures are handled by the same set of headers. 3952 const arch_name = if (target.abi.isMusl()) 3953 musl.archName(target.cpu.arch) 3954 else if (target.cpu.arch.isThumb()) 3955 // ARM headers are valid for Thumb too. 3956 switch (target.cpu.arch) { 3957 .thumb => "arm", 3958 .thumbeb => "armeb", 3959 else => unreachable, 3960 } 3961 else 3962 @tagName(target.cpu.arch); 3963 const os_name = @tagName(target.os.tag); 3964 // Musl's headers are ABI-agnostic and so they all have the "musl" ABI name. 3965 const abi_name = if (target.abi.isMusl()) "musl" else @tagName(target.abi); 3966 const s = std.fs.path.sep_str; 3967 const arch_include_dir = try std.fmt.allocPrint( 3968 arena, 3969 "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "{s}-{s}-{s}", 3970 .{ zig_lib_dir, arch_name, os_name, abi_name }, 3971 ); 3972 const generic_include_dir = try std.fmt.allocPrint( 3973 arena, 3974 "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "generic-{s}", 3975 .{ zig_lib_dir, generic_name }, 3976 ); 3977 const generic_arch_name = target_util.osArchName(target); 3978 const arch_os_include_dir = try std.fmt.allocPrint( 3979 arena, 3980 "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "{s}-{s}-any", 3981 .{ zig_lib_dir, generic_arch_name, os_name }, 3982 ); 3983 const generic_os_include_dir = try std.fmt.allocPrint( 3984 arena, 3985 "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "any-{s}-any", 3986 .{ zig_lib_dir, os_name }, 3987 ); 3988 3989 const list = try arena.alloc([]const u8, 4); 3990 list[0] = arch_include_dir; 3991 list[1] = generic_include_dir; 3992 list[2] = arch_os_include_dir; 3993 list[3] = generic_os_include_dir; 3994 3995 return LibCDirs{ 3996 .libc_include_dir_list = list, 3997 .libc_installation = null, 3998 }; 3999 }, 4000 } 4001 } 4002 4003 // If zig can't build the libc for the target and we are targeting the 4004 // native abi, fall back to using the system libc installation. 4005 // On windows, instead of the native (mingw) abi, we want to check 4006 // for the MSVC abi as a fallback. 4007 const use_system_abi = if (builtin.target.os.tag == .windows) 4008 target.abi == .msvc 4009 else 4010 is_native_abi; 4011 4012 if (use_system_abi) { 4013 const libc = try arena.create(LibCInstallation); 4014 libc.* = try LibCInstallation.findNative(.{ .allocator = arena, .verbose = true }); 4015 return detectLibCFromLibCInstallation(arena, target, libc); 4016 } 4017 4018 return LibCDirs{ 4019 .libc_include_dir_list = &[0][]u8{}, 4020 .libc_installation = null, 4021 }; 4022} 4023 4024fn detectLibCFromLibCInstallation(arena: Allocator, target: Target, lci: *const LibCInstallation) !LibCDirs { 4025 var list = try std.ArrayList([]const u8).initCapacity(arena, 4); 4026 4027 list.appendAssumeCapacity(lci.include_dir.?); 4028 4029 const is_redundant = mem.eql(u8, lci.sys_include_dir.?, lci.include_dir.?); 4030 if (!is_redundant) list.appendAssumeCapacity(lci.sys_include_dir.?); 4031 4032 if (target.os.tag == .windows) { 4033 if (std.fs.path.dirname(lci.include_dir.?)) |include_dir_parent| { 4034 const um_dir = try std.fs.path.join(arena, &[_][]const u8{ include_dir_parent, "um" }); 4035 list.appendAssumeCapacity(um_dir); 4036 4037 const shared_dir = try std.fs.path.join(arena, &[_][]const u8{ include_dir_parent, "shared" }); 4038 list.appendAssumeCapacity(shared_dir); 4039 } 4040 } 4041 if (target.os.tag == .haiku) { 4042 const include_dir_path = lci.include_dir orelse return error.LibCInstallationNotAvailable; 4043 const os_dir = try std.fs.path.join(arena, &[_][]const u8{ include_dir_path, "os" }); 4044 list.appendAssumeCapacity(os_dir); 4045 4046 const config_dir = try std.fs.path.join(arena, &[_][]const u8{ include_dir_path, "config" }); 4047 list.appendAssumeCapacity(config_dir); 4048 } 4049 4050 return LibCDirs{ 4051 .libc_include_dir_list = list.items, 4052 .libc_installation = lci, 4053 }; 4054} 4055 4056pub fn get_libc_crt_file(comp: *Compilation, arena: Allocator, basename: []const u8) ![]const u8 { 4057 if (comp.wantBuildGLibCFromSource() or 4058 comp.wantBuildMuslFromSource() or 4059 comp.wantBuildMinGWFromSource() or 4060 comp.wantBuildWasiLibcFromSource()) 4061 { 4062 return comp.crt_files.get(basename).?.full_object_path; 4063 } 4064 const lci = comp.bin_file.options.libc_installation orelse return error.LibCInstallationNotAvailable; 4065 const crt_dir_path = lci.crt_dir orelse return error.LibCInstallationMissingCRTDir; 4066 const full_path = try std.fs.path.join(arena, &[_][]const u8{ crt_dir_path, basename }); 4067 return full_path; 4068} 4069 4070fn wantBuildLibCFromSource(comp: Compilation) bool { 4071 const is_exe_or_dyn_lib = switch (comp.bin_file.options.output_mode) { 4072 .Obj => false, 4073 .Lib => comp.bin_file.options.link_mode == .Dynamic, 4074 .Exe => true, 4075 }; 4076 return comp.bin_file.options.link_libc and is_exe_or_dyn_lib and 4077 comp.bin_file.options.libc_installation == null and 4078 comp.bin_file.options.object_format != .c; 4079} 4080 4081fn wantBuildGLibCFromSource(comp: Compilation) bool { 4082 return comp.wantBuildLibCFromSource() and comp.getTarget().isGnuLibC(); 4083} 4084 4085fn wantBuildMuslFromSource(comp: Compilation) bool { 4086 return comp.wantBuildLibCFromSource() and comp.getTarget().isMusl() and 4087 !comp.getTarget().isWasm(); 4088} 4089 4090fn wantBuildWasiLibcFromSource(comp: Compilation) bool { 4091 return comp.wantBuildLibCFromSource() and comp.getTarget().isWasm() and 4092 comp.getTarget().os.tag == .wasi; 4093} 4094 4095fn wantBuildMinGWFromSource(comp: Compilation) bool { 4096 return comp.wantBuildLibCFromSource() and comp.getTarget().isMinGW(); 4097} 4098 4099fn wantBuildLibUnwindFromSource(comp: *Compilation) bool { 4100 const is_exe_or_dyn_lib = switch (comp.bin_file.options.output_mode) { 4101 .Obj => false, 4102 .Lib => comp.bin_file.options.link_mode == .Dynamic, 4103 .Exe => true, 4104 }; 4105 return is_exe_or_dyn_lib and comp.bin_file.options.link_libunwind and 4106 comp.bin_file.options.object_format != .c; 4107} 4108 4109fn setMiscFailure( 4110 comp: *Compilation, 4111 tag: MiscTask, 4112 comptime format: []const u8, 4113 args: anytype, 4114) Allocator.Error!void { 4115 try comp.misc_failures.ensureUnusedCapacity(comp.gpa, 1); 4116 const msg = try std.fmt.allocPrint(comp.gpa, format, args); 4117 const gop = comp.misc_failures.getOrPutAssumeCapacity(tag); 4118 if (gop.found_existing) { 4119 gop.value_ptr.deinit(comp.gpa); 4120 } 4121 gop.value_ptr.* = .{ .msg = msg }; 4122} 4123 4124pub fn dump_argv(argv: []const []const u8) void { 4125 for (argv[0 .. argv.len - 1]) |arg| { 4126 std.debug.print("{s} ", .{arg}); 4127 } 4128 std.debug.print("{s}\n", .{argv[argv.len - 1]}); 4129} 4130 4131pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Allocator.Error![:0]u8 { 4132 const tracy_trace = trace(@src()); 4133 defer tracy_trace.end(); 4134 4135 var buffer = std.ArrayList(u8).init(allocator); 4136 defer buffer.deinit(); 4137 4138 const target = comp.getTarget(); 4139 const generic_arch_name = target.cpu.arch.genericName(); 4140 const use_stage1 = build_options.is_stage1 and comp.bin_file.options.use_stage1; 4141 const stage2_x86_cx16 = target.cpu.arch == .x86_64 and 4142 std.Target.x86.featureSetHas(target.cpu.features, .cx16); 4143 4144 @setEvalBranchQuota(4000); 4145 try buffer.writer().print( 4146 \\const std = @import("std"); 4147 \\/// Zig version. When writing code that supports multiple versions of Zig, prefer 4148 \\/// feature detection (i.e. with `@hasDecl` or `@hasField`) over version checks. 4149 \\pub const zig_version = std.SemanticVersion.parse("{s}") catch unreachable; 4150 \\/// Temporary until self-hosted is feature complete. 4151 \\pub const zig_is_stage2 = {}; 4152 \\/// Temporary until self-hosted supports the `cpu.arch` value. 4153 \\pub const stage2_arch: std.Target.Cpu.Arch = .{}; 4154 \\/// Temporary until self-hosted can call `std.Target.x86.featureSetHas` at comptime. 4155 \\pub const stage2_x86_cx16 = {}; 4156 \\ 4157 \\pub const output_mode = std.builtin.OutputMode.{}; 4158 \\pub const link_mode = std.builtin.LinkMode.{}; 4159 \\pub const is_test = {}; 4160 \\pub const single_threaded = {}; 4161 \\pub const abi = std.Target.Abi.{}; 4162 \\pub const cpu: std.Target.Cpu = .{{ 4163 \\ .arch = .{}, 4164 \\ .model = &std.Target.{}.cpu.{}, 4165 \\ .features = std.Target.{}.featureSet(&[_]std.Target.{}.Feature{{ 4166 \\ 4167 , .{ 4168 build_options.version, 4169 !use_stage1, 4170 std.zig.fmtId(@tagName(target.cpu.arch)), 4171 stage2_x86_cx16, 4172 std.zig.fmtId(@tagName(comp.bin_file.options.output_mode)), 4173 std.zig.fmtId(@tagName(comp.bin_file.options.link_mode)), 4174 comp.bin_file.options.is_test, 4175 comp.bin_file.options.single_threaded, 4176 std.zig.fmtId(@tagName(target.abi)), 4177 std.zig.fmtId(@tagName(target.cpu.arch)), 4178 std.zig.fmtId(generic_arch_name), 4179 std.zig.fmtId(target.cpu.model.name), 4180 std.zig.fmtId(generic_arch_name), 4181 std.zig.fmtId(generic_arch_name), 4182 }); 4183 4184 for (target.cpu.arch.allFeaturesList()) |feature, index_usize| { 4185 const index = @intCast(std.Target.Cpu.Feature.Set.Index, index_usize); 4186 const is_enabled = target.cpu.features.isEnabled(index); 4187 if (is_enabled) { 4188 try buffer.writer().print(" .{},\n", .{std.zig.fmtId(feature.name)}); 4189 } 4190 } 4191 4192 try buffer.writer().print( 4193 \\ }}), 4194 \\}}; 4195 \\pub const os = std.Target.Os{{ 4196 \\ .tag = .{}, 4197 \\ .version_range = .{{ 4198 , 4199 .{std.zig.fmtId(@tagName(target.os.tag))}, 4200 ); 4201 4202 switch (target.os.getVersionRange()) { 4203 .none => try buffer.appendSlice(" .none = {} }\n"), 4204 .semver => |semver| try buffer.writer().print( 4205 \\ .semver = .{{ 4206 \\ .min = .{{ 4207 \\ .major = {}, 4208 \\ .minor = {}, 4209 \\ .patch = {}, 4210 \\ }}, 4211 \\ .max = .{{ 4212 \\ .major = {}, 4213 \\ .minor = {}, 4214 \\ .patch = {}, 4215 \\ }}, 4216 \\ }}}}, 4217 \\ 4218 , .{ 4219 semver.min.major, 4220 semver.min.minor, 4221 semver.min.patch, 4222 4223 semver.max.major, 4224 semver.max.minor, 4225 semver.max.patch, 4226 }), 4227 .linux => |linux| try buffer.writer().print( 4228 \\ .linux = .{{ 4229 \\ .range = .{{ 4230 \\ .min = .{{ 4231 \\ .major = {}, 4232 \\ .minor = {}, 4233 \\ .patch = {}, 4234 \\ }}, 4235 \\ .max = .{{ 4236 \\ .major = {}, 4237 \\ .minor = {}, 4238 \\ .patch = {}, 4239 \\ }}, 4240 \\ }}, 4241 \\ .glibc = .{{ 4242 \\ .major = {}, 4243 \\ .minor = {}, 4244 \\ .patch = {}, 4245 \\ }}, 4246 \\ }}}}, 4247 \\ 4248 , .{ 4249 linux.range.min.major, 4250 linux.range.min.minor, 4251 linux.range.min.patch, 4252 4253 linux.range.max.major, 4254 linux.range.max.minor, 4255 linux.range.max.patch, 4256 4257 linux.glibc.major, 4258 linux.glibc.minor, 4259 linux.glibc.patch, 4260 }), 4261 .windows => |windows| try buffer.writer().print( 4262 \\ .windows = .{{ 4263 \\ .min = {s}, 4264 \\ .max = {s}, 4265 \\ }}}}, 4266 \\ 4267 , 4268 .{ windows.min, windows.max }, 4269 ), 4270 } 4271 try buffer.appendSlice("};\n"); 4272 4273 // This is so that compiler_rt and libc.zig libraries know whether they 4274 // will eventually be linked with libc. They make different decisions 4275 // about what to export depending on whether another libc will be linked 4276 // in. For example, compiler_rt will not export the __chkstk symbol if it 4277 // knows libc will provide it, and likewise c.zig will not export memcpy. 4278 const link_libc = comp.bin_file.options.link_libc or 4279 (comp.bin_file.options.skip_linker_dependencies and comp.bin_file.options.parent_compilation_link_libc); 4280 4281 try buffer.writer().print( 4282 \\pub const target = std.Target{{ 4283 \\ .cpu = cpu, 4284 \\ .os = os, 4285 \\ .abi = abi, 4286 \\}}; 4287 \\pub const object_format = std.Target.ObjectFormat.{}; 4288 \\pub const mode = std.builtin.Mode.{}; 4289 \\pub const link_libc = {}; 4290 \\pub const link_libcpp = {}; 4291 \\pub const have_error_return_tracing = {}; 4292 \\pub const valgrind_support = {}; 4293 \\pub const position_independent_code = {}; 4294 \\pub const position_independent_executable = {}; 4295 \\pub const strip_debug_info = {}; 4296 \\pub const code_model = std.builtin.CodeModel.{}; 4297 \\ 4298 , .{ 4299 std.zig.fmtId(@tagName(comp.bin_file.options.object_format)), 4300 std.zig.fmtId(@tagName(comp.bin_file.options.optimize_mode)), 4301 link_libc, 4302 comp.bin_file.options.link_libcpp, 4303 comp.bin_file.options.error_return_tracing, 4304 comp.bin_file.options.valgrind, 4305 comp.bin_file.options.pic, 4306 comp.bin_file.options.pie, 4307 comp.bin_file.options.strip, 4308 std.zig.fmtId(@tagName(comp.bin_file.options.machine_code_model)), 4309 }); 4310 4311 if (target.os.tag == .wasi) { 4312 const wasi_exec_model_fmt = std.zig.fmtId(@tagName(comp.bin_file.options.wasi_exec_model)); 4313 try buffer.writer().print( 4314 \\pub const wasi_exec_model = std.builtin.WasiExecModel.{}; 4315 \\ 4316 , .{wasi_exec_model_fmt}); 4317 } 4318 4319 if (comp.bin_file.options.is_test) { 4320 try buffer.appendSlice( 4321 \\pub var test_functions: []std.builtin.TestFn = undefined; // overwritten later 4322 \\ 4323 ); 4324 if (comp.test_evented_io) { 4325 try buffer.appendSlice( 4326 \\pub const test_io_mode = .evented; 4327 \\ 4328 ); 4329 } else { 4330 try buffer.appendSlice( 4331 \\pub const test_io_mode = .blocking; 4332 \\ 4333 ); 4334 } 4335 } 4336 4337 return buffer.toOwnedSliceSentinel(0); 4338} 4339 4340pub fn updateSubCompilation(sub_compilation: *Compilation) !void { 4341 try sub_compilation.update(); 4342 4343 // Look for compilation errors in this sub_compilation 4344 // TODO instead of logging these errors, handle them in the callsites 4345 // of updateSubCompilation and attach them as sub-errors, properly 4346 // surfacing the errors. You can see an example of this already 4347 // done inside buildOutputFromZig. 4348 var errors = try sub_compilation.getAllErrorsAlloc(); 4349 defer errors.deinit(sub_compilation.gpa); 4350 4351 if (errors.list.len != 0) { 4352 for (errors.list) |full_err_msg| { 4353 switch (full_err_msg) { 4354 .src => |src| { 4355 log.err("{s}:{d}:{d}: {s}", .{ 4356 src.src_path, 4357 src.line + 1, 4358 src.column + 1, 4359 src.msg, 4360 }); 4361 }, 4362 .plain => |plain| { 4363 log.err("{s}", .{plain.msg}); 4364 }, 4365 } 4366 } 4367 return error.BuildingLibCObjectFailed; 4368 } 4369} 4370 4371fn buildOutputFromZig( 4372 comp: *Compilation, 4373 src_basename: []const u8, 4374 output_mode: std.builtin.OutputMode, 4375 out: *?CRTFile, 4376 misc_task_tag: MiscTask, 4377) !void { 4378 const tracy_trace = trace(@src()); 4379 defer tracy_trace.end(); 4380 4381 std.debug.assert(output_mode != .Exe); 4382 const special_sub = "std" ++ std.fs.path.sep_str ++ "special"; 4383 const special_path = try comp.zig_lib_directory.join(comp.gpa, &[_][]const u8{special_sub}); 4384 defer comp.gpa.free(special_path); 4385 4386 var special_dir = try comp.zig_lib_directory.handle.openDir(special_sub, .{}); 4387 defer special_dir.close(); 4388 4389 var main_pkg: Package = .{ 4390 .root_src_directory = .{ 4391 .path = special_path, 4392 .handle = special_dir, 4393 }, 4394 .root_src_path = src_basename, 4395 }; 4396 defer main_pkg.deinitTable(comp.gpa); 4397 const root_name = src_basename[0 .. src_basename.len - std.fs.path.extension(src_basename).len]; 4398 const target = comp.getTarget(); 4399 const bin_basename = try std.zig.binNameAlloc(comp.gpa, .{ 4400 .root_name = root_name, 4401 .target = target, 4402 .output_mode = output_mode, 4403 }); 4404 defer comp.gpa.free(bin_basename); 4405 4406 const emit_bin = Compilation.EmitLoc{ 4407 .directory = null, // Put it in the cache directory. 4408 .basename = bin_basename, 4409 }; 4410 const sub_compilation = try Compilation.create(comp.gpa, .{ 4411 .global_cache_directory = comp.global_cache_directory, 4412 .local_cache_directory = comp.global_cache_directory, 4413 .zig_lib_directory = comp.zig_lib_directory, 4414 .target = target, 4415 .root_name = root_name, 4416 .main_pkg = &main_pkg, 4417 .output_mode = output_mode, 4418 .thread_pool = comp.thread_pool, 4419 .libc_installation = comp.bin_file.options.libc_installation, 4420 .emit_bin = emit_bin, 4421 .optimize_mode = comp.compilerRtOptMode(), 4422 .link_mode = .Static, 4423 .function_sections = true, 4424 .want_sanitize_c = false, 4425 .want_stack_check = false, 4426 .want_red_zone = comp.bin_file.options.red_zone, 4427 .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer, 4428 .want_valgrind = false, 4429 .want_tsan = false, 4430 .want_pic = comp.bin_file.options.pic, 4431 .want_pie = comp.bin_file.options.pie, 4432 .emit_h = null, 4433 .strip = comp.compilerRtStrip(), 4434 .is_native_os = comp.bin_file.options.is_native_os, 4435 .is_native_abi = comp.bin_file.options.is_native_abi, 4436 .self_exe_path = comp.self_exe_path, 4437 .verbose_cc = comp.verbose_cc, 4438 .verbose_link = comp.bin_file.options.verbose_link, 4439 .verbose_air = comp.verbose_air, 4440 .verbose_llvm_ir = comp.verbose_llvm_ir, 4441 .verbose_cimport = comp.verbose_cimport, 4442 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, 4443 .clang_passthrough_mode = comp.clang_passthrough_mode, 4444 .skip_linker_dependencies = true, 4445 .parent_compilation_link_libc = comp.bin_file.options.link_libc, 4446 }); 4447 defer sub_compilation.destroy(); 4448 4449 try sub_compilation.update(); 4450 // Look for compilation errors in this sub_compilation. 4451 var keep_errors = false; 4452 var errors = try sub_compilation.getAllErrorsAlloc(); 4453 defer if (!keep_errors) errors.deinit(sub_compilation.gpa); 4454 4455 if (errors.list.len != 0) { 4456 try comp.misc_failures.ensureUnusedCapacity(comp.gpa, 1); 4457 comp.misc_failures.putAssumeCapacityNoClobber(misc_task_tag, .{ 4458 .msg = try std.fmt.allocPrint(comp.gpa, "sub-compilation of {s} failed", .{ 4459 @tagName(misc_task_tag), 4460 }), 4461 .children = errors, 4462 }); 4463 keep_errors = true; 4464 return error.SubCompilationFailed; 4465 } 4466 4467 assert(out.* == null); 4468 out.* = Compilation.CRTFile{ 4469 .full_object_path = try sub_compilation.bin_file.options.emit.?.directory.join(comp.gpa, &[_][]const u8{ 4470 sub_compilation.bin_file.options.emit.?.sub_path, 4471 }), 4472 .lock = sub_compilation.bin_file.toOwnedLock(), 4473 }; 4474} 4475 4476fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node) !void { 4477 const tracy_trace = trace(@src()); 4478 defer tracy_trace.end(); 4479 4480 var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa); 4481 defer arena_allocator.deinit(); 4482 const arena = arena_allocator.allocator(); 4483 4484 // Here we use the legacy stage1 C++ compiler to compile Zig code. 4485 const mod = comp.bin_file.options.module.?; 4486 const directory = mod.zig_cache_artifact_directory; // Just an alias to make it shorter to type. 4487 const main_zig_file = try mod.main_pkg.root_src_directory.join(arena, &[_][]const u8{ 4488 mod.main_pkg.root_src_path, 4489 }); 4490 const zig_lib_dir = comp.zig_lib_directory.path.?; 4491 const builtin_zig_path = try directory.join(arena, &[_][]const u8{"builtin.zig"}); 4492 const target = comp.getTarget(); 4493 const id_symlink_basename = "stage1.id"; 4494 const libs_txt_basename = "libs.txt"; 4495 4496 // The include_compiler_rt stored in the bin file options here means that we need 4497 // compiler-rt symbols *somehow*. However, in the context of using the stage1 backend 4498 // we need to tell stage1 to include compiler-rt only if stage1 is the place that 4499 // needs to provide those symbols. Otherwise the stage2 infrastructure will take care 4500 // of it in the linker, by putting compiler_rt.o into a static archive, or linking 4501 // compiler_rt.a against an executable. In other words we only want to set this flag 4502 // for stage1 if we are using build-obj. 4503 const include_compiler_rt = comp.bin_file.options.output_mode == .Obj and 4504 comp.bin_file.options.include_compiler_rt; 4505 4506 // We are about to obtain this lock, so here we give other processes a chance first. 4507 comp.releaseStage1Lock(); 4508 4509 // Unlike with the self-hosted Zig module, stage1 does not support incremental compilation, 4510 // so we input all the zig source files into the cache hash system. We're going to keep 4511 // the artifact directory the same, however, so we take the same strategy as linking 4512 // does where we have a file which specifies the hash of the output directory so that we can 4513 // skip the expensive compilation step if the hash matches. 4514 var man = comp.cache_parent.obtain(); 4515 defer man.deinit(); 4516 4517 _ = try man.addFile(main_zig_file, null); 4518 { 4519 var seen_table = std.AutoHashMap(*Package, void).init(arena_allocator.allocator()); 4520 try addPackageTableToCacheHash(&man.hash, &arena_allocator, mod.main_pkg.table, &seen_table, .{ .files = &man }); 4521 } 4522 man.hash.add(comp.bin_file.options.valgrind); 4523 man.hash.add(comp.bin_file.options.single_threaded); 4524 man.hash.add(target.os.getVersionRange()); 4525 man.hash.add(comp.bin_file.options.dll_export_fns); 4526 man.hash.add(comp.bin_file.options.function_sections); 4527 man.hash.add(include_compiler_rt); 4528 man.hash.add(comp.bin_file.options.is_test); 4529 man.hash.add(comp.bin_file.options.emit != null); 4530 man.hash.add(mod.emit_h != null); 4531 if (mod.emit_h) |emit_h| { 4532 man.hash.addEmitLoc(emit_h.loc); 4533 } 4534 man.hash.addOptionalEmitLoc(comp.emit_asm); 4535 man.hash.addOptionalEmitLoc(comp.emit_llvm_ir); 4536 man.hash.addOptionalEmitLoc(comp.emit_llvm_bc); 4537 man.hash.addOptionalEmitLoc(comp.emit_analysis); 4538 man.hash.addOptionalEmitLoc(comp.emit_docs); 4539 man.hash.add(comp.test_evented_io); 4540 man.hash.addOptionalBytes(comp.test_filter); 4541 man.hash.addOptionalBytes(comp.test_name_prefix); 4542 man.hash.addListOfBytes(comp.clang_argv); 4543 4544 // Capture the state in case we come back from this branch where the hash doesn't match. 4545 const prev_hash_state = man.hash.peekBin(); 4546 const input_file_count = man.files.items.len; 4547 4548 const hit = man.hit() catch |err| { 4549 const i = man.failed_file_index orelse return err; 4550 const file_path = man.files.items[i].path orelse return err; 4551 fatal("unable to build stage1 zig object: {s}: {s}", .{ @errorName(err), file_path }); 4552 }; 4553 if (hit) { 4554 const digest = man.final(); 4555 4556 // We use an extra hex-encoded byte here to store some flags. 4557 var prev_digest_buf: [digest.len + 2]u8 = undefined; 4558 const prev_digest: []u8 = Cache.readSmallFile( 4559 directory.handle, 4560 id_symlink_basename, 4561 &prev_digest_buf, 4562 ) catch |err| blk: { 4563 log.debug("stage1 {s} new_digest={s} error: {s}", .{ 4564 mod.main_pkg.root_src_path, 4565 std.fmt.fmtSliceHexLower(&digest), 4566 @errorName(err), 4567 }); 4568 // Handle this as a cache miss. 4569 break :blk prev_digest_buf[0..0]; 4570 }; 4571 if (prev_digest.len >= digest.len + 2) hit: { 4572 if (!mem.eql(u8, prev_digest[0..digest.len], &digest)) 4573 break :hit; 4574 4575 log.debug("stage1 {s} digest={s} match - skipping invocation", .{ 4576 mod.main_pkg.root_src_path, 4577 std.fmt.fmtSliceHexLower(&digest), 4578 }); 4579 var flags_bytes: [1]u8 = undefined; 4580 _ = std.fmt.hexToBytes(&flags_bytes, prev_digest[digest.len..]) catch { 4581 log.warn("bad cache stage1 digest: '{s}'", .{std.fmt.fmtSliceHexLower(prev_digest)}); 4582 break :hit; 4583 }; 4584 4585 if (directory.handle.readFileAlloc(comp.gpa, libs_txt_basename, 10 * 1024 * 1024)) |libs_txt| { 4586 var it = mem.tokenize(u8, libs_txt, "\n"); 4587 while (it.next()) |lib_name| { 4588 try comp.stage1AddLinkLib(lib_name); 4589 } 4590 } else |err| switch (err) { 4591 error.FileNotFound => {}, // That's OK, it just means 0 libs. 4592 else => { 4593 log.warn("unable to read cached list of link libs: {s}", .{@errorName(err)}); 4594 break :hit; 4595 }, 4596 } 4597 comp.stage1_lock = man.toOwnedLock(); 4598 mod.stage1_flags = @bitCast(@TypeOf(mod.stage1_flags), flags_bytes[0]); 4599 return; 4600 } 4601 log.debug("stage1 {s} prev_digest={s} new_digest={s}", .{ 4602 mod.main_pkg.root_src_path, 4603 std.fmt.fmtSliceHexLower(prev_digest), 4604 std.fmt.fmtSliceHexLower(&digest), 4605 }); 4606 man.unhit(prev_hash_state, input_file_count); 4607 } 4608 4609 // We are about to change the output file to be different, so we invalidate the build hash now. 4610 directory.handle.deleteFile(id_symlink_basename) catch |err| switch (err) { 4611 error.FileNotFound => {}, 4612 else => |e| return e, 4613 }; 4614 4615 const stage2_target = try arena.create(stage1.Stage2Target); 4616 stage2_target.* = .{ 4617 .arch = @enumToInt(target.cpu.arch) + 1, // skip over ZigLLVM_UnknownArch 4618 .os = @enumToInt(target.os.tag), 4619 .abi = @enumToInt(target.abi), 4620 .is_native_os = comp.bin_file.options.is_native_os, 4621 .is_native_cpu = false, // Only true when bootstrapping the compiler. 4622 .llvm_cpu_name = if (target.cpu.model.llvm_name) |s| s.ptr else null, 4623 .llvm_cpu_features = comp.bin_file.options.llvm_cpu_features.?, 4624 .llvm_target_abi = if (target_util.llvmMachineAbi(target)) |s| s.ptr else null, 4625 }; 4626 4627 comp.stage1_cache_manifest = &man; 4628 4629 const main_pkg_path = mod.main_pkg.root_src_directory.path orelse ""; 4630 4631 const stage1_module = stage1.create( 4632 @enumToInt(comp.bin_file.options.optimize_mode), 4633 main_pkg_path.ptr, 4634 main_pkg_path.len, 4635 main_zig_file.ptr, 4636 main_zig_file.len, 4637 zig_lib_dir.ptr, 4638 zig_lib_dir.len, 4639 stage2_target, 4640 comp.bin_file.options.is_test, 4641 ) orelse return error.OutOfMemory; 4642 4643 const emit_bin_path = if (comp.bin_file.options.emit != null) blk: { 4644 const obj_basename = try std.zig.binNameAlloc(arena, .{ 4645 .root_name = comp.bin_file.options.root_name, 4646 .target = target, 4647 .output_mode = .Obj, 4648 }); 4649 break :blk try directory.join(arena, &[_][]const u8{obj_basename}); 4650 } else ""; 4651 4652 if (mod.emit_h != null) { 4653 log.warn("-femit-h is not available in the stage1 backend; no .h file will be produced", .{}); 4654 } 4655 const emit_h_loc: ?EmitLoc = if (mod.emit_h) |emit_h| emit_h.loc else null; 4656 const emit_h_path = try stage1LocPath(arena, emit_h_loc, directory); 4657 const emit_asm_path = try stage1LocPath(arena, comp.emit_asm, directory); 4658 const emit_llvm_ir_path = try stage1LocPath(arena, comp.emit_llvm_ir, directory); 4659 const emit_llvm_bc_path = try stage1LocPath(arena, comp.emit_llvm_bc, directory); 4660 const emit_analysis_path = try stage1LocPath(arena, comp.emit_analysis, directory); 4661 const emit_docs_path = try stage1LocPath(arena, comp.emit_docs, directory); 4662 const stage1_pkg = try createStage1Pkg(arena, "root", mod.main_pkg, null); 4663 const test_filter = comp.test_filter orelse ""[0..0]; 4664 const test_name_prefix = comp.test_name_prefix orelse ""[0..0]; 4665 const subsystem = if (comp.bin_file.options.subsystem) |s| 4666 @intToEnum(stage1.TargetSubsystem, @enumToInt(s)) 4667 else 4668 stage1.TargetSubsystem.Auto; 4669 stage1_module.* = .{ 4670 .root_name_ptr = comp.bin_file.options.root_name.ptr, 4671 .root_name_len = comp.bin_file.options.root_name.len, 4672 .emit_o_ptr = emit_bin_path.ptr, 4673 .emit_o_len = emit_bin_path.len, 4674 .emit_h_ptr = emit_h_path.ptr, 4675 .emit_h_len = emit_h_path.len, 4676 .emit_asm_ptr = emit_asm_path.ptr, 4677 .emit_asm_len = emit_asm_path.len, 4678 .emit_llvm_ir_ptr = emit_llvm_ir_path.ptr, 4679 .emit_llvm_ir_len = emit_llvm_ir_path.len, 4680 .emit_bitcode_ptr = emit_llvm_bc_path.ptr, 4681 .emit_bitcode_len = emit_llvm_bc_path.len, 4682 .emit_analysis_json_ptr = emit_analysis_path.ptr, 4683 .emit_analysis_json_len = emit_analysis_path.len, 4684 .emit_docs_ptr = emit_docs_path.ptr, 4685 .emit_docs_len = emit_docs_path.len, 4686 .builtin_zig_path_ptr = builtin_zig_path.ptr, 4687 .builtin_zig_path_len = builtin_zig_path.len, 4688 .test_filter_ptr = test_filter.ptr, 4689 .test_filter_len = test_filter.len, 4690 .test_name_prefix_ptr = test_name_prefix.ptr, 4691 .test_name_prefix_len = test_name_prefix.len, 4692 .userdata = @ptrToInt(comp), 4693 .main_pkg = stage1_pkg, 4694 .code_model = @enumToInt(comp.bin_file.options.machine_code_model), 4695 .subsystem = subsystem, 4696 .err_color = @enumToInt(comp.color), 4697 .pic = comp.bin_file.options.pic, 4698 .pie = comp.bin_file.options.pie, 4699 .lto = comp.bin_file.options.lto, 4700 .unwind_tables = comp.unwind_tables, 4701 .link_libc = comp.bin_file.options.link_libc, 4702 .link_libcpp = comp.bin_file.options.link_libcpp, 4703 .strip = comp.bin_file.options.strip, 4704 .is_single_threaded = comp.bin_file.options.single_threaded, 4705 .dll_export_fns = comp.bin_file.options.dll_export_fns, 4706 .link_mode_dynamic = comp.bin_file.options.link_mode == .Dynamic, 4707 .valgrind_enabled = comp.bin_file.options.valgrind, 4708 .tsan_enabled = comp.bin_file.options.tsan, 4709 .function_sections = comp.bin_file.options.function_sections, 4710 .include_compiler_rt = include_compiler_rt, 4711 .enable_stack_probing = comp.bin_file.options.stack_check, 4712 .red_zone = comp.bin_file.options.red_zone, 4713 .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer, 4714 .enable_time_report = comp.time_report, 4715 .enable_stack_report = comp.stack_report, 4716 .test_is_evented = comp.test_evented_io, 4717 .verbose_ir = comp.verbose_air, 4718 .verbose_llvm_ir = comp.verbose_llvm_ir, 4719 .verbose_cimport = comp.verbose_cimport, 4720 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, 4721 .main_progress_node = main_progress_node, 4722 .have_c_main = false, 4723 .have_winmain = false, 4724 .have_wwinmain = false, 4725 .have_winmain_crt_startup = false, 4726 .have_wwinmain_crt_startup = false, 4727 .have_dllmain_crt_startup = false, 4728 }; 4729 4730 const inferred_lib_start_index = comp.bin_file.options.system_libs.count(); 4731 stage1_module.build_object(); 4732 4733 if (comp.bin_file.options.system_libs.count() > inferred_lib_start_index) { 4734 // We need to save the inferred link libs to the cache, otherwise if we get a cache hit 4735 // next time we will be missing these libs. 4736 var libs_txt = std.ArrayList(u8).init(arena); 4737 for (comp.bin_file.options.system_libs.keys()[inferred_lib_start_index..]) |key| { 4738 try libs_txt.writer().print("{s}\n", .{key}); 4739 } 4740 try directory.handle.writeFile(libs_txt_basename, libs_txt.items); 4741 } 4742 4743 mod.stage1_flags = .{ 4744 .have_c_main = stage1_module.have_c_main, 4745 .have_winmain = stage1_module.have_winmain, 4746 .have_wwinmain = stage1_module.have_wwinmain, 4747 .have_winmain_crt_startup = stage1_module.have_winmain_crt_startup, 4748 .have_wwinmain_crt_startup = stage1_module.have_wwinmain_crt_startup, 4749 .have_dllmain_crt_startup = stage1_module.have_dllmain_crt_startup, 4750 }; 4751 4752 stage1_module.destroy(); 4753 4754 const digest = man.final(); 4755 4756 // Update the small file with the digest. If it fails we can continue; it only 4757 // means that the next invocation will have an unnecessary cache miss. 4758 const stage1_flags_byte = @bitCast(u8, mod.stage1_flags); 4759 log.debug("stage1 {s} final digest={s} flags={x}", .{ 4760 mod.main_pkg.root_src_path, std.fmt.fmtSliceHexLower(&digest), stage1_flags_byte, 4761 }); 4762 var digest_plus_flags: [digest.len + 2]u8 = undefined; 4763 digest_plus_flags[0..digest.len].* = digest; 4764 assert(std.fmt.formatIntBuf(digest_plus_flags[digest.len..], stage1_flags_byte, 16, .lower, .{ 4765 .width = 2, 4766 .fill = '0', 4767 }) == 2); 4768 log.debug("saved digest + flags: '{s}' (byte = {}) have_winmain_crt_startup={}", .{ 4769 digest_plus_flags, stage1_flags_byte, mod.stage1_flags.have_winmain_crt_startup, 4770 }); 4771 Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest_plus_flags) catch |err| { 4772 log.warn("failed to save stage1 hash digest file: {s}", .{@errorName(err)}); 4773 }; 4774 // Failure here only means an unnecessary cache miss. 4775 man.writeManifest() catch |err| { 4776 log.warn("failed to write cache manifest when linking: {s}", .{@errorName(err)}); 4777 }; 4778 // We hang on to this lock so that the output file path can be used without 4779 // other processes clobbering it. 4780 comp.stage1_lock = man.toOwnedLock(); 4781} 4782 4783fn stage1LocPath(arena: Allocator, opt_loc: ?EmitLoc, cache_directory: Directory) ![]const u8 { 4784 const loc = opt_loc orelse return ""; 4785 const directory = loc.directory orelse cache_directory; 4786 return directory.join(arena, &[_][]const u8{loc.basename}); 4787} 4788 4789fn createStage1Pkg( 4790 arena: Allocator, 4791 name: []const u8, 4792 pkg: *Package, 4793 parent_pkg: ?*stage1.Pkg, 4794) error{OutOfMemory}!*stage1.Pkg { 4795 const child_pkg = try arena.create(stage1.Pkg); 4796 4797 const pkg_children = blk: { 4798 var children = std.ArrayList(*stage1.Pkg).init(arena); 4799 var it = pkg.table.iterator(); 4800 while (it.next()) |entry| { 4801 if (mem.eql(u8, entry.key_ptr.*, "std") or 4802 mem.eql(u8, entry.key_ptr.*, "builtin") or 4803 mem.eql(u8, entry.key_ptr.*, "root")) 4804 { 4805 continue; 4806 } 4807 try children.append(try createStage1Pkg(arena, entry.key_ptr.*, entry.value_ptr.*, child_pkg)); 4808 } 4809 break :blk children.items; 4810 }; 4811 4812 const src_path = try pkg.root_src_directory.join(arena, &[_][]const u8{pkg.root_src_path}); 4813 4814 child_pkg.* = .{ 4815 .name_ptr = name.ptr, 4816 .name_len = name.len, 4817 .path_ptr = src_path.ptr, 4818 .path_len = src_path.len, 4819 .children_ptr = pkg_children.ptr, 4820 .children_len = pkg_children.len, 4821 .parent = parent_pkg, 4822 }; 4823 return child_pkg; 4824} 4825 4826pub fn build_crt_file( 4827 comp: *Compilation, 4828 root_name: []const u8, 4829 output_mode: std.builtin.OutputMode, 4830 c_source_files: []const Compilation.CSourceFile, 4831) !void { 4832 const tracy_trace = trace(@src()); 4833 defer tracy_trace.end(); 4834 4835 const target = comp.getTarget(); 4836 const basename = try std.zig.binNameAlloc(comp.gpa, .{ 4837 .root_name = root_name, 4838 .target = target, 4839 .output_mode = output_mode, 4840 }); 4841 errdefer comp.gpa.free(basename); 4842 4843 // TODO: This is extracted into a local variable to work around a stage1 miscompilation. 4844 const emit_bin = Compilation.EmitLoc{ 4845 .directory = null, // Put it in the cache directory. 4846 .basename = basename, 4847 }; 4848 const sub_compilation = try Compilation.create(comp.gpa, .{ 4849 .local_cache_directory = comp.global_cache_directory, 4850 .global_cache_directory = comp.global_cache_directory, 4851 .zig_lib_directory = comp.zig_lib_directory, 4852 .target = target, 4853 .root_name = root_name, 4854 .main_pkg = null, 4855 .output_mode = output_mode, 4856 .thread_pool = comp.thread_pool, 4857 .libc_installation = comp.bin_file.options.libc_installation, 4858 .emit_bin = emit_bin, 4859 .optimize_mode = comp.compilerRtOptMode(), 4860 .want_sanitize_c = false, 4861 .want_stack_check = false, 4862 .want_red_zone = comp.bin_file.options.red_zone, 4863 .omit_frame_pointer = comp.bin_file.options.omit_frame_pointer, 4864 .want_valgrind = false, 4865 .want_tsan = false, 4866 .want_pic = comp.bin_file.options.pic, 4867 .want_pie = comp.bin_file.options.pie, 4868 .want_lto = switch (output_mode) { 4869 .Lib => comp.bin_file.options.lto, 4870 .Obj, .Exe => false, 4871 }, 4872 .emit_h = null, 4873 .strip = comp.compilerRtStrip(), 4874 .is_native_os = comp.bin_file.options.is_native_os, 4875 .is_native_abi = comp.bin_file.options.is_native_abi, 4876 .self_exe_path = comp.self_exe_path, 4877 .c_source_files = c_source_files, 4878 .verbose_cc = comp.verbose_cc, 4879 .verbose_link = comp.bin_file.options.verbose_link, 4880 .verbose_air = comp.verbose_air, 4881 .verbose_llvm_ir = comp.verbose_llvm_ir, 4882 .verbose_cimport = comp.verbose_cimport, 4883 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, 4884 .clang_passthrough_mode = comp.clang_passthrough_mode, 4885 .skip_linker_dependencies = true, 4886 .parent_compilation_link_libc = comp.bin_file.options.link_libc, 4887 }); 4888 defer sub_compilation.destroy(); 4889 4890 try sub_compilation.updateSubCompilation(); 4891 4892 try comp.crt_files.ensureUnusedCapacity(comp.gpa, 1); 4893 4894 comp.crt_files.putAssumeCapacityNoClobber(basename, .{ 4895 .full_object_path = try sub_compilation.bin_file.options.emit.?.directory.join(comp.gpa, &[_][]const u8{ 4896 sub_compilation.bin_file.options.emit.?.sub_path, 4897 }), 4898 .lock = sub_compilation.bin_file.toOwnedLock(), 4899 }); 4900} 4901 4902pub fn stage1AddLinkLib(comp: *Compilation, lib_name: []const u8) !void { 4903 // Avoid deadlocking on building import libs such as kernel32.lib 4904 // This can happen when the user uses `build-exe foo.obj -lkernel32` and then 4905 // when we create a sub-Compilation for zig libc, it also tries to build kernel32.lib. 4906 if (comp.bin_file.options.skip_linker_dependencies) return; 4907 4908 // This happens when an `extern "foo"` function is referenced by the stage1 backend. 4909 // If we haven't seen this library yet and we're targeting Windows, we need to queue up 4910 // a work item to produce the DLL import library for this. 4911 const gop = try comp.bin_file.options.system_libs.getOrPut(comp.gpa, lib_name); 4912 if (!gop.found_existing and comp.getTarget().os.tag == .windows) { 4913 try comp.work_queue.writeItem(.{ 4914 .windows_import_lib = comp.bin_file.options.system_libs.count() - 1, 4915 }); 4916 } 4917} 4918 4919/// This decides the optimization mode for all zig-provided libraries, including 4920/// compiler-rt, libcxx, libc, libunwind, etc. 4921pub fn compilerRtOptMode(comp: Compilation) std.builtin.Mode { 4922 if (comp.debug_compiler_runtime_libs) { 4923 return comp.bin_file.options.optimize_mode; 4924 } 4925 switch (comp.bin_file.options.optimize_mode) { 4926 .Debug, .ReleaseSafe => return target_util.defaultCompilerRtOptimizeMode(comp.getTarget()), 4927 .ReleaseFast => return .ReleaseFast, 4928 .ReleaseSmall => return .ReleaseSmall, 4929 } 4930} 4931 4932/// This decides whether to strip debug info for all zig-provided libraries, including 4933/// compiler-rt, libcxx, libc, libunwind, etc. 4934pub fn compilerRtStrip(comp: Compilation) bool { 4935 if (comp.debug_compiler_runtime_libs) { 4936 return comp.bin_file.options.strip; 4937 } else { 4938 return true; 4939 } 4940} 4941