Contents

C interop using dart:ffi

Dart mobile, command-line, and server apps running on the Dart Native platform can use the dart:ffi library to call native C APIs, and to read, write, allocate, and deallocate native memory. FFI stands for foreign function interface. Other terms for similar functionality include native interface and language bindings.

API documentation is available in the dart:ffi API reference.

Download example files

#

To work with the examples in this guide, download the full ffi samples directory. It includes the following examples show how to use the dart:ffi library:

ExampleDescription
hello_worldHow to call a C function with no arguments and no return value.
primitivesHow to call C functions that have arguments and return values that are ints or pointers.
structsHow to use structs to pass strings to and from C and to handle simple and complex C structures.
test_utilsCommon testing utilities for all of these examples.

Review the hello_world example

#

The hello_world example has the minimum necessary code for calling a C library. This example can be found in the samples/ffi you downloaded in the previous section.

Files

#

The hello_world example has the following files:

Source fileDescription
hello.dartA Dart file that uses the hello_world() function from a C library.
pubspec.yamlThe Dart pubspec file, with an SDK lower bound of 3.4.
hello_library/hello.hDeclares the hello_world() function.
hello_library/hello.cA C file that imports hello.h and defines the hello_world() function.
hello_library/hello.defA module-definition file which specifies information used when building a DLL.
hello_library/CMakeLists.txtA CMake build file for compiling the C code into a dynamic library.

Building the C library creates several files, including a dynamic library file named libhello.dylib (macOS), libhello.dll (Windows), or libhello.so (Linux).

Build and execute

#

The commands to build the dynamic library and execute the Dart app would resemble the following series.

$ cd hello_library
$ cmake .
...
$ make
...
$ cd ..
$ dart pub get
$ dart run hello.dart
Hello World

Leverage dart:ffi

#

To learn how to call a C function using the dart:ffi library, review the hello.dart file. This section explains the contents of this file.

  1. Import dart:ffi.

    dart
    import 'dart:ffi' as ffi;
  2. Import the path library that you'll use to store the path of dynamic library.

    dart
    import 'dart:io' show Platform, Directory;
    import 'package:path/path.dart' as path;
  3. Create a typedef with the FFI type signature of the C function.
    To learn about the most used types according to the dart:ffi library consult Interfacing with native types.

    dart
    typedef hello_world_func = ffi.Void Function();
  4. Create a typedef for the variable to use when calling the C function.

    dart
    typedef HelloWorld = void Function();
  5. Create a variable to store the path of the dynamic library.

    dart
    var libraryPath = path.join(Directory.current.path, 'hello_library',
        'libhello.so');
    if (Platform.isMacOS) {
      libraryPath = path.join(Directory.current.path, 'hello_library',
          'libhello.dylib');
    } else if (Platform.isWindows) {
      libraryPath = path.join(Directory.current.path, 'hello_library',
          'Debug', 'hello.dll');
    }
  6. Open the dynamic library that contains the C function.

    dart
    final dylib = ffi.DynamicLibrary.open(libraryPath);
  7. Get a reference to the C function, and put it into a variable. This code uses the typedefs from steps 2 and 3, along with the dynamic library variable from step 4.

    dart
    final HelloWorld hello = dylib
        .lookup<ffi.NativeFunction<hello_world_func>>('hello_world')
        .asFunction();
  8. Call the C function.

    dart
    hello();

Once you understand the hello_world example, consult the other dart:ffi examples.

Bundle and load C libraries

#

The method to bundle / package / distribute then load a native C library depends on the platform and library type.

To learn how, consult the following pages and examples.

Interface with native types

#

The dart:ffi library provides multiple types that implement NativeType and represent native types in C. You can instantiate some native types. Some other native types can be used only as markers in type signatures.

Can instantiate these type signature markers

#

The following native types can be used as markers in type signatures. They or their subtypes can be instantiated in Dart code.

Dart typeDescription
ArrayA fixed-sized array of items. Supertype of type specific arrays.
PointerRepresents a pointer into native C memory.
StructThe supertype of all FFI struct types.
UnionThe supertype of all FFI union types.

Serve as type signature markers only

#

The following list shows which platform-agnostic native types that serve as markers in type signatures. They can't be instantiated in Dart code.

Dart typeDescription
BoolRepresents a native bool in C.
DoubleRepresents a native 64 bit double in C.
FloatRepresents a native 32 bit float in C.
Int8Represents a native signed 8 bit integer in C.
Int16Represents a native signed 16 bit integer in C.
Int32Represents a native signed 32 bit integer in C.
Int64Represents a native signed 64 bit integer in C.
NativeFunctionRepresents a function type in C.
OpaqueThe supertype of all opaque types in C.
Uint8Represents a native unsigned 8 bit integer in C.
Uint16Represents a native unsigned 16 bit integer in C.
Uint32Represents a native unsigned 32 bit integer in C.
Uint64Represents a native unsigned 64 bit integer in C.
VoidRepresents the void type in C.

There are also many ABI specific marker native types that extend AbiSpecificInteger. To learn how these types map on specific platforms, consult the API documentation linked in the following table.

Dart typeDescription
AbiSpecificIntegerThe supertype of all ABI-specific integer types.
IntRepresents the int type in C.
IntPtrRepresents the intptr_t type in C.
LongRepresents the long int (long) type in C.
LongLongRepresents the long long type in C.
ShortRepresents the short type in C.
SignedCharRepresents the signed char type in C.
SizeRepresents the size_t type in C.
UintPtrRepresents the uintptr_t type in C.
UnsignedCharRepresents the unsigned char type in C.
UnsignedIntRepresents the unsigned int type in C.
UnsignedLongRepresents the unsigned long int type in C.
UnsignedLongLongRepresents the unsigned long long type in C.
UnsignedShortRepresents the unsigned short type in C.
WCharRepresents the wchar_t type in C.

Generate FFI bindings with package:ffigen

#

For large API surfaces, it can be time-consuming to write the Dart bindings that integrate with the C code. To have Dart create FFI wrappers from C header files, use the package:ffigen binding generator.

Build and bundle native assets

#

The Native Assets feature should resolve a number of issues associated with the distribution of Dart packages that depend on native code. It does so by providing uniform hooks for integrating with various build systems involved in building Flutter and standalone Dart applications.

This feature should simplify how Dart packages depend on and use native code. Native Assets should provide the following benefits:

  • Build the native code or obtains the binaries using a package's hook/build.dart build hook.
  • Bundle the native Asset that the build.dart build hook reports.
  • Make native assets available at runtime through declarative @Native<>() extern functions using the assetId.

When you opt in to the native experiment, The flutter (run|build) and dart (run|build) commands build and bundle native code with the Dart code.

Review the native_add_library example

#

The native_add_library example includes the minimum code to build and bundle C code in a Dart package.

The example includes the following files:

Source fileDescription
src/native_add_library.cThe C file containing the code for add.
lib/native_add_library.dartThe Dart file that invokes the C function add in asset package:native_add_library/native_add_library.dart through FFI. (Note that asset id defaults to the library uri.)
test/native_add_library_test.dartA Dart test using the native code.
hook/build.dartA build hook for compiling src/native_add_library.c and declaring the compiled asset with id package:native_add_library/native_add_library.dart.

When a Dart or Flutter project depends on package:native_add_library, it invokes the hook/build.dart build hook on run, build, and test commands. The native_add_app example showcases a use of native_add_library.

Review Native Asset API documentation

#

API documentation can be found for the following packages:

Opt-in to the experiment

#

To learn how to enable the experiment and provide feedback, consult these tracking issues: