Skip to content

Commit ea68835

Browse files
committed
std.Build: add precompiled C header creation
adds a new mode to the Compile step. It shares most of the code with previous compile steps, but with extra constraints expressed by assert checks.
1 parent aabd291 commit ea68835

File tree

3 files changed

+59
-12
lines changed

3 files changed

+59
-12
lines changed

lib/std/Build.zig

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -748,6 +748,31 @@ pub fn addObject(b: *Build, options: ObjectOptions) *Step.Compile {
748748
});
749749
}
750750

751+
pub const PchOptions = struct {
752+
name: []const u8,
753+
target: ResolvedTarget,
754+
optimize: std.builtin.OptimizeMode,
755+
max_rss: usize = 0,
756+
link_libc: ?bool = null,
757+
link_libcpp: ?bool = null,
758+
};
759+
760+
pub fn addPrecompiledCHeader(b: *Build, options: PchOptions, source: Module.CSourceFile) *Step.Compile {
761+
const pch = Step.Compile.create(b, .{
762+
.name = options.name,
763+
.root_module = .{
764+
.target = options.target,
765+
.optimize = options.optimize,
766+
.link_libc = options.link_libc,
767+
.link_libcpp = options.link_libcpp,
768+
},
769+
.kind = .pch,
770+
.max_rss = options.max_rss,
771+
});
772+
pch.addCSourceFile(source);
773+
return pch;
774+
}
775+
751776
pub const SharedLibraryOptions = struct {
752777
name: []const u8,
753778
/// To choose the same computer as the one building the package, pass the

lib/std/Build/Step/Compile.zig

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,7 @@ pub const Kind = enum {
267267
exe,
268268
lib,
269269
obj,
270+
pch,
270271
@"test",
271272
};
272273

@@ -350,24 +351,29 @@ pub fn create(owner: *std.Build, options: Options) *Compile {
350351
.exe => "zig build-exe",
351352
.lib => "zig build-lib",
352353
.obj => "zig build-obj",
354+
.pch => "zig build-pch",
353355
.@"test" => "zig test",
354356
},
355357
name_adjusted,
356358
@tagName(options.root_module.optimize orelse .Debug),
357359
resolved_target.query.zigTriple(owner.allocator) catch @panic("OOM"),
358360
});
359361

360-
const out_filename = std.zig.binNameAlloc(owner.allocator, .{
361-
.root_name = name,
362-
.target = target,
363-
.output_mode = switch (options.kind) {
364-
.lib => .Lib,
365-
.obj => .Obj,
366-
.exe, .@"test" => .Exe,
367-
},
368-
.link_mode = options.linkage,
369-
.version = options.version,
370-
}) catch @panic("OOM");
362+
const out_filename = if (options.kind == .pch)
363+
std.fmt.allocPrint(owner.allocator, "{s}.pch", .{name}) catch @panic("OOM")
364+
else
365+
std.zig.binNameAlloc(owner.allocator, .{
366+
.root_name = name,
367+
.target = target,
368+
.output_mode = switch (options.kind) {
369+
.lib => .Lib,
370+
.obj => .Obj,
371+
.exe, .@"test" => .Exe,
372+
.pch => unreachable,
373+
},
374+
.link_mode = options.linkage,
375+
.version = options.version,
376+
}) catch @panic("OOM");
371377

372378
const compile = owner.allocator.create(Compile) catch @panic("OOM");
373379
compile.* = .{
@@ -796,17 +802,20 @@ pub fn linkFrameworkWeak(c: *Compile, name: []const u8) void {
796802

797803
/// Handy when you have many C/C++ source files and want them all to have the same flags.
798804
pub fn addCSourceFiles(compile: *Compile, options: Module.AddCSourceFilesOptions) void {
805+
assert(compile.kind != .pch); // pch can only be generated from a single C header file
799806
compile.root_module.addCSourceFiles(options);
800807
}
801808

802809
pub fn addCSourceFile(compile: *Compile, source: Module.CSourceFile) void {
810+
assert(compile.kind != .pch or compile.root_module.link_objects.items.len == 0); // pch can only be generated from a single C header file
803811
compile.root_module.addCSourceFile(source);
804812
}
805813

806814
/// Resource files must have the extension `.rc`.
807815
/// Can be called regardless of target. The .rc file will be ignored
808816
/// if the target object format does not support embedded resources.
809817
pub fn addWin32ResourceFile(compile: *Compile, source: Module.RcSourceFile) void {
818+
assert(compile.kind != .pch); // pch can only be generated from a single C header file
810819
compile.root_module.addWin32ResourceFile(source);
811820
}
812821

@@ -887,14 +896,17 @@ pub fn getEmittedLlvmBc(compile: *Compile) LazyPath {
887896
}
888897

889898
pub fn addAssemblyFile(compile: *Compile, source: Module.AsmSourceFile) void {
899+
assert(compile.kind != .pch); // pch can only be generated from a single C header file
890900
compile.root_module.addAssemblyFile(source);
891901
}
892902

893903
pub fn addObjectFile(compile: *Compile, source: LazyPath) void {
904+
assert(compile.kind != .pch); // pch can only be generated from a single C header file
894905
compile.root_module.addObjectFile(source);
895906
}
896907

897908
pub fn addObject(compile: *Compile, object: *Compile) void {
909+
assert(compile.kind != .pch); // pch can only be generated from a single C header file
898910
compile.root_module.addObject(object);
899911
}
900912

@@ -1019,6 +1031,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 {
10191031
.lib => "build-lib",
10201032
.exe => "build-exe",
10211033
.obj => "build-obj",
1034+
.pch => "build-pch",
10221035
.@"test" => "test",
10231036
};
10241037
try zig_args.append(cmd);
@@ -1086,6 +1099,14 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 {
10861099
}
10871100
}
10881101

1102+
if (compile.kind == .pch) {
1103+
// precompiled headers must have a single input header file.
1104+
var it = compile.root_module.iterateDependencies(compile, false);
1105+
const link_objects = it.next().?.module.link_objects;
1106+
assert(link_objects.items.len == 1 and link_objects.items[0] == .c_source_file);
1107+
assert(it.next() == null);
1108+
}
1109+
10891110
var cli_named_modules = try CliNamedModules.init(arena, &compile.root_module);
10901111

10911112
// For this loop, don't chase dynamic libraries because their link
@@ -1197,6 +1218,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 {
11971218
switch (other.kind) {
11981219
.exe => return step.fail("cannot link with an executable build artifact", .{}),
11991220
.@"test" => return step.fail("cannot link with a test", .{}),
1221+
.pch => @panic("Cannot link with a precompiled header file"),
12001222
.obj => {
12011223
const included_in_lib_or_obj = !my_responsibility and
12021224
(dep.compile.?.kind == .lib or dep.compile.?.kind == .obj);

lib/std/Build/Step/InstallArtifact.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ pub fn create(owner: *std.Build, artifact: *Step.Compile, options: Options) *Ins
5656
const dest_dir: ?InstallDir = switch (options.dest_dir) {
5757
.disabled => null,
5858
.default => switch (artifact.kind) {
59-
.obj => @panic("object files have no standard installation procedure"),
59+
.obj, .pch => @panic("object files have no standard installation procedure"),
6060
.exe, .@"test" => .bin,
6161
.lib => if (artifact.isDll()) .bin else .lib,
6262
},

0 commit comments

Comments
 (0)