filleduchaos / dart-bindgen

An experimental library/tool for generating Dart interfaces from header files.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

dart-bindgen

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.

Usage

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 the bindgen 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

Sample output

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);
  }
}

About

An experimental library/tool for generating Dart interfaces from header files.

License:MIT License


Languages

Language:Dart 65.2%Language:C 30.0%Language:CMake 3.4%Language:C++ 1.2%Language:Shell 0.1%