From 9b0fa05f4780132e9bf7aad616b1f64f75b95635 Mon Sep 17 00:00:00 2001 From: dementive <87823030+dementive@users.noreply.github.com> Date: Fri, 12 Sep 2025 23:17:24 -0500 Subject: [PATCH] Add pre compiled headers build --- test/SConstruct | 5 +++ test/bd.py | 110 +++++++++++++++++++++++++++++++++++++++++++++++ test/src/pch.hpp | 13 ++++++ 3 files changed, 128 insertions(+) create mode 100755 test/bd.py create mode 100644 test/src/pch.hpp diff --git a/test/SConstruct b/test/SConstruct index b949bcacf..89989f890 100644 --- a/test/SConstruct +++ b/test/SConstruct @@ -1,5 +1,7 @@ #!/usr/bin/env python +import os + env = SConscript("../SConstruct") # For the reference: @@ -14,6 +16,9 @@ env = SConscript("../SConstruct") env.Append(CPPPATH=["src/"]) sources = Glob("src/*.cpp") +if "clang" in os.path.basename(env["CC"]) and ARGUMENTS.get("use_pch", "no") == "yes": + env.Append(CXXFLAGS=["-include-pch", f"{os.path.abspath('./src/pch.hpp.pch')}"]) + if env["target"] in ["editor", "template_debug"]: doc_data = env.GodotCPPDocData("src/gen/doc_data.gen.cpp", source=Glob("doc_classes/*.xml")) sources.append(doc_data) diff --git a/test/bd.py b/test/bd.py new file mode 100755 index 000000000..bf40c15ce --- /dev/null +++ b/test/bd.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python + +import argparse +import re +import subprocess +from dataclasses import dataclass + + +@dataclass() +class Opts: + use_llvm: str = "yes" + optimize: str = "none" + debug_symbols: str = "yes" + compiledb: str = "yes" + use_pch: str = "yes" + + +def get_command() -> str: + cmd = "scons" + for key, value in opts.__dict__.items(): + cmd += f" {key}={value}" + return cmd + + +def run(cmd: str = get_command()): + return subprocess.run(cmd, shell=True) + + +def get_pch_build_command(file_path: str, json_file_path: str = "compile_commands.json") -> str: + """ + Extracts the "command" associated with a given "file" from compile_commands.json. + + Scons and godot have no pre compiled header support for clang so have to use stupid hacks to make it work + Hacky steps to compile pch: + 1. Run `bd.py build_pch` this will then: + 2. find the pch.cpp (file_path) entry in the generated compile_commands.json file + 3. Copy the "command" parameter string to get the full compile command. + 4. Change "-o /path/to/pch.cpp" to -o /path/to/src/pch.hpp.pch at the front of the command + 5. Change the command target the the end of the command to "/path/to/src/pch.hpp" + 6. Run the compile command with the replaced output and input arguments to compile the pch file + + Note: If using with ccache make a file "~/.config/ccache/ccache.conf" with "sloppiness = pch_defines,time_macros" in it or ccache will not work with PCH. + """ + import json + + try: + with open(json_file_path, "r") as file: + data = json.load(file) + + if isinstance(data, list): + for entry in data: + if not isinstance(entry, dict): + continue + + command = entry.get("command") + cpp_file = entry.get("file") + if command and cpp_file and file_path in cpp_file: + return str(command) + + print(f"No pch command found for file: {file_path}") + return "" + + except FileNotFoundError: + print(f"Error: The file '{json_file_path}' was not found.") + except json.JSONDecodeError: + print("Error: Failed to decode JSON. Please check the file format.") + except Exception as e: + print(f"An unexpected error occurred: {e}") + + return "" + + +def build_pch(pch_path: str): + command = get_pch_build_command(pch_path + ".cpp") + if not command: + return + + command = command.replace(pch_path + ".os", pch_path + ".hpp.pch") + command = command.replace(pch_path + ".cpp", pch_path + ".hpp") + command = command.replace( + "-fno-exceptions", "-fno-exceptions -fpch-codegen -fpch-preprocess -fpch-instantiate-templates" + ) + command = re.sub(r"-include-pch\s.*(hpp\.pch)", "", command) + command = command.replace("register_types", "pch") + + print("Precompiling header: ", pch_path.replace("register_types", "pch") + ".hpp") + run(command) + + +parser = argparse.ArgumentParser() +parser.add_argument( + "command", + choices=[ + "build_pch", + "time_trace", + ], + nargs="?", + help="Build command to execute.", +) + +args = parser.parse_args() + +opts = Opts() + +if args.command == "build_pch": + opts.use_pch = "no" + build_pch("src/register_types") + exit(0) + +run() diff --git a/test/src/pch.hpp b/test/src/pch.hpp new file mode 100644 index 000000000..510ac3571 --- /dev/null +++ b/test/src/pch.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "example.h"