Skip to content

Commit

Permalink
std.Build: add precompiled C header creation
Browse files Browse the repository at this point in the history
  • Loading branch information
xxxbxxx committed Jan 31, 2024
1 parent 47c9876 commit a4a3163
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 15 deletions.
25 changes: 25 additions & 0 deletions lib/std/Build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -714,6 +714,31 @@ pub fn addObject(b: *Build, options: ObjectOptions) *Step.Compile {
});
}

pub const PchOptions = struct {
name: []const u8,
target: ResolvedTarget,
optimize: std.builtin.OptimizeMode,
max_rss: usize = 0,
link_libc: ?bool = null,
link_libcpp: ?bool = null,
};

pub fn addPrecompiledCHeader(b: *Build, options: PchOptions, source: Module.CSourceFile) *Step.Compile {
const pch = Step.Compile.create(b, .{
.name = options.name,
.root_module = .{
.target = options.target,
.optimize = options.optimize,
.link_libc = options.link_libc,
.link_libcpp = options.link_libcpp,
},
.kind = .pch,
.max_rss = options.max_rss,
});
pch.addCSourceFile(source);
return pch;
}

pub const SharedLibraryOptions = struct {
name: []const u8,
/// To choose the same computer as the one building the package, pass the
Expand Down
50 changes: 36 additions & 14 deletions lib/std/Build/Step/Compile.zig
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ pub const Kind = enum {
exe,
lib,
obj,
pch,
@"test",
};

Expand All @@ -263,27 +264,32 @@ pub fn create(owner: *std.Build, options: Options) *Compile {
.exe => "zig build-exe",
.lib => "zig build-lib",
.obj => "zig build-obj",
.pch => "zig build-pch",
.@"test" => "zig test",
},
name_adjusted,
@tagName(options.root_module.optimize orelse .Debug),
resolved_target.query.zigTriple(owner.allocator) catch @panic("OOM"),
});

const out_filename = std.zig.binNameAlloc(owner.allocator, .{
.root_name = name,
.target = target,
.output_mode = switch (options.kind) {
.lib => .Lib,
.obj => .Obj,
.exe, .@"test" => .Exe,
},
.link_mode = if (options.linkage) |some| @as(std.builtin.LinkMode, switch (some) {
.dynamic => .Dynamic,
.static => .Static,
}) else null,
.version = options.version,
}) catch @panic("OOM");
const out_filename = if (options.kind == .pch)
std.fmt.allocPrint(owner.allocator, "{s}.pch", .{name}) catch @panic("OOM")
else
std.zig.binNameAlloc(owner.allocator, .{
.root_name = name,
.target = target,
.output_mode = switch (options.kind) {
.lib => .Lib,
.obj => .Obj,
.exe, .@"test" => .Exe,
.pch => unreachable,
},
.link_mode = if (options.linkage) |some| @as(std.builtin.LinkMode, switch (some) {
.dynamic => .Dynamic,
.static => .Static,
}) else null,
.version = options.version,
}) catch @panic("OOM");

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

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

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

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

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

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

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

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

Expand Down Expand Up @@ -926,6 +938,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
.lib => "build-lib",
.exe => "build-exe",
.obj => "build-obj",
.pch => "build-pch",
.@"test" => "test",
};
try zig_args.append(cmd);
Expand Down Expand Up @@ -988,6 +1001,14 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
}
}

if (self.kind == .pch) {
// precompiled headers must have a single input header file.
var it = self.root_module.iterateDependencies(self, false);
const link_objects = it.next().?.module.link_objects;
assert(link_objects.items.len == 1 and link_objects.items[0] == .c_source_file);
assert(it.next() == null);
}

var cli_named_modules = try CliNamedModules.init(arena, &self.root_module);

// For this loop, don't chase dynamic libraries because their link
Expand Down Expand Up @@ -1096,6 +1117,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void {
switch (other.kind) {
.exe => return step.fail("cannot link with an executable build artifact", .{}),
.@"test" => return step.fail("cannot link with a test", .{}),
.pch => @panic("Cannot link with a precompiled header file"),
.obj => {
const included_in_lib_or_obj = !my_responsibility and (compile.kind == .lib or compile.kind == .obj);
if (!already_linked and !included_in_lib_or_obj) {
Expand Down
2 changes: 1 addition & 1 deletion lib/std/Build/Step/InstallArtifact.zig
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ pub fn create(owner: *std.Build, artifact: *Step.Compile, options: Options) *Ins
const dest_dir: ?InstallDir = switch (options.dest_dir) {
.disabled => null,
.default => switch (artifact.kind) {
.obj => @panic("object files have no standard installation procedure"),
.obj, .pch => @panic("object files have no standard installation procedure"),
.exe, .@"test" => InstallDir{ .bin = {} },
.lib => InstallDir{ .lib = {} },
},
Expand Down

0 comments on commit a4a3163

Please sign in to comment.