2011-09-20 6 views
18

Por lo tanto, hay mucha información sobre cómo llamar a las API de C desde dentro de D, pero ¿qué ocurre con el reverso? ¿Qué necesitas hacer para escribir una biblioteca en D que funcione como una biblioteca común C normal? He aquí un caso fácil:Implementación de una API de C en 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 tratando de construir y vincular estos con gcc y DMD simplemente se traduce en errores de enlace.

Vinculación con gcc foo.o main.o:

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

Vinculación 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

Um, no nos dejan colgando ... ¿cuáles son los errores? – Mehrdad

+0

Los errores del enlazador son: 'foo.o: en la función 'no symbol': foo.d :(. Text + 0x7): referencia indefinida a '_Dmodule_ref'' –

Respuesta

9

Mi respuesta es sobre el uso D bibliotecas estáticas de C. Sí, esto está un poco fuera de tema, pero las bibliotecas compartidas para Windows se describen en la documentación de D's (http://www.d-programming-language.org/dll.html) y para Linux aún están en construcción (http://www.digitalmars.com/d/2.0/changelog.html). Se adjuntan ejemplos de trabajo para ambos sistemas.

  • Win32: DMD + DMC funciona muy bien. Ejemplo: test_d_from_c_win32.zip

  • linux32: DMD añade un poco de materia requerido una vez que se ha encontrado D función principal, por lo que D's principal se necesita (la prueba de DMD2 + gcc en linux32). Su nombre de enlace es "_Dmain" y no se mezclará con el de C (real "principal"). Así que uno solo puede agregar el archivo dfakemain.d con el texto void main(){}. dmd -c dfakemain.d creará dfakemain.o con símbolos faltantes. Vincúlelo con sus archivos objeto y estará contento. Ejemplo: test_d_from_c_linux32.tar.gz

+1

Hmm, el método de Linux funcionó para mí, pero todavía tiene algunos problemas. Una de ellas es que requiere que uses dmd como tu enlazador. ¿Hay alguna biblioteca que pueda vincular para resolver ese problema? En segundo lugar, parece que pegar en un elemento principal falso hace que la biblioteca no sea también utilizable como una biblioteca D, y posiblemente incompatible con otras bibliotecas que utilizan el mismo truco. – sholte

+0

No, no requiere que use dmd como su enlazador_ (y no puede, porque dmd no puede enlazar, solo llama a un enlazador externo para hacerlo). Solo necesita vincular con 'dfakemain.o'. En mi ejemplo de Linux, gcc se usa como "llamador del vinculador". _¿Hay alguna biblioteca con la que puedas vincular para resolver ese problema? _ Sí. Es 'dfakemain.o'. Por ejemplo, no está vinculado con la biblioteca D (dlibrary.o) y no debería estarlo. Debería estar vinculado una vez por ejecutable si usa algunas bibliotecas D. – Denis

+0

Ah, veo que mi respuesta estaba en el build.sh de tu ejemplo. Me faltaba la parte -lrt -lphobos2 -lpthread -lm de tu solución. – sholte

6

Si gcc compila como C++, el enlace predeterminado que se utiliza para el externo será C++, no C. Tal vez puedas probar:

extern "C" int foo(int x); 

no parece haber nada mal con su sintaxis D no lo hace. Hay un párrafo que confirma su enfoque aquí: http://www.digitalmars.com/d/2.0/interfaceToC.html

+1

No, no se compila como C++. Simplemente viejo viejo gcc -c main.c – sholte

9

De acuerdo con un vistazo rápido al compiler source code, _Dmodule_ref es la lista vinculada de constructores de módulos. Para solucionar el problema, agregue esto a su main.c:

void* _Dmodule_ref; 

el programa ahora enlaces y funciona muy bien.

(Por lo menos, así es como creo que funciona.)

+2

Estoy bastante seguro de que tienes que hacer una llamada para inicializar el tiempo de ejecución D en lugar de simplemente arreglar los errores del enlazador, pero nunca he hecho esto antes, así que no lo hago. lo sé Sé que algunas personas en el grupo de noticias lo han estado haciendo para las aplicaciones GUI de Windows, por lo que _alguien_ sabe exactamente qué hacer. Acabo de publicar una pregunta al respecto en D.Learn. Con suerte, alguien allí que lo haya hecho responderá aquí. –

+0

Sí, si quieres cosas elegantes como asignaciones de memoria o incluso constructores estáticos, obviamente necesitas configurarlo :) pero si quieres usar D como una mejor C, esto podría funcionar. –

+0

Esto parece funcionar para este caso, pero querré darle un shakedown más completo. ¿Sabes lo que se supone que está haciendo este símbolo? – sholte