From 77dbf737baabc6b867d2f13028a3c88f7c517388 Mon Sep 17 00:00:00 2001 From: Togira <70365614+Togira123@users.noreply.github.com> Date: Wed, 29 Jul 2026 23:16:31 +0200 Subject: [PATCH] Add documentation for godot-cpp hook system --- .../scripting/cpp/build_system/cmake.rst | 14 ++++- .../scripting/cpp/build_system/scons.rst | 61 +++++++++++++++++++ 2 files changed, 74 insertions(+), 1 deletion(-) diff --git a/tutorials/scripting/cpp/build_system/cmake.rst b/tutorials/scripting/cpp/build_system/cmake.rst index 168ab58998c..7ccd696e64a 100644 --- a/tutorials/scripting/cpp/build_system/cmake.rst +++ b/tutorials/scripting/cpp/build_system/cmake.rst @@ -102,6 +102,12 @@ are the notable differences: will set this variable if it isn't already set. So, include it before other dependencies to have the value propagate across the projects. +Additionally, the :ref:`hook system ` works a +bit differently with CMake: + +* Your subclass has to be named ``CustomBindingGeneratorHooks``. +* Pass the filepath of the python file containing your subclass with the ``GODOTCPP_BINDING_HOOK_FILE`` option to CMake. + Basic Walk-Through ------------------ @@ -179,7 +185,9 @@ See setting-build-variables_ and build-configurations_ for more information. A non-exhaustive list of options: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. code-block:: text + +.. marked as glsl to highlight comments +.. code-block:: glsl // Path to a custom GDExtension API JSON file. // (takes precedence over GODOTCPP_GDEXTENSION_DIR) @@ -199,6 +207,10 @@ A non-exhaustive list of options: // Enable the extra accounting required to support hot reload. (ON|OFF) GODOTCPP_USE_HOT_RELOAD:BOOL= + // Use the binding generator's hook system to modify generated files. + // ( /path/to/custom_generator_file.py) + GODOTCPP_BINDING_HOOK_FILE:FILEPATH= + Compiling ~~~~~~~~~ diff --git a/tutorials/scripting/cpp/build_system/scons.rst b/tutorials/scripting/cpp/build_system/scons.rst index cde436da27d..b496f858481 100644 --- a/tutorials/scripting/cpp/build_system/scons.rst +++ b/tutorials/scripting/cpp/build_system/scons.rst @@ -107,3 +107,64 @@ the following line to your SConstruct file: .. code-block:: python localEnv["custom_api_file"] = "extension_api.json" + +.. _doc_godot_cpp_modifying_generated_files: + +Modifying generated files +------------------------- + +If you have to modify the files generated by godot-cpp, its *hook system* is the right +way of doing so. We provide the ``BindingGeneratorHooks`` class, located at ``godot-cpp/tools/binding_generator_hooks.py``. +Your custom hooks are a python class that extends ``BindingGeneratorHooks`` and overrides +(some of) its methods. After defining your subclass, you should export an instance of it +from your ``SConstruct`` with the key ``binding_hooks`` to godot-cpp's ``SConstruct``. +This way you let godot-cpp's ``SConstruct`` know about your class, see the example below for +one way of doing this. + +Example +~~~~~~~ + +This example adds a string constant of every signal in a class to its class header. +For example, in ``base_button.hpp`` we will add ``static constexpr char SIGNAL_PRESSED[] = "pressed";`` +for the ``pressed`` signal. We will use the ``SConstruct`` file from the `godot-cpp template `__. +We start by creating `custom_generator.py` at the root of our project. It only overrides +``alter_engine_class_header``, as that is all we need. + +.. code-block:: python + :caption: custom_generator.py + + import sys + + sys.path.insert(0, "godot-cpp") + from tools.binding_generator_hooks import BindingGeneratorHooks + + class CustomBindingGeneratorHooks(BindingGeneratorHooks): + def alter_engine_class_header(self, class_api, lines): + signals = [] + if "signals" in class_api: + for signal_api in class_api["signals"]: + name = signal_api["name"] + signal_constant = "\tstatic constexpr char SIGNAL_" + name.upper() + '[] = "' + name + '";' + signals.append(signal_constant) + try: + idx = lines.index("public:") + 1 + for signal_const in signals: + lines.insert(idx, signal_const) + idx += 1 + except ValueError: + print("no public keyword found, not adding signals") + return lines + +Next, we import the class in our ``SConstruct`` file: + +.. code-block:: python + + from custom_generator import CustomBindingGeneratorHooks + +Additionally, we edit the line that exports variables to ``godot-cpp/SConstruct`` to include an instance of our class, like so: + +.. code-block:: python + + env = SConscript("godot-cpp/SConstruct", {"env": env, "customs": customs, "binding_hooks": CustomBindingGeneratorHooks()}) + +This is everything you need, when you regenerate the files they should contain signal name constants for all signals in the API file.