Skip to content
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

Support variadic functions #497

Closed
dcharkes opened this issue Jan 4, 2023 · 8 comments · Fixed by dart-archive/ffigen#515
Closed

Support variadic functions #497

dcharkes opened this issue Jan 4, 2023 · 8 comments · Fixed by dart-archive/ffigen#515
Labels
package:ffigen type-enhancement A request for a change that isn't a bug waiting-on-dart-ffi Issues which are blocked by lacking suppport in dart:ffi

Comments

@dcharkes
Copy link
Collaborator

dcharkes commented Jan 4, 2023

We'll be adding support for variadic functions to dart:ffi:

One interesting thing to think about is how this would work for bindings generation from .h files: It wouldn't know what specific var-args signature to use when generating method(s) for a vararg method. Either it could generate a lookup of pointer and require users to fp.asFunction or one would need to specify in the configuration.

Originally posted by @mkustermann in dart-lang/sdk#38578 (comment)

Generating the function pointer would always require a cast, because a Pointer<NativeFunction<X Function(X, VarArgs(X, X))>> can't have the right signature. So it should probably be a Pointer<Void> if we go for that option. Which would result in:

somePointer.cast<NativeFunction<...>>.asFunction<...>();

However, that would not allow us to ever use variadic functions with static linking (@FfiNative) through ffigen.

Moreover, that requires the user to both write out the C type and Dart type of both the non-variadic arguments and variadic arguments.

So, I believe it would be better to specify the variadic arguments wanted in the config. That way the user only has to write out the C types, and only for the variadic arguments (not for the arguments before the ...).

Also, since Dart doesn't have overloading, we would need to invent names if we want a function more than once. Adding a number is a bad idea, because when adding a variadic args config it might renumber, maybe we can default to appending the variadic argument types? Or default to appending the variadic argument types if there's more than one config?

functions:
  variadic-arguments:
    'printf':
      - [uint32_t, double] # Single config generates `printf`.
functions:
  variadic-arguments:
    'printf':
      - [uint32_t, double] # Generates `printfUInt32Double`.
      - [uint32_t, char*]  # Generates `printfUInt32CharPointer`.
functions:
  variadic-arguments:
    'printf':
      - [uint32_t, double] # Generates `printfUInt32Double`.
      - types: [uint32_t, char*]
        postfix: 'IntString' # Generates `printfIntString`.

Related issue:

@mannprerak2 @mkustermann @Sunbreak WDYT? Any alternative ideas?

@dcharkes dcharkes added type-enhancement A request for a change that isn't a bug waiting-on-dart-ffi Issues which are blocked by lacking suppport in dart:ffi labels Jan 4, 2023
@mannprerak2
Copy link
Contributor

Some high level doubts-

  1. The examples use uint32_t but I suppose we can also use something platform dependant like int or long?
  2. Do we support structs and union? and what about imported types (type-map)
  3. What should be the default behaviour if nothing is specified in the config? Do we just print a warning?

@dcharkes
Copy link
Collaborator Author

dcharkes commented Jan 5, 2023

  1. The examples use uint32_t but I suppose we can also use something platform dependant like int or long?

Yes.

One question is whether it's easier to support the literal C strings representing the types or whether we should go for the Dart types representing the C types. E.g. int32_t vs Int32.

  1. Do we support structs and union?

Yes. Varargs can be structs/unions. They cannot be be int8/int16/float, that is undefined behavior in C.

and what about imported types (type-map)

Yeah, why not.

  1. What should be the default behaviour if nothing is specified in the config? Do we just print a warning?

Probably a warning and not emit it, it's unlikely that you want to call the variadic function without any variadic arguments. (But technically you can, e.g. printf("Some string with no format strings in there.\n").)

@mannprerak2
Copy link
Contributor

mannprerak2 commented Jan 8, 2023

whether we should go for the Dart types representing the C types

The dart type, since then we can do something like this

ffi.Int
ffi.Int32
StructA
UnionB
custom_lib.StructC

Which allows the user to specify any type. Although, we may need to remove validations on these types, since we don't know the types in custom_lib, or dart:ffi may add a new type which would require an update to ffigen, or a struct being generated is renamed by user or by us due to collision. (We can still check the library prefix - ffi is predefined and custom_lib must be part of the config's library import)

@mannprerak2
Copy link
Contributor

They cannot be be int8/int16/float, that is undefined behavior in C.

We'll also need to handle this, and all the dart:ffi types since they have different C and Dart types (int/Int32)

@dcharkes
Copy link
Collaborator Author

dcharkes commented Jan 9, 2023

whether we should go for the Dart types representing the C types

The dart type, since then we can do something like this

ffi.Int ffi.Int32 StructA UnionB custom_lib.StructC

Which allows the user to specify any type.

But, do we always know how to get back to the C type then? Because we will also need to generate the C type in the signature. (If it turns out to be hard to generate the C type from the Dart type, and the Dart type from the C type, then we could consider writing a C file with the C types and parsing it with libclang. But that would be hard with imported types again.)

@mannprerak2
Copy link
Contributor

But, do we always know how to get back to the C type then?

Wouldn't it be enough to handle all the basic C native types which are part of dart:ffi (Int, Int32, Int64, etc)

@dcharkes
Copy link
Collaborator Author

dcharkes commented Jan 9, 2023

But, do we always know how to get back to the C type then?

Wouldn't it be enough to handle all the basic C native types which are part of dart:ffi (Int, Int32, Int64, etc)

Users can use arbitrary types right? AbiSpecificIntegers, Structs, Unions, Pointers to everything.

@mannprerak2
Copy link
Contributor

Users can use arbitrary types right? AbiSpecificIntegers, Structs, Unions, Pointers to everything.

Yeah, maybe I'm forgetting something? 🤔 Isn't the C and Dart type same except for the native types.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
package:ffigen type-enhancement A request for a change that isn't a bug waiting-on-dart-ffi Issues which are blocked by lacking suppport in dart:ffi
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants