Skip to content
HN On Hacker News ↗

Using any C++ library in Godot - Conan Blog

▲ 169 points • 68 comments • by czoido • 2w ago • HN discussion ↗

Pangram verdict · v3.3

We believe that this text is a mix of AI and human-written content.

67 %

AI likelihood · overall

Mixed
34% human-written 66% AI-generated
SEGMENTS · HUMAN 2 of 7
SEGMENTS · AI 4 of 7
WORD COUNT 1,498
PEAK AI % 94% · §3
Analyzed
Sep 29
backend: pangram/v3.3
Segments scanned
7 windows
avg 214 words each
Distribution
34 / 66%
human / AI fraction
Verdict
Mixed
Pangram v3.3

Article text · 1,498 words · 7 segments analyzed

Human AI-generated
§1 AI · 81%

Godot has become one of the most popular game engines of the last few years. It is free, open source under the MIT license, and small enough to download and start using in minutes. Most Godot games are written in GDScript, the engine’s own scripting language. Sooner or later, though, many projects need something that already exists as a C or C++ library: a simulation library, a database, a networking protocol, a machine learning runtime. GDScript cannot call native code, but Godot can load it through GDExtension, and godot-cpp, the official C++ bindings, lets you expose that code as regular engine classes. Writing the C++ code is the easy part. The hard part is the build: godot-cpp has to match your Godot version, and every library you add has to be compiled for each platform you ship to. In this post we give a short tour of Godot, explain how C++ extensions work, and show how to bring C++ libraries into a Godot game with Conan and godot-cpp 10, now available in ConanCenter. As an example we will use flecs, an Entity Component System library, to simulate 100,000 particles inside a Godot scene.

§2 Human · 24%

Download the video 100,000 particles simulated with flecs inside a Godot scene, fleeing from the mouse cursor A Quick Introduction to Godot Godot is a general purpose engine for 2D and 3D games.

§3 AI · 94%

Everything in a Godot project is built from two concepts: Nodes are the basic building blocks. Each node has a type (Sprite2D, Camera3D, AudioStreamPlayer, Timer…), a set of properties you can edit in the Inspector, and callbacks such as _ready() or _process() that the engine calls during the game loop. Scenes are trees of nodes saved to disk as .tscn files. A scene can be a character, a menu or a whole level, and scenes can be instanced inside other scenes. Behavior is usually added by attaching a script to a node. GDScript is a Python-like language designed for the engine, and it is great for gameplay logic because changes show up immediately without a compile step. What makes Godot interesting for C++ developers is that the engine itself is written in C++, and it can load extensions written in C++ without being recompiled. A class that comes from one of these extensions becomes a regular engine class: it shows up in the editor next to the built-in nodes, with its properties in the Inspector, and GDScript can use it like any other node. The next section explains how these extensions work. Extending Godot with C++ There are two ways to add C++ code to Godot: Engine modules are compiled into the engine itself. They have full access to the internals, but you need to build and ship your own copy of Godot, including the editor and export templates for every platform. GDExtension loads a shared library (.dll, .so, .dylib, or .wasm on the web) into an official, unmodified Godot build at runtime. The engine talks to the library through a stable C interface. GDExtension is the recommended approach for most projects, and it is how many popular plugins are distributed today. Because the C interface is verbose to use directly, the Godot team maintains godot-cpp, a C++ library that wraps it with an API very close to the one used inside the engine. It provides a C++ class for every engine class, such as Node2D, Sprite2D or Input. Your own classes are regular C++ code that derives from those classes. A node written with godot-cpp looks like this: #include <godot_cpp/classes/node2d.hpp> namespace godot { class MyNode : public Node2D { GDCLASS(MyNode, Node2D) protected: static void _bind_methods() {} public: void _process(double p_delta) override { // runs every frame } }; } // namespace godot Since version 10.0, a single godot-cpp release works with any Godot version from 4.3 onwards. You pick one with the api_version build option, and godot-cpp generates its C++ classes from the API of that version. An extension built for Godot 4.3 also works in newer versions, but not in older ones, so you usually pick the oldest Godot version you want to support. Build targets and feature tags There is one more concept you need to know before building anything. godot-cpp is compiled for one of three targets, named after the Godot builds that load the library: template_debug: the default. Enables debug checks through the DEBUG_ENABLED definition. This library is loaded by the editor and by debug exports. template_release: for release exports, with the debug checks removed. editor: for libraries that are only loaded by the editor. Which library Godot loads is decided at runtime by a small .gdextension file. It maps feature tags to library paths.

§4 Mixed · 36%

