| ... | ... | @@ -284,7 +284,8 @@ pub const File = struct { |
| 284 | 284 | /// rewriting it. A malicious file is detected as incremental link failure |
| 285 | 285 | /// and does not cause Illegal Behavior. This operation is not atomic. |
| 286 | 286 | pub fn openPath(allocator: Allocator, options: Options) !*File { |
| 287 | | if (options.target.ofmt == .macho) { |
| 287 | const have_macho = !build_options.only_c; |
| 288 | if (have_macho and options.target.ofmt == .macho) { |
| 288 | 289 | return &(try MachO.openPath(allocator, options)).base; |
| 289 | 290 | } |
| 290 | 291 | |
| ... | ... | @@ -332,18 +333,40 @@ pub const File = struct { |
| 332 | 333 | } else emit.sub_path; |
| 333 | 334 | errdefer if (use_lld) allocator.free(sub_path); |
| 334 | 335 | |
| 335 | | const file: *File = switch (options.target.ofmt) { |
| 336 | | .coff => &(try Coff.openPath(allocator, sub_path, options)).base, |
| 337 | | .elf => &(try Elf.openPath(allocator, sub_path, options)).base, |
| 338 | | .macho => unreachable, |
| 339 | | .plan9 => &(try Plan9.openPath(allocator, sub_path, options)).base, |
| 340 | | .wasm => &(try Wasm.openPath(allocator, sub_path, options)).base, |
| 341 | | .c => &(try C.openPath(allocator, sub_path, options)).base, |
| 342 | | .spirv => &(try SpirV.openPath(allocator, sub_path, options)).base, |
| 343 | | .nvptx => &(try NvPtx.openPath(allocator, sub_path, options)).base, |
| 344 | | .hex => return error.HexObjectFormatUnimplemented, |
| 345 | | .raw => return error.RawObjectFormatUnimplemented, |
| 346 | | .dxcontainer => return error.DirectXContainerObjectFormatUnimplemented, |
| 336 | const file: *File = f: { |
| 337 | switch (options.target.ofmt) { |
| 338 | .coff => { |
| 339 | if (build_options.only_c) unreachable; |
| 340 | break :f &(try Coff.openPath(allocator, sub_path, options)).base; |
| 341 | }, |
| 342 | .elf => { |
| 343 | if (build_options.only_c) unreachable; |
| 344 | break :f &(try Elf.openPath(allocator, sub_path, options)).base; |
| 345 | }, |
| 346 | .macho => unreachable, |
| 347 | .plan9 => { |
| 348 | if (build_options.only_c) unreachable; |
| 349 | break :f &(try Plan9.openPath(allocator, sub_path, options)).base; |
| 350 | }, |
| 351 | .wasm => { |
| 352 | if (build_options.only_c) unreachable; |
| 353 | break :f &(try Wasm.openPath(allocator, sub_path, options)).base; |
| 354 | }, |
| 355 | .c => { |
| 356 | break :f &(try C.openPath(allocator, sub_path, options)).base; |
| 357 | }, |
| 358 | .spirv => { |
| 359 | if (build_options.only_c) unreachable; |
| 360 | break :f &(try SpirV.openPath(allocator, sub_path, options)).base; |
| 361 | }, |
| 362 | .nvptx => { |
| 363 | if (build_options.only_c) unreachable; |
| 364 | break :f &(try NvPtx.openPath(allocator, sub_path, options)).base; |
| 365 | }, |
| 366 | .hex => return error.HexObjectFormatUnimplemented, |
| 367 | .raw => return error.RawObjectFormatUnimplemented, |
| 368 | .dxcontainer => return error.DirectXContainerObjectFormatUnimplemented, |
| 369 | } |
| 347 | 370 | }; |
| 348 | 371 | |
| 349 | 372 | if (use_lld) { |
| ... | ... | @@ -366,6 +389,7 @@ pub const File = struct { |
| 366 | 389 | pub fn makeWritable(base: *File) !void { |
| 367 | 390 | switch (base.tag) { |
| 368 | 391 | .coff, .elf, .macho, .plan9, .wasm => { |
| 392 | if (build_options.only_c) unreachable; |
| 369 | 393 | if (base.file != null) return; |
| 370 | 394 | const emit = base.options.emit orelse return; |
| 371 | 395 | base.file = try emit.directory.handle.createFile(emit.sub_path, .{ |
| ... | ... | @@ -389,6 +413,7 @@ pub const File = struct { |
| 389 | 413 | } |
| 390 | 414 | switch (base.tag) { |
| 391 | 415 | .macho => if (base.file) |f| { |
| 416 | if (build_options.only_c) unreachable; |
| 392 | 417 | if (comptime builtin.target.isDarwin() and builtin.target.cpu.arch == .aarch64) { |
| 393 | 418 | if (base.options.target.cpu.arch == .aarch64) { |
| 394 | 419 | // XNU starting with Big Sur running on arm64 is caching inodes of running binaries. |
| ... | ... | @@ -407,6 +432,7 @@ pub const File = struct { |
| 407 | 432 | base.file = null; |
| 408 | 433 | }, |
| 409 | 434 | .coff, .elf, .plan9, .wasm => if (base.file) |f| { |
| 435 | if (build_options.only_c) unreachable; |
| 410 | 436 | if (base.intermediary_basename != null) { |
| 411 | 437 | // The file we have open is not the final file that we want to |
| 412 | 438 | // make executable, so we don't have to close it. |
| ... | ... | @@ -454,6 +480,7 @@ pub const File = struct { |
| 454 | 480 | /// constant. Returns the symbol index of the lowered constant in the read-only section |
| 455 | 481 | /// of the final binary. |
| 456 | 482 | pub fn lowerUnnamedConst(base: *File, tv: TypedValue, decl_index: Module.Decl.Index) UpdateDeclError!u32 { |
| 483 | if (build_options.only_c) @compileError("unreachable"); |
| 457 | 484 | const decl = base.options.module.?.declPtr(decl_index); |
| 458 | 485 | log.debug("lowerUnnamedConst {*} ({s})", .{ decl, decl.name }); |
| 459 | 486 | switch (base.tag) { |
| ... | ... | @@ -474,6 +501,7 @@ pub const File = struct { |
| 474 | 501 | /// If no symbol exists yet with this name, a new undefined global symbol will |
| 475 | 502 | /// be created. This symbol may get resolved once all relocatables are (re-)linked. |
| 476 | 503 | pub fn getGlobalSymbol(base: *File, name: []const u8) UpdateDeclError!u32 { |
| 504 | if (build_options.only_c) @compileError("unreachable"); |
| 477 | 505 | log.debug("getGlobalSymbol '{s}'", .{name}); |
| 478 | 506 | switch (base.tag) { |
| 479 | 507 | // zig fmt: off |
| ... | ... | @@ -495,6 +523,10 @@ pub const File = struct { |
| 495 | 523 | const decl = module.declPtr(decl_index); |
| 496 | 524 | log.debug("updateDecl {*} ({s}), type={}", .{ decl, decl.name, decl.ty.fmtDebug() }); |
| 497 | 525 | assert(decl.has_tv); |
| 526 | if (build_options.only_c) { |
| 527 | assert(base.tag == .c); |
| 528 | return @fieldParentPtr(C, "base", base).updateDecl(module, decl_index); |
| 529 | } |
| 498 | 530 | switch (base.tag) { |
| 499 | 531 | // zig fmt: off |
| 500 | 532 | .coff => return @fieldParentPtr(Coff, "base", base).updateDecl(module, decl_index), |
| ... | ... | @@ -516,6 +548,10 @@ pub const File = struct { |
| 516 | 548 | log.debug("updateFunc {*} ({s}), type={}", .{ |
| 517 | 549 | owner_decl, owner_decl.name, owner_decl.ty.fmtDebug(), |
| 518 | 550 | }); |
| 551 | if (build_options.only_c) { |
| 552 | assert(base.tag == .c); |
| 553 | return @fieldParentPtr(C, "base", base).updateFunc(module, func, air, liveness); |
| 554 | } |
| 519 | 555 | switch (base.tag) { |
| 520 | 556 | // zig fmt: off |
| 521 | 557 | .coff => return @fieldParentPtr(Coff, "base", base).updateFunc(module, func, air, liveness), |
| ... | ... | @@ -535,6 +571,10 @@ pub const File = struct { |
| 535 | 571 | decl, decl.name, decl.src_line + 1, |
| 536 | 572 | }); |
| 537 | 573 | assert(decl.has_tv); |
| 574 | if (build_options.only_c) { |
| 575 | assert(base.tag == .c); |
| 576 | return @fieldParentPtr(C, "base", base).updateDeclLineNumber(module, decl); |
| 577 | } |
| 538 | 578 | switch (base.tag) { |
| 539 | 579 | .coff => return @fieldParentPtr(Coff, "base", base).updateDeclLineNumber(module, decl), |
| 540 | 580 | .elf => return @fieldParentPtr(Elf, "base", base).updateDeclLineNumber(module, decl), |
| ... | ... | @@ -554,6 +594,10 @@ pub const File = struct { |
| 554 | 594 | pub fn allocateDeclIndexes(base: *File, decl_index: Module.Decl.Index) error{OutOfMemory}!void { |
| 555 | 595 | const decl = base.options.module.?.declPtr(decl_index); |
| 556 | 596 | log.debug("allocateDeclIndexes {*} ({s})", .{ decl, decl.name }); |
| 597 | if (build_options.only_c) { |
| 598 | assert(base.tag == .c); |
| 599 | return; |
| 600 | } |
| 557 | 601 | switch (base.tag) { |
| 558 | 602 | .coff => return @fieldParentPtr(Coff, "base", base).allocateDeclIndexes(decl_index), |
| 559 | 603 | .elf => return @fieldParentPtr(Elf, "base", base).allocateDeclIndexes(decl_index), |
| ... | ... | @@ -584,16 +628,19 @@ pub const File = struct { |
| 584 | 628 | base.options.system_libs.deinit(base.allocator); |
| 585 | 629 | switch (base.tag) { |
| 586 | 630 | .coff => { |
| 631 | if (build_options.only_c) unreachable; |
| 587 | 632 | const parent = @fieldParentPtr(Coff, "base", base); |
| 588 | 633 | parent.deinit(); |
| 589 | 634 | base.allocator.destroy(parent); |
| 590 | 635 | }, |
| 591 | 636 | .elf => { |
| 637 | if (build_options.only_c) unreachable; |
| 592 | 638 | const parent = @fieldParentPtr(Elf, "base", base); |
| 593 | 639 | parent.deinit(); |
| 594 | 640 | base.allocator.destroy(parent); |
| 595 | 641 | }, |
| 596 | 642 | .macho => { |
| 643 | if (build_options.only_c) unreachable; |
| 597 | 644 | const parent = @fieldParentPtr(MachO, "base", base); |
| 598 | 645 | parent.deinit(); |
| 599 | 646 | base.allocator.destroy(parent); |
| ... | ... | @@ -604,21 +651,25 @@ pub const File = struct { |
| 604 | 651 | base.allocator.destroy(parent); |
| 605 | 652 | }, |
| 606 | 653 | .wasm => { |
| 654 | if (build_options.only_c) unreachable; |
| 607 | 655 | const parent = @fieldParentPtr(Wasm, "base", base); |
| 608 | 656 | parent.deinit(); |
| 609 | 657 | base.allocator.destroy(parent); |
| 610 | 658 | }, |
| 611 | 659 | .spirv => { |
| 660 | if (build_options.only_c) unreachable; |
| 612 | 661 | const parent = @fieldParentPtr(SpirV, "base", base); |
| 613 | 662 | parent.deinit(); |
| 614 | 663 | base.allocator.destroy(parent); |
| 615 | 664 | }, |
| 616 | 665 | .plan9 => { |
| 666 | if (build_options.only_c) unreachable; |
| 617 | 667 | const parent = @fieldParentPtr(Plan9, "base", base); |
| 618 | 668 | parent.deinit(); |
| 619 | 669 | base.allocator.destroy(parent); |
| 620 | 670 | }, |
| 621 | 671 | .nvptx => { |
| 672 | if (build_options.only_c) unreachable; |
| 622 | 673 | const parent = @fieldParentPtr(NvPtx, "base", base); |
| 623 | 674 | parent.deinit(); |
| 624 | 675 | base.allocator.destroy(parent); |
| ... | ... | @@ -629,6 +680,10 @@ pub const File = struct { |
| 629 | 680 | /// Commit pending changes and write headers. Takes into account final output mode |
| 630 | 681 | /// and `use_lld`, not only `effectiveOutputMode`. |
| 631 | 682 | pub fn flush(base: *File, comp: *Compilation, prog_node: *std.Progress.Node) !void { |
| 683 | if (build_options.only_c) { |
| 684 | assert(base.tag == .c); |
| 685 | return @fieldParentPtr(C, "base", base).flush(comp, prog_node); |
| 686 | } |
| 632 | 687 | if (comp.clang_preprocessor_mode == .yes) { |
| 633 | 688 | const emit = base.options.emit orelse return; // -fno-emit-bin |
| 634 | 689 | // TODO: avoid extra link step when it's just 1 object file (the `zig cc -c` case) |
| ... | ... | @@ -663,6 +718,10 @@ pub const File = struct { |
| 663 | 718 | /// Commit pending changes and write headers. Works based on `effectiveOutputMode` |
| 664 | 719 | /// rather than final output mode. |
| 665 | 720 | pub fn flushModule(base: *File, comp: *Compilation, prog_node: *std.Progress.Node) !void { |
| 721 | if (build_options.only_c) { |
| 722 | assert(base.tag == .c); |
| 723 | return @fieldParentPtr(C, "base", base).flushModule(comp, prog_node); |
| 724 | } |
| 666 | 725 | switch (base.tag) { |
| 667 | 726 | .coff => return @fieldParentPtr(Coff, "base", base).flushModule(comp, prog_node), |
| 668 | 727 | .elf => return @fieldParentPtr(Elf, "base", base).flushModule(comp, prog_node), |
| ... | ... | @@ -677,6 +736,10 @@ pub const File = struct { |
| 677 | 736 | |
| 678 | 737 | /// Called when a Decl is deleted from the Module. |
| 679 | 738 | pub fn freeDecl(base: *File, decl_index: Module.Decl.Index) void { |
| 739 | if (build_options.only_c) { |
| 740 | assert(base.tag == .c); |
| 741 | return @fieldParentPtr(C, "base", base).freeDecl(decl_index); |
| 742 | } |
| 680 | 743 | switch (base.tag) { |
| 681 | 744 | .coff => @fieldParentPtr(Coff, "base", base).freeDecl(decl_index), |
| 682 | 745 | .elf => @fieldParentPtr(Elf, "base", base).freeDecl(decl_index), |
| ... | ... | @@ -716,6 +779,10 @@ pub const File = struct { |
| 716 | 779 | const decl = module.declPtr(decl_index); |
| 717 | 780 | log.debug("updateDeclExports {*} ({s})", .{ decl, decl.name }); |
| 718 | 781 | assert(decl.has_tv); |
| 782 | if (build_options.only_c) { |
| 783 | assert(base.tag == .c); |
| 784 | return @fieldParentPtr(C, "base", base).updateDeclExports(module, decl_index, exports); |
| 785 | } |
| 719 | 786 | switch (base.tag) { |
| 720 | 787 | .coff => return @fieldParentPtr(Coff, "base", base).updateDeclExports(module, decl_index, exports), |
| 721 | 788 | .elf => return @fieldParentPtr(Elf, "base", base).updateDeclExports(module, decl_index, exports), |
| ... | ... | @@ -739,6 +806,7 @@ pub const File = struct { |
| 739 | 806 | /// memory buffer, `offset`, so that it can make a note of potential relocation sites, should the |
| 740 | 807 | /// `Decl`'s address was not yet resolved, or the containing atom gets moved in virtual memory. |
| 741 | 808 | pub fn getDeclVAddr(base: *File, decl_index: Module.Decl.Index, reloc_info: RelocInfo) !u64 { |
| 809 | if (build_options.only_c) unreachable; |
| 742 | 810 | switch (base.tag) { |
| 743 | 811 | .coff => return @fieldParentPtr(Coff, "base", base).getDeclVAddr(decl_index, reloc_info), |
| 744 | 812 | .elf => return @fieldParentPtr(Elf, "base", base).getDeclVAddr(decl_index, reloc_info), |