目录

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. 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.

Examples

The following examples show how to use the dart:ffi library:

Example Description
hello_world How to call a C function with no arguments and no return value.
primitives How to call C functions that have arguments and return values that are ints or pointers. Also demonstrates varargs.
structs How to use structs to pass strings to and from C and to handle simple and complex C structures.
sqlite An example in the Dart SDK repo that comes with a mini tutorial.

Walkthrough of hello_world

The hello_world example has the minimum necessary code for calling a C library.

Files

The hello_world example has the following files:

Source file Description
hello.dart A Dart file that uses the hello_world() function from a C library.
pubspec.yaml The usual Dart pubspec, with a lower bounds on the SDK that’s at least 2.6.
hello_library/hello.h Declares the hello_world() function.
hello_library/hello.c A C file that imports hello.h and defines the hello_world() function.
hello_library/CMakeLists.txt A 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).

Building and running

Here’s an example of building the dynamic library and executing the Dart app:

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

Using dart:ffi

The hello.dart file illustrates the steps for using dart:ffi to call a C function:

  1. Import dart:ffi.
  2. Import the path library that you’ll use to store the path of dynamic library.
  3. Create a typedef with the FFI type signature of the C function.
  4. Create a typedef for the variable that you’ll use when calling the C function.
  5. Create a variable to store the path of the dynamic library.
  6. Open the dynamic library that contains the C function.
  7. Get a reference to the C function, and put it into a variable.
  8. Call the C function.

Here’s the code for each step.

  1. Import dart:ffi.
    import 'dart:ffi' as ffi;
    
  2. Import the path library that you’ll use to store the path of dynamic library.
    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.
    Commonly used types defined by dart:ffi library include Double, Int32, NativeFunction, Pointer, Struct, Uint8, and Void.
    typedef hello_world_func = ffi.Void Function();
    
  4. Create a typedef for the variable that you’ll use when calling the C function.
    typedef HelloWorld = void Function();
    
  5. Create a variable to store the path of the dynamic library.
    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.
      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 defined in steps 2 and 3, along with the dynamic library variable from step 4.
      final HelloWorld hello = dylib
       .lookup<ffi.NativeFunction<hello_world_func>>('hello_world')
       .asFunction();
    
  8. Call the C function.
      hello();
    

Once you understand the hello_world example, you should be ready to look at the other dart:ffi examples.

Bundling and loading C libraries

How you bundle (or package or distribute) a C library with your package or app and then load that library depends on your platform and the type of library. For details, see the following:

Generating 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 reduce this burden, you can use the package:ffigen binding generator to automatically create FFI wrappers from C header files.