Aris wasmjsextend - Binding generator for FFI bindings

Overview

pub package Build Status Coverage Status

Binding generator for FFI bindings.

Note: ffigen only supports parsing C headers.

Example

For some header file example.h:

int sum(int a, int b);

Add configurations to Pubspec File:

ffigen:
  output: 'generated_bindings.dart'
  headers:
    entry-points:
      - 'example.h'

Output (generated_bindings.dart).

class NativeLibrary {
  final Pointer<T> Function<T extends NativeType>(String symbolName)
      _lookup;
  NativeLibrary(DynamicLibrary dynamicLibrary)
      : _lookup = dynamicLibrary.lookup;
  NativeLibrary.fromLookup(
      Pointer<T> Function<T extends NativeType>(String symbolName)
          lookup)
      : _lookup = lookup;

  int sum(int a, int b) {
    return _sum(a, b);
  }

  late final _sumPtr = _lookup<ffi.NativeFunction<ffi.Int32 Function(ffi.Int32, ffi.Int32)>>('sum');
  late final _sum = _sum_ptr.asFunction<int Function(int, int)>();
}

Using this package

  • Add ffigen under dev_dependencies in your pubspec.yaml.
  • Install LLVM (see Installing LLVM).
  • Configurations must be provided in pubspec.yaml or in a custom YAML file (see configurations).
  • Run the tool- dart run ffigen.

Jump to FAQ.

Installing LLVM

package:ffigen uses LLVM. Install LLVM (9+) in the following way.

ubuntu/linux

  1. Install libclangdev - sudo apt-get install libclang-dev.

Windows

  1. Install Visual Studio with C++ development support.
  2. Install LLVM or winget install -e --id LLVM.LLVM.

MacOS

  1. Install Xcode.
  2. Install LLVM - brew install llvm.

Configurations

Configurations can be provided in 2 ways-

  1. In the project's pubspec.yaml file under the key ffigen.
  2. Via a custom YAML file, then specify this file while running - dart run ffigen --config config.yaml

The following configuration options are available-

Key Explaination Example
output
(Required)
Output path of the generated bindings.
output: 'generated_bindings.dart'
llvm-path Path to llvm folder.
ffigen will sequentially search for `lib/libclang.so` on linux, `lib/libclang.dylib` on macOs and `bin\libclang.dll` on windows, in the specified paths.

Complete path to the dynamic library can also be supplied.
Required if ffigen is unable to find this at default locations.
llvm-path:
  - '/usr/local/opt/llvm'
  - 'C:\Program Files\llvm`
  - '/usr/lib/llvm-11'
  # Specify exact path to dylib
  - '/usr/lib64/libclang.so'
headers
(Required)
The header entry-points and include-directives. Glob syntax is allowed.
If include-directives are not specified ffigen will generate everything directly/transitively under the entry-points.
headers:
  entry-points:
    - 'folder/**.h'
    - 'folder/specific_header.h'
  include-directives:
    - '**index.h'
    - '**/clang-c/**'
    - '/full/path/to/a/header.h'
name
(Prefer)
Name of generated class.
name: 'SQLite'
description
(Prefer)
Dart Doc for generated class.
description: 'Bindings to SQLite'
compiler-opts Pass compiler options to clang. You can also pass these via the command line tool.
compiler-opts:
  - '-I/usr/lib/llvm-9/include/'

and/or via the command line -

dart run ffigen --compiler-opts "-I/headers
-L 'path/to/folder name/file'"
compiler-opts-automatic -> macos -> include-c-standard-library Tries to automatically find and add C standard library path to compiler-opts on macos.
Default: true
compiler-opts-automatic:
  macos:
    include-c-standard-library: false
functions

structs

unions

enums

unnamed-enums

macros

globals
Filters for declarations.
Default: all are included.

Options -
- Include/Exclude declarations.
- Rename declarations.
- Rename enum and struct members.
- Expose symbol-address for functions and globals.
functions:
  include: # 'exclude' is also available.
    # Matches using regexp.
    - [a-z][a-zA-Z0-9]*
    # '.' matches any character.
    - prefix.*
    # Matches with exact name
    - someFuncName
    # Full names have higher priority.
    - anotherName
  rename:
    # Regexp groups based replacement.
    'clang_(.*)': '$1'
    'clang_dispose': 'dispose'
    # Removes '_' from beginning.
    '_(.*)': '$1'
  symbol-address:
    # Used to expose symbol address.
    include:
      - myFunc
