WIP libffi bindings for Godot 4.1+.
Warning
Misuse may easily crash the Godot editor and built games/apps, use with caution!
- Supports Windows, Linux, macOS, iOS and Android platforms, including running in the Godot editor
- Custom ".ffilibrary" file format, which are INI files with a
[libraries]
section that defines paths to native libraries separately per platform/architecture, using the exact same format as ".gdextension" files. They are imported as CFFILibrary resources.- TODO: support the
[dependencies]
section
- TODO: support the
- Editor export plugin that bundles the correct native library in builds, based on the configurations from ".ffilibrary" files
- Supports built-in types like
int
andfloat
, pointer types likeconst char *
and struct types- TODO: arrays, union, enums, function pointers
- Scoped type definitions, so that different types can be defined with the same name in different libraries.
- Instantiate FFI types using
CFFIType.alloc
. The returnedCFFIOwnedValue
is RefCounted and releases the memory automatically whenever it gets destroyed. - Get/set struct fields by name from
CFFIPointer
s - Construct
String
s andPackedByteArray
s fromCFFIPointer
s with a single method call - Use Dictionaries as literal struct values, for example when calling a function
- Enable the
cffi
editor plugin inProject -> Project Settings... -> Plugins
tab. - Build your native DLLs and add them to your project
- Create a ".ffilibrary" file and define the paths of the native libraries per platform/architecture inside the
[libraries]
section, exactly like you would do for .gdextension files. This file will be imported as a CFFILibrary Resource. - Call
CFFILibrary.open()
to open aCFFILibraryHandle
- Get native functions using
CFFILibraryHandle.get_function
and invoke them withinvoke
orinvokev
. - Mess with native data using
CFFIPointer
s, hopefully not crashing your app - Enjoy 🍾
// native_plugin.c
typedef struct ExampleStruct {
int a;
int b;
} ExampleStruct;
const char *get_message() {
return "Hello world!";
}
int get_a(ExampleStruct s) {
return s.a;
}
# native_plugin.ffilibrary
[libraries]
windows.x86_64 = "res://native_plugin_windows_x86_64.dll"
windows.x86 = "res://native_plugin_windows_x86.dll"
linux.x86_64 = "res://native_plugin_linux_x86_64.so"
linux.x86 = "res://native_plugin_linux_x86.so"
macos = "res://native_plugin_macos.dylib"
# script.gd
extends Node
# Using ".ffilibrary" files is the preferred way of bundling FFI libraries in projects.
# You can also use `CFFI.open` to load libraries by name or path directly instead.
static var native_plugin_dll = load("res://native_plugin.ffilibrary").open()
static var ExampleStruct = native_plugin_dll.define_struct("ExampleStruct", {
"a": "int",
"b": "int",
})
static var get_message = native_plugin_dll.get_function("get_message", "const char *")
static var get_a = native_plugin_dll.get_function("get_a", "int", ["ExampleStruct"])
func _ready():
var message_ptr: CFFIPointer = get_message.invoke()
var message = message_ptr.get_string_from_utf8()
print(message) # "Hello world!"
var example_struct = ExampleStruct.alloc()
example_struct.a = 42
var a = get_a.invoke(example_struct)
assert(a == example_struct.a)
assert(a == 42)
There is also an example native_plugin.ffilibrary in the "test/native_plugin" folder showing how to setup a native library resource. The script Test.gd shows how to use the FFI to call the native library functions. Refer to plugin.c for the native function implementations in this sample.
- Accept a pointer when expecting a value, just dereference it automagically
- Accept a value when expecting pointer? Could be useful in function calls, but not when setting struct fields
- Support defining and using unions
- Support FFI array types, both fixed and variable length
- Support function pointers
- Support variadic native functions (the
variadic
flag is there, but theffi_cif
is not being prep'd correctly) - Support
[dependencies]
section in ".ffilibrary" files - Define enum values? Enum constants can easily be defined as constants in GDScript directly, so this isn't a requirement. Would be nice for self documenting function arguments/return types, though.
CFFI GDExtension uses the following open-source libraries: