2016-01-08 44 views
5

C'è un modo per chiamare una funzione C caricata da un dylib da Swift?Swift: Come chiamare una funzione C caricata da un dylib

Questo è il mio dylib di 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 

compilazione di dylib e verificare:

nm -gU libCppDemoLibrary.dylib 
0000000000000f80 T _add 

... copiare libCppDemoLibrary.dylib-~/lib ...

programma Swift:

@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) 
     } 
    } 
} 

Come chiamare la funzione add? Va bene usare un dylib? Dovrei invece aggiungere queste fonti al mio progetto rapido?

+0

1. Perché dyld? 2. Hai provato a trasformarlo in un modulo e importarlo da Swift? – jtbandes

+0

Vedere http://spin.atomicobject.com/2015/02/23/c-libraries-swift/ – jtbandes

+0

Il titolo della domanda è un po 'fuorviante perché 'add' ha il collegamento C. Non è possibile chiamare una funzione C++ da Swift. –

risposta

5

chiamando la funzione add da Swift è possibile perché si definito avere C collegamento con extern "C".

Fare biblioteca un modulo Swift (come suggerito da jtbandes di sopra commenti) potrebbe essere la soluzione migliore, ma qui è come è possibile utilizzare il ritorno puntatore a funzione da dlsym() da Swift:

Prima aggiungere

typedef int(*addFunc)(int, int); 

al file di intestazione di transizione, o alternativamente definire

typealias addFunc = @convention(c) (CInt, CInt) -> CInt 

in Swift. Poi le seguenti opere:

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) 
} 

Naturalmente questo andrà in crash se addFunc non corrisponde al firma effettiva della funzione caricato.


Aggiornamento per 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) 
} 
+0

Questo ha funzionato alla grande. Grazie anche per il suggerimento di rendere questo un modulo. – Andres

+0

@Andres: siete i benvenuti!- Il suggerimento è venuto da jtbandes nel suo commento alla tua domanda :) –

+0

Le app iOS che utilizzano questa API verranno rifiutate per l'App Store? – chrisamanse

Problemi correlati