Creating a sbt plugin for using jextract to create scala/dotty bindings to C
Mark Hammons
mark.hammons at inaf.cnrs-gif.fr
Wed Nov 6 21:24:47 UTC 2019
Hi all,
As per my last discussion on this mailing list, I'm using jextract and
creating outputted .java files that I'm now parsing using javaparser
into an AST of my own making. I'll then use this AST to generate a dotty
interface (and maybe a scala interface). I'm doing this for a number of
reasons, one of which being that I can make structs available to dotty's
typeclass derivation, and more. However, going through the generated
java, I have a few questions.
First off, I notice that jextract tends to generate what appears to be
dummy structs in header bindings that use but don't define said struct.
For example
@NativeStruct("[u64(impl):${wlr_backend_impl}${anon$backend_h$449}(events)](wlr_backend)")
public static interface wlr_backend extends Struct<wlr_backend> {
}
this dummy interface is defined in wlr_output_h.java, but the real
wlr_backend struct that is used by functions is defined in
wlr_backend_h.java.
Also, jextract creates dummy callback interfaces such as:
@Target(ElementType.TYPE_USE)
@Retention(RetentionPolicy.RUNTIME)
public static @interface wlr_renderer_create_func_t {
}
this callback is actually defined as FI1 later in the file, and used as
such in pretty much all cases. Do I need to bother having my generate
define such interfaces or can I ignore these?
Second, I was wondering about native callbacks and scopes. As I
mentioned above, callback types like wlr_renderer_create_func_t are
renamed to stuff like FI1 by jextract, which is not particularly helpful
when figuring out what is needed by that function. However, even if the
original name wlr_renderer_create_func_t was used instead, that doesn't
help the user a lot. I'm thinking of autogenerating inline methods from
dotty that will make things a bit easier on users. IE:
public static interface FI1 {
public
java.foreign.memory.Pointer<wlroots.wlr_renderer_h.wlr_renderer>
fn(java.foreign.memory.Pointer<wlroots.egl_h.wlr_egl> $arg0, int $arg1,
java.foreign.memory.Pointer<?> $arg2,
java.foreign.memory.Pointer<java.lang.Integer> $arg3, int $arg4);
}
public void iTakeFI1(Callback<FI1> arg0);
turns into:
sealed trait FI1 {
def fn(arg0: Pointer[wlr_egl], arg1: Int, arg2: Pointer[_],
arg3: Pointer[Int], arg4: Int): Pointer[wlr_renderer]
}
def iTakeFI1(arg0: Callback[FI1]): Unit
inline def iTakeFI1(arg0: (Pointer[wlr_egl], Int, Pointer[_],
Pointer[Int], Int) => wlr_renderer) = {
iTakeFI1(scope.allocateCallback(arg0: FI1))
}
or something like that. Do I need to worry about leaking callbacks? I'm
looking at other options too, like renaming FI1 to a representation of
the arguments and returns so that it's easier for users to tell at a
glance what a function wants.
Finally, I guess my final question is if the code that jextract is
outputting is wildly different than the one of the last EA release.
Thanks a lot, once I have my sbt plugin in working order I'll post it here.
~Mark
More information about the panama-dev
mailing list