2011-09-20 10 views
18

Quindi ci sono un sacco di informazioni su come chiamare le API C da D, ma che dire del contrario? Cosa devi fare per scrivere una libreria in D che funzioni come una normale libreria condivisa in C? Ecco un caso semplice:Implementazione di un'API C in D

main.c

extern int foo(int x); 
void main() { 
    printf("foo(5)=%d\n",foo(5)); 
} 

foo.d

extern(C) 
{ 
    int foo(int x) 
    { 
     return x*x; 
    } 
} 

Ingenuamente cercando di costruire e collegare questi con gcc e DMD solo si traduce in errori del linker.

collegamento con gcc main.o foo.o:

doFoo.o: In function `no symbol': 
doFoo.d:(.text+0x7): undefined reference to `_Dmodule_ref' 
collect2: ld returned 1 exit status 

collegamento con DMD main.o foo.o:

/usr/lib64/libphobos2.a(deh2_2eb_525.o): In function `_D2rt4deh213__eh_finddataFPvZPS2rt4deh213DHandlerTable': 
src/rt/deh2.d:(.text._D2rt4deh213__eh_finddataFPvZPS2rt4deh213DHandlerTable+0xa): undefined reference to `_deh_beg' 
src/rt/deh2.d:(.text._D2rt4deh213__eh_finddataFPvZPS2rt4deh213DHandlerTable+0x14): undefined reference to `_deh_beg' 
src/rt/deh2.d:(.text._D2rt4deh213__eh_finddataFPvZPS2rt4deh213DHandlerTable+0x1e): undefined reference to `_deh_end' 
src/rt/deh2.d:(.text._D2rt4deh213__eh_finddataFPvZPS2rt4deh213DHandlerTable+0x46): undefined reference to `_deh_end' 
/usr/lib64/libphobos2.a(lifetime.o): In function `_D2rt8lifetime18_sharedStaticCtor9FZv': 
src/rt/lifetime.d:(.text._D2rt8lifetime18_sharedStaticCtor9FZv+0x15): undefined reference to `_tlsend' 
src/rt/lifetime.d:(.text._D2rt8lifetime18_sharedStaticCtor9FZv+0x29): undefined reference to `_tlsstart' 
/usr/lib64/libphobos2.a(thread_a3_258.o): In function `_D4core6thread6Thread6__ctorMFPFZvmZC4core6thread6Thread': 
src/core/thread.d:(.text._D4core6thread6Thread6__ctorMFPFZvmZC4core6thread6Thread+0x2b): undefined reference to `_tlsend' 
src/core/thread.d:(.text._D4core6thread6Thread6__ctorMFPFZvmZC4core6thread6Thread+0x36): undefined reference to `_tlsstart' 
/usr/lib64/libphobos2.a(thread_a3_258.o): In function `_D4core6thread6Thread6__ctorMFDFZvmZC4core6thread6Thread': 
src/core/thread.d:(.text._D4core6thread6Thread6__ctorMFDFZvmZC4core6thread6Thread+0x28): undefined reference to `_tlsend' 
src/core/thread.d:(.text._D4core6thread6Thread6__ctorMFDFZvmZC4core6thread6Thread+0x33): undefined reference to `_tlsstart' 
/usr/lib64/libphobos2.a(thread_a3_258.o): In function `_D4core6thread6Thread6__ctorMFZC4core6thread6Thread': 
src/core/thread.d:(.text._D4core6thread6Thread6__ctorMFZC4core6thread6Thread+0x26): undefined reference to `_tlsend' 
src/core/thread.d:(.text._D4core6thread6Thread6__ctorMFZC4core6thread6Thread+0x31): undefined reference to `_tlsstart' 
/usr/lib64/libphobos2.a(thread_a0_713.o): In function `thread_entryPoint': 
src/core/thread.d:(.text.thread_entryPoint+0x36): undefined reference to `_tlsend' 
src/core/thread.d:(.text.thread_entryPoint+0x41): undefined reference to `_tlsstart' 
collect2: ld returned 1 exit status 
--- errorlevel 1 
+2

