diff --git a/lib/std/Build/Module.zig b/lib/std/Build/Module.zig index 9a8831dea59e..82508dd9fdf9 100644 --- a/lib/std/Build/Module.zig +++ b/lib/std/Build/Module.zig @@ -153,18 +153,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(file: CSourceFile, b: *std.Build) CSourceFile { return .{ .file = file.file.dupe(b), .lang = file.lang, .flags = b.dupeStrings(file.flags), + .precompiled_header = file.precompiled_header, }; } }; @@ -557,6 +560,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. @@ -579,9 +583,14 @@ 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"); addLazyPathDependenciesOnly(m, c_source_files.root); + + if (options.precompiled_header) |pch| { + addLazyPathDependenciesOnly(m, pch); + } } pub fn addCSourceFile(m: *Module, source: CSourceFile) void { @@ -591,6 +600,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 d5d9328126e8..7d9531fd4e0b 100644 --- a/lib/std/Build/Step/Compile.zig +++ b/lib/std/Build/Step/Compile.zig @@ -1272,7 +1272,7 @@ fn getZigArgs(compile: *Compile) ![][]const u8 { .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("--"); @@ -1283,6 +1283,11 @@ fn getZigArgs(compile: *Compile) ![][]const u8 { 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; } @@ -1304,7 +1309,7 @@ fn getZigArgs(compile: *Compile) ![][]const u8 { .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("--"); @@ -1315,6 +1320,13 @@ fn getZigArgs(compile: *Compile) ![][]const u8 { 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 8e4d727642ec..dd6d7d40112a 100644 --- a/test/standalone/build.zig.zon +++ b/test/standalone/build.zig.zon @@ -173,6 +173,9 @@ .dependencyFromBuildZig = .{ .path = "dependencyFromBuildZig", }, + .precompiled_c_headers = .{ + .path = "pch", + }, .run_output_paths = .{ .path = "run_output_paths", }, diff --git a/test/standalone/pch/build.zig b/test/standalone/pch/build.zig new file mode 100644 index 000000000000..81c77a47ae96 --- /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 = b.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 = b.path("include_a.h"), + .flags = &[_][]const u8{}, + .lang = .hpp, + }); + + exe.addCSourceFile(.{ + .file = b.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; +} +