From a4a316357d4014f6ef906a91c143d89f694ffe44 Mon Sep 17 00:00:00 2001 From: Xavier Bouchoux Date: Sat, 27 Jan 2024 14:08:34 +0100 Subject: [PATCH] std.Build: add precompiled C header creation --- lib/std/Build.zig | 25 +++++++++++++ lib/std/Build/Step/Compile.zig | 50 ++++++++++++++++++-------- lib/std/Build/Step/InstallArtifact.zig | 2 +- 3 files changed, 62 insertions(+), 15 deletions(-) diff --git a/lib/std/Build.zig b/lib/std/Build.zig index 59dee7d89db2..9835c9f9cc09 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -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 diff --git a/lib/std/Build/Step/Compile.zig b/lib/std/Build/Step/Compile.zig index 251a68c2a664..cc4e18bb8ff7 100644 --- a/lib/std/Build/Step/Compile.zig +++ b/lib/std/Build/Step/Compile.zig @@ -238,6 +238,7 @@ pub const Kind = enum { exe, lib, obj, + pch, @"test", }; @@ -263,6 +264,7 @@ 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, @@ -270,20 +272,24 @@ pub fn create(owner: *std.Build, options: Options) *Compile { 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.* = .{ @@ -701,10 +707,12 @@ 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); } @@ -712,6 +720,7 @@ pub fn addCSourceFile(self: *Compile, source: Module.CSourceFile) void { /// 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); } @@ -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); } @@ -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); @@ -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 @@ -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) { diff --git a/lib/std/Build/Step/InstallArtifact.zig b/lib/std/Build/Step/InstallArtifact.zig index b9c3acfbc912..fc8777dbdb7c 100644 --- a/lib/std/Build/Step/InstallArtifact.zig +++ b/lib/std/Build/Step/InstallArtifact.zig @@ -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 = {} }, },