Uhm, non lasciare noi Hangin' ... quali sono gli errori? – Mehrdad

+0

Gli errori del linker sono: 'foo.o: nella funzione 'no symbol': foo.d :(. Testo + 0x7): riferimento non definito a '_Dmodule_ref'' –

risposta

9

La mia risposta è sull'utilizzo D librerie statiche da C. Sì, questo è un po 'fuori tema, ma le librerie condivise per Windows sono descritte nella documentazione di D (http://www.d-programming-language.org/dll.html) e per Linux sono ancora in costruzione (http://www.digitalmars.com/d/2.0/changelog.html). Sono allegati esempi di lavoro per entrambi i sistemi.

  • Win32: DMD + dmc grandi opere. Esempio: test_d_from_c_win32.zip

  • Linux32: DMD aggiunge alcune cose necessarie una volta che ha trovato funzione principale D, in modo da D's principale è necessario (testato per dmd2 + gcc su Linux32). Il nome del collegamento è "_Dmain" e non sarà missato con quello di C (vero "main"). Quindi si può semplicemente aggiungere il file dfakemain.d con il testo void main(){}. dmd -c dfakemain.d creerà dfakemain.o con simboli mancanti. Collegalo con i tuoi file oggetto e sarai felice.Esempio: test_d_from_c_linux32.tar.gz

+1

Hmm il metodo linux ha funzionato per me, ma ha ancora alcuni problemi. Uno è che richiede di usare dmd come linker. C'è qualche libreria alla quale potresti collegarti per risolvere quel problema? In secondo luogo, sembra che l'inserimento di un falso main rende la libreria non utilizzabile anche una libreria D, ed eventualmente incompatibile con altre librerie che utilizzano lo stesso trucco. – sholte

+0

No, non è necessario per usare dmd come linker_ (e non può, perché dmd non può collegarsi, chiama semplicemente un linker esterno per farlo). Devi solo collegarti a 'dfakemain.o'. Nel mio esempio Linux gcc è usato come "chiamante del linker". _È disponibile una libreria per la risoluzione di questo problema? _ Sì. È 'dfakemain.o'. Ad esempio, non è collegato alla libreria D (dlibrary.o) e non dovrebbe. Dovrebbe essere collegato una volta per eseguibile se utilizza alcune librerie di tipo D. – Denis

+0

Ah, vedo che la mia risposta era in realtà nel build.sh del tuo esempio. Mi mancava la -lrt -lphobos2 -lpthread -lm parte della tua soluzione. – sholte

6

Se gcc di compilare come C++, il collegamento predefinito utilizzato per l'extern sarà C++, non C. Prova a modificare:

extern "C" int foo(int x); 

non sembra essere qualcosa di sbagliato con la sintassi D. C'è un paragrafo che conferma il tuo approccio qui: http://www.digitalmars.com/d/2.0/interfaceToC.html

+1

No, non compilato come C++. Semplicemente vecchio gcc -c main.c – sholte

9

Secondo una rapida occhiata allo compiler source code, _Dmodule_ref è l'elenco collegato dei costruttori di moduli. Per risolvere il problema, aggiungere questo al tuo main.c:

void* _Dmodule_ref; 

adesso il programma link e funziona bene.

(Almeno, è così che penso che funziona.)

+2

Sono abbastanza sicuro di dover effettuare una chiamata per inizializzare il runtime D piuttosto che correggere gli errori del linker, ma non l'ho mai fatto prima, quindi non lo faccio lo so. So che alcuni membri del newsgroup lo hanno fatto per le app della GUI di Windows, quindi _someone_ sa esattamente cosa fare. Ho appena pubblicato una domanda al riguardo in D.Learn. Spero che qualcuno che l'ha fatto risponda qui. –

+0

Sì, se vuoi cose fantastiche come allocazioni di memoria o anche costruttori statici, allora ovviamente devi configurarlo :) ma se vuoi usare D come C migliore, questo potrebbe funzionare. –

+0

Questo sembra funzionare per questo caso, ma voglio dargli uno shakedown più completo. Sai cosa dovrebbe fare questo simbolo? – sholte