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
This commit is contained in:
Andrew Kelley
2026-03-25 18:29:19 -07:00
parent 54b3484256
commit abd131e336
5 changed files with 47 additions and 15 deletions
+1
View File
@@ -1121,6 +1121,7 @@ pub const ClangCliParam = struct {
rtlib,
static,
dynamic,
version,
};
pub fn matchEql(self: @This(), arg: []const u8) u2 {
+16 -11
View File
@@ -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| {
+2 -1
View File
@@ -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" },
.{
+24 -3
View File
@@ -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
+4
View File
@@ -590,6 +590,10 @@ const known_options = [_]KnownOpt{
.name = "dynamic",
.ident = "dynamic",
},
.{
.name = "version",
.ident = "version",
},
};
const blacklisted_options = [_][]const u8{};