The debug tag matches the editor and debug exports, and the release tag matches release exports: [configuration] entry_symbol = "gdexample_library_init" compatibility_minimum = "4.7" [libraries] macos.debug = "res://bin/libgdexample.template_debug.dylib" macos.release = "res://bin/libgdexample.template_release.dylib" linux.debug = "res://bin/libgdexample.template_debug.so" linux.release = "res://bin/libgdexample.template_release.so" windows.debug = "res://bin/libgdexample.template_debug.dll" windows.release = "res://bin/libgdexample.template_release.dll" The usual workflow The Godot documentation recommends adding godot-cpp to your repository as a git submodule and building it together with your library using SCons.

§5 AI · 81%

That works well for a first extension, but every project ends up compiling its own godot-cpp for each target, platform and architecture, and any third party library you wrap, such as a physics engine or a machine learning runtime, has to be vendored and built with matching flags for every platform Godot exports to. Both are exactly the kind of problem Conan was built to solve. Managing the Dependencies with Conan With the godot-cpp recipe in ConanCenter, godot-cpp becomes a regular package. The two parameters discussed above are Conan options: api_version: the Godot API version the bindings target, from 4.3 to 4.7 (the default). target: template_debug (the default), template_release or editor. Each combination is built once and then reused by every project that needs it, instead of being compiled inside each extension. Your GDExtension becomes just another C++ project with dependencies. Any of the more than 1,900 libraries in ConanCenter, or one you package yourself with a Conan recipe, can be added next to godot-cpp, and Conan builds all of them consistently for every platform you target. A Practical Example: A Swarm of 100,000 Particles To show how this works in practice, we will write a GDExtension that registers a new Swarm node. It simulates 100,000 particles that flee from the mouse cursor and bounce off the window edges, and draws all of them in a Godot scene. The simulation runs on flecs, an Entity Component System (ECS) library for C and C++. In an ECS, entities are plain ids, components are plain data structs attached to them, and systems are functions that run over every entity that has a given set of components. Components of the same type are stored together in memory, which makes iterating over large numbers of entities very fast. That is why ECS is a popular choice for simulations, crowds or bullet hell games. It is also the kind of work where native code pays off, since updating this many entities every frame is much faster in C++ than in GDScript.

§6 Human · 16%

You can find the complete example in the Conan examples2 repository: $ git clone https://github.com/conan-io/examples2.git $ cd examples2/examples/libraries/godot-cpp/gdextension The src folder contains the extension code, and demo is a regular Godot project that loads it.

§7 AI · 90%

Declaring the dependencies The conanfile.py requires godot-cpp and flecs from ConanCenter: from conan import ConanFile from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout class GDExtensionExample(ConanFile): package_type = "shared-library" settings = "os", "compiler", "build_type", "arch" generators = "CMakeDeps" def requirements(self): self.requires("godot-cpp/10.0.0") self.requires("flecs/4.1.6") def layout(self): cmake_layout(self) def generate(self): tc = CMakeToolchain(self) # Godot picks the library to load by its build "target", so we name # the output after the target godot-cpp was built with tc.cache_variables["GODOTCPP_TARGET"] = str(self.dependencies["godot-cpp"].options.target) tc.generate() def build(self): cmake = CMake(self) cmake.configure() cmake.build() The only Godot specific detail is in generate(). We read the target option of the godot-cpp dependency and pass it to CMake, so the name of the library always matches the godot-cpp binary it was linked against. The CMakeLists.txt cmake_minimum_required(VERSION 3.15) project(gdexample LANGUAGES CXX) find_package(godot-cpp REQUIRED CONFIG) find_package(flecs REQUIRED CONFIG) add_library(gdexample SHARED src/register_types.cpp src/swarm.cpp ) target_link_libraries(gdexample PRIVATE godot-cpp flecs::flecs_static) # Output as demo/bin/libgdexample.<target>.<ext>, the path the # demo/bin/gdexample.gdextension file points Godot to. The generator # expression prevents multi-config generators from adding a Release/ subfolder set_target_properties(gdexample PROPERTIES OUTPUT_NAME "gdexample.${GODOTCPP_TARGET}" PREFIX "lib" LIBRARY_OUTPUT_DIRECTORY "$<1:${CMAKE_SOURCE_DIR}/demo/bin>" RUNTIME_OUTPUT_DIRECTORY "$<1:${CMAKE_SOURCE_DIR}/demo/bin>" ) This is a completely standard CMake project. The extension is a shared library that links godot-cpp and flecs statically, so there is a single library file to ship. We write it straight into demo/bin so Godot finds it without an extra copy step. Writing the node The Swarm class derives from Node2D and owns the flecs world. The components of each particle are plain structs. The GDCLASS macro adds the boilerplate that Godot’s class system needs, and _bind_methods() declares what Godot can see, in this case the count and flee_radius properties. Once the class is registered, they appear in the Inspector and can be used from GDScript.