zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit abd131e3367bb10a67bc4c240b87b05d1de4e42f (tree)
parent 54b3484256695381c034aa30f322b1499a4b27c8
Author: Andrew Kelley <andrew@ziglang.org>
Date:   Wed, 25 Mar 2026 18:29:19 -0700

zig cc: make --version use the full clang CLI lowering code path

because clang wants to parse the -target argument with clang -target
syntax.

closes #30178

Diffstat:
Mlib/std/zig.zig | 1+
Msrc/Compilation.zig | 27++++++++++++++++-----------
Msrc/clang_options.zon | 3++-
Msrc/main.zig | 27++++++++++++++++++++++++---
Mtools/update_clang_options.zig | 4++++
5 files changed, 47 insertions(+), 15 deletions(-)

diff --git a/lib/std/zig.zig b/lib/std/zig.zig @@ -1121,6 +1121,7 @@ pub const ClangCliParam = struct { rtlib, static, dynamic, + version, }; pub fn matchEql(self: @This(), arg: []const u8) u2 { diff --git a/src/Compilation.zig b/src/Compilation.zig @@ -1471,6 +1471,8 @@ pub const ClangPreprocessorMode = enum { stdout, /// precompiled C header pch, + /// `--version` + version, }; pub const Framework = link.File.MachO.Framework; @@ -2936,16 +2938,16 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE .none => unreachable, .manifest_create, .manifest_read, .manifest_lock => |e| return comp.setMiscFailure( .check_whole_cache, - "failed to check cache: {s} {s}", - .{ @tagName(man.diagnostic), @errorName(e) }, + "failed to check cache: {t} {t}", + .{ man.diagnostic, e }, ), .file_open, .file_stat, .file_read, .file_hash => |op| { const pp = man.files.keys()[op.file_index].prefixed_path; const prefix = man.cache.prefixes()[pp.prefix]; return comp.setMiscFailure( .check_whole_cache, - "failed to check cache: '{f}{s}' {s} {s}", - .{ prefix, pp.sub_path, @tagName(man.diagnostic), @errorName(op.err) }, + "failed to check cache: '{f}{s}' {t} {t}", + .{ prefix, pp.sub_path, man.diagnostic, op.err }, ); }, }, @@ -5739,6 +5741,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr .yes => argv.appendSliceAssumeCapacity(&.{ "-E", "-o", out_obj_path }), .pch => argv.appendSliceAssumeCapacity(&.{ "-Xclang", "-emit-pch", "-o", out_obj_path }), .stdout => argv.appendAssumeCapacity("-E"), + .version => argv.appendAssumeCapacity("--version"), } if (comp.emit_asm != null) { @@ -5782,6 +5785,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr .yes => argv.appendSliceAssumeCapacity(&.{ "-E", "-o", out_obj_path }), .pch => argv.appendSliceAssumeCapacity(&.{ "-Xclang", "-emit-pch", "-o", out_obj_path }), .stdout => argv.appendAssumeCapacity("-E"), + .version => argv.appendAssumeCapacity("--version"), } if (out_diag_path) |diag_file_path| { argv.appendSliceAssumeCapacity(&.{ "--serialize-diagnostics", diag_file_path }); @@ -5830,8 +5834,10 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr if (code != 0) { std.process.exit(code); } - if (comp.clang_preprocessor_mode == .stdout) - std.process.exit(0); + switch (comp.clang_preprocessor_mode) { + .stdout, .version => std.process.exit(0), + else => {}, + } }, else => std.process.abort(), } @@ -5879,11 +5885,10 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr return comp.failCObj(c_object, "clang exited with code {d}", .{exit_code}); } } - if (comp.clang_passthrough_mode and - comp.clang_preprocessor_mode == .stdout) - { - std.process.exit(0); - } + if (comp.clang_passthrough_mode) switch (comp.clang_preprocessor_mode) { + .stdout, .version => std.process.exit(0), + else => {}, + }; } if (out_dep_path) |dep_file_path| { diff --git a/src/clang_options.zon b/src/clang_options.zon @@ -637,6 +637,7 @@ }, .{ .name = "version", + .ze = .version, .pd1 = false, .pd2 = true, }, @@ -3378,7 +3379,7 @@ }, .{ .name = "verify-ignore-unexpected" }, .{ .name = "verify-pch" }, -.{ .name = "version" }, +.{ .name = "version", .ze = .version }, .{ .name = "via-file-asm", .pd2 = true }, .{ .name = "w" }, .{ diff --git a/src/main.zig b/src/main.zig @@ -1889,6 +1889,7 @@ fn buildOutputType( object, assembly, preprocessor, + version, }; var c_out_mode: ?COutMode = null; var out_path: ?[]const u8 = null; @@ -1917,6 +1918,10 @@ fn buildOutputType( .c, .r => c_out_mode = .object, // -c or -r .asm_only => c_out_mode = .assembly, // -S .preprocess_only => c_out_mode = .preprocessor, // -E + .version => { + c_out_mode = .version; // --version + disable_c_depfile = true; + }, .emit_llvm => emit_llvm = true, .x => { const lang = mem.sliceTo(it.only_arg, 0); @@ -2939,9 +2944,11 @@ fn buildOutputType( } // precompiled header syntax: "zig cc -x c-header test.h -o test.pch" - const emit_pch = ((file_ext == .h or file_ext == .hpp or file_ext == .hm or file_ext == .hmm) and c_out_mode == null); - if (emit_pch) - c_out_mode = .preprocessor; + const emit_pch = if (file_ext) |fe| switch (fe) { + .h, .hpp, .hm, .hmm => c_out_mode == null, + else => false, + } else false; + if (emit_pch) c_out_mode = .preprocessor; switch (c_out_mode orelse .link) { .link => { @@ -3009,6 +3016,20 @@ fn buildOutputType( } } }, + .version => { + // We can't allow control flow to reach the simpler logic + // below because the -target argument has to be lowered to + // clang syntax in Compilation. + create_module.opts.output_mode = .Obj; + clang_preprocessor_mode = .version; + if (create_module.c_source_files.items.len == 0) { + try create_module.c_source_files.append(arena, .{ + .owner = undefined, + .src_path = "a.c", // dummy name + .ext = .c, + }); + } + }, } if (create_module.c_source_files.items.len == 0 and !anyObjectLinkInputs(create_module.cli_link_inputs.items) and diff --git a/tools/update_clang_options.zig b/tools/update_clang_options.zig @@ -590,6 +590,10 @@ const known_options = [_]KnownOpt{ .name = "dynamic", .ident = "dynamic", }, + .{ + .name = "version", + .ident = "version", + }, }; const blacklisted_options = [_][]const u8{};