gdextension

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

GDExtension

GDExtension

Run native C++ (or Rust) in Godot as a shared library without recompiling the engine. Use it for performance-critical code, wrapping existing C/C++ libraries, or language bindings.
Related skills: csharp-godot for when C# is enough, gdscript-advanced for GDScript performance idioms first, godot-optimization for profiling before going native, addon-development for distributing the result, export-pipeline for shipping the binaries.

在 Godot 中以共享库形式运行原生 C++(或 Rust),无需重新编译引擎。适用于性能关键型代码、封装现有 C/C++ 库或语言绑定。
相关 skill: csharp-godot(当 C# 已足够时)、gdscript-advanced(优先采用 GDScript 性能惯用模式)、godot-optimization(转为原生方案前进行性能分析)、addon-development(用于分发结果)、export-pipeline(用于发布二进制文件)。

1. When to reach for GDExtension

1. 何时使用 GDExtension

Reach for GDScript or C# for almost all game logic. Choose GDExtension only when you genuinely need it:
  • Native speed in a hot loop that GDScript/C# can't keep up with (profile first — see godot-optimization).
  • Wrapping a C/C++ library you must call directly.
  • Building a language binding.
Contrast with C++ modules, which are compiled into the engine and therefore require shipping a custom engine binary. GDExtension's key advantage is that it runs against a stock Godot — you distribute just a shared library. It is "more complicated to use than GDScript and C#," so don't reach for it by default.
⚠️ Changed in Godot 4.7: Custom text servers are no longer a GDExtension use case — TextServer GDExtension build support was removed, so a custom
TextServer
must be compiled into the engine as a C++ module. See GH-117056.

几乎所有游戏逻辑都应使用 GDScript 或 C#。仅在确实需要时才选择 GDExtension:
  • 原生速度:适用于 GDScript/C# 无法满足性能要求的热循环(请先进行性能分析——参见 godot-optimization)。
  • 封装 C/C++ 库:直接调用必须使用的 C/C++ 库。
  • 构建语言绑定。
相比之下,C++ 模块会被编译进引擎,因此需要分发自定义引擎二进制文件。GDExtension 的主要优势在于它可运行在标准版 Godot 上——只需分发共享库即可。它“比 GDScript 和 C# 更难使用”,因此不要默认选择它。
⚠️ Godot 4.7 中的变更: 自定义文本服务器不再是 GDExtension 用例——TextServer GDExtension 构建支持已被移除,因此自定义
TextServer
必须作为 C++ 模块编译进引擎。请参阅 GH-117056。

2. Project & build setup

2. 项目与构建配置

bash
mkdir gdextension_example && cd gdextension_example
git init
bash
mkdir gdextension_example && cd gdextension_example
git init

IMPORTANT: use the godot-cpp branch matching your target engine version (e.g. 4.3),

IMPORTANT: use the godot-cpp branch matching your target engine version (e.g. 4.3),

not the literal "4.x".

not the literal "4.x".

git submodule add -b 4.3 https://github.com/godotengine/godot-cpp cd godot-cpp && git submodule update --init && cd ..

Directory layout:
gdextension_example/ ├── project/ # demo project to test the extension │ └── bin/example.gdextension ├── godot-cpp/ # C++ bindings (submodule) └── src/ ├── register_types.{h,cpp} └── gdexample.{h,cpp}

Build with `scons platform=<platform>` (omit the platform to target the current one; default build is **debug**). The official `SConstruct` is a downloadable file from the C++ tutorial rather than hand-rolled here — follow godot-cpp's build docs. SCons is the official path; godot-cpp also supports CMake.

> **Godot 4.7+:** Upstream's reference GDExtension interface files (e.g. `gdextension_interface.h`) now live in the godot-headers repository instead of godot-cpp ([GH-115401](https://github.com/godotengine/godot/pull/115401)). godot-cpp consumes them from there, so the submodule workflow above is unchanged — this only matters if you vendor the raw interface headers directly (e.g. for a custom language binding).

---
git submodule add -b 4.3 https://github.com/godotengine/godot-cpp cd godot-cpp && git submodule update --init && cd ..

目录结构:
gdextension_example/ ├── project/ # demo project to test the extension │ └── bin/example.gdextension ├── godot-cpp/ # C++ bindings (submodule) └── src/ ├── register_types.{h,cpp} └── gdexample.{h,cpp}

使用 `scons platform=<platform>` 构建(省略 platform 则以当前平台为目标;默认构建配置为 **debug**)。官方 `SConstruct` 是 C++ 教程提供的可下载文件,此处不手工创建——请遵循 godot-cpp 的构建文档。SCons 是官方支持的构建方式;godot-cpp 也支持 CMake。

> **Godot 4.7+:** 上游的参考 GDExtension 接口文件(例如 `gdextension_interface.h`)现在位于 godot-headers 仓库,而不是 godot-cpp([GH-115401](https://github.com/godotengine/godot/pull/115401))。godot-cpp 会从那里使用这些文件,因此上述子模块工作流保持不变——仅当直接内置原始接口头文件时(例如用于自定义语言绑定)才需要注意这一点。

---

3. Binding a class (C++)

3. 绑定类(C++)

Header (
gdexample.h
):
cpp
#pragma once
#include <godot_cpp/classes/sprite2d.hpp>

namespace godot {
class GDExample : public Sprite2D {
    GDCLASS(GDExample, Sprite2D)
private:
    double time_passed = 0.0;
    double amplitude = 10.0;
    double speed = 1.0;
protected:
    static void _bind_methods();
public:
    void _process(double delta) override;
    void set_amplitude(double p_amplitude);
    double get_amplitude() const;
    void set_speed(double p_speed);
    double get_speed() const;
};
}
Bindings (
gdexample.cpp
—
_bind_methods
):
cpp
void GDExample::_bind_methods() {
    ClassDB::bind_method(D_METHOD("get_amplitude"), &GDExample::get_amplitude);
    ClassDB::bind_method(D_METHOD("set_amplitude", "p_amplitude"), &GDExample::set_amplitude);
    ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "amplitude"), "set_amplitude", "get_amplitude");

    ClassDB::bind_method(D_METHOD("get_speed"), &GDExample::get_speed);
    ClassDB::bind_method(D_METHOD("set_speed", "p_speed"), &GDExample::set_speed);
    ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed", PROPERTY_HINT_RANGE, "0,20,0.01"),
                 "set_speed", "get_speed");

    ADD_SIGNAL(MethodInfo("position_changed",
               PropertyInfo(Variant::OBJECT, "node"),
               PropertyInfo(Variant::VECTOR2, "new_pos")));
}
The patterns:
  • GDCLASS(Class, Parent)
    — first line of every native class body; wires up the type into Godot's
    ClassDB
    .
  • ClassDB::bind_method(D_METHOD("name", "arg"), &Class::method)
    — exposes a method (and names its arguments) so GDScript/C#/the editor can call it.
  • ADD_PROPERTY(PropertyInfo(...), setter, getter)
    — registers an Inspector property; bind the getter and setter first, then reference them here by name.
  • PROPERTY_HINT_RANGE
    with
    "0,20,0.01"
    turns the Inspector field into a slider (min, max, step).
  • ADD_SIGNAL(MethodInfo("name", PropertyInfo(...), ...))
    — declares a signal with typed arguments; emit it from code with
    emit_signal("position_changed", this, new_pos)
    .
