Skip to content

Commit 1685f0a

Browse files
committed
std.Build: add precompiled C header creation
1 parent a3e4718 commit 1685f0a

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.* = .{
@@ -691,17 +697,20 @@ pub fn linkFrameworkWeak(c: *Compile, name: []const u8) void {
691697

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

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

701709
/// Resource files must have the extension `.rc`.
702710
/// Can be called regardless of target. The .rc file will be ignored
703711
/// if the target object format does not support embedded resources.
704712
pub fn addWin32ResourceFile(self: *Compile, source: Module.RcSourceFile) void {
713+
assert(self.kind != .pch); // pch can only be generated from a single C header file
705714
self.root_module.addWin32ResourceFile(source);
706715
}
707716

@@ -784,14 +793,17 @@ pub fn getEmittedLlvmBc(self: *Compile) LazyPath {
784793
}
785794

786795
pub fn addAssemblyFile(self: *Compile, source: LazyPath) void {
796+
assert(self.kind != .pch); // pch can only be generated from a single C header file
787797
self.root_module.addAssemblyFile(source);
788798
}
789799

790800
pub fn addObjectFile(self: *Compile, source: LazyPath) void {
801+
assert(self.kind != .pch); // pch can only be generated from a single C header file
791802
self.root_module.addObjectFile(source);
792803
}
793804

794805
pub fn addObject(self: *Compile, object: *Compile) void {
806+
assert(self.kind != .pch); // pch can only be generated from a single C header file
795807
self.root_module.addObject(object);
796808
}
797809

@@ -916,6 +928,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
916928
.lib => "build-lib",
917929
.exe => "build-exe",
918930
.obj => "build-obj",
931+
.pch => "build-pch",
919932
.@"test" => "test",
920933
};
921934
try zig_args.append(cmd);
@@ -975,6 +988,14 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
975988
}
976989
}
977990

991+
if (self.kind == .pch) {
992+
// precompiled headers must have a single input header file.
993+
var it = self.root_module.iterateDependencies(self, false);
994+
const link_objects = it.next().?.module.link_objects;
995+
assert(link_objects.items.len == 1 and link_objects.items[0] == .c_source_file);
996+
assert(it.next() == null);
997+
}
998+
978999
var cli_named_modules = try CliNamedModules.init(arena, &self.root_module);
9791000

9801001
// For this loop, don't chase dynamic libraries because their link
@@ -1076,6 +1097,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
10761097
switch (other.kind) {
10771098
.exe => return step.fail("cannot link with an executable build artifact", .{}),
10781099
.@"test" => return step.fail("cannot link with a test", .{}),
1100+
.pch => @panic("Cannot link with a precompiled header file"),
10791101
.obj => {
10801102
const included_in_lib_or_obj = !my_responsibility and (compile.kind == .lib or compile.kind == .obj);
10811103
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)