2011-09-20 15 views
18

Więc jest mnóstwo informacji o wywoływaniu C API z wnętrza D, ale co z odwrotnością? Co musisz zrobić, aby napisać bibliotekę w D, która działa jak normalna biblioteka współdzielona C? Oto prosty przypadek:Implementacja C API w 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; 
    } 
} 

naiwnie próbuje budować i łączyć je z gcc i DMD tylko powoduje błędy linkera.

Powiązanie z 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 

Powiązanie z 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

Um, nie zostawiaj nas nachylona ... jakie są błędy? – Mehrdad

+0

Błędy łącznika to: 'foo.o: W funkcji 'brak symbolu': foo.d :(. Tekst + 0x7): niezdefiniowane odwołanie do '_Dmodule_ref'' –

Odpowiedz

9

Moja odpowiedź jest na temat korzystania D statycznych bibliotek z C. Tak, jest to nieco nie na temat, ale udostępnione biblioteki dla Windows są opisane w dokumentacji D (http://www.d-programming-language.org/dll.html) i dla Linux są nadal w budowie (http://www.digitalmars.com/d/2.0/changelog.html). Załączono przykłady robocze dla obu systemów.

  • Win32: DMD + DMC działa świetnie. Przykład: test_d_from_c_win32.zip

  • Narzędzie linux32: DMD dodaje pewne wymagane materiał raz znalazła ona D główną funkcję, tak D'Głównym jest potrzebne (testowane na dmd2 + GCC na Narzędzie linux32). Jego nazwa połączenia to "_Dmain" i nie zostanie połączona z C (prawdziwy "główny"). Po prostu można dodać plik dfakemain.d z tekstem void main(){}. dmd -c dfakemain.d utworzy dfakemain.o z brakującymi symbolami. Połącz go z plikami obiektów, a będziesz szczęśliwy.Przykład: test_d_from_c_linux32.tar.gz

+1

Hmm metoda linuxa działała dla mnie, ale nadal ma pewne problemy. Jedną z nich jest to, że wymaga użycia dmd jako łącznika. Czy istnieje jakaś biblioteka, z którą można połączyć, aby rozwiązać ten problem? Po drugie, wygląda na to, że trzymanie się fałszywej głównej sprawia, że ​​biblioteka nie może również używać biblioteki D i prawdopodobnie jest niezgodna z innymi bibliotekami, które używają tej samej sztuczki. – sholte

+0

Nie wymaga od ciebie użycia dmd jako twojego linkera (a nie może, ponieważ dmd nie może połączyć, po prostu wywołuje zewnętrzny linker, aby to zrobić). Musisz tylko połączyć się z 'dfakemain.o'. W moim przykładzie Linuksa gcc jest używany jako "wywołujący linker". _ Czy jest jakaś biblioteka, z którą można połączyć, aby rozwiązać ten problem? _ Tak. To jest 'dfakemain.o'. Na przykład nie jest połączony z biblioteką D (diborg.o), a nie powinien. Powinien być połączony raz na plik wykonywalny, jeśli używa niektórych bibliotek D. – Denis

+0

Ach, widzę, że moja odpowiedź była faktycznie w build.sh twojego przykładu. Brakowało mi części -lrt -lphobos2 -lpthread -lm twojego rozwiązania. – sholte

6

Jeśli gcc kompiluje jak C++, domyślne powiązania używany extern będzie C++, a nie C. Wypróbuj zamiast tego:

extern "C" int foo(int x); 

Nie wydaje się, że jest coś złego w Twojej składni D. Tutaj znajduje się akapit potwierdzający twoje podejście: http://www.digitalmars.com/d/2.0/interfaceToC.html

+1

Nie, nie kompilowanie jako C++. Po prostu stary gcc -c main.c – sholte

9

Zgodnie z krótkim spojrzeniem na compiler source code, _Dmodule_ref jest połączoną listą konstruktorów modułów. Aby rozwiązać ten problem, należy dodać go do main.c:

void* _Dmodule_ref; 

program aktualnie łączy i działa poprawnie.

(Przynajmniej tak właśnie myślę, że to działa.)

+2

Jestem prawie pewny, że faktycznie musisz wykonać połączenie inicjujące środowisko wykonawcze D, zamiast tylko naprawiać błędy łącznika, ale nigdy wcześniej tego nie robiłem, więc nie robię tego. nie wiem. Wiem, że niektórzy ludzie z grupy dyskusyjnej robią to dla aplikacji Windows GUI, więc ktoś wie dokładnie, co robić. Właśnie napisałem pytanie na ten temat w D.Learn. Mam nadzieję, że ktoś, kto to zrobił, odpowie tutaj. –

+0

Tak, jeśli chcesz fantazyjne elementy, takie jak alokacja pamięci, a nawet statyczne konstruktory, to oczywiście musisz je skonfigurować :), ale jeśli chcesz używać D jako lepszego C, to może działać. –

+0

Wydaje się, że działa to w tym przypadku, ale chcę je dokładniej sprawdzić. Czy wiesz, co ten symbol ma robić? – sholte