Skip to content

dart:ffi only supports calling static Dart functions from native code #47405

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
azan-n opened this issue Oct 7, 2021 · 2 comments
Closed

dart:ffi only supports calling static Dart functions from native code #47405

azan-n opened this issue Oct 7, 2021 · 2 comments
Labels
area-vm Use area-vm for VM related issues, including code coverage, and the AOT and JIT backends. library-ffi

Comments

@azan-n
Copy link

azan-n commented Oct 7, 2021

dart --version
Dart SDK version: 2.15.0-116.0.dev (dev) (Thu Sep 16 09:47:01 2021 -0700) on "linux_x64"

I've been looking up examples for callbacks and I have tried to get callbacks working for me in FFI.

My current situation

I have a function in my library which expects a pointer to a function. The bindings for the same generated by ffigen seem correct to me.

int SetCallback(
    CallbackType callback,
  ) {
    return _SetCallback(
      callback,
    );
  }

  late final _SetCallbackPtr =
      _lookup<NativeFunction<Int32 Function(CallbackType)>>(
          'SetCallback');
  late final _SetCallback =
      _SetCallbackPtr.asFunction<int Function(CallbackType)>();

where, typedef CallbackType = Pointer<NativeFunction<Void Function(Uint32)>>;.

What I want to do here is to setup this callback in Dart, pass it to the FFI, essentially using it as my callback as I would have in C. In my API which abstracts away from FFI code (which means I have a class MyLibrary full of static functions that the user will call directly, which in turn calls functions from an object _nativeLibrary of the class MyNativeLibrary I have created), I have:

  static int SetCallback({required CallbackFuncDart callback}) {
    Pointer<NativeFunction<CallbackFunc>> pointer = Pointer.fromFunction(callback);

    int status = _nativeLibrary.SetCallback(
      pointer,
    );
    if (STATUS_OK != status) {
      throw LibLexemeException(status);
    }
    return status;
  }

typedef CallbackFunc = Void Function(Uint32);
typedef CallbackFuncDart = void Function(int);

While the sqlite ffi example states here that

Features which dart:ffi does not support yet:

Callbacks from C back into Dart.

I believe the docs haven't been updated to reflect the changes at the samples here. The samples haven't been very clear due to them not having any C/C++ files, or an idea of how the C functions work. I do believe that the ffi documentation is a bit lacking and I'd like to contribute if it is of any use. Even so, I think this example contains a segment(last code block) where a Dart function is being passed as a callback which I have replicated in my program. It is not clear to me how this will work but upon trying to compile my program I get:

ERROR: ../lib/library_lexeme.dart:180:74: Error: fromFunction expects a static function as parameter. dart:ffi only supports calling static Dart functions from native code. Closures and tear-offs are not supported because they can capture context.
ERROR:     Pointer<NativeFunction<CallbackFunc>> pointer = Pointer.fromFunction(callback);
@lrhn lrhn added area-vm Use area-vm for VM related issues, including code coverage, and the AOT and JIT backends. library-ffi labels Oct 7, 2021
@mattetti
Copy link

Based on #35903 I think that this limitation was added on purpose. As the error explains: dart:ffi only supports calling static Dart functions from native code. Closures and tear-offs are not supported because they can capture context. The only way I understand you can use callbacks is to define them outside of your method/class. Which is exactly what is done in the example you pointed to: https://github.com/dart-lang/sdk/blob/master/samples/ffi/sample_ffi_functions_callbacks.dart#L28

int myPlus(int a, int b) {}

Is a static function, the author then gets a native function pointer to it and pass it as a callback:

Pointer<NativeFunction<NativeIntptrBinOp>> pointer =
        Pointer.fromFunction(myPlus, 0);
// [...]
int result = applyTo42And74(pointer);

Where applyTo42And74() is the C function taking the callback.

@dcharkes
Copy link
Contributor

NativeCallables can now take closures.

https://api.dart.dev/dev/3.3.0-214.0.dev/dart-ffi/NativeCallable-class.html

We're not intending to add this support to Pointer.fromFunction.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-vm Use area-vm for VM related issues, including code coverage, and the AOT and JIT backends. library-ffi
Projects
None yet
Development

No branches or pull requests

4 participants