Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

zig cc: expose clang precompiled C header support #18600

Merged
merged 1 commit into from
Jan 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 24 additions & 10 deletions src/Compilation.zig
Original file line number Diff line number Diff line change
Expand Up @@ -270,11 +270,11 @@ pub const LangToExt = std.ComptimeStringMap(FileExt, .{
.{ "c", .c },
.{ "c-header", .h },
.{ "c++", .cpp },
.{ "c++-header", .h },
.{ "c++-header", .hpp },
.{ "objective-c", .m },
.{ "objective-c-header", .h },
.{ "objective-c-header", .hm },
.{ "objective-c++", .mm },
.{ "objective-c++-header", .h },
.{ "objective-c++-header", .hmm },
.{ "assembler", .assembly },
.{ "assembler-with-cpp", .assembly_with_cpp },
.{ "cuda", .cu },
Expand Down Expand Up @@ -887,6 +887,8 @@ pub const ClangPreprocessorMode = enum {
yes,
/// This means we are doing `zig cc -E`.
stdout,
/// precompiled C header
pch,
};

pub const Framework = link.File.MachO.Framework;
Expand Down Expand Up @@ -4393,6 +4395,10 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P
.assembly_with_cpp => "assembler-with-cpp",
.c => "c",
.cpp => "c++",
.h => "c-header",
.hpp => "c++-header",
.hm => "objective-c-header",
.hmm => "objective-c++-header",
.cu => "cuda",
.m => "objective-c",
.mm => "objective-c++",
Expand All @@ -4418,10 +4424,11 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P
else
"/dev/null";

try argv.ensureUnusedCapacity(5);
try argv.ensureUnusedCapacity(6);
switch (comp.clang_preprocessor_mode) {
.no => argv.appendSliceAssumeCapacity(&[_][]const u8{ "-c", "-o", out_obj_path }),
.yes => argv.appendSliceAssumeCapacity(&[_][]const u8{ "-E", "-o", out_obj_path }),
.no => argv.appendSliceAssumeCapacity(&.{ "-c", "-o", out_obj_path }),
.yes => argv.appendSliceAssumeCapacity(&.{ "-E", "-o", out_obj_path }),
.pch => argv.appendSliceAssumeCapacity(&.{ "-Xclang", "-emit-pch", "-o", out_obj_path }),
.stdout => argv.appendAssumeCapacity("-E"),
}

Expand Down Expand Up @@ -4456,10 +4463,11 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P
try argv.appendSlice(c_object.src.extra_flags);
try argv.appendSlice(c_object.src.cache_exempt_flags);

try argv.ensureUnusedCapacity(5);
try argv.ensureUnusedCapacity(6);
switch (comp.clang_preprocessor_mode) {
.no => argv.appendSliceAssumeCapacity(&.{ "-c", "-o", out_obj_path }),
.yes => argv.appendSliceAssumeCapacity(&.{ "-E", "-o", out_obj_path }),
.pch => argv.appendSliceAssumeCapacity(&.{ "-Xclang", "-emit-pch", "-o", out_obj_path }),
.stdout => argv.appendAssumeCapacity("-E"),
}
if (comp.clang_passthrough_mode) {
Expand Down Expand Up @@ -5101,7 +5109,7 @@ pub fn addCCArgs(
try argv.appendSlice(&[_][]const u8{ "-target", llvm_triple });

if (target.os.tag == .windows) switch (ext) {
.c, .cpp, .m, .mm, .h, .cu, .rc, .assembly, .assembly_with_cpp => {
.c, .cpp, .m, .mm, .h, .hpp, .hm, .hmm, .cu, .rc, .assembly, .assembly_with_cpp => {
const minver: u16 = @truncate(@intFromEnum(target.os.getVersionRange().windows.min) >> 16);
try argv.append(
try std.fmt.allocPrint(arena, "-D_WIN32_WINNT=0x{x:0>4}", .{minver}),
Expand All @@ -5111,7 +5119,7 @@ pub fn addCCArgs(
};

switch (ext) {
.c, .cpp, .m, .mm, .h, .cu, .rc => {
.c, .cpp, .m, .mm, .h, .hpp, .hm, .hmm, .cu, .rc => {
try argv.appendSlice(&[_][]const u8{
"-nostdinc",
"-fno-spell-checking",
Expand Down Expand Up @@ -5679,6 +5687,9 @@ pub const FileExt = enum {
cpp,
cu,
h,
hpp,
hm,
hmm,
m,
mm,
ll,
Expand All @@ -5697,7 +5708,7 @@ pub const FileExt = enum {

pub fn clangSupportsDepFile(ext: FileExt) bool {
return switch (ext) {
.c, .cpp, .h, .m, .mm, .cu => true,
.c, .cpp, .h, .hpp, .hm, .hmm, .m, .mm, .cu => true,

.ll,
.bc,
Expand All @@ -5722,6 +5733,9 @@ pub const FileExt = enum {
.cpp => ".cpp",
.cu => ".cu",
.h => ".h",
.hpp => ".h",
.hm => ".h",
.hmm => ".h",
.m => ".m",
.mm => ".mm",
.ll => ".ll",
Expand Down
2 changes: 1 addition & 1 deletion src/link.zig
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,7 @@ pub const File = struct {
return @fieldParentPtr(C, "base", base).flush(arena, prog_node);
}
const comp = base.comp;
if (comp.clang_preprocessor_mode == .yes) {
if (comp.clang_preprocessor_mode == .yes or comp.clang_preprocessor_mode == .pch) {
const gpa = comp.gpa;
const emit = base.emit;
// TODO: avoid extra link step when it's just 1 object file (the `zig cc -c` case)
Expand Down
43 changes: 28 additions & 15 deletions src/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1694,7 +1694,7 @@ fn buildOutputType(
fatal("only one manifest file can be specified, found '{s}' after '{s}'", .{ arg, other });
} else manifest_file = arg;
},
.assembly, .assembly_with_cpp, .c, .cpp, .h, .ll, .bc, .m, .mm, .cu => {
.assembly, .assembly_with_cpp, .c, .cpp, .h, .hpp, .hm, .hmm, .ll, .bc, .m, .mm, .cu => {
try create_module.c_source_files.append(arena, .{
// Populated after module creation.
.owner = undefined,
Expand Down Expand Up @@ -1746,7 +1746,7 @@ fn buildOutputType(
assembly,
preprocessor,
};
var c_out_mode: COutMode = .link;
var c_out_mode: ?COutMode = null;
var out_path: ?[]const u8 = null;
var is_shared_lib = false;
var linker_args = std.ArrayList([]const u8).init(arena);
Expand Down Expand Up @@ -1789,7 +1789,7 @@ fn buildOutputType(
try cc_argv.appendSlice(arena, it.other_args);
},
.positional => switch (file_ext orelse Compilation.classifyFileExt(mem.sliceTo(it.only_arg, 0))) {
.assembly, .assembly_with_cpp, .c, .cpp, .ll, .bc, .h, .m, .mm, .cu => {
.assembly, .assembly_with_cpp, .c, .cpp, .ll, .bc, .h, .hpp, .hm, .hmm, .m, .mm, .cu => {
try create_module.c_source_files.append(arena, .{
// Populated after module creation.
.owner = undefined,
Expand Down Expand Up @@ -2462,7 +2462,12 @@ fn buildOutputType(
}
}

switch (c_out_mode) {
// 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;

switch (c_out_mode orelse .link) {
.link => {
create_module.opts.output_mode = if (is_shared_lib) .Lib else .Exe;
emit_bin = if (out_path) |p| .{ .yes = p } else EmitBin.yes_a_out;
Expand Down Expand Up @@ -2511,11 +2516,16 @@ fn buildOutputType(
// For example `zig cc` and no args should print the "no input files" message.
return process.exit(try clangMain(arena, all_args));
}
if (out_path) |p| {
emit_bin = .{ .yes = p };
clang_preprocessor_mode = .yes;
if (emit_pch) {
emit_bin = if (out_path) |p| .{ .yes = p } else .yes_default_path;
clang_preprocessor_mode = .pch;
} else {
clang_preprocessor_mode = .stdout;
if (out_path) |p| {
emit_bin = .{ .yes = p };
clang_preprocessor_mode = .yes;
} else {
clang_preprocessor_mode = .stdout;
}
}
},
}
Expand Down Expand Up @@ -2882,13 +2892,16 @@ fn buildOutputType(
},
}
},
.basename = try std.zig.binNameAlloc(arena, .{
.root_name = root_name,
.target = target,
.output_mode = create_module.resolved_options.output_mode,
.link_mode = create_module.resolved_options.link_mode,
.version = optional_version,
}),
.basename = if (clang_preprocessor_mode == .pch)
try std.fmt.allocPrint(arena, "{s}.pch", .{root_name})
else
try std.zig.binNameAlloc(arena, .{
.root_name = root_name,
.target = target,
.output_mode = create_module.resolved_options.output_mode,
.link_mode = create_module.resolved_options.link_mode,
.version = optional_version,
}),
},
.yes => |full_path| b: {
const basename = fs.path.basename(full_path);
Expand Down