From 9dd535773a3108f7559ca444d91f1bdb861a6ca1 Mon Sep 17 00:00:00 2001 From: Chan Lee Date: Fri, 3 Jan 2025 14:00:45 +0800 Subject: [PATCH 1/9] windows-gnu: Adhere to MinGW convention for debug format and object file extension. --- lib/compiler/aro/aro/Driver.zig | 4 ++-- lib/std/Build/Step/Compile.zig | 16 +++++++++++++--- lib/std/Target.zig | 10 ++++++---- lib/std/debug/SelfInfo.zig | 2 +- lib/std/zig.zig | 12 ++++++++---- src/Compilation.zig | 4 ++-- src/Compilation/Config.zig | 5 +++-- src/link.zig | 10 +++++----- src/link/Coff.zig | 11 +++++++---- src/main.zig | 5 ++++- tools/docgen.zig | 2 +- tools/doctest.zig | 2 +- 12 files changed, 53 insertions(+), 30 deletions(-) diff --git a/lib/compiler/aro/aro/Driver.zig b/lib/compiler/aro/aro/Driver.zig index c89dafe00222..8db4fd8464c5 100644 --- a/lib/compiler/aro/aro/Driver.zig +++ b/lib/compiler/aro/aro/Driver.zig @@ -765,7 +765,7 @@ fn processSource( const fmt_template = "{s}{s}"; const fmt_args = .{ std.fs.path.stem(source.path), - d.comp.target.ofmt.fileExt(d.comp.target.cpu.arch), + d.comp.target.ofmt.fileExt(d.comp.target.abi, d.comp.target.cpu.arch), }; break :blk d.output_name orelse std.fmt.bufPrint(&name_buf, fmt_template, fmt_args) catch return d.fatal("Filename too long for filesystem: " ++ fmt_template, fmt_args); @@ -781,7 +781,7 @@ fn processSource( const fmt_template = "/tmp/{s}{s}"; const fmt_args = .{ random_name, - d.comp.target.ofmt.fileExt(d.comp.target.cpu.arch), + d.comp.target.ofmt.fileExt(d.comp.target.abi, d.comp.target.cpu.arch), }; break :blk std.fmt.bufPrint(&name_buf, fmt_template, fmt_args) catch return d.fatal("Filename too long for filesystem: " ++ fmt_template, fmt_args); }; diff --git a/lib/std/Build/Step/Compile.zig b/lib/std/Build/Step/Compile.zig index 3c6e8231caa1..240847354043 100644 --- a/lib/std/Build/Step/Compile.zig +++ b/lib/std/Build/Step/Compile.zig @@ -464,7 +464,10 @@ pub fn create(owner: *std.Build, options: Options) *Compile { compile.name_only_filename = owner.fmt("lib{s}.dylib", .{compile.name}); compile.out_lib_filename = compile.out_filename; } else if (target.os.tag == .windows) { - compile.out_lib_filename = owner.fmt("{s}.lib", .{compile.name}); + compile.out_lib_filename = if (target.abi.isGnu()) + owner.fmt("lib{s}.dll.a", .{compile.name}) + else + owner.fmt("{s}.lib", .{compile.name}); } else { compile.major_only_filename = owner.fmt("lib{s}.so.{d}", .{ compile.name, version.major }); compile.name_only_filename = owner.fmt("lib{s}.so", .{compile.name}); @@ -474,7 +477,10 @@ pub fn create(owner: *std.Build, options: Options) *Compile { if (target.isDarwin()) { compile.out_lib_filename = compile.out_filename; } else if (target.os.tag == .windows) { - compile.out_lib_filename = owner.fmt("{s}.lib", .{compile.name}); + compile.out_lib_filename = if (target.abi.isGnu()) + owner.fmt("lib{s}.dll.a", .{compile.name}) + else + owner.fmt("{s}.lib", .{compile.name}); } else { compile.out_lib_filename = compile.out_filename; } @@ -651,6 +657,7 @@ pub fn producesPdbFile(compile: *Compile) bool { .windows, .uefi => {}, else => return false, } + if (target.abi.isGnu()) return false; if (target.ofmt == .c) return false; if (compile.root_module.strip == true or (compile.root_module.strip == null and compile.root_module.optimize == .ReleaseSmall)) @@ -1801,7 +1808,10 @@ fn make(step: *Step, options: Step.MakeOptions) !void { // -femit-implib[=path] (default) Produce an import .lib when building a Windows DLL if (compile.generated_implib) |implib| { - implib.path = b.fmt("{}" ++ sep ++ "{s}.lib", .{ output_dir, compile.name }); + if (compile.rootModuleTarget().abi.isGnu()) + implib.path = b.fmt("{}" ++ sep ++ "lib{s}.dll.a", .{ output_dir, compile.name }) + else + implib.path = b.fmt("{}" ++ sep ++ "{s}.lib", .{ output_dir, compile.name }); } // -femit-h[=path] Generate a C header file (.h) diff --git a/lib/std/Target.zig b/lib/std/Target.zig index 95aef4a7c7bc..05bfede73a36 100644 --- a/lib/std/Target.zig +++ b/lib/std/Target.zig @@ -114,7 +114,8 @@ pub const Os = struct { return switch (abi) { .msvc, .itanium => ".lib", else => switch (tag) { - .windows, .uefi => ".lib", + .uefi => ".lib", + .windows => if (abi.isGnu()) ".a" else ".lib", else => ".a", }, }; @@ -138,7 +139,8 @@ pub const Os = struct { return switch (abi) { .msvc, .itanium => "", else => switch (tag) { - .windows, .uefi => "", + .uefi => "", + .windows => if (abi.isGnu()) "lib" else "", else => "lib", }, }; @@ -1033,10 +1035,10 @@ pub const ObjectFormat = enum { // LLVM tags deliberately omitted: // - dxcontainer - pub fn fileExt(of: ObjectFormat, arch: Cpu.Arch) [:0]const u8 { + pub fn fileExt(of: ObjectFormat, abi: Abi, arch: Cpu.Arch) [:0]const u8 { return switch (of) { .c => ".c", - .coff => ".obj", + .coff => if (abi.isGnu()) ".o" else ".obj", .elf, .goff, .macho, .wasm, .xcoff => ".o", .hex => ".ihex", .nvptx => ".ptx", diff --git a/lib/std/debug/SelfInfo.zig b/lib/std/debug/SelfInfo.zig index 544cf0ac6ff4..f774ad2377f1 100644 --- a/lib/std/debug/SelfInfo.zig +++ b/lib/std/debug/SelfInfo.zig @@ -1003,7 +1003,7 @@ fn readCoffDebugInfo(allocator: Allocator, coff_obj: *coff.Coff) !Module { di.dwarf = dwarf; } - const raw_path = try coff_obj.getPdbPath() orelse return di; + const raw_path = (coff_obj.getPdbPath() catch return di) orelse return di; const path = blk: { if (fs.path.isAbsolute(raw_path)) { break :blk raw_path; diff --git a/lib/std/zig.zig b/lib/std/zig.zig index 7af8bacb3459..88c020e71b4f 100644 --- a/lib/std/zig.zig +++ b/lib/std/zig.zig @@ -157,13 +157,17 @@ pub fn binNameAlloc(allocator: Allocator, options: BinNameOptions) error{OutOfMe .coff => switch (options.output_mode) { .Exe => return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, t.exeFileExt() }), .Lib => { + const prefix = if (t.abi.isGnu()) "lib" else ""; const suffix = switch (options.link_mode orelse .static) { - .static => ".lib", + .static => if (t.abi.isGnu()) ".a" else ".lib", .dynamic => ".dll", }; - return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, suffix }); + return std.fmt.allocPrint(allocator, "{s}{s}{s}", .{ prefix, root_name, suffix }); }, - .Obj => return std.fmt.allocPrint(allocator, "{s}.obj", .{root_name}), + .Obj => if (t.abi.isGnu()) + return std.fmt.allocPrint(allocator, "{s}.o", .{root_name}) + else + return std.fmt.allocPrint(allocator, "{s}.obj", .{root_name}), }, .elf, .goff, .xcoff => switch (options.output_mode) { .Exe => return allocator.dupe(u8, root_name), @@ -228,7 +232,7 @@ pub fn binNameAlloc(allocator: Allocator, options: BinNameOptions) error{OutOfMe .plan9 => switch (options.output_mode) { .Exe => return allocator.dupe(u8, root_name), .Obj => return std.fmt.allocPrint(allocator, "{s}{s}", .{ - root_name, t.ofmt.fileExt(t.cpu.arch), + root_name, t.ofmt.fileExt(t.abi, t.cpu.arch), }), .Lib => return std.fmt.allocPrint(allocator, "{s}{s}.a", .{ t.libPrefix(), root_name, diff --git a/src/Compilation.zig b/src/Compilation.zig index 241386f10c57..44b311956f2a 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -4724,7 +4724,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr c_source_basename[0 .. c_source_basename.len - std.fs.path.extension(c_source_basename).len]; const target = comp.getTarget(); - const o_ext = target.ofmt.fileExt(target.cpu.arch); + const o_ext = target.ofmt.fileExt(target.abi, 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(gpa); defer argv.deinit(); @@ -5992,7 +5992,7 @@ pub const FileExt = enum { .assembly => ".s", .assembly_with_cpp => ".S", .shared_library => target.dynamicLibSuffix(), - .object => target.ofmt.fileExt(target.cpu.arch), + .object => target.ofmt.fileExt(target.abi, target.cpu.arch), .static_library => target.staticLibSuffix(), .zig => ".zig", .def => ".def", diff --git a/src/Compilation/Config.zig b/src/Compilation/Config.zig index e91055709c81..414b2001ecd2 100644 --- a/src/Compilation/Config.zig +++ b/src/Compilation/Config.zig @@ -446,9 +446,10 @@ pub fn resolve(options: Options) ResolveError!Config { if (options.debug_format) |x| break :b x; break :b switch (target.ofmt) { .elf, .goff, .macho, .wasm, .xcoff => .{ .dwarf = .@"32" }, - .coff => .code_view, + .coff => if (target.abi.isGnu()) .{ .dwarf = .@"32" } else .code_view, .c => switch (target.os.tag) { - .windows, .uefi => .code_view, + .uefi => .code_view, + .windows => if (target.abi.isGnu()) .{ .dwarf = .@"32" } else .code_view, else => .{ .dwarf = .@"32" }, }, .spirv, .nvptx, .hex, .raw, .plan9 => .strip, diff --git a/src/link.zig b/src/link.zig index fd1ef7ce334a..dfdf40d21b2b 100644 --- a/src/link.zig +++ b/src/link.zig @@ -2096,17 +2096,17 @@ fn resolveLibInput( return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query); } - // In the case of MinGW, the main check will be .lib but we also need to - // look for `libfoo.a`. - if (target.isMinGW() and link_mode == .static) mingw: { + // In the case of MinGW, the main check will be `libfoo.dll` but we also need to + // look for `libfoo.dll.a`. + if (target.isMinGW() and link_mode == .dynamic) mingw: { const test_path: Path = .{ .root_dir = lib_directory, - .sub_path = try std.fmt.allocPrint(arena, "lib{s}.a", .{lib_name}), + .sub_path = try std.fmt.allocPrint(arena, "lib{s}.dll.a", .{lib_name}), }; try checked_paths.writer(gpa).print("\n {}", .{test_path}); var file = test_path.root_dir.handle.openFile(test_path.sub_path, .{}) catch |err| switch (err) { error.FileNotFound => break :mingw, - else => |e| fatal("unable to search for static library '{}': {s}", .{ test_path, @errorName(e) }), + else => |e| fatal("unable to search for DLL import library '{}': {s}", .{ test_path, @errorName(e) }), }; errdefer file.close(); return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query); diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 1242385b263d..38e0b649f4fd 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -1844,7 +1844,10 @@ fn linkWithLLD(coff: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: try argv.append("-ERRORLIMIT:0"); try argv.append("-NOLOGO"); - if (comp.config.debug_format != .strip) { + if (comp.config.debug_format == .dwarf) { + try argv.append("-DEBUG:DWARF"); + } + if (comp.config.debug_format == .code_view) { try argv.append("-DEBUG"); const out_ext = std.fs.path.extension(full_out_path); @@ -2070,17 +2073,17 @@ fn linkWithLLD(coff: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: } if (is_dyn_lib) { - try argv.append(try comp.crtFileAsString(arena, "dllcrt2.obj")); + try argv.append(try comp.crtFileAsString(arena, "dllcrt2.o")); if (target.cpu.arch == .x86) { try argv.append("-ALTERNATENAME:__DllMainCRTStartup@12=_DllMainCRTStartup@12"); } else { try argv.append("-ALTERNATENAME:_DllMainCRTStartup=DllMainCRTStartup"); } } else { - try argv.append(try comp.crtFileAsString(arena, "crt2.obj")); + try argv.append(try comp.crtFileAsString(arena, "crt2.o")); } - try argv.append(try comp.crtFileAsString(arena, "mingw32.lib")); + try argv.append(try comp.crtFileAsString(arena, "libmingw32.a")); } else { const lib_str = switch (comp.config.link_mode) { .dynamic => "", diff --git a/src/main.zig b/src/main.zig index 7bb51bbd8ea9..02e1be9d61f3 100644 --- a/src/main.zig +++ b/src/main.zig @@ -3293,7 +3293,10 @@ fn buildOutputType( fatal("the argument -femit-implib is allowed only when building a Windows DLL", .{}); } } - const default_implib_basename = try std.fmt.allocPrint(arena, "{s}.lib", .{root_name}); + const default_implib_basename = try if (target.abi.isGnu()) + std.fmt.allocPrint(arena, "lib{s}.dll.a", .{root_name}) + else + std.fmt.allocPrint(arena, "{s}.lib", .{root_name}); var emit_implib_resolved = switch (emit_implib) { .no => Emit.Resolved{ .data = null, .dir = null }, .yes => |p| emit_implib.resolve(default_implib_basename, output_to_cache) catch |err| { diff --git a/tools/docgen.zig b/tools/docgen.zig index 1e9c409fa4af..a7ebf59984d5 100644 --- a/tools/docgen.zig +++ b/tools/docgen.zig @@ -14,7 +14,7 @@ const fatal = std.zig.fatal; const max_doc_file_size = 10 * 1024 * 1024; -const obj_ext = builtin.object_format.fileExt(builtin.cpu.arch); +const obj_ext = builtin.object_format.fileExt(builtin.abi, builtin.cpu.arch); const usage = \\Usage: docgen [options] input output diff --git a/tools/doctest.zig b/tools/doctest.zig index 070a59ee37a1..2b50a89b0a17 100644 --- a/tools/doctest.zig +++ b/tools/doctest.zig @@ -107,7 +107,7 @@ fn printOutput( try env_map.put("CLICOLOR_FORCE", "1"); const host = try std.zig.system.resolveTargetQuery(.{}); - const obj_ext = builtin.object_format.fileExt(builtin.cpu.arch); + const obj_ext = builtin.object_format.fileExt(builtin.abi, builtin.cpu.arch); const print = std.debug.print; var shell_buffer = std.ArrayList(u8).init(arena); From d7298e35232224b561330b39baf9ce6f0f3475de Mon Sep 17 00:00:00 2001 From: Chan Lee Date: Fri, 3 Jan 2025 22:03:43 +0800 Subject: [PATCH 2/9] windows-gnu: Add support for `-mwindows` option. --- src/clang_options_data.zig | 9 ++++++++- src/main.zig | 7 +++++++ tools/update_clang_options.zig | 4 ++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/clang_options_data.zig b/src/clang_options_data.zig index 88cf41d0d4ff..89de37e8ac73 100644 --- a/src/clang_options_data.zig +++ b/src/clang_options_data.zig @@ -7350,7 +7350,14 @@ joinpd1("mthreads"), .pd2 = false, .psl = false, }, -joinpd1("mwindows"), +.{ + .name = "mwindows", + .syntax = .joined, + .zig_equivalent = .mingw_subsystem_windows, + .pd1 = true, + .pd2 = false, + .psl = false, +}, .{ .name = "offload=", .syntax = .comma_joined, diff --git a/src/main.zig b/src/main.zig index 02e1be9d61f3..685838d1e1bf 100644 --- a/src/main.zig +++ b/src/main.zig @@ -473,6 +473,7 @@ const usage_build_generic = \\ -fno-structured-cfg (SPIR-V) force SPIR-V kernels to not use structured control flow \\ -mexec-model=[value] (WASI) Execution model \\ -municode (Windows) Use wmain/wWinMain as entry point + \\ -mwindows (Windows) Specifies a GUI application is to be generated \\ \\Per-Module Compile Options: \\ -target [name] -- see the targets command @@ -1746,6 +1747,8 @@ fn buildOutputType( create_module.opts.wasi_exec_model = parseWasiExecModel(arg["-mexec-model=".len..]); } else if (mem.eql(u8, arg, "-municode")) { mingw_unicode_entry_point = true; + } else if (mem.eql(u8, arg, "-mwindows")) { + subsystem = .Windows; } else { fatal("unrecognized parameter: '{s}'", .{arg}); } @@ -2255,6 +2258,7 @@ fn buildOutputType( }, .force_load_objc => force_load_objc = true, .mingw_unicode_entry_point => mingw_unicode_entry_point = true, + .mingw_subsystem_windows => subsystem = .Windows, .weak_library => try create_module.cli_link_inputs.append(arena, .{ .name_query = .{ .name = it.only_arg, .query = .{ @@ -2560,6 +2564,8 @@ fn buildOutputType( minor, @errorName(err), }); }; + } else if (mem.eql(u8, arg, "-mwindows")) { + subsystem = .Windows; } else if (mem.eql(u8, arg, "-framework")) { try create_module.frameworks.put(arena, linker_args_it.nextOrFatal(), .{}); } else if (mem.eql(u8, arg, "-weak_framework")) { @@ -5834,6 +5840,7 @@ pub const ClangArgIterator = struct { undefined, force_load_objc, mingw_unicode_entry_point, + mingw_subsystem_windows, san_cov_trace_pc_guard, san_cov, no_san_cov, diff --git a/tools/update_clang_options.zig b/tools/update_clang_options.zig index 9cc0ad90cd71..b8916e5e6aac 100644 --- a/tools/update_clang_options.zig +++ b/tools/update_clang_options.zig @@ -548,6 +548,10 @@ const known_options = [_]KnownOpt{ .name = "municode", .ident = "mingw_unicode_entry_point", }, + .{ + .name = "mwindows", + .ident = "mingw_subsystem_windows", + }, .{ .name = "fsanitize-coverage-trace-pc-guard", .ident = "san_cov_trace_pc_guard", From 8e2c06fb542db483ceaec4bbc996f537462b06dd Mon Sep 17 00:00:00 2001 From: Chan Lee Date: Fri, 3 Jan 2025 23:43:37 +0800 Subject: [PATCH 3/9] windows-gnu: Disable default implib emission in `zig cc` mode. This change aligns `zig cc` with GCC and Clang, which do not emit import libraries by default. --- src/main.zig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main.zig b/src/main.zig index 685838d1e1bf..26d8eef73357 100644 --- a/src/main.zig +++ b/src/main.zig @@ -835,7 +835,7 @@ fn buildOutputType( var emit_llvm_ir: Emit = .no; var emit_llvm_bc: Emit = .no; var emit_docs: Emit = .no; - var emit_implib: Emit = .yes_default_path; + var emit_implib: Emit = undefined; var emit_implib_arg_provided = false; var target_arch_os_abi: ?[]const u8 = null; var target_mcpu: ?[]const u8 = null; @@ -1022,6 +1022,7 @@ fn buildOutputType( } soname = .yes_default_value; + emit_implib = .yes_default_path; var args_iter = ArgsIterator{ .args = all_args[2..], @@ -1819,6 +1820,7 @@ fn buildOutputType( emit_h = .no; soname = .no; + emit_implib = .no; create_module.opts.ensure_libc_on_non_freestanding = true; create_module.opts.ensure_libcpp_on_non_freestanding = arg_mode == .cpp; create_module.want_native_include_dirs = true; From f4f639905c050338fded25f4e8b5a28918464d48 Mon Sep 17 00:00:00 2001 From: Chan Lee Date: Sat, 4 Jan 2025 10:26:28 +0800 Subject: [PATCH 4/9] windows-gnu: Enhance MinGW library resolution to include additional file formats --- src/link.zig | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/src/link.zig b/src/link.zig index dfdf40d21b2b..b29088cd299d 100644 --- a/src/link.zig +++ b/src/link.zig @@ -2096,20 +2096,32 @@ fn resolveLibInput( return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query); } - // In the case of MinGW, the main check will be `libfoo.dll` but we also need to - // look for `libfoo.dll.a`. - if (target.isMinGW() and link_mode == .dynamic) mingw: { - const test_path: Path = .{ - .root_dir = lib_directory, - .sub_path = try std.fmt.allocPrint(arena, "lib{s}.dll.a", .{lib_name}), - }; - try checked_paths.writer(gpa).print("\n {}", .{test_path}); - var file = test_path.root_dir.handle.openFile(test_path.sub_path, .{}) catch |err| switch (err) { - error.FileNotFound => break :mingw, - else => |e| fatal("unable to search for DLL import library '{}': {s}", .{ test_path, @errorName(e) }), - }; - errdefer file.close(); - return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query); + // In the case of MinGW, the main check will be `libfoo.dll` and `libfoo.a`, but we also need to + // look for `foo.dll`, `foo.lib` and `libfoo.dll.a`. + if (target.isMinGW()) { + const sub_paths = if (link_mode == .dynamic) + &[_][]const u8{ + try std.fmt.allocPrint(arena, "lib{s}.dll.a", .{lib_name}), + try std.fmt.allocPrint(arena, "{s}.dll", .{lib_name}), + try std.fmt.allocPrint(arena, "{s}.lib", .{lib_name}), + } + else + &[_][]const u8{ + try std.fmt.allocPrint(arena, "{s}.lib", .{lib_name}), + }; + for (sub_paths) |sub_path| { + const test_path: Path = .{ + .root_dir = lib_directory, + .sub_path = sub_path, + }; + try checked_paths.writer(gpa).print("\n {}", .{test_path}); + var file = test_path.root_dir.handle.openFile(test_path.sub_path, .{}) catch |err| switch (err) { + error.FileNotFound => continue, + else => |e| fatal("unable to search for {s} library '{}': {s}", .{ @tagName(link_mode), test_path, @errorName(e) }), + }; + errdefer file.close(); + return finishResolveLibInput(resolved_inputs, test_path, file, link_mode, name_query.query); + } } return .no_match; From 552fc9816604325e0511f77c0d4c774fadc20d79 Mon Sep 17 00:00:00 2001 From: Chan Lee Date: Sun, 5 Jan 2025 13:53:22 +0800 Subject: [PATCH 5/9] windows-gnu: Fix minor code formatting issues --- src/main.zig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main.zig b/src/main.zig index 26d8eef73357..31ee3d47acd1 100644 --- a/src/main.zig +++ b/src/main.zig @@ -473,7 +473,7 @@ const usage_build_generic = \\ -fno-structured-cfg (SPIR-V) force SPIR-V kernels to not use structured control flow \\ -mexec-model=[value] (WASI) Execution model \\ -municode (Windows) Use wmain/wWinMain as entry point - \\ -mwindows (Windows) Specifies a GUI application is to be generated + \\ -mwindows (Windows) Specify that a GUI application is to be generated \\ \\Per-Module Compile Options: \\ -target [name] -- see the targets command @@ -3301,10 +3301,10 @@ fn buildOutputType( fatal("the argument -femit-implib is allowed only when building a Windows DLL", .{}); } } - const default_implib_basename = try if (target.abi.isGnu()) - std.fmt.allocPrint(arena, "lib{s}.dll.a", .{root_name}) + const default_implib_basename = if (target.abi.isGnu()) + try std.fmt.allocPrint(arena, "lib{s}.dll.a", .{root_name}) else - std.fmt.allocPrint(arena, "{s}.lib", .{root_name}); + try std.fmt.allocPrint(arena, "{s}.lib", .{root_name}); var emit_implib_resolved = switch (emit_implib) { .no => Emit.Resolved{ .data = null, .dir = null }, .yes => |p| emit_implib.resolve(default_implib_basename, output_to_cache) catch |err| { From 67afb8665ab6d3a62993a6221eaf727ecf4c19a3 Mon Sep 17 00:00:00 2001 From: Chan Lee Date: Mon, 6 Jan 2025 09:11:59 +0800 Subject: [PATCH 6/9] Target: Add `objFileExt()` convenience wrapper Added the `objFileExt()` function to Target, streamlining access to target-specific data in a manner consistent with other convenience functions. --- lib/compiler/aro/aro/Driver.zig | 4 ++-- lib/std/Target.zig | 4 ++++ lib/std/zig.zig | 2 +- src/Compilation.zig | 4 ++-- tools/docgen.zig | 2 +- tools/doctest.zig | 2 +- 6 files changed, 11 insertions(+), 7 deletions(-) diff --git a/lib/compiler/aro/aro/Driver.zig b/lib/compiler/aro/aro/Driver.zig index 8db4fd8464c5..c92ef15da18e 100644 --- a/lib/compiler/aro/aro/Driver.zig +++ b/lib/compiler/aro/aro/Driver.zig @@ -765,7 +765,7 @@ fn processSource( const fmt_template = "{s}{s}"; const fmt_args = .{ std.fs.path.stem(source.path), - d.comp.target.ofmt.fileExt(d.comp.target.abi, d.comp.target.cpu.arch), + d.comp.target.objFileExt(), }; break :blk d.output_name orelse std.fmt.bufPrint(&name_buf, fmt_template, fmt_args) catch return d.fatal("Filename too long for filesystem: " ++ fmt_template, fmt_args); @@ -781,7 +781,7 @@ fn processSource( const fmt_template = "/tmp/{s}{s}"; const fmt_args = .{ random_name, - d.comp.target.ofmt.fileExt(d.comp.target.abi, d.comp.target.cpu.arch), + d.comp.target.objFileExt(), }; break :blk std.fmt.bufPrint(&name_buf, fmt_template, fmt_args) catch return d.fatal("Filename too long for filesystem: " ++ fmt_template, fmt_args); }; diff --git a/lib/std/Target.zig b/lib/std/Target.zig index 05bfede73a36..b724c08ec29a 100644 --- a/lib/std/Target.zig +++ b/lib/std/Target.zig @@ -2045,6 +2045,10 @@ pub fn exeFileExt(target: Target) [:0]const u8 { return target.os.tag.exeFileExt(target.cpu.arch); } +pub fn objFileExt(target: Target) [:0]const u8 { + return target.ofmt.fileExt(target.abi, target.cpu.arch); +} + pub fn staticLibSuffix(target: Target) [:0]const u8 { return target.os.tag.staticLibSuffix(target.abi); } diff --git a/lib/std/zig.zig b/lib/std/zig.zig index 88c020e71b4f..8c68c84abc1e 100644 --- a/lib/std/zig.zig +++ b/lib/std/zig.zig @@ -232,7 +232,7 @@ pub fn binNameAlloc(allocator: Allocator, options: BinNameOptions) error{OutOfMe .plan9 => switch (options.output_mode) { .Exe => return allocator.dupe(u8, root_name), .Obj => return std.fmt.allocPrint(allocator, "{s}{s}", .{ - root_name, t.ofmt.fileExt(t.abi, t.cpu.arch), + root_name, t.objFileExt(), }), .Lib => return std.fmt.allocPrint(allocator, "{s}{s}.a", .{ t.libPrefix(), root_name, diff --git a/src/Compilation.zig b/src/Compilation.zig index 44b311956f2a..946942f42565 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -4724,7 +4724,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr c_source_basename[0 .. c_source_basename.len - std.fs.path.extension(c_source_basename).len]; const target = comp.getTarget(); - const o_ext = target.ofmt.fileExt(target.abi, target.cpu.arch); + const o_ext = target.objFileExt(); const digest = if (!comp.disable_c_depfile and try man.hit()) man.final() else blk: { var argv = std.ArrayList([]const u8).init(gpa); defer argv.deinit(); @@ -5992,7 +5992,7 @@ pub const FileExt = enum { .assembly => ".s", .assembly_with_cpp => ".S", .shared_library => target.dynamicLibSuffix(), - .object => target.ofmt.fileExt(target.abi, target.cpu.arch), + .object => target.objFileExt(), .static_library => target.staticLibSuffix(), .zig => ".zig", .def => ".def", diff --git a/tools/docgen.zig b/tools/docgen.zig index a7ebf59984d5..e02a4f39da2b 100644 --- a/tools/docgen.zig +++ b/tools/docgen.zig @@ -14,7 +14,7 @@ const fatal = std.zig.fatal; const max_doc_file_size = 10 * 1024 * 1024; -const obj_ext = builtin.object_format.fileExt(builtin.abi, builtin.cpu.arch); +const obj_ext = builtin.target.objFileExt(); const usage = \\Usage: docgen [options] input output diff --git a/tools/doctest.zig b/tools/doctest.zig index 2b50a89b0a17..0f52bb5bce8c 100644 --- a/tools/doctest.zig +++ b/tools/doctest.zig @@ -107,7 +107,7 @@ fn printOutput( try env_map.put("CLICOLOR_FORCE", "1"); const host = try std.zig.system.resolveTargetQuery(.{}); - const obj_ext = builtin.object_format.fileExt(builtin.abi, builtin.cpu.arch); + const obj_ext = builtin.target.objFileExt(); const print = std.debug.print; var shell_buffer = std.ArrayList(u8).init(arena); From eef344fc394937cd26a26821d699f4a007ccc2f3 Mon Sep 17 00:00:00 2001 From: Chan Lee Date: Tue, 7 Jan 2025 13:05:11 +0800 Subject: [PATCH 7/9] Debug: Move `Compilation.Config.DebugFormat` to `std.builtin` for broader usage --- lib/std/builtin.zig | 8 ++++++++ src/Compilation.zig | 6 +++--- src/Compilation/Config.zig | 11 +++-------- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index eda7f0ff4f5e..d7260e44bba4 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -160,6 +160,14 @@ pub const OptimizeMode = enum { /// Deprecated; use OptimizeMode. pub const Mode = OptimizeMode; +/// DebugFormat specifies which type of debug information to generate: +pub const DebugFormat = union(enum) { + /// No debug information. + strip, + dwarf: std.dwarf.Format, + code_view, +}; + /// The calling convention of a function defines how arguments and return values are passed, as well /// as any other requirements which callers and callees must respect, such as register preservation /// and stack alignment. diff --git a/src/Compilation.zig b/src/Compilation.zig index 946942f42565..1b66f5da3321 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -883,13 +883,13 @@ pub const cache_helpers = struct { addEmitLoc(hh, optional_emit_loc orelse return); } - pub fn addOptionalDebugFormat(hh: *Cache.HashHelper, x: ?Config.DebugFormat) void { + pub fn addOptionalDebugFormat(hh: *Cache.HashHelper, x: ?std.builtin.DebugFormat) void { hh.add(x != null); addDebugFormat(hh, x orelse return); } - pub fn addDebugFormat(hh: *Cache.HashHelper, x: Config.DebugFormat) void { - const tag: @typeInfo(Config.DebugFormat).@"union".tag_type.? = x; + pub fn addDebugFormat(hh: *Cache.HashHelper, x: std.builtin.DebugFormat) void { + const tag: @typeInfo(std.builtin.DebugFormat).@"union".tag_type.? = x; hh.add(tag); switch (x) { .strip, .code_view => {}, diff --git a/src/Compilation/Config.zig b/src/Compilation/Config.zig index 414b2001ecd2..5165b58666fd 100644 --- a/src/Compilation/Config.zig +++ b/src/Compilation/Config.zig @@ -56,7 +56,7 @@ import_memory: bool, export_memory: bool, shared_memory: bool, is_test: bool, -debug_format: DebugFormat, +debug_format: std.builtin.DebugFormat, root_strip: bool, root_error_tracing: bool, dll_export_fns: bool, @@ -67,11 +67,6 @@ pub const CFrontend = enum { clang, aro }; pub const LtoMode = enum { none, full, thin }; -pub const DebugFormat = union(enum) { - strip, - dwarf: std.dwarf.Format, - code_view, -}; pub const Options = struct { output_mode: std.builtin.OutputMode, @@ -109,7 +104,7 @@ pub const Options = struct { import_memory: ?bool = null, export_memory: ?bool = null, shared_memory: ?bool = null, - debug_format: ?DebugFormat = null, + debug_format: ?std.builtin.DebugFormat = null, dll_export_fns: ?bool = null, rdynamic: ?bool = null, san_cov_trace_pc_guard: bool = false, @@ -441,7 +436,7 @@ pub fn resolve(options: Options) ResolveError!Config { break :b false; }; - const debug_format: DebugFormat = b: { + const debug_format: std.builtin.DebugFormat = b: { if (root_strip and !options.any_non_stripped) break :b .strip; if (options.debug_format) |x| break :b x; break :b switch (target.ofmt) { From a49834a47cc8e3dd211e126adfbd8c55405e1231 Mon Sep 17 00:00:00 2001 From: Chan Lee Date: Tue, 7 Jan 2025 13:05:50 +0800 Subject: [PATCH 8/9] Debug: Replace `Module.dwarf_format` with `std.builtin.debug_format` for enhanced flexibility --- lib/std/Build/Module.zig | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/lib/std/Build/Module.zig b/lib/std/Build/Module.zig index 1f2b4f3fcb7f..867978204755 100644 --- a/lib/std/Build/Module.zig +++ b/lib/std/Build/Module.zig @@ -8,7 +8,7 @@ import_table: std.StringArrayHashMapUnmanaged(*Module), resolved_target: ?std.Build.ResolvedTarget = null, optimize: ?std.builtin.OptimizeMode = null, -dwarf_format: ?std.dwarf.Format, +debug_format: ?std.builtin.DebugFormat, c_macros: std.ArrayListUnmanaged([]const u8), include_dirs: std.ArrayListUnmanaged(IncludeDir), @@ -219,7 +219,7 @@ pub const CreateOptions = struct { single_threaded: ?bool = null, strip: ?bool = null, unwind_tables: ?std.builtin.UnwindTables = null, - dwarf_format: ?std.dwarf.Format = null, + debug_format: ?std.builtin.DebugFormat = null, code_model: std.builtin.CodeModel = .default, stack_protector: ?bool = null, stack_check: ?bool = null, @@ -259,7 +259,7 @@ pub fn init( .optimize = options.optimize, .link_libc = options.link_libc, .link_libcpp = options.link_libcpp, - .dwarf_format = options.dwarf_format, + .debug_format = options.debug_format, .c_macros = .{}, .include_dirs = .{}, .lib_paths = .{}, @@ -525,11 +525,17 @@ pub fn appendZigProcessFlags( try addFlag(zig_args, m.pic, "-fPIC", "-fno-PIC"); try addFlag(zig_args, m.red_zone, "-mred-zone", "-mno-red-zone"); - if (m.dwarf_format) |dwarf_format| { - try zig_args.append(switch (dwarf_format) { - .@"32" => "-gdwarf32", - .@"64" => "-gdwarf64", - }); + if (m.debug_format) |debug_format| { + switch (debug_format) { + .strip => {}, + .dwarf => |fmt| switch (fmt) { + .@"32" => try zig_args.append("-gdwarf32"), + .@"64" => try zig_args.append("-gdwarf64"), + }, + .code_view => { + try zig_args.append("-gcodeview"); + }, + } } if (m.unwind_tables) |unwind_tables| { From e69c4ad82158038a1e47d5853384c1ddea4dfdce Mon Sep 17 00:00:00 2001 From: Chan Lee Date: Tue, 7 Jan 2025 16:24:58 +0800 Subject: [PATCH 9/9] windows-gnu: Add support for `-gcodeview` flag --- lib/std/Build/Step/Compile.zig | 6 +++++- src/Compilation.zig | 2 ++ src/Compilation/Config.zig | 1 - src/clang_options_data.zig | 9 ++++++++- src/main.zig | 7 +++++++ tools/update_clang_options.zig | 4 ++++ 6 files changed, 26 insertions(+), 3 deletions(-) diff --git a/lib/std/Build/Step/Compile.zig b/lib/std/Build/Step/Compile.zig index 240847354043..3c6b43e79a2b 100644 --- a/lib/std/Build/Step/Compile.zig +++ b/lib/std/Build/Step/Compile.zig @@ -657,7 +657,11 @@ pub fn producesPdbFile(compile: *Compile) bool { .windows, .uefi => {}, else => return false, } - if (target.abi.isGnu()) return false; + if (compile.root_module.debug_format) |fmt| { + if (fmt != .code_view) return false; + } else { + if (target.abi.isGnu()) return false; + } if (target.ofmt == .c) return false; if (compile.root_module.strip == true or (compile.root_module.strip == null and compile.root_module.optimize == .ReleaseSmall)) diff --git a/src/Compilation.zig b/src/Compilation.zig index 1b66f5da3321..e48bccf52616 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -6321,6 +6321,7 @@ fn buildOutputFromZig( .emit_bin = true, .root_optimize_mode = optimize_mode, .root_strip = strip, + .debug_format = comp.config.debug_format, .link_libc = comp.config.link_libc, }); @@ -6457,6 +6458,7 @@ pub fn build_crt_file( .emit_bin = true, .root_optimize_mode = comp.compilerRtOptMode(), .root_strip = comp.compilerRtStrip(), + .debug_format = comp.config.debug_format, .link_libc = false, .lto = switch (output_mode) { .Lib => comp.config.lto, diff --git a/src/Compilation/Config.zig b/src/Compilation/Config.zig index 5165b58666fd..909ddb9db23d 100644 --- a/src/Compilation/Config.zig +++ b/src/Compilation/Config.zig @@ -67,7 +67,6 @@ pub const CFrontend = enum { clang, aro }; pub const LtoMode = enum { none, full, thin }; - pub const Options = struct { output_mode: std.builtin.OutputMode, resolved_target: Module.ResolvedTarget, diff --git a/src/clang_options_data.zig b/src/clang_options_data.zig index 89de37e8ac73..75a83bf61387 100644 --- a/src/clang_options_data.zig +++ b/src/clang_options_data.zig @@ -4148,7 +4148,14 @@ flagpd1("g3"), .pd2 = false, .psl = false, }, -flagpd1("gcodeview"), +.{ + .name = "gcodeview", + .syntax = .flag, + .zig_equivalent = .gcodeview, + .pd1 = true, + .pd2 = false, + .psl = false, +}, flagpd1("gcodeview-command-line"), flagpd1("gcodeview-ghash"), flagpd1("gcolumn-info"), diff --git a/src/main.zig b/src/main.zig index 31ee3d47acd1..f54ed41dee47 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1547,6 +1547,8 @@ fn buildOutputType( create_module.opts.debug_format = .{ .dwarf = .@"32" }; } else if (mem.eql(u8, arg, "-gdwarf64")) { create_module.opts.debug_format = .{ .dwarf = .@"64" }; + } else if (mem.eql(u8, arg, "-gcodeview")) { + create_module.opts.debug_format = .code_view; } else if (mem.eql(u8, arg, "-fformatted-panics")) { // Remove this after 0.15.0 is tagged. warn("-fformatted-panics is deprecated and does nothing", .{}); @@ -2181,6 +2183,10 @@ fn buildOutputType( try cc_argv.appendSlice(arena, it.other_args); } }, + .gcodeview => { + mod_opts.strip = false; + create_module.opts.debug_format = .code_view; + }, .gdwarf32 => { mod_opts.strip = false; create_module.opts.debug_format = .{ .dwarf = .@"32" }; @@ -5797,6 +5803,7 @@ pub const ClangArgIterator = struct { asm_only, optimize, debug, + gcodeview, gdwarf32, gdwarf64, sanitize, diff --git a/tools/update_clang_options.zig b/tools/update_clang_options.zig index b8916e5e6aac..de8caa1f59d9 100644 --- a/tools/update_clang_options.zig +++ b/tools/update_clang_options.zig @@ -252,6 +252,10 @@ const known_options = [_]KnownOpt{ .name = "debug", .ident = "debug", }, + .{ + .name = "gcodeview", + .ident = "gcodeview", + }, .{ .name = "gdwarf32", .ident = "gdwarf32",