An experimental library/tool for generating Dart interfaces to C or C ABI compatible code from header files.
The aim of this project is to make it less tedious to use dart:ffi
especially with existing libraries, in a way that's configurable/extensible from Dart. The author is also exploring implementing a Dart backend for Swig as dart:ffi
becomes more mature.
Currently it relies exclusively on libclang, although it's fairly easy to implement support for another compiler/format.
Warning: This library is currently in a very pre-alpha state. You can check the first release label for work that's in progress for and/or blocking the 0.1.0 release.
Currently to use this project you have to clone and build it yourself. You will have to have CMake (minimum 3.7) and Clang (including libclang) installed.
- Run
git clone --recurse-submodules <repo_path>
(there are a couple of C dependencies added as submodules). - Build the Clang bindgen plugin:
cd clang_plugin
mkdir build && cd build
cmake -S ..
make && make install
- Now you can use the tool by running
dart bin/bindgen.dart
from thebindgen
folder.
dart bin/bindgen.dart --help
dart_bindgen: Generate Dart FFI bindings for C libraries
Usage: <script> <options> /path/to/header/file
Options:
-l, --loader The loader to read the header file with (defaults to "clang")
-n, --name The name of the library to be generated (defaults to the header filename)
-o, --output The file to output the generated library to (defaults to the library name in the current directory)
-v, --verbose Whether or not to print debug info
-h, --help Print this help message
This is the file written out from running the tool against the structs FFI example:
/// Auto-generated file: Do not edit unless you know what you are doing
/// Dart bindings for structs, generated by bindgen
import 'dart:ffi' as ffi;
import 'package:ffi/ffi.dart' as ffi;
class Coordinate extends ffi.Struct {
@ffi.Double()
double latitude;
@ffi.Double()
double longitude;
}
class Place extends ffi.Struct {
ffi.Pointer<ffi.Utf8> name;
ffi.Pointer<Coordinate> coordinate;
}
typedef _create_coordinate_func = ffi.Pointer<Coordinate> Function(ffi.Double latitude, ffi.Double longitude);
typedef _CreateCoordinate = ffi.Pointer<Coordinate> Function(double latitude, double longitude);
typedef _create_place_func = ffi.Pointer<Place> Function(ffi.Pointer<ffi.Utf8> name, ffi.Double latitude, ffi.Double longitude);
typedef _CreatePlace = ffi.Pointer<Place> Function(ffi.Pointer<ffi.Utf8> name, double latitude, double longitude);
typedef _hello_world_func = ffi.Pointer<ffi.Utf8> Function();
typedef _reverse_func = ffi.Pointer<ffi.Utf8> Function(ffi.Pointer<ffi.Utf8> str, ffi.Int32 length);
typedef _Reverse = ffi.Pointer<ffi.Utf8> Function(ffi.Pointer<ffi.Utf8> str, int length);
class LibStructs {
static ffi.DynamicLibrary _lib;
static final Map<String, Function> _symbolCache = {};
T _$getDartFunctionFromCache<T>(String name) {
final func = _symbolCache[name];
if (func == null) {
_lib ??= ffi.DynamicLibrary.open('structs');
}
return func as T;
}
ffi.Pointer<Coordinate> createCoordinate(double latitude, double longitude) {
var cachedFunc = _$getDartFunctionFromCache<_CreateCoordinate>('create_coordinate');
if (cachedFunc != null) return cachedFunc(latitude, longitude);
_symbolCache['create_coordinate'] = _lib.lookupFunction<_create_coordinate_func, _CreateCoordinate>('create_coordinate');
return _symbolCache['create_coordinate'](latitude, longitude);
}
ffi.Pointer<Place> createPlace(ffi.Pointer<ffi.Utf8> name, double latitude, double longitude) {
var cachedFunc = _$getDartFunctionFromCache<_CreatePlace>('create_place');
if (cachedFunc != null) return cachedFunc(name, latitude, longitude);
_symbolCache['create_place'] = _lib.lookupFunction<_create_place_func, _CreatePlace>('create_place');
return _symbolCache['create_place'](name, latitude, longitude);
}
ffi.Pointer<ffi.Utf8> helloWorld() {
var cachedFunc = _$getDartFunctionFromCache<_hello_world_func>('hello_world');
if (cachedFunc != null) return cachedFunc();
_symbolCache['hello_world'] = _lib.lookupFunction<_hello_world_func, _hello_world_func>('hello_world');
return _symbolCache['hello_world']();
}
ffi.Pointer<ffi.Utf8> reverse(ffi.Pointer<ffi.Utf8> str, int length) {
var cachedFunc = _$getDartFunctionFromCache<_Reverse>('reverse');
if (cachedFunc != null) return cachedFunc(str, length);
_symbolCache['reverse'] = _lib.lookupFunction<_reverse_func, _Reverse>('reverse');
return _symbolCache['reverse'](str, length);
}
}