You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Add option to expose function pointers & typedefs #521
For some users it might be useful to expose the function pointers instead of Dart wrapper functions. In the use case where they want to pass these function pointers to C.
We should probably have a similar exclude/include mechanism specifying which functions should be exposed as function pointers.
Does this issue cover the option of choosing whether generated structs should be private or not?
I'm trying to wrap ALSA on linux and get a bunch of [WARNING]: Generated declaration '_snd_pcm' start's with '_' and therefore will be private.
and similar.
I would like to access the struct types (snd_pcm) from the outside.
I'm not sure if my usecase is covered by this issue so feel free to tell me to file a new issue 🙂
So what I'm trying to do is use libfuse which basically boils down to passing in to its fuse_main() a huge struct full of function pointers that are callbacks for various filesystem operations (getattr, read, write, mkdir, etc) that I as the user of libfuse implement.
So what I was hoping ffigen could do foor me is generate all the Dart function typedefs that I need for the callback struct so I could then implement functions of those typedefs in my hand written code, use something like ffi.Pointer.fromFunction(myGetAttrCallback, X) to get a pointer to each once, stuff it in the struct and pass that struct in when calling fuse's fuse_main()
But thats not quite what I end up with in my generated code as ffigen seems to generate mechanically named typedefs for the functions in the struct, eg. for mkdir:
and it also includes all the wrapper functions to call into C code which I don't actually need because there are no C implementations as they are callbacks that I want to implement in Dart.
While as pointed out in previous comments, the actual typedefs I'd like to implement are actually private, eg
typedef _dart_fuse_fs_mkdir =intFunction(
ffi.Pointer<fuse_fs> fs,
ffi.Pointer<ffi.Int8> path,
int mode,
);
I hope that makes sense?
So I'm not sure if I'm "holding it wrong" here or if my usecase is not really a scenerio that ffigen is meant to work with at the moment?
Hi @maks, we could consider generating the dart types, but in my opinion, those typedefs will not be of a lot of help, once you know the dart type (which you can deduce see via the C type) you need to define a top-level function. E.g -
@mannprerak2 thanks that is a very good point! With a primarily callback based library like libfuse, I'm not really going to get much of the benefits of using ffigen, though using the generated code, even as it is now will be a better starting point than writing it all from scratch so thanks for your work on ffigen and your help on this and the other issue I opened 👍
We can add a new config for this with an include/exclude mechanism and if the function name matches, we expose the function pointer, C, and Dart typedefs.
Should we also expose this =>_lookup<ffi.NativeFunction<_c_divide>>('divide');.
or is this => _lookup<ffi.NativeFunction<_c_divide>>('divide') .asFunction<_dart_dividePercision>() enough?
Then we can add a C Function pointer
Dart Function Pointer => Before => _divide, After =====> _divide_dart_ptr or divide_dart_ptr
C Function Pointer => Before => None, After =====> _divide_c_ptr or divide_c_ptr
Dart Function Pointer => Before => _divide, After =====> _divide_ptr or divide_ptr
We don't have to expose the Dart function pointer, because we can just use a tear-off from the public function (Bindings.divide).
Dart typedef ====> Before => _dart_divide, After => _divide_dart or divide_dart.
This is also not needed for using the C function pointers.
As for config, do we want or need to distinguish function pointers vs non-function pointers? If we only support function pointers, we might nest it under function: in the config.
Maybe instead of expose, pointer or symbol-location or symbol-address?
As for config, do we want or need to distinguish function pointers vs non-function pointers? If we only support function pointers, we might nest it under function: in the config.
Great, yeah we can nest the config key. This key can then be used for function and global declarations to expose the underlying C pointer (and typedefs).
Maybe instead of expose, pointer or symbol-location or symbol-address
The config basically is exposing some things which were private, so how about expose-pointer?
Does this seem okay -
intsum(inta, intb);
classNativeLibrary {
...
intsum(int a, int b) {
return_sum(a, b);
}
latefinal sum_ptr = _lookup<ffi.NativeFunction<sum_c>>('sum');
latefinal sum_dart _sum = sum_ptr.asFunction<sum_dart>(); // This will always be private.
}
typedef sum_c = ffi.Int32Function(ffi.Int32 a, ffi.Int32 b);
typedef sum_dart =intFunction(int a, int b);
Using late final will make the type non-nullable and will let the user know that this is final.
classNativeLibrary {
...
intsum(int a, int b) {
return_sum(a, b);
}
latefinal sum_ptr = _lookup<ffi.NativeFunction<Native_sum>>('sum');
latefinal sum_dart _sum = sum_ptr.asFunction<_sum_dart>(); // This will always be private.
}
typedefNative_sum= ffi.Int32Function(ffi.Int32 a, ffi.Int32 b);
typedef _sum_dart =intFunction(int a, int b); // This will always be private.
Or to prevent concatenating c symbols with _ptr
classNativeLibrary {
...
intsum(int a, int b) {
return_sum(a, b);
}
latefinal _sum_ptr = _lookup<ffi.NativeFunction<Native_sum>>('sum');
latefinal sum_dart _sum = sum_ptr.asFunction<_sum_dart>(); // This will always be private.latefinalNativeLibraryAddresses addresses =NativeLibraryAddresses(this);
}
classNativeLibraryAddresses {
finalNativeLibrary _library;
get sum => _library._sum_ptr;
}
The config basically is exposing some things which were private, so how about expose-pointer?
That is thought from an implementation point of view. It should have a name from a users point of view. The dlsym documentation:
The function dlsym() takes a "handle" of a dynamic library returned by dlopen() and the null-terminated symbol name, returning the address where that symbol is loaded into memory.
Activity
[-]Add option to expose function pointers [/-][+]Add option to expose function pointers & typedefs[/+]dcharkes commentedon Jul 23, 2020
Also not having the typedefs private would be useful in that situation.
mortenboye commentedon Oct 30, 2020
Does this issue cover the option of choosing whether generated structs should be private or not?
I'm trying to wrap ALSA on linux and get a bunch of
[WARNING]: Generated declaration '_snd_pcm' start's with '_' and therefore will be private.and similar.
I would like to access the struct types (snd_pcm) from the outside.
mannprerak2 commentedon Oct 30, 2020
Hi @mortenboye
For your purposes, you can rename declarations, using which you should be able to remove the underscore prefix.
Here's an FAQ regarding that -
https://github.com/dart-lang/ffigen#can-ffigen-be-used-for-removing-underscores-or-renaming-declarations
It's fairly simple regexp based renaming, but let me know if you need more assistance on that.
mortenboye commentedon Oct 30, 2020
@mannprerak2 Thanks! That was very helpful, and solved my issue.
maks commentedon Jan 19, 2021
I'm not sure if my usecase is covered by this issue so feel free to tell me to file a new issue 🙂
So what I'm trying to do is use libfuse which basically boils down to passing in to its
fuse_main()a huge struct full of function pointers that are callbacks for various filesystem operations (getattr, read, write, mkdir, etc) that I as the user of libfuse implement.So what I was hoping ffigen could do foor me is generate all the Dart function typedefs that I need for the callback struct so I could then implement functions of those typedefs in my hand written code, use something like
ffi.Pointer.fromFunction(myGetAttrCallback, X)to get a pointer to each once, stuff it in the struct and pass that struct in when calling fuse'sfuse_main()But thats not quite what I end up with in my generated code as ffigen seems to generate mechanically named typedefs for the functions in the struct, eg. for mkdir:
and it also includes all the wrapper functions to call into C code which I don't actually need because there are no C implementations as they are callbacks that I want to implement in Dart.
While as pointed out in previous comments, the actual typedefs I'd like to implement are actually private, eg
I hope that makes sense?
So I'm not sure if I'm "holding it wrong" here or if my usecase is not really a scenerio that ffigen is meant to work with at the moment?
mannprerak2 commentedon Jan 19, 2021
Hi @maks, we could consider generating the dart types, but in my opinion, those typedefs will not be of a lot of help, once you know the dart type (which you can deduce see via the C type) you need to define a top-level function. E.g -
For this typedef -
Even if the dart type is generated you would do this -
which is not a lot different than doing -
It is very simple to deduce the dart type from the C type which has been generated, you simply
int. Float\Double todouble, Void tovoid, etc.Pointer<Int8>will remain the same)And the static type system will always let you know of a type mismatch.
maks commentedon Jan 20, 2021
@mannprerak2 thanks that is a very good point! With a primarily callback based library like libfuse, I'm not really going to get much of the benefits of using ffigen, though using the generated code, even as it is now will be a better starting point than writing it all from scratch so thanks for your work on ffigen and your help on this and the other issue I opened 👍
dcharkes commentedon Mar 4, 2021
We need the function pointer for the resource-release functions used with native finalizers:
https://github.com/google/webcrypto.dart/blob/e5c87ad597e21226180f2f7d0391f3c1104af87d/lib/src/impl_ffi/impl_ffi.utils.dart#L32
Both the function pointer and the Dart function are exposed in the handwritten bindings:
https://github.com/google/webcrypto.dart/blob/e5c87ad597e21226180f2f7d0391f3c1104af87d/lib/src/boringssl/evp.dart#L38-L52
We cannot use a
fromFunctionbecause finalizers cannot execute Dart code.mannprerak2 commentedon Mar 4, 2021
We can add a new config for this with an include/exclude mechanism and if the function name matches, we expose the function pointer, C, and Dart typedefs.
Syntax -
divide. This will generate the followingdivide, After ======>divide._divide, After =====>_divide_ptrordivide_ptr_c_divide, After ===>_divide_cordivide_c._dart_divide, After =>_divide_dartordivide_dart.wdyt? @dcharkes
mannprerak2 commentedon Mar 4, 2021
Should we also expose this =>
_lookup<ffi.NativeFunction<_c_divide>>('divide');.or is this =>
_lookup<ffi.NativeFunction<_c_divide>>('divide') .asFunction<_dart_dividePercision>()enough?Then we can add a C Function pointer
_divide, After =====>_divide_dart_ptrordivide_dart_ptr_divide_c_ptrordivide_c_ptrdcharkes commentedon Mar 4, 2021
Yes, this is what we need.
How about an api such as this:
Pointer<NativeFunction<Native_divide>> divide_ptr = ...We don't have to expose the Dart function pointer, because we can just use a tear-off from the public function (
Bindings.divide).This is also not needed for using the C function pointers.
As for config, do we want or need to distinguish function pointers vs non-function pointers? If we only support function pointers, we might nest it under
function:in the config.Maybe instead of
expose,pointerorsymbol-locationorsymbol-address?mannprerak2 commentedon Mar 4, 2021
Great, yeah we can nest the config key. This key can then be used for
functionandglobaldeclarations to expose the underlying C pointer (and typedefs).The config basically is exposing some things which were private, so how about
expose-pointer?Does this seem okay -
Using
late finalwill make the type non-nullable and will let the user know that this is final.dcharkes commentedon Mar 4, 2021
Or to prevent concatenating c symbols with
_ptrThat is thought from an implementation point of view. It should have a name from a users point of view. The dlsym documentation:
So I'd prefer
symbol-address.mannprerak2 commentedon Mar 4, 2021
Cool.
Great suggestion! Also, we can keep this class private. (
_SymbolAddresses)