Skip to content

Commit 67f7019

Browse files
committed
std.Build: add precompiled C header creation
1 parent ab5d1b4 commit 67f7019

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
@@ -741,6 +741,31 @@ pub fn addObject(b: *Build, options: ObjectOptions) *Step.Compile {
741741
});
742742
}
743743

744+
pub const PchOptions = struct {
745+
name: []const u8,
746+
target: ResolvedTarget,
747+
optimize: std.builtin.OptimizeMode,
748+
max_rss: usize = 0,
749+
link_libc: ?bool = null,
750+
link_libcpp: ?bool = null,
751+
};
752+
753+
pub fn addPrecompiledCHeader(b: *Build, options: PchOptions, source: Module.CSourceFile) *Step.Compile {
754+
const pch = Step.Compile.create(b, .{
755+
.name = options.name,
756+
.root_module = .{
757+
.target = options.target,
758+
.optimize = options.optimize,
759+
.link_libc = options.link_libc,
760+
.link_libcpp = options.link_libcpp,
761+
},
762+
.kind = .pch,
763+
.max_rss = options.max_rss,
764+
});
765+
pch.addCSourceFile(source);
766+
return pch;
767+
}
768+
744769
pub const SharedLibraryOptions = struct {
745770
name: []const u8,
746771
/// 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
@@ -252,6 +252,7 @@ pub const Kind = enum {
252252
exe,
253253
lib,
254254
obj,
255+
pch,
255256
@"test",
256257
};
257258

@@ -359,24 +360,29 @@ pub fn create(owner: *std.Build, options: Options) *Compile {
359360
.exe => "zig build-exe",
360361
.lib => "zig build-lib",
361362
.obj => "zig build-obj",
363+
.pch => "zig build-pch",
362364
.@"test" => "zig test",
363365
},
364366
name_adjusted,
365367
@tagName(options.root_module.optimize orelse .Debug),
366368
resolved_target.query.zigTriple(owner.allocator) catch @panic("OOM"),
367369
});
368370

369-
const out_filename = std.zig.binNameAlloc(owner.allocator, .{
370-
.root_name = name,
371-
.target = target,
372-
.output_mode = switch (options.kind) {
373-
.lib => .Lib,
374-
.obj => .Obj,
375-
.exe, .@"test" => .Exe,
376-
},
377-
.link_mode = options.linkage,
378-
.version = options.version,
379-
}) catch @panic("OOM");
371+
const out_filename = if (options.kind == .pch)
372+
std.fmt.allocPrint(owner.allocator, "{s}.pch", .{name}) catch @panic("OOM")
373+
else
374+
std.zig.binNameAlloc(owner.allocator, .{
375+
.root_name = name,
376+
.target = target,
377+
.output_mode = switch (options.kind) {
378+
.lib => .Lib,
379+
.obj => .Obj,
380+
.exe, .@"test" => .Exe,
381+
.pch => unreachable,
382+
},
383+
.link_mode = options.linkage,
384+
.version = options.version,
385+
}) catch @panic("OOM");
380386

381387
const self = owner.allocator.create(Compile) catch @panic("OOM");
382388
self.* = .{
@@ -801,17 +807,20 @@ pub fn linkFrameworkWeak(c: *Compile, name: []const u8) void {
801807

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

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

811819
/// Resource files must have the extension `.rc`.
812820
/// Can be called regardless of target. The .rc file will be ignored
813821
/// if the target object format does not support embedded resources.
814822
pub fn addWin32ResourceFile(self: *Compile, source: Module.RcSourceFile) void {
823+
assert(self.kind != .pch); // pch can only be generated from a single C header file
815824
self.root_module.addWin32ResourceFile(source);
816825
}
817826

@@ -894,14 +903,17 @@ pub fn getEmittedLlvmBc(self: *Compile) LazyPath {
894903
}
895904

896905
pub fn addAssemblyFile(self: *Compile, source: LazyPath) void {
906+
assert(self.kind != .pch); // pch can only be generated from a single C header file
897907
self.root_module.addAssemblyFile(source);
898908
}
899909

900910
pub fn addObjectFile(self: *Compile, source: LazyPath) void {
911+
assert(self.kind != .pch); // pch can only be generated from a single C header file
901912
self.root_module.addObjectFile(source);
902913
}
903914

904915
pub fn addObject(self: *Compile, object: *Compile) void {
916+
assert(self.kind != .pch); // pch can only be generated from a single C header file
905917
self.root_module.addObject(object);
906918
}
907919

@@ -1026,6 +1038,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
10261038
.lib => "build-lib",
10271039
.exe => "build-exe",
10281040
.obj => "build-obj",
1041+
.pch => "build-pch",
10291042
.@"test" => "test",
10301043
};
10311044
try zig_args.append(cmd);
@@ -1098,6 +1111,14 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
10981111
}
10991112
}
11001113

1114+
if (self.kind == .pch) {
1115+
// precompiled headers must have a single input header file.
1116+
var it = self.root_module.iterateDependencies(self, false);
1117+
const link_objects = it.next().?.module.link_objects;
1118+
assert(link_objects.items.len == 1 and link_objects.items[0] == .c_source_file);
1119+
assert(it.next() == null);
1120+
}
1121+
11011122
var cli_named_modules = try CliNamedModules.init(arena, &self.root_module);
11021123

11031124
// For this loop, don't chase dynamic libraries because their link
@@ -1206,6 +1227,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
12061227
switch (other.kind) {
12071228
.exe => return step.fail("cannot link with an executable build artifact", .{}),
12081229
.@"test" => return step.fail("cannot link with a test", .{}),
1230+
.pch => @panic("Cannot link with a precompiled header file"),
12091231
.obj => {
12101232
const included_in_lib_or_obj = !my_responsibility and (compile.kind == .lib or compile.kind == .obj);
12111233
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)