diff --git a/lib/std/Build/Module.zig b/lib/std/Build/Module.zig index 98879852117d..c813890b58ba 100644 --- a/lib/std/Build/Module.zig +++ b/lib/std/Build/Module.zig @@ -127,18 +127,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, }; } }; @@ -504,6 +507,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. @@ -516,8 +520,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 { @@ -527,6 +536,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 3f06c436e71e..9766f485adcb 100644 --- a/lib/std/Build/Step/Compile.zig +++ b/lib/std/Build/Step/Compile.zig @@ -1151,7 +1151,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("--"); @@ -1162,6 +1162,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; } @@ -1178,7 +1183,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("--"); @@ -1189,6 +1194,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.zig b/test/standalone.zig index 3740ddb80adb..dbd2ac9851e5 100644 --- a/test/standalone.zig +++ b/test/standalone.zig @@ -265,6 +265,10 @@ pub const build_cases = [_]BuildCase{ .build_root = "test/standalone/depend_on_main_mod", .import = @import("standalone/depend_on_main_mod/build.zig"), }, + .{ + .build_root = "test/standalone/pch", + .import = @import("standalone/pch/build.zig"), + }, }; const std = @import("std"); 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/include_c.h b/test/standalone/pch/include_c.h new file mode 100644 index 000000000000..50a91512c418 --- /dev/null +++ b/test/standalone/pch/include_c.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +#define C_INCLUDED 1 + +int one = 3; 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; +} +