2016-04-12 14 views
7

C'è un modo per compilare codice C o C++ nativo ed esporlo a Swift su Linux? Vedo che diverse librerie Apple come libdispatch sono scritte in puro C e che puoi accedervi in ​​Swift semplicemente importandole.Compilare il codice C ed esporlo a Swift sotto Linux

Per impostare l'esempio, diciamo che ho due file Car.c e Car.h che definiscono la struttura denominata Car. C'è un modo in cui posso compilarli e usarli in Swift scrivendo istruzioni import?

import Car 

Ho provato a scrivere module.modulemap file all'interno di directory in cui, si trovano .h e Package.swift file .c:

module Car { 
    header "Car.h" 
    export * 
} 

e funzionante swift build. Questo errore resa:

<unknown>:0: error: unexpected 'commands' value (expected map) 
<unknown>:0: error: unable to load build file 

Sto usando Swift versione 3.0-dev (24 marzo 2016)

[Update 1]

Ho contattato Max (MXCL) - uno dei i creatori di Swift Package Manager e mi ha detto di sbarazzarmi dello modulemap e di mettere i file .c e .h direttamente nella cartella Sources. Dopo che ho fatto il pacchetto compilato ma non è disponibile come modulo. Inoltre, non è possibile chiamare nessuna delle funzioni definite nel file .h.

+1

Dai un'occhiata al bridging o ai moduli Objective-C. –

risposta

11

Se si crea una libreria dal vostro codice C, è possibile creare un per il modulo di sistema, che può quindi essere importato in Swift, vedere questa risposta: Use a C library in Swift on Linux.

Un altro modo per avvicinarsi a questa attività è creare un'intestazione di bridging, come suggerito da @Philip. Ecco un esempio semplificato. Consideriamo il seguente codice C:

/* In car.h */ 
int getInt(); 

/* In car.c */ 
int getInt() { return 123; } 

Utilizzeremo car.h come intestazione del ponte. La fonte rapida è (nel file di junk.swift):

print("Hi from swift!") 
var i = getInt() 
print("And here is an int from C: \(i)!") 

In primo luogo, creare un file oggetto, car.o, da car.c:

gcc -c car.c 

Ora Creare un file eseguibile, junk, come segue:

swiftc -import-objc-header car.h junk.swift car.o -o junk 

L'esecuzione dell'eseguibile dà:

$ ./junk 
Hi from swift! 
And here is an int from C: 123! 

L'opzione -import-objc-header è nascosta. Per vedere e un sacco di altre opzioni nascoste, eseguire:

swiftc -help-hidden 

Ho fatto questo utilizzando Swift snapshot 3.0 di sviluppo per Ubuntu 14.04 dal 12 aprile, disponibile qui: https://swift.org/builds/development/ubuntu1404/swift-DEVELOPMENT-SNAPSHOT-2016-04-12-a/swift-DEVELOPMENT-SNAPSHOT-2016-04-12-a-ubuntu14.04.tar.gz

Ora, se si desidera utilizzare C++, dovrai creare un wrapper, scritto in un file sorgente C++ e compilato con un compilatore C++, ma con funzioni richiamabili da C usando extern "C". Queste funzioni possono quindi essere richiamate da Swift come qualsiasi funzione C. Vedi, per esempio, questa risposta: Can I mix Swift with C++? Like the Objective - C .mm files

+0

Se stai cercando di farlo funzionare e ricevi un errore "Nessun modulo" su un'istruzione "import", rimuovi l'istruzione "import" che sta causando il errore. Questo metodo non crea un modulo Swift da utilizzare con l'importazione. Piuttosto crea funzioni, come "getInt()", nell'ambito globale. – pauln

3

L'utilizzo delle funzioni C in swift richiede un'intestazione di bridging che include tutte le funzionalità C necessarie. Ad esempio, myBridgingHeader.h che contiene # include "Car.h" e qualsiasi altra roba C desideri. Credo che C++ non sia attualmente supportato.

Una volta che si ha l'intestazione del bridging, è necessario rendersene conto rapidamente. Gli utenti Xcode ottengono questo gratuitamente quando lo aggiungono al progetto. In Linux, usa flag "-import-objc-header/path/to/header" durante la compilazione.

Modifica: ho aggiunto un esempio completo di seguito costituito da 6 file per tutti gli altri che possono avere questa domanda. È praticamente uguale a quello sopra, ma non ho visto che fino a quel momento l'avevo già messo insieme. Inoltre, potrebbe essere utile per qualcuno che deve collegarsi alle librerie statiche.

Copiare il contenuto del file di seguito per file con nome appropriato, make, quindi ./hello e che dovrebbe funzionare. Per la cronaca, ho eseguito solo questo sul veloce versione 2.2-dev (uso swift --version per verificare la vostra)

  • hello.swift:

    let n: Int32 = 5 
    print("Hello, Swift World!") 
    print("mult2(\(n,N)) = \(mult2(n,N))") 
    print("CONST1=\(CONST1), CONST2=\(CONST2), CONST3=\(CONST3)") 
    
  • bridge.h:

    #include "defs.h" 
    #include "mult.h" 
    
  • defs.h:

    #define CONST1 1 
    #define CONST2 2 
    #define CONST3 3 
    
  • mult.h:

    #define N 7 
    int mult2(int,int); 
    
  • mult.c:

    #include "defs.h" 
    #include "mult.h" 
    int mult2(int a, int b) 
    { 
        return a*b; 
    } 
    
  • Makefile:

    all: hello 
    
    hello: libmult.a 
        swiftc hello.swift -import-objc-header ./bridge.h -L. -lmult -o hello 
    
    libmult.a: mult.o 
        ar -rc libmult.a mult.o 
        ranlib libmult.a 
    
    mult.o: mult.c mult.h defs.h 
        gcc -c mult.c -o mult.o 
    
    .PHONY: clean 
    clean: 
        rm -f *.o *.a hello 
    
+0

I comandi 'swift', né' swift build' su Linux hanno l'opzione '-import-objc-header' (Swift 3.0) –

+2

Spiacenti, dovrei aver chiarito: dovresti compilare con 'swiftc' – Philip

+0

Ancora, non c'è' -importare opzione -objc-header'. –

Problemi correlati