Automatic function wrapping for C Module


(Geordie J) #1

Hi,

First of all thanks to Joe Groff for his insight, pull request, and guidance re the @_cdecl attribute, which is important for what follows below.

I’ve been working on a JNI (Java Native Interface) integration for the Android port of Swift (github.com/SwiftAndroid) with good results so far. Java->Swift->Java returns and method calls / passing data in either direction all seem fine, but require a lot of code mangling and weird constructs like 'env.memory.memory' that are very un-Swift-like. So I’m wondering how one might go about wrapping the JNI API in some kind of automated way.

To provide some context, the Java VM calls a native (Swift) function, passing a number of parameters, almost all of which are pointers or pointers to pointers (hence memory.memory). All of the functions again take the pointer to itself as the first parameter like this:

env.memory.memory.GetJavaVM(env, &_emptyJavaVMPointerToPointer)

Note the ‘env’ first parameter. Also these are almost all pointer operations, which are inherently unsafe and become tiresome in Swift pretty quickly for good reasons.

Questions:

Is there a way of wrapping env (which is of type UnsafeMutablePointer<UnsafePointer<JNINativeInterface>>) to have some sane calling standards like

let vm = swiftEnv.getJavaVM()

without manually writting a SwiftJNIEnv Class and wrapping each function individually? I understand the OSX / iOS SDKs were automatically wrapped in a way comparable to this.

If the best solution currently involves automation via .gyb files, is this option available to the Swift Package Manager, or would it make more sense to build a JNI module along with the stdlib for Android (in the same way Glibc is built and bundled with the stdlib on Linux)?

As an aside: I understand the JNI works this way because C natively has no concept of objects. When working with C++, Java is able to directly pass objects to the native code that have much saner method signatures. Is there any scope to accept an object in this way via a @convenction( c ) function or are we stuck with this pointer pattern until C++ compatibility arrives (which is presumably still a year or two away at least)?

Thanks
-Geordie