2016-01-08 6 views
5

Gibt es eine Möglichkeit, eine C-Funktion aufzurufen, die von einer Dylib von Swift geladen wurde?Swift: So rufen Sie eine C-Funktion auf, die von einer Dylib geladen wurde

Das ist mein dylib Datei:

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 

kompilieren dylib und überprüfen:

nm -gU libCppDemoLibrary.dylib 
0000000000000f80 T _add 

... kopieren libCppDemoLibrary.dylib-~/lib ...

Swift Programm:

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

Wie rufe ich die add Funktion? Ist es in Ordnung, eine Dylib zu verwenden? Sollte ich stattdessen diese Quellen meinem schnellen Projekt hinzufügen?

+0

1. Warum dyld? 2. Haben Sie versucht, es zu einem Modul zu machen und es von Swift zu importieren? – jtbandes

+0

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

+0

Der Titel der Frage ist ein wenig irreführend, weil 'add' eine C-Verknüpfung hat. Sie konnten eine C++ Funktion von Swift nicht aufrufen. –

Antwort

5

Aufruf die add Funktion von Swift möglich ist, weil Sie es definierten C-Bindung mit extern "C" haben.

Herstellung der Bibliothek ein Swift-Modul (wie im oben Kommentare von jtbandes vorgeschlagen) könnte die bessere Lösung, aber hier ist, wie Sie den Funktionszeiger Rückkehr von dlsym() von Swift verwenden können:

Erste hinzufügen

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

zur Verbrückung Header-Datei oder alternativ definieren

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

in Swift. Dann wird die folgenden Werke:

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

Natürlich wird dies zum Absturz bringen, wenn addFunc nicht die tatsächliche Unterschrift der geladenen Funktion entspricht.


Update für 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

Dieser hat super funktioniert. Danke auch für den Vorschlag, dies zu einem Modul zu machen. – Andres

+0

@Andres: Gern geschehen!- Der Vorschlag stammt jedoch von jtbandes in seinem Kommentar zu Ihrer Frage :) –

+0

Werden iOS-Apps, die diese API verwenden, für den App Store abgelehnt? – chrisamanse

Verwandte Themen