structs:
  rename:
    # Removes prefix underscores
    # from all structures.
    '_(.*)': '$1'
  member-rename:
    '.*': # Matches any struct.
      # Removes prefix underscores
      # from members.
      '_(.*)': '$1'
enums:
  rename:
    # Regexp groups based replacement.
    'CXType_(.*)': '$1'
  member-rename:
    '(.*)': # Matches any enum.
      # Removes '_' from beginning
      # enum member name.
      '_(.*)': '$1'
    # Full names have higher priority.
    'CXTypeKind':
      # $1 keeps only the 1st
      # group i.e only '(.*)'.
      'CXType(.*)': '$1'
globals:
  exclude:
    - aGlobal
  rename:
    # Removes '_' from
    # beginning of a name.
    '_(.*)': '$1'
typedefs Filters for referred typedefs.

Options -
- Include/Exclude (referred typedefs only).
- Rename typedefs.

Note: Typedefs that are not referred to anywhere will not be generated.
typedefs:
  exclude:
    # Typedefs starting with `p` are not generated.
    - 'p.*'
  rename:
    # Removes '_' from beginning of a typedef.
    '_(.*)': '$1'
functions -> expose-typedefs Generate the typedefs to Native and Dart type of a function
Default: Inline types are used and no typedefs to Native/Dart type are generated.
functions:
  expose-typedefs:
    include:
      # Match function name.
      - 'myFunc'
       # Do this to expose types for all function.
      - '.*'
    exclude:
      # If you only use exclude, then everything
      # not excluded is generated.
      - 'dispose'
structs -> pack Override the @Packed(X) annotation for generated structs.

Options - none, 1, 2, 4, 8, 16
You can use RegExp to match with the generated names.

Note: Ffigen can only reliably identify packing specified using __attribute__((__packed__)). However, structs packed using `#pragma pack(...)` or any other way could potentially be incorrect in which case you can override the generated annotations.
structs:
  pack:
    # Matches with the generated name.
    'NoPackStruct': none # No packing
    '.*': 1 # Pack all structs with value 1
comments Extract documentation comments for declarations.
The style and length of the comments recognized can be specified with the following options-
style: doxygen(default) | any
length: brief | full(default)
If you want to disable all comments you can also pass
comments: false.
comments:
  style: any
  length: full
structs -> dependency-only

unions -> dependency-only
If `opaque`, generates empty `Opaque` structs/unions if they were not included in config (but were added since they are a dependency) and only passed by reference(pointer).
Options - full(default) | opaque
structs:
  dependency-only: opaque
unions:
  dependency-only: opaque
sort Sort the bindings according to name.
Default: false, i.e keep the order as in the source files.
sort: true
use-supported-typedefs Should automatically map typedefs, E.g uint8_t => Uint8, int16_t => Int16 etc.
Default: true
use-supported-typedefs: true
dart-bool Should generate dart `bool` instead of Uint8 for c99 bool in functions.
Default: true
dart-bool: true
use-dart-handle Should map `Dart_Handle` to `Handle`.
Default: true
use-dart-handle: true
preamble Raw header of the file, pasted as-it-is.
preamble: |
  // ignore_for_file: camel_case_types, non_constant_identifier_names
typedef-map Map typedefs to Native Types.
Values can only be Void, Uint8, Int8, Uint16, Int16, Uint32, Int32, Uint64, Int64, IntPtr, Float and Double.
typedef-map:
  'my_custom_type': 'IntPtr'
  'size_t': 'Int64'
size-map Size of integers to use (in bytes).
The defaults (see example) may not be portable on all OS. Do not change these unless absolutely sure.
# These are optional and also default,
# Omitting any and the default
# will be used.
size-map:
  char: 1
  unsigned char: 1
  short: 2
  unsigned short: 2
  int: 4
  unsigned int: 4
  long: 8
  unsigned long: 8
  long long: 8
  unsigned long long: 8
  enum: 4

Limitations

  1. Multi OS support for types such as long. Issue #7

Trying out examples

  1. cd examples/ , Run dart pub get.
  2. Run dart run ffigen.