⚠️ Changed in Godot 4.7: The GDExtension interface functions
object_cast_to
and
classdb_get_class_tag
are deprecated in favor of
is_class
-based casts. Binding libraries (godot-cpp, gdext) handle this internally — but native code that calls these interface functions directly should migrate its cast paths. See GH-119254.

头文件(
gdexample.h
):
cpp
#pragma once
#include <godot_cpp/classes/sprite2d.hpp>

namespace godot {
class GDExample : public Sprite2D {
    GDCLASS(GDExample, Sprite2D)
private:
    double time_passed = 0.0;
    double amplitude = 10.0;
    double speed = 1.0;
protected:
    static void _bind_methods();
public:
    void _process(double delta) override;
    void set_amplitude(double p_amplitude);
    double get_amplitude() const;
    void set_speed(double p_speed);
    double get_speed() const;
};
}
绑定(
gdexample.cpp
——
_bind_methods
):
cpp
void GDExample::_bind_methods() {
    ClassDB::bind_method(D_METHOD("get_amplitude"), &GDExample::get_amplitude);
    ClassDB::bind_method(D_METHOD("set_amplitude", "p_amplitude"), &GDExample::set_amplitude);
    ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "amplitude"), "set_amplitude", "get_amplitude");

    ClassDB::bind_method(D_METHOD("get_speed"), &GDExample::get_speed);
    ClassDB::bind_method(D_METHOD("set_speed", "p_speed"), &GDExample::set_speed);
    ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed", PROPERTY_HINT_RANGE, "0,20,0.01"),
                 "set_speed", "get_speed");

    ADD_SIGNAL(MethodInfo("position_changed",
               PropertyInfo(Variant::OBJECT, "node"),
               PropertyInfo(Variant::VECTOR2, "new_pos")));
}
这些模式包括:
  • GDCLASS(Class, Parent)
    ——原生类主体中的第一行;将该类型接入 Godot 的
    ClassDB
    。
  • ClassDB::bind_method(D_METHOD("name", "arg"), &Class::method)
    ——公开方法(并指定参数名称),以便 GDScript、C# 或编辑器调用。
  • ADD_PROPERTY(PropertyInfo(...), setter, getter)
    ——注册 Inspector 属性;先绑定 getter 和 setter,然后在此按名称引用它们。
  • PROPERTY_HINT_RANGE
    配合
    "0,20,0.01"
    可将 Inspector 字段变成滑块(最小值、最大值、步长)。
  • ADD_SIGNAL(MethodInfo("name", PropertyInfo(...), ...))
    ——声明带类型参数的信号;可从代码中调用
    emit_signal("position_changed", this, new_pos)
    发出该信号。
