Attention: Here be dragons

This is the latest (unstable) version of this documentation, which may document features not available in or compatible with released stable versions of Godot.

Main build system: Working with SCons

See also

This page documents how to compile godot-cpp. If you're looking to compile Godot instead, see Introduction to the buildsystem.

godot-cpp uses SCons as its main build system. It is modeled after Godot's build system, and some commands available there are also available in godot-cpp projects.

Getting started

To build a godot-cpp project, it is generally sufficient to install SCons, and simply run it in the project directory:

scons

You may want to learn about available options:

scons --help

To cleanly re-build your project, add --clean to your build command:

scons --clean

You can find more information about common SCons arguments and build patterns in the SCons User Guide. Additional commands may be added by individual godot-cpp projects, so consult their specific documentation for more information on those.

Configuring an IDE

Most IDEs can use a compile_commands.json file to understand a C++ project. You can generate it with godot-cpp using the following command:

# Generate compile_commands.json while compiling.
scons compiledb=yes

# Generate compile_commands.json without compiling.
scons compiledb=yes compile_commands.json

For more information, please check out the IDE configuration guides. Although written for Godot engine contributors, they are largely applicable to godot-cpp projects as well.

Loading your GDExtension in Godot

Godot loads GDExtensions by finding .gdextension files in the project directory. .gdextension files are used to select and load a binary compatible with the current computer / operating system.

The godot-cpp-template, as well as the Getting Started section, provide example .gdextension files for GDExtensions that are widely compatible to many different systems.

Building for multiple platforms

GDExtensions are expected to run on many different systems, each with separate binaries and build configurations. If you are planning to publish your GDExtension, we recommend you provide binaries for all configurations that are mentioned in the godot-cpp-template .gdextension file.

There are two popular ways by which cross platform builds can be achieved:

  • Cross-platform build tools

  • Continuous Integration (CI)

godot-cpp-template contains an example setup for a GitHub based CI workflow.

Using a custom API file

Every branch of godot-cpp comes with an API file (extension_api.json) appropriate for the respective Godot version (e.g. the 4.3 branch comes with the API file compatible with Godot version 4.3 and later).

However, you may want to use a custom extension_api.json, for example:

  • If you want to use the latest APIs from Godot master.

  • If you build Godot yourself with different options than the official builds (e.g. disable_3d=yes or precision=double).

  • If you want to use APIs exposed by custom modules.

To use a custom API file, you first have to generate it from the appropriate Godot executable:

godot --dump-extension-api

The resulting extension_api.json file will be created in the executable's directory. To use it, you can add custom_api_file to your build command:

scons platform=<platform> custom_api_file=<PATH_TO_FILE>

Alternatively, you can add it as the default API file to your project by adding the following line to your SConstruct file:

localEnv["custom_api_file"] = "extension_api.json"

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.

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:

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:

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.


User-contributed notes

Please read the User-contributed notes policy before submitting a comment.