From bf04bae5764857c6bbe8232e0c86de7c47abed46 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 | 24 +++++++++++++++++++++++- lib/std/Build/Step/InstallArtifact.zig | 2 +- 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/lib/std/Build.zig b/lib/std/Build.zig index 2c644ce4b031..8f106e01f570 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -741,6 +741,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 e451b09ac450..db7dff3bc43b 100644 --- a/lib/std/Build/Step/Compile.zig +++ b/lib/std/Build/Step/Compile.zig @@ -252,6 +252,7 @@ pub const Kind = enum { exe, lib, obj, + pch, @"test", }; @@ -359,6 +360,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, @@ -366,13 +368,17 @@ 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, .{ + 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 = options.linkage, .version = options.version, @@ -801,10 +807,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); } @@ -812,6 +820,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); } @@ -894,14 +903,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); } @@ -1026,6 +1038,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); @@ -1098,6 +1111,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 @@ -1206,6 +1227,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 7ebe8fdaf091..5a4f63f2729c 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 = {} }, },