Commit b975f7a56f

Andrew Kelley <andrew@ziglang.org>
2022-08-19 03:58:28
std.Target gains ObjectFormat field
1 parent 517eb73
lib/std/zig/system/NativeTargetInfo.zig
@@ -276,6 +276,7 @@ fn detectAbiAndDynamicLinker(
     };
     var ld_info_list_buffer: [all_abis.len]LdInfo = undefined;
     var ld_info_list_len: usize = 0;
+    const ofmt = cross_target.ofmt orelse Target.ObjectFormat.default(os.tag, cpu.arch);
 
     for (all_abis) |abi| {
         // This may be a nonsensical parameter. We detect this with error.UnknownDynamicLinkerPath and
@@ -284,6 +285,7 @@ fn detectAbiAndDynamicLinker(
             .cpu = cpu,
             .os = os,
             .abi = abi,
+            .ofmt = ofmt,
         };
         const ld = target.standardDynamicLinkerPath();
         if (ld.get() == null) continue;
@@ -346,6 +348,7 @@ fn detectAbiAndDynamicLinker(
                 .cpu = cpu,
                 .os = os_adjusted,
                 .abi = cross_target.abi orelse found_ld_info.abi,
+                .ofmt = cross_target.ofmt orelse Target.ObjectFormat.default(os_adjusted.tag, cpu.arch),
             },
             .dynamic_linker = if (cross_target.dynamic_linker.get() == null)
                 DynamicLinker.init(found_ld_path)
@@ -539,6 +542,7 @@ pub fn abiAndDynamicLinkerFromFile(
             .cpu = cpu,
             .os = os,
             .abi = cross_target.abi orelse Target.Abi.default(cpu.arch, os),
+            .ofmt = cross_target.ofmt orelse Target.ObjectFormat.default(os.tag, cpu.arch),
         },
         .dynamic_linker = cross_target.dynamic_linker,
     };
@@ -829,6 +833,7 @@ fn defaultAbiAndDynamicLinker(cpu: Target.Cpu, os: Target.Os, cross_target: Cros
         .cpu = cpu,
         .os = os,
         .abi = cross_target.abi orelse Target.Abi.default(cpu.arch, os),
+        .ofmt = cross_target.ofmt orelse Target.ObjectFormat.default(os.tag, cpu.arch),
     };
     return NativeTargetInfo{
         .target = target,
lib/std/zig/CrossTarget.zig
@@ -42,6 +42,9 @@ abi: ?Target.Abi = null,
 /// based on the `os_tag`.
 dynamic_linker: DynamicLinker = DynamicLinker{},
 
+/// `null` means default for the cpu/arch/os combo.
+ofmt: ?Target.ObjectFormat = null,
+
 pub const CpuModel = union(enum) {
     /// Always native
     native,
@@ -168,6 +171,7 @@ pub fn toTarget(self: CrossTarget) Target {
         .cpu = self.getCpu(),
         .os = self.getOs(),
         .abi = self.getAbi(),
+        .ofmt = self.getObjectFormat(),
     };
 }
 
@@ -197,6 +201,8 @@ pub const ParseOptions = struct {
     /// detected path, or a standard path.
     dynamic_linker: ?[]const u8 = null,
 
+    object_format: ?[]const u8 = null,
+
     /// If this is provided, the function will populate some information about parsing failures,
     /// so that user-friendly error messages can be delivered.
     diagnostics: ?*Diagnostics = null,
@@ -321,6 +327,11 @@ pub fn parse(args: ParseOptions) !CrossTarget {
         }
     }
 
+    if (args.object_format) |ofmt_name| {
+        result.ofmt = std.meta.stringToEnum(Target.ObjectFormat, ofmt_name) orelse
+            return error.UnknownObjectFormat;
+    }
+
     return result;
 }
 
@@ -620,7 +631,7 @@ pub fn setGnuLibCVersion(self: *CrossTarget, major: u32, minor: u32, patch: u32)
 }
 
 pub fn getObjectFormat(self: CrossTarget) Target.ObjectFormat {
-    return Target.getObjectFormatSimple(self.getOsTag(), self.getCpuArch());
+    return self.ofmt orelse Target.ObjectFormat.default(self.getOsTag(), self.getCpuArch());
 }
 
 pub fn updateCpuFeatures(self: CrossTarget, set: *Target.Cpu.Feature.Set) void {
lib/std/target.zig
@@ -9,6 +9,7 @@ pub const Target = struct {
     cpu: Cpu,
     os: Os,
     abi: Abi,
+    ofmt: ObjectFormat,
 
     pub const Os = struct {
         tag: Tag,
@@ -594,6 +595,20 @@ pub const Target = struct {
                 .nvptx => ".ptx",
             };
         }
+
+        pub fn default(os_tag: Os.Tag, cpu_arch: Cpu.Arch) ObjectFormat {
+            return switch (os_tag) {
+                .windows, .uefi => .coff,
+                .ios, .macos, .watchos, .tvos => .macho,
+                .plan9 => .plan9,
+                else => return switch (cpu_arch) {
+                    .wasm32, .wasm64 => .wasm,
+                    .spirv32, .spirv64 => .spirv,
+                    .nvptx, .nvptx64 => .nvptx,
+                    else => .elf,
+                },
+            };
+        }
     };
 
     pub const SubSystem = enum {
@@ -1381,24 +1396,6 @@ pub const Target = struct {
         return libPrefix_os_abi(self.os.tag, self.abi);
     }
 
-    pub fn getObjectFormatSimple(os_tag: Os.Tag, cpu_arch: Cpu.Arch) ObjectFormat {
-        return switch (os_tag) {
-            .windows, .uefi => .coff,
-            .ios, .macos, .watchos, .tvos => .macho,
-            .plan9 => .plan9,
-            else => return switch (cpu_arch) {
-                .wasm32, .wasm64 => .wasm,
-                .spirv32, .spirv64 => .spirv,
-                .nvptx, .nvptx64 => .nvptx,
-                else => .elf,
-            },
-        };
-    }
-
-    pub fn getObjectFormat(self: Target) ObjectFormat {
-        return getObjectFormatSimple(self.os.tag, self.cpu.arch);
-    }
-
     pub fn isMinGW(self: Target) bool {
         return self.os.tag == .windows and self.isGnu();
     }
lib/std/zig.zig
@@ -103,7 +103,6 @@ pub const BinNameOptions = struct {
     target: std.Target,
     output_mode: std.builtin.OutputMode,
     link_mode: ?std.builtin.LinkMode = null,
-    object_format: ?std.Target.ObjectFormat = null,
     version: ?std.builtin.Version = null,
 };
 
@@ -111,8 +110,7 @@ pub const BinNameOptions = struct {
 pub fn binNameAlloc(allocator: std.mem.Allocator, options: BinNameOptions) error{OutOfMemory}![]u8 {
     const root_name = options.root_name;
     const target = options.target;
-    const ofmt = options.object_format orelse target.getObjectFormat();
-    switch (ofmt) {
+    switch (target.ofmt) {
         .coff => switch (options.output_mode) {
             .Exe => return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, target.exeFileExt() }),
             .Lib => {
@@ -186,8 +184,12 @@ pub fn binNameAlloc(allocator: std.mem.Allocator, options: BinNameOptions) error
         .raw => return std.fmt.allocPrint(allocator, "{s}.bin", .{root_name}),
         .plan9 => switch (options.output_mode) {
             .Exe => return allocator.dupe(u8, root_name),
-            .Obj => return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, ofmt.fileExt(target.cpu.arch) }),
-            .Lib => return std.fmt.allocPrint(allocator, "{s}{s}.a", .{ target.libPrefix(), root_name }),
+            .Obj => return std.fmt.allocPrint(allocator, "{s}{s}", .{
+                root_name, target.ofmt.fileExt(target.cpu.arch),
+            }),
+            .Lib => return std.fmt.allocPrint(allocator, "{s}{s}.a", .{
+                target.libPrefix(), root_name,
+            }),
         },
         .nvptx => return std.fmt.allocPrint(allocator, "{s}", .{root_name}),
     }
src/codegen/llvm.zig
@@ -273,7 +273,7 @@ pub const Object = struct {
         var di_compile_unit: ?*llvm.DICompileUnit = null;
 
         if (!options.strip) {
-            switch (options.object_format) {
+            switch (options.target.ofmt) {
                 .coff => llvm_module.addModuleCodeViewFlag(),
                 else => llvm_module.addModuleDebugInfoFlag(),
             }
src/link/C.zig
@@ -48,7 +48,7 @@ const DeclBlock = struct {
 };
 
 pub fn openPath(gpa: Allocator, sub_path: []const u8, options: link.Options) !*C {
-    assert(options.object_format == .c);
+    assert(options.target.ofmt == .c);
 
     if (options.use_llvm) return error.LLVMHasNoCBackend;
     if (options.use_lld) return error.LLDHasNoCBackend;
src/link/Coff.zig
@@ -128,7 +128,7 @@ pub const TextBlock = struct {
 pub const SrcFn = void;
 
 pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Coff {
-    assert(options.object_format == .coff);
+    assert(options.target.ofmt == .coff);
 
     if (build_options.have_llvm and options.use_llvm) {
         return createEmpty(allocator, options);
src/link/Elf.zig
@@ -249,7 +249,7 @@ pub const Export = struct {
 };
 
 pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Elf {
-    assert(options.object_format == .elf);
+    assert(options.target.ofmt == .elf);
 
     if (build_options.have_llvm and options.use_llvm) {
         return createEmpty(allocator, options);
src/link/MachO.zig
@@ -270,7 +270,7 @@ pub const Export = struct {
 };
 
 pub fn openPath(allocator: Allocator, options: link.Options) !*MachO {
-    assert(options.object_format == .macho);
+    assert(options.target.ofmt == .macho);
 
     const use_stage1 = build_options.is_stage1 and options.use_stage1;
     if (use_stage1 or options.emit == null) {
@@ -289,7 +289,7 @@ pub fn openPath(allocator: Allocator, options: link.Options) !*MachO {
         // we also want to put the intermediary object file in the cache while the
         // main emit directory is the cwd.
         self.base.intermediary_basename = try std.fmt.allocPrint(allocator, "{s}{s}", .{
-            emit.sub_path, options.object_format.fileExt(options.target.cpu.arch),
+            emit.sub_path, options.target.ofmt.fileExt(options.target.cpu.arch),
         });
     }
 
src/link/NvPtx.zig
@@ -57,7 +57,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*NvPtx {
 pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*NvPtx {
     if (!build_options.have_llvm) @panic("nvptx target requires a zig compiler with llvm enabled.");
     if (!options.use_llvm) return error.PtxArchNotSupported;
-    assert(options.object_format == .nvptx);
+    assert(options.target.ofmt == .nvptx);
 
     const nvptx = try createEmpty(allocator, options);
     log.info("Opening .ptx target file {s}", .{sub_path});
src/link/Plan9.zig
@@ -657,7 +657,7 @@ pub const base_tag = .plan9;
 pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Plan9 {
     if (options.use_llvm)
         return error.LLVMBackendDoesNotSupportPlan9;
-    assert(options.object_format == .plan9);
+    assert(options.target.ofmt == .plan9);
 
     const self = try createEmpty(allocator, options);
     errdefer self.base.destroy();
src/link/SpirV.zig
@@ -99,7 +99,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*SpirV {
 }
 
 pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*SpirV {
-    assert(options.object_format == .spirv);
+    assert(options.target.ofmt == .spirv);
 
     if (options.use_llvm) return error.LLVM_BackendIsTODO_ForSpirV; // TODO: LLVM Doesn't support SpirV at all.
     if (options.use_lld) return error.LLD_LinkingIsTODO_ForSpirV; // TODO: LLD Doesn't support SpirV at all.
src/link/Wasm.zig
@@ -282,7 +282,7 @@ pub const StringTable = struct {
 };
 
 pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Wasm {
-    assert(options.object_format == .wasm);
+    assert(options.target.ofmt == .wasm);
 
     if (build_options.have_llvm and options.use_llvm) {
         return createEmpty(allocator, options);
src/stage1/codegen.cpp
@@ -10082,6 +10082,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
         "    .cpu = cpu,\n"
         "    .os = os,\n"
         "    .abi = abi,\n"
+        "    .ofmt = object_format,\n"
         "};\n"
     );
 
src/Compilation.zig
@@ -810,7 +810,6 @@ pub const InitOptions = struct {
     /// this flag would be set to disable this machinery to avoid false positives.
     disable_lld_caching: bool = false,
     cache_mode: CacheMode = .incremental,
-    object_format: ?std.Target.ObjectFormat = null,
     optimize_mode: std.builtin.Mode = .Debug,
     keep_source_files_loaded: bool = false,
     clang_argv: []const []const u8 = &[0][]const u8{},
@@ -1027,8 +1026,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
         const comp = try arena.create(Compilation);
         const root_name = try arena.dupeZ(u8, options.root_name);
 
-        const ofmt = options.object_format orelse options.target.getObjectFormat();
-
         const use_stage1 = options.use_stage1 orelse blk: {
             // Even though we may have no Zig code to compile (depending on `options.main_pkg`),
             // we may need to use stage1 for building compiler-rt and other dependencies.
@@ -1042,7 +1039,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
             }
 
             // If LLVM does not support the target, then we can't use it.
-            if (!target_util.hasLlvmSupport(options.target, ofmt))
+            if (!target_util.hasLlvmSupport(options.target, options.target.ofmt))
                 break :blk false;
 
             break :blk build_options.is_stage1;
@@ -1072,7 +1069,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
                 break :blk true;
 
             // If LLVM does not support the target, then we can't use it.
-            if (!target_util.hasLlvmSupport(options.target, ofmt))
+            if (!target_util.hasLlvmSupport(options.target, options.target.ofmt))
                 break :blk false;
 
             // Prefer LLVM for release builds.
@@ -1115,7 +1112,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
             if (!build_options.have_llvm)
                 break :blk false;
 
-            if (ofmt == .c)
+            if (options.target.ofmt == .c)
                 break :blk false;
 
             if (options.want_lto) |lto| {
@@ -1374,7 +1371,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
         cache.hash.add(options.target.os.getVersionRange());
         cache.hash.add(options.is_native_os);
         cache.hash.add(options.target.abi);
-        cache.hash.add(ofmt);
+        cache.hash.add(options.target.ofmt);
         cache.hash.add(pic);
         cache.hash.add(pie);
         cache.hash.add(lto);
@@ -1682,7 +1679,6 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
             .sysroot = sysroot,
             .output_mode = options.output_mode,
             .link_mode = link_mode,
-            .object_format = ofmt,
             .optimize_mode = options.optimize_mode,
             .use_lld = use_lld,
             .use_llvm = use_llvm,
@@ -1841,7 +1837,9 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
 
     const have_bin_emit = comp.bin_file.options.emit != null or comp.whole_bin_sub_path != null;
 
-    if (have_bin_emit and !comp.bin_file.options.skip_linker_dependencies) {
+    if (have_bin_emit and !comp.bin_file.options.skip_linker_dependencies and
+        options.target.ofmt != .c)
+    {
         if (comp.getTarget().isDarwin()) {
             switch (comp.getTarget().abi) {
                 .none,
@@ -3739,7 +3737,8 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P
     else
         c_source_basename[0 .. c_source_basename.len - std.fs.path.extension(c_source_basename).len];
 
-    const o_ext = comp.bin_file.options.object_format.fileExt(comp.bin_file.options.target.cpu.arch);
+    const target = comp.getTarget();
+    const o_ext = target.ofmt.fileExt(target.cpu.arch);
     const digest = if (!comp.disable_c_depfile and try man.hit()) man.final() else blk: {
         var argv = std.ArrayList([]const u8).init(comp.gpa);
         defer argv.deinit();
@@ -4092,7 +4091,7 @@ pub fn addCCArgs(
 
             if (!comp.bin_file.options.strip) {
                 try argv.append("-g");
-                switch (comp.bin_file.options.object_format) {
+                switch (target.ofmt) {
                     .coff => try argv.append("-gcodeview"),
                     else => {},
                 }
@@ -4660,7 +4659,7 @@ fn wantBuildLibCFromSource(comp: Compilation) bool {
     };
     return comp.bin_file.options.link_libc and is_exe_or_dyn_lib and
         comp.bin_file.options.libc_installation == null and
-        comp.bin_file.options.object_format != .c;
+        comp.bin_file.options.target.ofmt != .c;
 }
 
 fn wantBuildGLibCFromSource(comp: Compilation) bool {
@@ -4688,7 +4687,7 @@ fn wantBuildLibUnwindFromSource(comp: *Compilation) bool {
         .Exe => true,
     };
     return is_exe_or_dyn_lib and comp.bin_file.options.link_libunwind and
-        comp.bin_file.options.object_format != .c;
+        comp.bin_file.options.target.ofmt != .c;
 }
 
 fn setAllocFailure(comp: *Compilation) void {
@@ -4747,7 +4746,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Alloca
     const zig_backend: std.builtin.CompilerBackend = blk: {
         if (use_stage1) break :blk .stage1;
         if (build_options.have_llvm and comp.bin_file.options.use_llvm) break :blk .stage2_llvm;
-        if (comp.bin_file.options.object_format == .c) break :blk .stage2_c;
+        if (target.ofmt == .c) break :blk .stage2_c;
         break :blk switch (target.cpu.arch) {
             .wasm32, .wasm64 => std.builtin.CompilerBackend.stage2_wasm,
             .arm, .armeb, .thumb, .thumbeb => .stage2_arm,
@@ -4895,6 +4894,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Alloca
         \\    .cpu = cpu,
         \\    .os = os,
         \\    .abi = abi,
+        \\    .ofmt = object_format,
         \\}};
         \\pub const object_format = std.Target.ObjectFormat.{};
         \\pub const mode = std.builtin.Mode.{};
@@ -4909,7 +4909,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: Allocator) Alloca
         \\pub const code_model = std.builtin.CodeModel.{};
         \\
     , .{
-        std.zig.fmtId(@tagName(comp.bin_file.options.object_format)),
+        std.zig.fmtId(@tagName(target.ofmt)),
         std.zig.fmtId(@tagName(comp.bin_file.options.optimize_mode)),
         link_libc,
         comp.bin_file.options.link_libcpp,
src/link.zig
@@ -72,7 +72,6 @@ pub const Options = struct {
     target: std.Target,
     output_mode: std.builtin.OutputMode,
     link_mode: std.builtin.LinkMode,
-    object_format: std.Target.ObjectFormat,
     optimize_mode: std.builtin.Mode,
     machine_code_model: std.builtin.CodeModel,
     root_name: [:0]const u8,
@@ -273,13 +272,13 @@ pub const File = struct {
     /// rewriting it. A malicious file is detected as incremental link failure
     /// and does not cause Illegal Behavior. This operation is not atomic.
     pub fn openPath(allocator: Allocator, options: Options) !*File {
-        if (options.object_format == .macho) {
+        if (options.target.ofmt == .macho) {
             return &(try MachO.openPath(allocator, options)).base;
         }
 
         const use_stage1 = build_options.is_stage1 and options.use_stage1;
         if (use_stage1 or options.emit == null) {
-            return switch (options.object_format) {
+            return switch (options.target.ofmt) {
                 .coff => &(try Coff.createEmpty(allocator, options)).base,
                 .elf => &(try Elf.createEmpty(allocator, options)).base,
                 .macho => unreachable,
@@ -298,7 +297,7 @@ pub const File = struct {
             if (options.module == null) {
                 // No point in opening a file, we would not write anything to it.
                 // Initialize with empty.
-                return switch (options.object_format) {
+                return switch (options.target.ofmt) {
                     .coff => &(try Coff.createEmpty(allocator, options)).base,
                     .elf => &(try Elf.createEmpty(allocator, options)).base,
                     .macho => unreachable,
@@ -314,12 +313,12 @@ pub const File = struct {
             // Open a temporary object file, not the final output file because we
             // want to link with LLD.
             break :blk try std.fmt.allocPrint(allocator, "{s}{s}", .{
-                emit.sub_path, options.object_format.fileExt(options.target.cpu.arch),
+                emit.sub_path, options.target.ofmt.fileExt(options.target.cpu.arch),
             });
         } else emit.sub_path;
         errdefer if (use_lld) allocator.free(sub_path);
 
-        const file: *File = switch (options.object_format) {
+        const file: *File = switch (options.target.ofmt) {
             .coff => &(try Coff.openPath(allocator, sub_path, options)).base,
             .elf => &(try Elf.openPath(allocator, sub_path, options)).base,
             .macho => unreachable,
src/main.zig
@@ -2192,6 +2192,7 @@ fn buildOutputType(
         .arch_os_abi = target_arch_os_abi,
         .cpu_features = target_mcpu,
         .dynamic_linker = target_dynamic_linker,
+        .object_format = target_ofmt,
     };
 
     // Before passing the mcpu string in for parsing, we convert any -m flags that were
@@ -2494,28 +2495,7 @@ fn buildOutputType(
         }
     }
 
-    const object_format: std.Target.ObjectFormat = blk: {
-        const ofmt = target_ofmt orelse break :blk target_info.target.getObjectFormat();
-        if (mem.eql(u8, ofmt, "elf")) {
-            break :blk .elf;
-        } else if (mem.eql(u8, ofmt, "c")) {
-            break :blk .c;
-        } else if (mem.eql(u8, ofmt, "coff")) {
-            break :blk .coff;
-        } else if (mem.eql(u8, ofmt, "macho")) {
-            break :blk .macho;
-        } else if (mem.eql(u8, ofmt, "wasm")) {
-            break :blk .wasm;
-        } else if (mem.eql(u8, ofmt, "hex")) {
-            break :blk .hex;
-        } else if (mem.eql(u8, ofmt, "raw")) {
-            break :blk .raw;
-        } else if (mem.eql(u8, ofmt, "spirv")) {
-            break :blk .spirv;
-        } else {
-            fatal("unsupported object format: {s}", .{ofmt});
-        }
-    };
+    const object_format = target_info.target.ofmt;
 
     if (output_mode == .Obj and (object_format == .coff or object_format == .macho)) {
         const total_obj_count = c_source_files.items.len +
@@ -2569,7 +2549,6 @@ fn buildOutputType(
                 .target = target_info.target,
                 .output_mode = output_mode,
                 .link_mode = link_mode,
-                .object_format = object_format,
                 .version = optional_version,
             }),
         },
@@ -2859,7 +2838,6 @@ fn buildOutputType(
         .emit_implib = emit_implib_resolved.data,
         .link_mode = link_mode,
         .dll_export_fns = dll_export_fns,
-        .object_format = object_format,
         .optimize_mode = optimize_mode,
         .keep_source_files_loaded = false,
         .clang_argv = clang_argv.items,
@@ -3173,11 +3151,11 @@ fn parseCrossTargetOrReportFatalError(
                 for (diags.arch.?.allCpuModels()) |cpu| {
                     help_text.writer().print(" {s}\n", .{cpu.name}) catch break :help;
                 }
-                std.log.info("Available CPUs for architecture '{s}':\n{s}", .{
+                std.log.info("available CPUs for architecture '{s}':\n{s}", .{
                     @tagName(diags.arch.?), help_text.items,
                 });
             }
-            fatal("Unknown CPU: '{s}'", .{diags.cpu_name.?});
+            fatal("unknown CPU: '{s}'", .{diags.cpu_name.?});
         },
         error.UnknownCpuFeature => {
             help: {
@@ -3186,11 +3164,26 @@ fn parseCrossTargetOrReportFatalError(
                 for (diags.arch.?.allFeaturesList()) |feature| {
                     help_text.writer().print(" {s}: {s}\n", .{ feature.name, feature.description }) catch break :help;
                 }
-                std.log.info("Available CPU features for architecture '{s}':\n{s}", .{
+                std.log.info("available CPU features for architecture '{s}':\n{s}", .{
                     @tagName(diags.arch.?), help_text.items,
                 });
             }
-            fatal("Unknown CPU feature: '{s}'", .{diags.unknown_feature_name.?});
+            fatal("unknown CPU feature: '{s}'", .{diags.unknown_feature_name.?});
+        },
+        error.UnknownObjectFormat => {
+            {
+                var help_text = std.ArrayList(u8).init(allocator);
+                defer help_text.deinit();
+                inline for (@typeInfo(std.Target.ObjectFormat).Enum.fields) |field| {
+                    help_text.writer().print(" {s}\n", .{field.name}) catch
+                    // TODO change this back to `break :help`
+                    // this working around a stage1 bug.
+                    //break :help;
+                        @panic("out of memory");
+                }
+                std.log.info("available object formats:\n{s}", .{help_text.items});
+            }
+            fatal("unknown object format: '{s}'", .{opts.object_format.?});
         },
         else => |e| return e,
     };
@@ -3360,7 +3353,7 @@ fn updateModule(gpa: Allocator, comp: *Compilation, hook: AfterUpdateHook) !void
 
             // If a .pdb file is part of the expected output, we must also copy
             // it into place here.
-            const is_coff = comp.bin_file.options.object_format == .coff;
+            const is_coff = comp.bin_file.options.target.ofmt == .coff;
             const have_pdb = is_coff and !comp.bin_file.options.strip;
             if (have_pdb) {
                 // Replace `.out` or `.exe` with `.pdb` on both the source and destination
src/Sema.zig
@@ -20654,7 +20654,7 @@ fn panicWithMsg(
     const arena = sema.arena;
 
     const this_feature_is_implemented_in_the_backend =
-        mod.comp.bin_file.options.object_format == .c or
+        mod.comp.bin_file.options.target.ofmt == .c or
         mod.comp.bin_file.options.use_llvm;
     if (!this_feature_is_implemented_in_the_backend) {
         // TODO implement this feature in all the backends and then delete this branch