⚠️ Godot 4.7 中的变更: GDExtension 接口函数
object_cast_to
和
classdb_get_class_tag
已被弃用,应改用基于
is_class
的类型转换。绑定库(godot-cpp、gdext)会在内部处理这些弃用项——但直接调用这些接口函数的原生代码应迁移其类型转换路径。请参阅 GH-119254。

4. Entry point & the .gdextension file

4. 入口点与
.gdextension
文件

Entry point (
register_types.cpp
):
cpp
void initialize_example_module(ModuleInitializationLevel p_level) {
    if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) return;
    GDREGISTER_CLASS(GDExample);
}
void uninitialize_example_module(ModuleInitializationLevel p_level) {
    if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) return;
}
extern "C" {
GDExtensionBool GDE_EXPORT example_library_init(
    GDExtensionInterfaceGetProcAddress p_get_proc_address,
    const GDExtensionClassLibraryPtr p_library,
    GDExtensionInitialization *r_initialization) {
    godot::GDExtensionBinding::InitObject init_obj(p_get_proc_address, p_library, r_initialization);
    init_obj.register_initializer(initialize_example_module);
    init_obj.register_terminator(uninitialize_example_module);
    init_obj.set_minimum_library_initialization_level(MODULE_INITIALIZATION_LEVEL_SCENE);
    return init_obj.init();
}
}
The
.gdextension
file (
project/bin/example.gdextension
):
ini
[configuration]
entry_symbol = "example_library_init"
compatibility_minimum = "4.3"
reloadable = true

[libraries]
macos.debug = "res://bin/libgdexample.macos.template_debug.dylib"
macos.release = "res://bin/libgdexample.macos.template_release.dylib"
windows.debug.x86_64 = "res://bin/gdexample.windows.template_debug.x86_64.dll"
windows.release.x86_64 = "res://bin/gdexample.windows.template_release.x86_64.dll"
linux.debug.x86_64 = "res://bin/libgdexample.linux.template_debug.x86_64.so"
linux.release.x86_64 = "res://bin/libgdexample.linux.template_release.x86_64.so"
The exported
extern "C"
symbol name must equal
entry_symbol
, or the extension won't load. Register classes with
GDREGISTER_CLASS
, gated on
MODULE_INITIALIZATION_LEVEL_SCENE
. The
[libraries]
keys are
platform.feature.arch
tags;
template_debug
/
template_release
distinguish build configs. Optional sections:
[icons]
(per-node editor icon) and
[dependencies]
(extra libs copied on export).
Godot 4.7+: The raw GDExtension interface adds refcount-aware construction and registration entry points —
classdb_construct_object3
and
classdb_register_extension_class6
(GH-118214). Binding libraries built against 4.7 headers use them automatically; they only concern code that calls the interface directly.

