Skip to content

Commit 1ab485f

Browse files
committed
std.Build: add precompiled C header creation
1 parent b4cbc9f commit 1ab485f

File tree

3 files changed

+62
-15
lines changed

3 files changed

+62
-15
lines changed

lib/std/Build.zig

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

717+
pub const PchOptions = struct {
718+
name: []const u8,
719+
target: ResolvedTarget,
720+
optimize: std.builtin.OptimizeMode,
721+
max_rss: usize = 0,
722+
link_libc: ?bool = null,
723+
link_libcpp: ?bool = null,
724+
};
725+
726+
pub fn addPrecompiledCHeader(b: *Build, options: PchOptions, source: Module.CSourceFile) *Step.Compile {
727+
const pch = Step.Compile.create(b, .{
728+
.name = options.name,
729+
.root_module = .{
730+
.target = options.target,
731+
.optimize = options.optimize,
732+
.link_libc = options.link_libc,
733+
.link_libcpp = options.link_libcpp,
734+
},
735+
.kind = .pch,
736+
.max_rss = options.max_rss,
737+
});
738+
pch.addCSourceFile(source);
739+
return pch;
740+
}
741+
717742
pub const SharedLibraryOptions = struct {
718743
name: []const u8,
719744
/// To choose the same computer as the one building the package, pass the

lib/std/Build/Step/Compile.zig

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ pub const Kind = enum {
238238
exe,
239239
lib,
240240
obj,
241+
pch,
241242
@"test",
242243
};
243244

@@ -263,27 +264,32 @@ pub fn create(owner: *std.Build, options: Options) *Compile {
263264
.exe => "zig build-exe",
264265
.lib => "zig build-lib",
265266
.obj => "zig build-obj",
267+
.pch => "zig build-pch",
266268
.@"test" => "zig test",
267269
},
268270
name_adjusted,
269271
@tagName(options.root_module.optimize orelse .Debug),
270272
resolved_target.query.zigTriple(owner.allocator) catch @panic("OOM"),
271273
});
272274

273-
const out_filename = std.zig.binNameAlloc(owner.allocator, .{
274-
.root_name = name,
275-
.target = target,
276-
.output_mode = switch (options.kind) {
277-
.lib => .Lib,
278-
.obj => .Obj,
279-
.exe, .@"test" => .Exe,
280-
},
281-
.link_mode = if (options.linkage) |some| @as(std.builtin.LinkMode, switch (some) {
282-
.dynamic => .Dynamic,
283-
.static => .Static,
284-
}) else null,
285-
.version = options.version,
286-
}) catch @panic("OOM");
275+
const out_filename = if (options.kind == .pch)
276+
std.fmt.allocPrint(owner.allocator, "{s}.pch", .{name}) catch @panic("OOM")
277+
else
278+
std.zig.binNameAlloc(owner.allocator, .{
279+
.root_name = name,
280+
.target = target,
281+
.output_mode = switch (options.kind) {
282+
.lib => .Lib,
283+
.obj => .Obj,
284+
.exe, .@"test" => .Exe,
285+
.pch => unreachable,
286+
},
287+
.link_mode = if (options.linkage) |some| @as(std.builtin.LinkMode, switch (some) {
288+
.dynamic => .Dynamic,
289+
.static => .Static,
290+
}) else null,
291+
.version = options.version,
292+
}) catch @panic("OOM");
287293

288294
const self = owner.allocator.create(Compile) catch @panic("OOM");
289295
self.* = .{
@@ -701,17 +707,20 @@ pub fn linkFrameworkWeak(c: *Compile, name: []const u8) void {
701707

702708
/// Handy when you have many C/C++ source files and want them all to have the same flags.
703709
pub fn addCSourceFiles(self: *Compile, options: Module.AddCSourceFilesOptions) void {
710+
assert(self.kind != .pch); // pch can only be generated from a single C header file
704711
self.root_module.addCSourceFiles(options);
705712
}
706713

707714
pub fn addCSourceFile(self: *Compile, source: Module.CSourceFile) void {
715+
assert(self.kind != .pch or self.root_module.link_objects.items.len == 0); // pch can only be generated from a single C header file
708716
self.root_module.addCSourceFile(source);
709717
}
710718

711719
/// Resource files must have the extension `.rc`.
712720
/// Can be called regardless of target. The .rc file will be ignored
713721
/// if the target object format does not support embedded resources.
714722
pub fn addWin32ResourceFile(self: *Compile, source: Module.RcSourceFile) void {
723+
assert(self.kind != .pch); // pch can only be generated from a single C header file
715724
self.root_module.addWin32ResourceFile(source);
716725
}
717726

@@ -794,14 +803,17 @@ pub fn getEmittedLlvmBc(self: *Compile) LazyPath {
794803
}
795804

796805
pub fn addAssemblyFile(self: *Compile, source: LazyPath) void {
806+
assert(self.kind != .pch); // pch can only be generated from a single C header file
797807
self.root_module.addAssemblyFile(source);
798808
}
799809

800810
pub fn addObjectFile(self: *Compile, source: LazyPath) void {
811+
assert(self.kind != .pch); // pch can only be generated from a single C header file
801812
self.root_module.addObjectFile(source);
802813
}
803814

804815
pub fn addObject(self: *Compile, object: *Compile) void {
816+
assert(self.kind != .pch); // pch can only be generated from a single C header file
805817
self.root_module.addObject(object);
806818
}
807819

@@ -926,6 +938,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
926938
.lib => "build-lib",
927939
.exe => "build-exe",
928940
.obj => "build-obj",
941+
.pch => "build-pch",
929942
.@"test" => "test",
930943
};
931944
try zig_args.append(cmd);
@@ -988,6 +1001,14 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
9881001
}
9891002
}
9901003

1004+
if (self.kind == .pch) {
1005+
// precompiled headers must have a single input header file.
1006+
var it = self.root_module.iterateDependencies(self, false);
1007+
const link_objects = it.next().?.module.link_objects;
1008+
assert(link_objects.items.len == 1 and link_objects.items[0] == .c_source_file);
1009+
assert(it.next() == null);
1010+
}
1011+
9911012
var cli_named_modules = try CliNamedModules.init(arena, &self.root_module);
9921013

9931014
// For this loop, don't chase dynamic libraries because their link
@@ -1096,6 +1117,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
10961117
switch (other.kind) {
10971118
.exe => return step.fail("cannot link with an executable build artifact", .{}),
10981119
.@"test" => return step.fail("cannot link with a test", .{}),
1120+
.pch => @panic("Cannot link with a precompiled header file"),
10991121
.obj => {
11001122
const included_in_lib_or_obj = !my_responsibility and (compile.kind == .lib or compile.kind == .obj);
11011123
if (!already_linked and !included_in_lib_or_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" => InstallDir{ .bin = {} },
6161
.lib => InstallDir{ .lib = {} },
6262
},

0 commit comments

Comments
 (0)