0

I created a fresh project using flutter create --platforms=android,ios,macos,linux,windows --template=plugin_ffi demo_ffi

I depended on it in another flutter app and used the default shipped functions sum and sumAsync successfully without doing any change to the ffi plugin files.

  • Now I deleted the default functions and replaced them with this:

demo_ffi.cpp:

#include "demo_ffi.h"

void sayHi(){
    printf("Hi from C++");
}
  • I generated the bindings using ffigen, I inspected the generated file and they are generated correclty:
class DemoFfiBindings {
  /// Holds the symbol lookup function.
  final ffi.Pointer<T> Function<T extends ffi.NativeType>(String symbolName)
      _lookup;

  /// The symbols are looked up in [dynamicLibrary].
  DemoFfiBindings(ffi.DynamicLibrary dynamicLibrary)
      : _lookup = dynamicLibrary.lookup;

  /// The symbols are looked up with [lookup].
  DemoFfiBindings.fromLookup(
      ffi.Pointer<T> Function<T extends ffi.NativeType>(String symbolName)
          lookup)
      : _lookup = lookup;

  void sayHi() {
    return _sayHi();
  }

  late final _sayHiPtr =
      _lookup<ffi.NativeFunction<ffi.Void Function()>>('sayHi');
  late final _sayHi = _sayHiPtr.asFunction<void Function()>();
}

  • created a function to invoke the native code: void sayHi() => _bindings.sayHi();

  • Used this function in a flutter app, but I got:

Running "flutter pub get" in example...
Launching lib\main.dart on Windows in debug mode...
Building Windows application...
Debug service listening on ws://127.0.0.1:53129/fTa9IMYDG1M=/ws
Syncing files to device Windows...
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Invalid argument(s): Failed to lookup symbol 'sayHi': error code 127
#0      DynamicLibrary.lookup (dart:ffi-patch/ffi_dynamic_library_patch.dart:34:70)
#1      DemoFfiBindings._sayHiPtr (package:demo_ffi/demo_ffi_bindings_generated.dart:34:55)
#2      DemoFfiBindings._sayHiPtr (package:demo_ffi/demo_ffi_bindings_generated.dart)
#3      DemoFfiBindings._sayHi (package:demo_ffi/demo_ffi_bindings_generated.dart:35:23)
#4      DemoFfiBindings._sayHi (package:demo_ffi/demo_ffi_bindings_generated.dart)
#5      DemoFfiBindings.sayHi (package:demo_ffi/demo_ffi_bindings_generated.dart:30:12)
#6      sayHi (package:demo_ffi/demo_ffi.dart:25:27)
  • I used dumpbin -exports .\demo_ffi.dll on the generated library file in the Build/windows/runner/Debug folder, and it says that the function actually exists:
 dumpbin -exports .\demo_ffi.dll
Microsoft (R) COFF/PE Dumper Version 14.33.31630.0
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file .\demo_ffi.dll

File Type: DLL

  Section contains the following exports for demo_ffi.dll

    00000000 characteristics
    FFFFFFFF time date stamp
        0.00 version
           1 ordinal base
           1 number of functions
           1 number of names

    ordinal hint RVA      name

          1    0 000010A0 ?sayHi@@YAXXZ = @ILT+155(?sayHi@@YAXXZ)

  Summary

        1000 .00cfg
        1000 .data
        1000 .idata
        1000 .pdata
        3000 .rdata
        1000 .reloc
        1000 .rsrc
        8000 .text

So why is the function not found??

Update:

As per Richard's comment, I made EXTERN "C" unconditional for all systems (windows, linux, ...)

So now demo_ffi.h:

EXTERN "C" void sayHi(); // I also tried EXTERNC

I even made sayHi a no-op function:

demo_ffi.cpp:

#include "image_magick_ffi.h"

void sayHi(){}

So now when I build the app that uses this plugin, I get new errors and the app won't build:

[  +61 ms] D:\dev_haidar\flutter\ffi_app_demo\windows\flutter\ephemeral\.plugin_symlinks\image_magick_ffi\src\image_magick_ffi.h(1,8): error C2143: syntax error: missing ';' before 'string' [D:\dev_haidar\flutter\ffi_app_demo\build\windows\plugins\image_magick_ffi\shared\image_magick_ffi.vcxproj]
[   +1 ms] D:\dev_haidar\flutter\ffi_app_demo\windows\flutter\ephemeral\.plugin_symlinks\image_magick_ffi\src\image_magick_ffi.h(1,8): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int [D:\dev_haidar\flutter\ffi_app_demo\build\windows\plugins\image_magick_ffi\shared\image_magick_ffi.vcxproj]
[        ]   D:\dev_haidar\flutter\ffi_app_demo\windows\flutter\ephemeral\.plugin_symlinks\image_magick_ffi\src\image_magick_ffi.h(1,8): error C2143: syntax error: missing ';' before 'string' [D:\dev_haidar\flutter\ffi_app_demo\build\windows\plugins\image_magick_ffi\shared\image_magick_ffi.vcxproj]
[        ]   D:\dev_haidar\flutter\ffi_app_demo\windows\flutter\ephemeral\.plugin_symlinks\image_magick_ffi\src\image_magick_ffi.h(1,8): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int [D:\dev_haidar\flutter\ffi_app_demo\build\windows\plugins\image_magick_ffi\shared\image_magick_ffi.vcxproj]
[  +23 ms] Exception: Build process failed.
[   +3 ms] 
           #0      throwToolExit (package:flutter_tools/src/base/common.dart:10:3)
           #1      RunCommand.runCommand (package:flutter_tools/src/commands/run.dart:615:9)
           <asynchronous suspension>
           #2      FlutterCommand.run.<anonymous closure> (package:flutter_tools/src/runner/flutter_command.dart:1209:27)
           <asynchronous suspension>
           #3      AppContext.run.<anonymous closure> (package:flutter_tools/src/base/context.dart:150:19)
           <asynchronous suspension>
           #4      CommandRunner.runCommand (package:args/command_runner.dart:209:13)
           <asynchronous suspension>
           #5      FlutterCommandRunner.runCommand.<anonymous closure> (package:flutter_tools/src/runner/flutter_command_runner.dart:281:9)
           <asynchronous suspension>
           #6      AppContext.run.<anonymous closure> (package:flutter_tools/src/base/context.dart:150:19)
           <asynchronous suspension>
           #7      FlutterCommandRunner.runCommand (package:flutter_tools/src/runner/flutter_command_runner.dart:229:5)
           <asynchronous suspension>
           #8      run.<anonymous closure>.<anonymous closure> (package:flutter_tools/runner.dart:62:9)
           <asynchronous suspension>
           #9      AppContext.run.<anonymous closure> (package:flutter_tools/src/base/context.dart:150:19)
           <asynchronous suspension>
           #10     main (package:flutter_tools/executable.dart:91:3)
           <asynchronous suspension>

Note (I renamed the project in case you wonder from the latter error logs)

HII
  • 3,420
  • 1
  • 14
  • 35
  • "says that the function actually exists" - well, yes and no. Actually a function called `?sayHi@@YAXXZ` exists, which isn't actually the same as `sayHi`. Did you mark your C++ function as `extern C`? Compare to the `sum` function that you deleted. – Richard Heap Oct 09 '22 at 15:01
  • @RichardHeap I marked it with `FFI_PLUGIN_EXPORT ` which is defined for windows as `#define FFI_PLUGIN_EXPORT __declspec(dllexport)` as per default in the generated template, whereas `externC` is defined for linux and macos and other systems – HII Oct 09 '22 at 15:03
  • In the boilerplate, the `sum` function is in a `C` file, but looks like you've added a C++ source file. In C++ you will need to mark your functions as extern C. – Richard Heap Oct 09 '22 at 15:08
  • Check out https://stackoverflow.com/questions/61595179/can-i-call-a-c-constructor-function-in-dart-ffi/61597535#61597535 and https://stackoverflow.com/questions/71663278/flutter-c-bindings-with-dartffi – Richard Heap Oct 09 '22 at 15:12
  • @RichardHeap please see the update, I tried puttin extern C as you suggested but I got another errors – HII Oct 09 '22 at 15:52
  • You've broken your C/C++ code. See questions like this about conditional extern C: https://stackoverflow.com/questions/36785157/how-does-extern-c-allow-c-code-in-a-c-file – Richard Heap Oct 09 '22 at 16:03
  • It's not clear why you are introducing an apparently unnecessary C++ layer when talking to a C library. – Richard Heap Oct 09 '22 at 16:13
  • @RichardHeap this example is just me trying to prepare an app that will export `Magick++` library to dart, that's why I want to write c++ code in the c files. – HII Oct 09 '22 at 16:15
  • Yes, I guessed that. Skip Magick++ and go straight to Magick-Core – Richard Heap Oct 09 '22 at 16:31
  • @RichardHeap I already gave up on using c++ with dart ffi, using magick wand instead, thank you :) – HII Oct 09 '22 at 16:38

0 Answers0