入口点(
register_types.cpp
):
cpp
void initialize_example_module(ModuleInitializationLevel p_level) {
    if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) return;
    GDREGISTER_CLASS(GDExample);
}
void uninitialize_example_module(ModuleInitializationLevel p_level) {
    if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) return;
}
extern "C" {
GDExtensionBool GDE_EXPORT example_library_init(
    GDExtensionInterfaceGetProcAddress p_get_proc_address,
    const GDExtensionClassLibraryPtr p_library,
    GDExtensionInitialization *r_initialization) {
    godot::GDExtensionBinding::InitObject init_obj(p_get_proc_address, p_library, r_initialization);
    init_obj.register_initializer(initialize_example_module);
    init_obj.register_terminator(uninitialize_example_module);
    init_obj.set_minimum_library_initialization_level(MODULE_INITIALIZATION_LEVEL_SCENE);
    return init_obj.init();
}
}
.gdextension
文件(
project/bin/example.gdextension
):
ini
[configuration]
entry_symbol = "example_library_init"
compatibility_minimum = "4.3"
reloadable = true

[libraries]
macos.debug = "res://bin/libgdexample.macos.template_debug.dylib"
macos.release = "res://bin/libgdexample.macos.template_release.dylib"
windows.debug.x86_64 = "res://bin/gdexample.windows.template_debug.x86_64.dll"
windows.release.x86_64 = "res://bin/gdexample.windows.template_release.x86_64.dll"
linux.debug.x86_64 = "res://bin/libgdexample.linux.template_debug.x86_64.so"
linux.release.x86_64 = "res://bin/libgdexample.linux.template_release.x86_64.so"
导出的
extern "C"
符号名称必须与
entry_symbol
完全相同,否则扩展无法加载。使用
GDREGISTER_CLASS
注册类,并以
MODULE_INITIALIZATION_LEVEL_SCENE
为条件。[libraries] 的键采用
platform.feature.arch
标签格式;
template_debug
/
template_release
用于区分构建配置。可选部分包括:
[icons]
(每个节点的编辑器图标)和
[dependencies]
(导出时复制的额外库)。
Godot 4.7+: 原始 GDExtension 接口新增了支持引用计数的构造与注册入口点——
classdb_construct_object3
和
classdb_register_extension_class6
(GH-118214)。基于 4.7 头文件构建的绑定库会自动使用它们;这些变化仅与直接调用接口的代码有关。

5. Compatibility rules

5. 兼容性规则

Forward-but-not-backward. An extension targeting 4.2 works in 4.3, but one targeting 4.3 will not load in 4.2. Exception: extensions targeting 4.0 do not work in 4.1+.
  • The godot-cpp branch must match the engine version you build against.
  • reloadable = true
    hot reload works in debug builds only.
  • Set
    compatibility_minimum
    to the lowest engine version you actually support — too low and the extension fails to load at runtime.
  • Exported games need the matching
    template_release
    binaries present, or the native node type simply won't exist at runtime.
⚠️ Changed in Godot 4.7:
Object.is_class()
changed its
class
parameter type from
String
to
StringName
for performance. GDScript is unaffected and C# gained a compatibility method, but GDExtension binaries compiled against the old signature rely on the engine's compatibility mapping — rebuild against bindings matching your target version when updating to 4.7. See the 4.7 migration guide.

向前兼容,但不向后兼容。 面向 4.2 的扩展可在 4.3 中运行,但面向 4.3 的扩展无法在 4.2 中加载。例外: 面向 4.0 的扩展无法在 4.1+ 中运行。
  • godot-cpp 分支必须与构建时面向的引擎版本一致。
  • reloadable = true
    热重载仅适用于 debug 构建。
  • 将
    compatibility_minimum
    设为你实际支持的最低引擎版本——设置过低会导致扩展在运行时无法加载。
  • 导出的游戏需要包含匹配的
    template_release
    二进制文件,否则原生节点类型在运行时将不存在。