Running Tests

  1. Dynamic library for some tests need to be built before running the examples.
  2. cd test/native_test.
  3. Run dart build_test_dylib.dart.

Run tests from the root of the package with dart run test.

Note: If llvm is not installed in one of the default locations, tests may fail.

FAQ

Can ffigen be used for removing underscores or renaming declarations?

Ffigen supports regexp based renaming, the regexp must be a full match, for renaming you can use regexp groups ($1 means group 1).

E.g - For renaming clang_dispose_string to string_dispose. We can can match it using clang_(.*)_(.*) and rename with $2_$1.

Here's an example of how to remove prefix underscores from any struct and its members.

structs:
  ...
  rename:
    '_(.*)': '$1' # Removes prefix underscores from all structures.
  member-rename:
    '.*': # Matches any struct.
      '_(.*)': '$1' # Removes prefix underscores from members.

How to generate declarations only from particular headers?

The default behaviour is to include everything directly/transitively under each of the entry-points specified.

If you only want to have declarations directly particular header you can do so using include-directives. You can use glob matching to match header paths.

headers:
  entry-points:
    - 'path/to/my_header.h'
  include-directives:
    - '**my_header.h' # This glob pattern matches the header path.

Can ffigen filter declarations by name?

Ffigen supports including/excluding declarations using full regexp matching.

Here's an example to filter functions using names

functions:
  include:
    - 'clang.*' # Include all functions starting with clang.
  exclude:
    - '.*dispose': # Exclude all functions ending with dispose.

This will include clang_help. But will exclude clang_dispose.

Note: exclude overrides include.

How does ffigen handle C Strings?

Ffigen treats char* just as any other pointer,(Pointer ). To convert these to/from String, you can use package:ffi. Use ptr.cast ().toDartString() to convert char* to dart string and "str".toNativeUtf8() to convert string to char*.

How does ffigen handle C99 bool data type?

Although dart:ffi doesn't have a NativeType for bool, they can be implemented as Uint8. Ffigen generates dart bool for function parameters and return type by default. To disable this, and use int instead, set dart-bool: false in configurations.

How are unnamed enums handled?

Unnamed enums are handled separately, under the key unnamed-enums, and are generated as top level constants.

Here's an example that shows how to include/exclude/rename unnamed enums

unnamed-enums:
  include:
    - 'CX_.*'
  exclude:
    - '.*Flag'
  rename:
    'CXType_(.*)': '$1'

Why are some struct/union declarations generated even after excluded them in config?

This happens when an excluded struct/union is a dependency to some included declaration. (A dependency means a struct is being passed/returned by a function or is member of another struct in some way)

Note: If you supply structs -> dependency-only as opaque ffigen will generate these struct dependencies as Opaque if they were only passed by reference(pointer).

structs:
  dependency-only: opaque
unions:
  dependency-only: opaque

How to expose the native pointers?

By default the native pointers are private, but you can use the symbol-address subkey for functions/globals and make them public by matching with its name. The pointers are then accesible via nativeLibrary.addresses.

Example -

functions:
  symbol-address:
    include:
      - 'myFunc' # Match function name.
      - '.*' # Do this to expose all function pointers.
    exclude: # If you only use exclude, then everything not excluded is generated.
      - 'dispose'

How to get typedefs to Native and Dart type of a function?

By default these types are inline. But you can use the expose-typedef subkey for functions to generate them. This will expose the Native and Dart type. E.g - for a function named hello, the generated typedefs are named as NativeHello and DartHello.

Example -

functions:
  expose-typedefs:
    include:
      - 'myFunc' # Match function name.
      - '.*' # Do this to expose types for all function.
    exclude: # If you only use exclude, then everything not excluded is generated.
      - 'dispose'

How are Structs/Unions/Enums that are reffered to via typedefs handled?

Named declarations use their own names even when inside another typedef. However, unnamed declarations inside typedefs take the name of the first typedef that refers to them.

Why are some typedefs not generated?

The following typedefs are not generated -

  • They are not referred to anywhere in the included declarations.
  • They refer to a struct/union having the same name as itself.
  • They refer to a boolean, enum, inline array, Handle or any unsupported type.
You might also like...

Aris fltrtuber - Flutter Web App to list top 30 YouTubers who create tutorial on Flutter

Aris fltrtuber - Flutter Web App to list top 30 YouTubers who create tutorial on Flutter

