Внедрение C API в D
Итак, есть много информации о вызове C API изнутри D, но как насчет обратного? Что вам нужно сделать, чтобы написать библиотеку в D, которая работает как обычная C-библиотека? Здесь простой случай:
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;
}
}
Наивные попытки построить и связать их с gcc и dmd просто приводят к ошибкам компоновщика.
Связь с 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
Связь с 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
Ответы
Ответ 1
Мой ответ - использование D статических библиотек от C.
Да, это немного не по теме, но разделяемые библиотеки для Windows описаны в документации D (http://www.d-programming-language.org/dll.html) и для Linux все еще находятся в стадии разработки (http://www.digitalmars.com/d/2.0/changelog.html). Рабочие примеры для обеих систем прилагаются.
-
Win32: dmd + dmc отлично работает. Пример: test_d_from_c_win32.zip
-
Linux32: dmd добавляет некоторые необходимые материалы после того, как он нашел основную функцию D, поэтому необходим D main (проверен на dmd2 + gcc на Linux32).
Это имя ссылки "_Dmain", и оно не будет смешиваться с C one (real "main" ).
Поэтому можно просто добавить файл dfakemain.d
с текстом void main(){}
.
dmd -c dfakemain.d
создаст dfakemain.o с отсутствующими символами. Свяжите это с вашими объектными файлами, и вы будете счастливы. Пример: test_d_from_c_linux32.tar.gz
Ответ 2
Вкратце взглянув на исходный код компилятора, _Dmodule_ref
- это связанный список конструкторов модулей. Чтобы устранить проблему, добавьте ее в свой main.c
:
void* _Dmodule_ref;
Программа теперь соединяется и работает нормально.
(По крайней мере, я думаю, что это работает.)
Ответ 3
Если gcc компилируется как С++, ссылка по умолчанию, используемая для extern, будет С++, а не C. Попробуйте это вместо:
extern "C" int foo(int x);
В вашем синтаксисе D нет ничего плохого. Здесь приведен абзац, подтверждающий ваш подход: http://www.digitalmars.com/d/2.0/interfaceToC.html