This page covers the design and implementation of the BindingsGenerator — the tool that reads Godot's ClassDB at build time and emits C# source files exposing the full engine API to managed code. It covers the internal data model, type-mapping rules, documentation translation, and the two output assemblies.
For the runtime that loads and executes those assemblies, see CSharpLanguage & GDMono Runtime. For the interop bridge that the generated code calls into at runtime, see C++/C# Interop Bridge.
The C# bindings are generated source code, not hand-written wrappers. Every time the engine API changes, a "glue generation" pass re-inspects ClassDB and writes new .cs files. This decouples the C++ engine API from the C# surface: adding a method to a C++ class automatically propagates it to C# after regeneration.
The entry point is the BindingsGenerator class defined in modules/mono/editor/bindings_generator.h and modules/mono/editor/bindings_generator.cpp. It is compiled only when DEBUG_ENABLED is set (see #ifdef DEBUG_ENABLED guards in bindings_generator.h).
Generation trigger: When the engine is launched with --generate-mono-glue on the command line, CSharpLanguage::init() detects the flag and skips .NET runtime initialization (modules/mono/csharp_script.cpp103-106), deferring to the bindings generator instead. The generator itself reads ClassDB and EditorHelp::get_doc_data() to build its intermediate model, then writes the C# source files.
Output namespaces are defined in modules/mono/godotsharp_defs.h:
| Macro | Value | Purpose |
|---|---|---|
BINDINGS_NAMESPACE | "Godot" | All generated classes |
BINDINGS_NAMESPACE_COLLECTIONS | "Godot.Collections" | Collection wrappers |
CORE_API_ASSEMBLY_NAME | "GodotSharp" | Core engine API assembly |
EDITOR_API_ASSEMBLY_NAME | "GodotSharpEditor" | Editor-only API assembly |
Diagram: Generation pipeline from ClassDB to C# assemblies
Sources: modules/mono/editor/bindings_generator.h1-50 modules/mono/editor/bindings_generator.cpp1-130 modules/mono/godotsharp_defs.h1-43
BindingsGenerator is declared in modules/mono/editor/bindings_generator.h. It is only available in DEBUG_ENABLED builds. Its responsibilities are:
ClassDB.*Interface structs..cs file per class using StringBuilder, applying formatting templates encoded in the TypeInterface fields.EditorHelp to C# XML doc comments.BindingsGenerator uses a hierarchy of plain structs to represent the API surface. Each struct has two parallel sets of fields: one for the C/native side, one for the C#/managed side.
Diagram: BindingsGenerator internal struct hierarchy
Sources: modules/mono/editor/bindings_generator.h44-650
Each TypeInterface carries format strings that tell the code generator how to marshal values between the C++ side (via ptrcall) and the C# side. These are applied using a simple %N substitution system.
| Field | Role |
|---|---|
c_type | Underlying C type used in ptrcall (e.g. long, Object*) |
c_type_in | Type used in function parameter signatures |
c_type_out | Type used in return signatures |
c_in | Statement(s) that transform a C# parameter before ptrcall |
c_out | Statement(s) that form the return expression after ptrcall |
c_arg_in | Expression passed to ptrcall (defaults to %s = parameter name) |
c_in_vararg | Variant of c_in for vararg calls |
| Field | Role |
|---|---|
cs_type | Type appearing in C# method signatures |
cs_in_expr | Inline expression transforming a parameter before the internal call |
cs_in | Statement(s) if multi-line transformation is needed |
cs_out | Return statement wrapping the internal call result |
cs_variant_to_managed | Converts godot_variant to this managed type |
cs_managed_to_variant | Converts this managed type to godot_variant |
Enums are treated as int/long at the C boundary. TypeInterface::postsetup_enum_type() applies:
c_type = "long" (ptrcall uses 64-bit integers)c_in = "%5%0 %1_in = %1;\n" (local copy with widened type)cs_in_expr = "(int)%0" (cast enum to int for the call)cs_out = "%5return (%2)%0(%1);" (cast result back to enum type)modules/mono/editor/bindings_generator.cpp152-169
For each MethodInterface, the generator emits:
MethodBind field, named with the prefix MethodBind + index, initialized via ClassDB_get_method_with_compatibility. The method hash is included to guarantee the correct overload is resolved.TypeInterface.cs_in / TypeInterface.cs_in_expr, invokes the method bind, and returns using TypeInterface.cs_out.is_virtual = true, the generator also emits overrides of InvokeGodotClassMethod and HasGodotClassMethod so the C++ engine can call back into overridden C# virtual methods.Method visibility rules:
| Flag | C# visibility |
|---|---|
is_internal | internal (used for property getter/setter backing methods) |
is_hidden | public + [EditorBrowsable(Never)] |
is_compat | public + [EditorBrowsable(Never)] + deprecated attribute |
| default | public |
Relevant macros in bindings_generator.cpp:
| Macro | Value |
|---|---|
CS_STATIC_FIELD_METHOD_BIND_PREFIX | "MethodBind" |
ICALL_CLASSDB_GET_METHOD_WITH_COMPATIBILITY | "ClassDB_get_method_with_compatibility" |
CS_METHOD_INVOKE_GODOT_CLASS_METHOD | "InvokeGodotClassMethod" |
CS_METHOD_HAS_GODOT_CLASS_METHOD | "HasGodotClassMethod" |
CS_METHOD_HAS_GODOT_CLASS_SIGNAL | "HasGodotClassSignal" |
modules/mono/editor/bindings_generator.cpp77-122
For each SignalInterface, the generator emits:
SignalName nested class holding a StringName constant for the signal name.EventSignalCallable at the C++ interop layer.HasGodotClassSignal override so the C++ engine can check whether the signal is handled.Signals carry ArgumentInterface lists just like methods, enabling typed delegate signatures.
For each PropertyInterface, the generator locates the setter and getter MethodInterface entries by StringName. The property body calls through those methods, inheriting their ptrcall marshaling logic.
Properties with PROPERTY_USAGE_INTERNAL set in C++ have PropertyInterface::is_hidden = true and are emitted with [EditorBrowsable(EditorBrowsableState.Never)].
The list prop_allowed_inherited_member_hiding in bindings_generator.cpp tracks known cases where a property legally shadows an inherited member and suppresses unnecessary compiler warnings for those specific entries. modules/mono/editor/bindings_generator.cpp135-150
Godot's documentation is written in BBCode (e.g., [method Node._ready], [b]bold[/b]). The C# bindings need XML doc comments (/// <summary>, /// <param>, etc.).
BindingsGenerator provides two translators:
| Method | Output format | Use |
|---|---|---|
bbcode_to_xml() | C# XML doc (<see cref=.../>, <para>, etc.) | Main XML doc comments |
bbcode_to_text() | Plain text with single-quotes | Fallback / plain references |
Diagram: BBCode tag translation to C# XML doc comments
Certain BBCode keywords (true, false, null) are emitted as <see langword="..."/> rather than <c>...</c>. This list is defined in langword_check at modules/mono/editor/bindings_generator.cpp130-131
Cross-references to types, methods, signals, and enums are resolved through _get_type_or_null() and validated against the current API level before being emitted. References that cannot be resolved or that cross API level boundaries (core vs. editor) are emitted as plain <c>text</c>.
Both bindings_generator.cpp and csharp_script.cpp define a shared ignored_types list. Types on this list are skipped by the generator and by the instance binding setup, so GDExtension-derived classes that lack proper C# support fall back to their nearest exposed base class. The two lists must be kept in sync; the comment in csharp_script.cpp states this requirement explicitly.
modules/mono/csharp_script.cpp70-72 modules/mono/editor/bindings_generator.cpp124-126
The generator produces source files for two assemblies split by ClassDB::APIType:
| Assembly | API type | Content |
|---|---|---|
GodotSharp | API_CORE | All core engine classes, singletons, built-in types, global constants |
GodotSharpEditor | API_EDITOR | Editor-only classes (e.g. EditorPlugin, EditorInspector) |
The global scope class (@GlobalScope in GDScript) is emitted as a static C# class named GD (macro BINDINGS_GLOBAL_SCOPE_CLASS = "GD").
Singleton classes gain a Singleton property returning the cached instance, using the macro CS_PROPERTY_SINGLETON = "Singleton". Some singletons marked is_compat_singleton cannot be converted to fully static classes for backwards compatibility and instead use an instance property pattern.
The generated C# methods ultimately call into the interop layer through function pointers registered in GDMonoCache::ManagedCallbacks and NativeFuncs. The generated code uses these macro-named helpers:
| Macro | Resolves to |
|---|---|
ICALL_CLASSDB_GET_METHOD | ClassDB_get_method |
ICALL_CLASSDB_GET_CONSTRUCTOR | ClassDB_get_constructor |
C_METHOD_UNMANAGED_GET_MANAGED | InteropUtils.UnmanagedGetManaged |
C_METHOD_ENGINE_GET_SINGLETON | InteropUtils.EngineGetSingleton |
C_NS_MONOMARSHAL | Marshaling |
modules/mono/editor/bindings_generator.cpp100-122
For a full description of how C++ calls back into C# at runtime using these registered callbacks, see C++/C# Interop Bridge.
Refresh this wiki
This wiki was recently refreshed. Please wait 2 days to refresh again.