0

I have some dynamic libraries making available over 200 functions via C calling conventions. I have no access to the source. I'd like to provide these as functions callable by Swift.

Currently I am making each function from the dylibs available via code like this:

public func mainInit() -> Int64 {

    let dllMainInitPointer = getFunctionPointer(libHandle, "DllMainInit")

    typealias DllMainInitFunction = PtrDllMainInit
    let dllMainInit = unsafeBitCast(dllMainInitPointer, to: DllMainInitFunction.self)

    return dllMainInit()

}

where PtrDllMainInit is obtained by Swift interpreting the C function prototypes in the header file, in this case:

typedef int64_t (*PtrDllMainInit)(void);
 . . .
extern PtrDllMainInit DllMainInit;

which works. But (a) it returns the result of the function, and I'd rather it return the function itself, so it can be called independently, and (b) every use repeats executing the boilerplate code.

It seems that this boilerplate, in every function, could possibly be factored out. (I already factored, behind getFunctionPointer, calling dlsym and checking for missing symbols). Most of the dylib functions are generally more complex than this example, having multiple parameters; writing 200+ functions, like above, is time consuming and prone to error.

Ideally, I'd like a way auto-generate assignments that provide the Swift functions, using the dylib handle, the symbol name, and the C prototype; something like the following:

dllMainInit = magicFunction(libHandle, "DllMainInit", PtrDllMainInit)

In addition to factoring out repetition, one-liners (or, maybe two-liners) like this can be generated simply by processing the header file into this form.

Ultimately, allowing something of this form in the C headers:

typedef int (*PtrProp2)(int64_t key, double time, double llh[3]);

to be converted to a Swift function (closure?), and invoked, thusly:

let prop2 = magicFunction(libHandle, "DllProp2", PtrProp2)
 . . .
prop2(id, hours, &vector)

This is a bit tangled, I hope I've explained it well enough.


Edit: Well, this works for simple function I started with:

public func mainInit() -> () -> Int64 {

    unsafeBitCast(getFunctionPointer(libHandle, 
                                     "DllMainInit"), 
                  to: PtrDllMainInit.self)

}

The parameters of the returned closure can be derived from the .h file. I'll see if this mechanism hold up for more complications.

RamsayCons
  • 71
  • 3
  • Unless I'm missing something if you include the C headers .h in the bridging header of Swift and link the dynamic library with your app, you should be good to go. – Kamil.S Dec 10 '22 at 10:28

0 Answers0