diff --git a/lib/std/Build/Module.zig b/lib/std/Build/Module.zig index 348385f7ff76..eca4810c48db 100644 --- a/lib/std/Build/Module.zig +++ b/lib/std/Build/Module.zig @@ -126,18 +126,21 @@ pub const CSourceFiles = struct { files: []const []const u8, lang: ?CSourceLang = null, flags: []const []const u8, + precompiled_header: ?LazyPath = null, }; pub const CSourceFile = struct { file: LazyPath, lang: ?CSourceLang = null, flags: []const []const u8 = &.{}, + precompiled_header: ?LazyPath = null, pub fn dupe(self: CSourceFile, b: *std.Build) CSourceFile { return .{ .file = self.file.dupe(b), .lang = self.lang, .flags = b.dupeStrings(self.flags), + .precompiled_header = self.precompiled_header, }; } }; @@ -500,6 +503,7 @@ pub const AddCSourceFilesOptions = struct { files: []const []const u8, lang: ?CSourceLang = null, flags: []const []const u8 = &.{}, + precompiled_header: ?LazyPath = null, }; /// Handy when you have many C/C++ source files and want them all to have the same flags. @@ -522,8 +526,13 @@ pub fn addCSourceFiles(m: *Module, options: AddCSourceFilesOptions) void { .files = b.dupeStrings(options.files), .lang = options.lang, .flags = b.dupeStrings(options.flags), + .precompiled_header = options.precompiled_header, }; m.link_objects.append(allocator, .{ .c_source_files = c_source_files }) catch @panic("OOM"); + + if (options.precompiled_header) |pch| { + addLazyPathDependenciesOnly(m, pch); + } } pub fn addCSourceFile(m: *Module, source: CSourceFile) void { @@ -533,6 +542,10 @@ pub fn addCSourceFile(m: *Module, source: CSourceFile) void { c_source_file.* = source.dupe(b); m.link_objects.append(allocator, .{ .c_source_file = c_source_file }) catch @panic("OOM"); addLazyPathDependenciesOnly(m, source.file); + + if (source.precompiled_header) |pch| { + addLazyPathDependenciesOnly(m, pch); + } } /// Resource files must have the extension `.rc`. diff --git a/lib/std/Build/Step/Compile.zig b/lib/std/Build/Step/Compile.zig index db7dff3bc43b..b59d19357964 100644 --- a/lib/std/Build/Step/Compile.zig +++ b/lib/std/Build/Step/Compile.zig @@ -1281,7 +1281,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { .c_source_file => |c_source_file| l: { if (!my_responsibility) break :l; - if (c_source_file.flags.len == 0) { + if (c_source_file.flags.len == 0 and c_source_file.precompiled_header == null) { if (prev_has_cflags) { try zig_args.append("-cflags"); try zig_args.append("--"); @@ -1292,6 +1292,11 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { for (c_source_file.flags) |arg| { try zig_args.append(arg); } + if (c_source_file.precompiled_header) |pch| { + try zig_args.append("-include-pch"); + try zig_args.append(pch.getPath(b)); + try zig_args.append("-fpch-validate-input-files-content"); + } try zig_args.append("--"); prev_has_cflags = true; } @@ -1308,7 +1313,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { .c_source_files => |c_source_files| l: { if (!my_responsibility) break :l; - if (c_source_files.flags.len == 0) { + if (c_source_files.flags.len == 0 and c_source_files.precompiled_header == null) { if (prev_has_cflags) { try zig_args.append("-cflags"); try zig_args.append("--"); @@ -1319,6 +1324,13 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { for (c_source_files.flags) |flag| { try zig_args.append(flag); } + + if (c_source_files.precompiled_header) |pch| { + try zig_args.append("-include-pch"); + try zig_args.append(pch.getPath(b)); + try zig_args.append("-fpch-validate-input-files-content"); + } + try zig_args.append("--"); prev_has_cflags = true; } diff --git a/test/standalone/build.zig.zon b/test/standalone/build.zig.zon index 8b59f261179e..3e9515ca1e07 100644 --- a/test/standalone/build.zig.zon +++ b/test/standalone/build.zig.zon @@ -155,6 +155,9 @@ .install_headers = .{ .path = "install_headers", }, + .precompiled_c_headers = .{ + .path = "pch", + }, }, .paths = .{ "build.zig", diff --git a/test/standalone/pch/build.zig b/test/standalone/pch/build.zig new file mode 100644 index 000000000000..776f84d25be2 --- /dev/null +++ b/test/standalone/pch/build.zig @@ -0,0 +1,69 @@ +const std = @import("std"); + +pub fn build(b: *std.Build) void { + const test_step = b.step("test", "Test it"); + b.default_step = test_step; + + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + // c-header + { + const exe = b.addExecutable(.{ + .name = "pchtest", + .target = target, + .optimize = optimize, + .link_libc = true, + }); + + const pch = b.addPrecompiledCHeader(.{ + .name = "pch_c", + .target = target, + .optimize = optimize, + .link_libc = true, + }, .{ + .file = .{ .path = "include_a.h" }, + .flags = &[_][]const u8{}, + .lang = .h, + }); + + exe.addCSourceFiles(.{ + .files = &.{"test.c"}, + .flags = &[_][]const u8{}, + .lang = .c, + .precompiled_header = pch.getEmittedBin(), + }); + + test_step.dependOn(&b.addRunArtifact(exe).step); + } + + // c++-header + { + const exe = b.addExecutable(.{ + .name = "pchtest++", + .target = target, + .optimize = optimize, + .link_libc = true, + }); + exe.linkLibCpp(); + + const pch = b.addPrecompiledCHeader(.{ + .name = "pch_c++", + .target = target, + .optimize = optimize, + .link_libcpp = true, + }, .{ + .file = .{ .path = "include_a.h" }, + .flags = &[_][]const u8{}, + .lang = .hpp, + }); + + exe.addCSourceFile(.{ + .file = .{ .path = "test.cpp" }, + .flags = &[_][]const u8{}, + .precompiled_header = pch.getEmittedBin(), + }); + + test_step.dependOn(&b.addRunArtifact(exe).step); + } +} diff --git a/test/standalone/pch/include_a.h b/test/standalone/pch/include_a.h new file mode 100644 index 000000000000..42921826c8a7 --- /dev/null +++ b/test/standalone/pch/include_a.h @@ -0,0 +1,15 @@ +#pragma once + +#include "include_b.h" + +#include +#include + +#if defined(__cplusplus) +#include +#else +#include +#endif + +#define A_INCLUDED 1 + diff --git a/test/standalone/pch/include_b.h b/test/standalone/pch/include_b.h new file mode 100644 index 000000000000..13806ca6672c --- /dev/null +++ b/test/standalone/pch/include_b.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +typedef double real; + +#define B_INCLUDED 1 diff --git a/test/standalone/pch/test.c b/test/standalone/pch/test.c new file mode 100644 index 000000000000..ba7c9017752e --- /dev/null +++ b/test/standalone/pch/test.c @@ -0,0 +1,22 @@ + +// includes commented out to make sure the symbols come from the precompiled header. +//#include "include_a.h" +//#include "include_b.h" + +#ifndef A_INCLUDED +#error "pch not included" +#endif +#ifndef B_INCLUDED +#error "pch not included" +#endif + +int main(int argc, char *argv[]) +{ + real a = 0.123; + + if (argc > 1) { + fprintf(stdout, "abs(%g)=%g\n", a, fabs(a)); + } + + return EXIT_SUCCESS; +} diff --git a/test/standalone/pch/test.cpp b/test/standalone/pch/test.cpp new file mode 100644 index 000000000000..ebea93a565a5 --- /dev/null +++ b/test/standalone/pch/test.cpp @@ -0,0 +1,23 @@ + +// includes commented out to make sure the symbols come from the precompiled header. +//#include "includeA.h" +//#include "includeB.h" + +#ifndef A_INCLUDED +#error "pch not included" +#endif +#ifndef B_INCLUDED +#error "pch not included" +#endif + +int main(int argc, char *argv[]) +{ + real a = -0.123; + + if (argc > 1) { + std::cout << "abs(" << a << ")=" << fabs(a) << "\n"; + } + + return EXIT_SUCCESS; +} +