Fluttuber - Top 30 Flutter YouTubers Flutter Web App to list top 30 YouTubers wh

Jan 27, 2022

Pdfium_bindings - This project aims to wrap the complete Pdfium API in dart, over FFI

Pdfium_bindings - This project aims to wrap the complete Pdfium API in dart, over FFI

Oct 22, 2022

Flutter FFI+WebAssembly Example

flutter_ffi_plugin A new flutter plugin project. FFI # Remove Codesign on macos codesign --remove-signature /usr/local/bin/dart # Install cmake brew

Oct 22, 2022

Starter project for Flutter plugins willing to access native and synchronous rust code using FFI

Flutter Rust FFI Template This project is a Flutter Plugin template. It provides out-of-the box support for cross-compiling native Rust code for all a

Dec 7, 2022

A revolutionary new browser. HTML to Flutter transpiler. Written in Go (using Dart FFI) and Flutter.

A revolutionary new browser. HTML to Flutter transpiler. Written in Go (using Dart FFI) and Flutter.

Flutter Browser An experimental HTML & CSS to Flutter transpiler written in Go, using Dart FFI and Flutter. Screenshots Notice This works great for si

Oct 24, 2022

A convenient code generator for app styleguide, gallery, wireframes and/or storyboard.

A convenient code generator for app styleguide, gallery, wireframes and/or storyboard.

Framy A convenient code generator for app styleguide, gallery, wireframes and/or storyboard. 👉 Official documentation 👈 Packages In order to use Fra

Dec 19, 2022

A fully-featured Last.fm client and scrobbler with Shazam-like scrobbling, a collage generator, home screen widgets, and more!

Finale A fully-featured Last.fm client and scrobbler with Shazam-like scrobbling, a collage generator, and more! The app is available on iOS, Android,

Jan 5, 2023

Flutter route generator

Flutter route generator

--- for more docs with examples https://autoroute.vercel.app Introduction Installation Setup and Usage Generated routes Navigation Navigating Between

Jan 7, 2023

Dart and Flutter sealed class generator and annotations, with match methods and other utilities. There is also super_enum compatible API.

Dart Sealed Class Generator Generate sealed class hierarchy for Dart and Flutter. Features Generate sealed class with abstract super type and data sub

Jan 2, 2023
Owner
Behruz Hurramov
Behruz Hurramov
Behruz Hurramov
Binding and high-level wrapper on top of libssh - The SSH library!

Dart Binding to libssh version 0.9.6 binding and high-level wrapper on top of libssh - The SSH library! libssh is a multiplatform C library implementi

Isaque Neves 2 Dec 20, 2021
Android bindings plugin for Flutter.

Flutter Android Bindings This is a Flutter plugin for using Android's numerous platform-specific APIs in Flutter apps. Screenshot Prerequisites Dart 2

D.R.Y. Dart 133 Dec 29, 2022
This plugin create a binding between your translations from .arb files and your Flutter app.

PROJECT MAINTENANCE PAUSED This project is no longer maintained due to the lack of time and availability. I'm a developer to and I know how frustratin

Razvan Lung 255 Dec 3, 2022
Flutter bindings for libsodium

flutter_sodium With flutter_sodium you get access to the modern, easy-to-use libsodium crypto library in your Flutter apps. One set of crypto APIs sup

First Floor Software 99 Dec 12, 2022
Startup-Name-Generator-App-in-Flutter - Business Startup Name Generator App in Flutter

Business Startup Name Generator App #About APP: A simple mobile app that generat

AHSAN SIDDZ 0 Jan 30, 2022
Aris imageexmii - Learn everything about images such as adding filters, borders & different shapes

Flutter Tutorial - 2/2 Image - Deep Dive Learn everything about images such as a

Behruz Hurramov 0 Dec 29, 2021
Behruz Hurramov 0 Dec 29, 2021
Behruz Hurramov 0 Dec 29, 2021
Aris wallstreetnw - Showcase how to work with HttpClient in Flutter

Flutter News App Demo This project is to showcase how to work with HttpClient in

Behruz Hurramov 4 Mar 31, 2022
Aris interactivevwr - Simple use case for InteractiveViewer

interactive_viewer_demo Simple use case for InteractiveViewer | Flutter 1.20 If

Behruz Hurramov 2 Jan 9, 2022