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