There’s two parts to this:
-
Calling a C dynamic library from Swift (A)
-
Doing that in SPM (B)
As I’ve mentioned on an earlier threads, I can’t help with B. However, that thread does have some suggestions from others about how to proceed.
With regards A, I tested this here in my office today using the following steps:
-
Using Xcode 11.1 GM seed on macOS 10.14.6, I created a new project macOS > App template.
-
Within that project I created a new target from the macOS > Library template, selecting None (Plain C/C++) in the Framework popup and Dynamic in the Type popup.
-
In the library target, I created a file from the macOS > C File template, making sure that “Also create a header file” was checked.
-
In the header I added this code:
struct WaffleVarnish { int glossiness; int durability; }; typedef struct WaffleVarnish WaffleVarnish; extern WaffleVarnish waffleVarnishDoubleDurability(WaffleVarnish existing);
.
-
In the C file I added this code:
extern WaffleVarnish waffleVarnishDoubleDurability(WaffleVarnish existing) { existing.durability *= 2; existing.glossiness /= 2; return existing; }
.
-
I built the library target, just to make sure it was working.
-
I switched to the app target and added a target dependency on the library target.
-
I then created a Copy Files build phase to copy the library to the Frameworks directory of the app.
-
Still in the app target, I use the macOS > Cocoa Class template to create an Objective-C class called
Hack
. This is an easy way to trigger the creation of a bridging header. -
I then deleted
Hack.h
andHack.m
because I don’t need them. -
In the bridging header I added this:
#include "QTestLib.h" typedef WaffleVarnish (*WaffleVarnishDoubleDurabilityFunctionPointer)(WaffleVarnish existing);
QTestLib.h
is the name of the C header from step 3. -
I then added the following code to the app:
let libURL = Bundle.main.bundleURL .appendingPathComponent("Contents") .appendingPathComponent("Frameworks") .appendingPathComponent("libQTestLib.dylib") guard let lib = dlopen(libURL.path, RTLD_LAZY) else { // … handle error … return } guard let sym = dlsym(lib, "waffleVarnishDoubleDurability") else { // … handle error … return } let waffleVarnishDoubleDurability = unsafeBitCast(sym, to: WaffleVarnishDoubleDurabilityFunctionPointer.self) let before = WaffleVarnish(glossiness: 32, durability: 10) let after = waffleVarnishDoubleDurability(before) print(after)
.
-
When I run this, it prints:
WaffleVarnish(glossiness: 16, durability: 20)
.
Share and Enjoy
Quinn “The Eskimo!” @ DTS @ Apple