⚠️ Godot 4.7 中的变更: 为提高性能,
Object.is_class()
的
class
参数类型从
String
改为
StringName
。GDScript 不受影响,C# 增加了兼容方法,但针对旧签名编译的 GDExtension 二进制文件依赖引擎的兼容映射——升级到 4.7 时,请使用与目标版本匹配的绑定重新构建。请参阅 4.7 迁移指南。

6. Using it from GDScript and C#

6. 在 GDScript 和 C# 中使用

After building and placing the
.gdextension
file, the native class appears as a normal node type: bound properties show up in the Inspector (range hints become sliders) and signals appear in the Node dock.
构建并放置
.gdextension
文件后,原生类会显示为普通节点类型:绑定的属性会显示在 Inspector 中(范围提示会变成滑块),信号会显示在 Node 面板中。

GDScript

GDScript

gdscript
extends Node

func _ready():
    var node := GDExample.new()
    node.speed = 2.0
    node.position_changed.connect(_on_position_changed)
    add_child(node)

func _on_position_changed(node, new_pos):
    print("%s is now at %s" % [node.get_class(), new_pos])
gdscript
extends Node

func _ready():
    var node := GDExample.new()
    node.speed = 2.0
    node.position_changed.connect(_on_position_changed)
    add_child(node)

func _on_position_changed(node, new_pos):
    print("%s is now at %s" % [node.get_class(), new_pos])

C# Equivalent

C# 等效实现

csharp
using Godot;

public partial class Demo : Node
{
    public override void _Ready()
    {
        var node = new GDExample(); // The native class is available like any Godot type.
        node.Set("speed", 2.0);
        node.Connect("position_changed", Callable.From<Node, Vector2>(OnPositionChanged));
        AddChild(node);
    }

    private void OnPositionChanged(Node node, Vector2 newPos)
        => GD.Print($"{node.GetClass()} is now at {newPos}");
}
To get a strongly-typed C# wrapper you can ship a C# glue class, but the extension is fully usable via the dynamic
Set
/
Connect
/
Call
API shown above.
Other languages & debugging: Rust (gdext) · Debugging native code

csharp
using Godot;

public partial class Demo : Node
{
    public override void _Ready()
    {
        var node = new GDExample(); // The native class is available like any Godot type.
        node.Set("speed", 2.0);
        node.Connect("position_changed", Callable.From<Node, Vector2>(OnPositionChanged));
        AddChild(node);
    }

    private void OnPositionChanged(Node node, Vector2 newPos)
        => GD.Print($"{node.GetClass()} is now at {newPos}");
}
如果需要强类型 C# 包装器,可以随扩展一起提供 C# 胶水类;但通过上面所示的动态
Set
/
Connect
/
Call
API,扩展已经可以完全正常使用。
其他语言与调试: Rust(gdext) · 调试原生代码

Implementation Checklist

实现检查清单

  • Confirmed native is actually needed (profiled; GDScript/C# insufficient — see godot-optimization)
  • godot-cpp submodule on the branch matching the target engine version
  • _bind_methods
    binds every exposed method/property/signal
  • entry_symbol
    in
    .gdextension
    matches the exported
    extern "C"
    symbol
  • compatibility_minimum
    set to the lowest engine version you support
  • [libraries]
    has correct paths for every shipped platform/arch (debug + release)
  • Release export includes the
    template_release
    binaries
  • 已确认确实需要原生方案(已完成性能分析;GDScript/C# 不足——参见 godot-optimization)
  • godot-cpp 子模块位于与目标引擎版本匹配的分支上
  • _bind_methods
    绑定了所有对外暴露的方法、属性和信号
  • .gdextension
    中的
    entry_symbol
    与导出的
    extern "C"
    符号一致
  • compatibility_minimum
    已设置为你支持的最低引擎版本
  • [libraries]
    已为每个发布的平台/架构配置正确路径(debug + release)
  • Release 导出包含
    template_release
    二进制文件