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