Closed mraleph closed 3 years ago
A general FFI could also be useful for interaction with JavaScript, so we should consider whether it's possible to make something general wihout compromising on the usability on each platform.
The current JS-interop functionality is not a clean design, it should be possible to improve it.
@lrhn:
The current JS-interop functionality is not a clean design, it should be possible to improve it.
I would not assume that without talking to @vsmenon. The syntax might leave a little to be desired, but I have no desire to make a breaking change to the syntax unless it vastly improves end users, not just the fact it isn't a "clean design".
Providing a new syntax / library doesn't necessarily imply removing the existing support. With that in mind, I think @lrhn 's suggestion is good.
@lrhn @vsmenon I think C/C++-oriented interop makes sense on the Web in the context of WebAssembly. I wouldn't sacrifice native FFI capabilities due to JS. It's fine to have two systems that work best for their respective constraints.
Is this referring to Dart calling C/C++ interfaces or vice versa?
@krisgiesing Initially it will be Dart calling C, later we would like to extend this to C calling Dart.
Though it is very hard to draw a line because we plan to support callbacks as part of the initial offering - so C would be able to call back into Dart.
Here is the markdown version of the vision doc (implementation is currently being prototyped).
Let me know if you have any comments on that one.
This potentially requires using conditional imports.
Conditional compilation is a pain for IDEs. It's worth looking into how Kotlin handles a similar problem with expect/actual declarations on a language level. In a nutshell, expect/actual
means that you write a single header/interface file, and a corresponding implementation for each platform. Because the interface is shared between all platforms, IDE does not need to know the "current" platform to do IDE stuff.
@matklad the expect/actual stuff is pretty close to interface libraries that were discussed in context of the conditional imports long time ago - exactly to solve IDE problem. However I don't think this went anywhere - and I think conditional imports are pretty much dead.
I think in the context of FFI we will be implementing what Structure Layouts and Portability describes.
I will amend the section that still talks about conditional imports.
Any updates for dart lang FFi ? very happy if there have usable FFI . We can import c/cpp language lib with it.
@netroby I'm working on it. We plan to add an initial version during Q1. So far the prototype closely follows the vision doc. Let me know whether that covers your use case.
Seems great, calling C is a must have. Is there a way to get access to the proto? Thanks.
@fimbault we plan to release prototype for public consumption later this quarter in few stages: first we will land support for FFI in JIT mode on X64 only, then it will be expanded to cover X64, ARM, ARM64 in JIT and AOT.
@matklad the expect/actual stuff is pretty close to interface libraries that were discussed in context of the conditional imports long time ago - exactly to solve IDE problem. However I don't think this went anywhere - and I think conditional imports are pretty much dead.
I think in the context of FFI we will be implementing what Structure Layouts and Portability describes.
I will amend the section that still talks about conditional imports.
are you talking about this: https://github.com/dart-lang/sdk/issues/24581 ?
I use it and it is great.
Are there plans to support calling into shared libraries similar to python's ctypes?
@robertmuth yes, please see the doc referenced from https://github.com/dart-lang/sdk/issues/34452#issuecomment-449941065 for more details.
It will be great to have FFI in Dart. From my perspective, FFI includes the following major features:
There is proposal for all of them here. Some thoughts:
For 1. It's proposed to load library by name manually:
final lib = DynamicLibrary.open('libfoo.so');
It is good approach. However there are some alternative ways:
a. Load library manually but return class were all native (or abstract) functions resolved to dynamic library functions:
class Foo extends DynamicLibrary {
int add(int a, int b) native;
}
final Foo lib = DynamicLibrary.open<Foo>(Platform.isLinux ? 'libfoo.so' : 'foo.dll');
lib.add(1,2); //3
Dart VM lookup all native function in class automatically. JNA
b. The same as a. but use class name as dynamic library name:
//mapped to libfoo.so on Linux, to libfoo.dylib on macOS and foo.dll on Windows
class Foo extends DynamicLibrary {
int add(int a, int b) native;
}
final Foo lib = new Foo();
This automatic mapping is implemented in native extensions: Dart's library name mapped to dynamic library name. Nothing new.
c. The same as a. but use annotation on class:
@ffi.Library('foo')
class MyFoo {
int add(int a, int b) native;
}
final Foo lib = new Foo();
If library has different names (for instance OpenGL) than annotation can accept list of names.
@ffi.Library('Opengl32.dll', 'libGL.so.1')
class OpenGL {
}
d. Don't use class and define library name for each function:
@ffi.Library('foo')
int add(int a, int b) native;
C# DllImport. Dart automatically load dynamic library by name and lookup function (symbol). Disadvantages: developer doesn't control when dynamic library is loaded/unloaded. At least special API is needed.
e. Use Dart library name as in native extensions Disadvantages: developer doesn't control when dynamic library is loaded/unloaded, there is no way to define different names.
For 2. It is OK to be able to lookup function manually. However, imagine a library with hundreds functions. Have hundreds lines of code like:
final add = lib.lookupFunction<ffi.Int32 Function(ffi.Int32, ffi.Int32), int Function(int, int)>('add');
isn't great.
There are some other options to lookup function automatically:
a. Lookup by function name:
int add(int a, int b) native; //lookup 'add' function in dynamic library
b. Define name after native keyword as in native extensions:
int myadd(int a, int b) native 'add'; //lookup 'add' function in dynamic library
c. Lookup by name in annotation:
@ffi.Function('add')
int myadd(int a, int b) native; // lookup 'add' function in dynamic library
It works in for cases 1.a-1.c and for 1.d. Anyway, I believe, it should be a way to load functions automatically based on function signature, which is already defined in my Dart code.
For 3. and 4. It would be great to have something like this:
int add(@ffi.Type('Int') int a, @ffi.Type('Int') int b)
where annotation @ffi.Type define C type of parameter.
Top C data types should be supported: integer types (char, short, int, long, long long including unsigned), float types, pointers etc. Dart VM should resolve their sizes in bits automatically based on run-time platform. It isn't enough to support platform-independent types like int32_t or unit64_t. It would be inconvenient to define sizes for each platform manually.
Some real world examples:
void srand(@ffi.Type('Uint') int seed); //libc on Linux
@ffi.Type('Ulong') int GetLastError(); //kernel32 on Windows
int SDL_Init(@ffi.Type('Int32') int flags); //SDL cross-platform
void SDL_ShowWindow(@ffi.Type('IntPtr') int window); //SDL cross-platform
For instance, SDL uses both platform-independent (int32_t) and platform-dependent (int, int *) types in API.
For structs it would be great to have automatic struct packing based on field order, its C type and run-time platform. Instead of:
@ffi.struct({
'x64 && linux': { // Layout on 64-bit Linux
'x': ffi.Field(ffi.Double, 0),
'y': ffi.Field(ffi.Double, 8),
'next': ffi.Field(ffi.Double, 16)
},
'arm && ios': { // Layout on 32-bit iOS
'x': ffi.Field(ffi.Float, 4),
'y': ffi.Field(ffi.Float, 8),
'next': ffi.Field(ffi.Pointer, 0)
},
})
class Point extends ffi.Pointer<Point> {
double x;
double y;
Point next;
}
it would be great to write something like:
class Point {
@ffi.Type('Double')
double x;
@ffi.Type('Double')
double y;
@ffi.Type('Pointer')
Point next;
}
It is enough information for Dart VM to pack structure on each supported platform. However, ability to define field offset and struct size manually is welcome:
@ffi.StructSize(24)
class Point {
@ffi.Offset(0)
@ffi.Type('Double')
double x;
@ffi.Offset(8)
@ffi.Type('Double')
double y;
@ffi.Offset(16)
@ffi.Type('Pointer')
Point next;
}
The dart:ffi
prototype has progressed to the point where we are deciding on API decisions. (Some design decisions are discussed here.)
To make informed design decisions, we would like more examples on what C APIs you would like to bind. The Flutter C++ interop issue mentions SQLite, Realm, OpenCV, Superpowered, and ffmpeg. Any other APIs we should consider?
@dcharkes two APIS i've been thinking about are libvlc
and telegrams tdlib https://github.com/tdlib/td and possibly SDL2
I believe databases support is often arises as a problem. ODBC, Oracle OCI and so on would be helpful
I personally made some half baked wrapper for http://www.libxl.com/ . It would be much prettier with the new FFI, I think
Having a convenient way to interact with Kotlin/Native would be extremly usefull (even if it would of course "somehow" work with a simple C FFI).
I'm looking forward to the possibility of accelerated cryptographic ops using libsodium or openssl
It isn't popular case (server-side) but still: SDL2, OpenGL, Vulkan, OpenAL. I wish I can remove all native extensions code and achieve better performance with FFI. Also kernel32.dll and user32.dll on Windows and libc.so on Linux.
I am interested in using GTK+ with Dart.
Is there a plan for distributing packages that use the new FFI, i.e. on Pub? On Tue, Mar 5, 2019 at 8:20 AM Herman Bergwerf notifications@github.com wrote:
I am interested in using GTK+ with Dart.
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/dart-lang/sdk/issues/34452#issuecomment-469676879, or mute the thread https://github.com/notifications/unsubscribe-auth/AJiKPIItmOmpY0HU8T4sdiAYiiWR1MgXks5vTm86gaJpZM4Wl8MH .
Is there a plan for distributing packages that use the new FFI, i.e. on Pub?
@thosakwe I've discussed this @jonasfj, but at this point we don't know how yet we want to approach this. Should we distribute source or binaries? (Or provide the option to do either?) It probably depends on the use case. And if the package is used within Flutter, can we reuse something that Flutter does? We're aware of these questions, but do not have an answer yet.
@thosakwe i believe providing both options would be a huge plus.
I think that distributing binaries would be easier in that Pub itself wouldn’t really need to change at all.
I personally prefer getting a source package, and then the package manager compiling it, but the infrastructure for that doesn’t exist in Dart, and I guess it’s unrealistic to expect things to change so drastically for just one feature. There’s also no post-install hook functionality in Pub, so ultimately I think distributing binaries would be the best way.
If there’s any disadvantage to that, it’s that you’d have to build your project separately on each different platform. But also, if you are providing support for Linux, etc., you’ve probably already built it on that platform, so it’s not that much of a problem. On Tue, Mar 5, 2019 at 9:04 AM Glenford Williams notifications@github.com wrote:
@thosakwe https://github.com/thosakwe i believe providing both options would be a huge plus.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/dart-lang/sdk/issues/34452#issuecomment-469691161, or mute the thread https://github.com/notifications/unsubscribe-auth/AJiKPPWk_ptAL32032NeYHDzluAQeABFks5vTnlzgaJpZM4Wl8MH .
Google LevelDB bindings would be an interesting exercise for the FFI.
On Tue, 5 Mar 2019 at 15:14, Tobe Osakwe notifications@github.com wrote:
I think that distributing binaries would be easier in that Pub itself wouldn’t really need to change at all.
I personally prefer getting a source package, and then the package manager compiling it, but the infrastructure for that doesn’t exist in Dart, and I guess it’s unrealistic to expect things to change so drastically for just one feature. There’s also no post-install hook functionality in Pub, so ultimately I think distributing binaries would be the best way.
If there’s any disadvantage to that, it’s that you’d have to build your project separately on each different platform. But also, if you are providing support for Linux, etc., you’ve probably already built it on that platform, so it’s not that much of a problem. On Tue, Mar 5, 2019 at 9:04 AM Glenford Williams <notifications@github.com
wrote:
@thosakwe https://github.com/thosakwe i believe providing both options would be a huge plus.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/dart-lang/sdk/issues/34452#issuecomment-469691161, or mute the thread < https://github.com/notifications/unsubscribe-auth/AJiKPPWk_ptAL32032NeYHDzluAQeABFks5vTnlzgaJpZM4Wl8MH
.
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/dart-lang/sdk/issues/34452#issuecomment-469694585, or mute the thread https://github.com/notifications/unsubscribe-auth/AAMrs3lZBtub-BRHFWYFuAgbu2sOok25ks5vTnu4gaJpZM4Wl8MH .
@dcharkes For me this would be to use libgit2 with Flutter.
I'm interested in embedding my own business-logic as a library in Flutter.
crypto lib write by C or Rust
It would be nice to have a rust-bindgen alternative for the Dart
Using Dart / Flutter with Qt might be interesting for desktop apps.
Using Dart / Flutter with Qt might be interesting for desktop apps.
Why?
Skia works in all the major platforms. Sublime Text uses Skia and is pretty fast and lightweight as well :)
Using Dart / Flutter with Qt might be interesting for desktop apps.
Why? Skia works in all the major platforms. Sublime Text uses Skia and is pretty fast and lightweight as well :)
Skia is brilliant and it can be used in Qt apps as well (either by painting an SkSurface to a QWidget with QPainter, or by painting directly to a QWindow's context) with Qt providing things like cross-platform windowing and docking, c++ plugin support, installers/bundle builders, networking APIs, parsers and more.
@vejmartin This would increase the size of the executable by a big margin in case you use native features, I think
Another great thing would be using the FFI to access serial ports.
We are now at a point where we would like to offer an early preview to get some feedback. We’re looking for feedback on how ergonomic the feature is to use, what the main gaps are, and lastly on general stability and performance.
We are looking for testers who are willing to:
There is a small SQLite sample demonstrating the FFI feature in the SDK: Readme, FFI wrapper, sample program.
If you are interested, please consider one or more potential libraries you are interested in, and send an email with a description of those to dart-ffi-team@googlegroups.com
(we’ll try to make sure we don’t several wrapping the same lib).
Also, you should be aware of the following current main limitations:
On behalf of the Dart FFI team, Michael
I'm so sorry, but we had an issue with the google group mentioned above, so if you already sent an email to dart-ffi-team@googlegroups.com
, can you please send it again?
Thanks much!
@mit-mit tried loading a basic shared library built from go on Linux but i am unable to get it to work
shared library build command
go build -o dart/bin/test.so -buildmode=c-shared lib.go
and tried opening using
ffi.DynamicLibrary l = dlopenPlatformSpecific("test", path:"/home/kingwill101/go/src/gitlab.com/kingwill101/test/dart/bin/");
dlopenPlatformSpecific
comes from the examples provided
ArgumentError (Invalid argument(s): Failed to load dynamic library(lib/home/kingwill101/go/src/gitlab.com/kingwill101/test/dart/bin/libtest.so: cannot open shared object file: No such file or directory))
loading a system library works but trying to load using a relative path to the library fails.
@glenfordwilliams I suggest extending dlopenPlatformSpecific
to create a full path based on where your .dart
file is. You can construct the full path in Dart.
Explanation: the paths are directly interpreted by dlopen
. This means the relative paths are relative to the dart binary. (This test uses a relative path, and the .so
file lives right next to the dart binary.) In general, one would want a path to the .so
file relative to the .dart
file using that .so
file, which would be constructed in Dart.
@dcharkes i tried doing that earlier but for some reason dart adds lib
in front of the created path
Exception has occurred.
ArgumentError (Invalid argument(s): Failed to load dynamic library(lib/home/kingwill101/go/src/gitlab.com/kingwill101/test/dart/bin/test.so: cannot open shared object file: No such file or directory))
@glenfordwilliams Yes, you're gonna have to modify or make your own version of dlopenPlatformSpecific
. The example implementation simply prepends "lib"
on Linux on line 10.
It's Linux convention to prepend lib
to the names of shared libraries. However, go build
won't do that automatically. If you're not planning to run your code on other platforms, you can just use DynamicLibrary.open
directly.
sorry about that, vscode seems to be caching old code
import 'dart:ffi' as ffi;
import 'dart:io';
import "package:path/path.dart" show dirname;
import 'dart:io' show Platform;
typedef GoFunction = ffi.Void Function();
typedef GoFunctionOp = void Function();
ffi.DynamicLibrary dlopenPlatformSpecific(String name, {String path}) {
String fullPath = dirname(Platform.script.path) + "/" + name;
return ffi.DynamicLibrary.open(fullPath);
}
main(List<String> arguments) {
Directory current = Directory.current;
print(current.path);
ffi.DynamicLibrary l;
try {
l = dlopenPlatformSpecific("libtest.so");
} catch (e) {
print(e.toString());
}
var go = l.lookupFunction<GoFunction, GoFunctionOp>("AGoFunction");
go();
}
strange thing is i get everything to work when i run from the command line
kingwill101@kingtech:~/go/src/gitlab.com/kingwill101/test/dart$ ~/flutter/bin/cache/dart-sdk/bin/dart bin/main.dart
/home/kingwill101/go/src/gitlab.com/kingwill101/test/dart
AGOFUNCTION()
kingwill101@kingtech:~/go/src/gitlab.com/kingwill101/test/dart$
but when i run from vscode i get
bin/main.dart:25:14: Error: Expected type 'NativeFunction<Void Function()>' to be a valid and instantiated subtype of 'NativeType'.
- 'NativeFunction' is from 'dart:ffi'.
- 'Void' is from 'dart:ffi'.
var go = l.lookupFunction<GoFunction, GoFunctionOp>("AGoFunction");
^
The present feature tracks the implementation of Dart FFI support enabling interop with C & C++ code from Dart.
Status
The feature will be in stable as of Dart 2.12. More details here: https://dart.dev/guides/libraries/c-interop
For any discussion of this feature, or feedback or questions regarding the feature, kindly join and post the dart-ffi group: https://groups.google.com/forum/#!forum/dart-ffi
We will still actively adding new features to
dart:ffi
. Please refer to https://github.com/dart-lang/sdk/labels/library-ffi for open issues and feature requests.Background
Some inspirational references: