Skip to content

Commit cbc23ba

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 bdda749 commit cbc23ba

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
@@ -273,6 +273,7 @@ pub const Kind = enum {
273273
exe,
274274
lib,
275275
obj,
276+
pch,
276277
@"test",
277278
};
278279

@@ -356,24 +357,29 @@ pub fn create(owner: *std.Build, options: Options) *Compile {
356357
.exe => "zig build-exe",
357358
.lib => "zig build-lib",
358359
.obj => "zig build-obj",
360+
.pch => "zig build-pch",
359361
.@"test" => "zig test",
360362
},
361363
name_adjusted,
362364
@tagName(options.root_module.optimize orelse .Debug),
363365
resolved_target.query.zigTriple(owner.allocator) catch @panic("OOM"),
364366
});
365367

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

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

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

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

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

@@ -893,14 +902,17 @@ pub fn getEmittedLlvmBc(compile: *Compile) LazyPath {
893902
}
894903

895904
pub fn addAssemblyFile(compile: *Compile, source: Module.AsmSourceFile) void {
905+
assert(compile.kind != .pch); // pch can only be generated from a single C header file
896906
compile.root_module.addAssemblyFile(source);
897907
}
898908

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

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

@@ -1025,6 +1037,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 {
10251037
.lib => "build-lib",
10261038
.exe => "build-exe",
10271039
.obj => "build-obj",
1040+
.pch => "build-pch",
10281041
.@"test" => "test",
10291042
};
10301043
try zig_args.append(cmd);
@@ -1092,6 +1105,14 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 {
10921105
}
10931106
}
10941107

1108+
if (compile.kind == .pch) {
1109+
// precompiled headers must have a single input header file.
1110+
var it = compile.root_module.iterateDependencies(compile, false);
1111+
const link_objects = it.next().?.module.link_objects;
1112+
assert(link_objects.items.len == 1 and link_objects.items[0] == .c_source_file);
1113+
assert(it.next() == null);
1114+
}
1115+
10951116
var cli_named_modules = try CliNamedModules.init(arena, &compile.root_module);
10961117

10971118
// For this loop, don't chase dynamic libraries because their link
@@ -1203,6 +1224,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 {
12031224
switch (other.kind) {
12041225
.exe => return step.fail("cannot link with an executable build artifact", .{}),
12051226
.@"test" => return step.fail("cannot link with a test", .{}),
1227+
.pch => @panic("Cannot link with a precompiled header file"),
12061228
.obj => {
12071229
const included_in_lib_or_obj = !my_responsibility and
12081230
(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)