Question or problem in the Swift programming language:
Is there a way to call a C function loaded from a dylib from Swift?
This is my dylib file:
cppdemofile.cpp
#include "cppdemofile.h" int add(int a, int b) { return a + b; }
cppdemofile.h
#ifndef __CppDemoLibrary__cppdemofile__ #define __CppDemoLibrary__cppdemofile__ #pragma GCC visibility push(default) extern "C" int add(int a, int b); #pragma GCC visibility pop #endif
compile to dylib and check:
nm -gU libCppDemoLibrary.dylib 0000000000000f80 T _add
… copy libCppDemoLibrary.dylib to ~/lib…
Swift program:
@IBAction func buttonClick(sender: NSButton) { let handle = dlopen("libCppDemoLibrary.dylib", RTLD_NOW) if (handle != nil) { var sym = dlsym(handle, "add") if (sym != nil) { let pointer = UnsafeMutablePointer<(CInt, CInt) -> CInt>(sym) // When debugging, I'm reaching up to this point... // but now, how do I call the 'add' function here??? // var result = ??? // label.stringValue = "Total: " + String(result) } } }
How do I call the add function? Is it ok to use a dylib? Should I instead add these sources to my swift project?
How to solve the problem:
Solution 1:
Calling the add
function from Swift is possible because you
defined it to have C linkage with extern "C"
.
Making the library a Swift module (as suggested by jtbandes in above
comments) might be the better solution,
but here is how you can use the function pointer return by dlsym()
from Swift:
First add
typedef int(*addFunc)(int, int);
to the bridging header file, or alternatively define
typealias addFunc = @convention(c) (CInt, CInt) -> CInt
in Swift. Then the following works:
let handle = dlopen(path, RTLD_NOW) if (handle != nil) { var sym = dlsym(handle, "add") if (sym != nil) { let f = unsafeBitCast(sym, addFunc.self) let result = f(12, 45) print(result) } dlclose(handle) }
Of course this will crash if addFunc
does not match the
actual signature of the loaded function.
Update for Swift 3:
if let handle = dlopen(path, RTLD_NOW) { if let sym = dlsym(handle, "add") { let f = unsafeBitCast(sym, to: addFunc.self) let result = f(12, 45) print(result) } dlclose(handle) }
Solution 2:
In order to use C++ code in Swift, you need to wrap it in C functions or Objective-C classes.
Also see Call a C++ function from Swift