【问题标题】:Implementing a C API in D在 D 中实现 C API
【发布时间】:2011-11-20 18:10:42
【问题描述】:

所以有很多关于从 D 中调用 C API 的信息,但是反过来呢?你需要做什么才能用 D 语言编写一个像普通 C 共享库一样工作的库?这是一个简单的案例:

main.c

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

食物.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

【问题讨论】:

  • 嗯,别让我们呆着......有什么错误?
  • 链接器错误是:foo.o: In function 'no symbol': foo.d:(.text+0x7): undefined reference to '_Dmodule_ref'

标签: c d


【解决方案1】:

我的答案是关于使用 C 中的 D 静态库。 是的,这有点跑题了,但是在 D 的文档 (http://www.d-programming-language.org/dll.html) 和 中描述了用于 Windows 的共享库Linux 仍在建设中 (http://www.digitalmars.com/d/2.0/changelog.html)。附上两个系统的工作示例。

  • Win32:dmd+dmc 效果很好。 示例test_d_from_c_win32.zip

  • Linux32:dmd 找到 D main 函数后会添加一些必需的东西,因此需要 D 的 main(在 Linux32 上测试 dmd2+gcc)。 它的链接名称是“_Dmain”,它不会与 C 的链接名称(真正的“main”)混合。 因此,只需添加文件dfakemain.d 和文本void main(){}dmd -c dfakemain.d 将创建缺少符号的 dfakemain.o。将它与您的目标文件链接起来,您会很高兴。 示例test_d_from_c_linux32.tar.gz

【讨论】:

  • 嗯 linux 方法对我有用,但它仍然存在一些问题。一是它要求您使用 dmd 作为链接器。是否有一些库可以链接以解决该问题?其次,似乎坚持使用虚假的 main 会使库不能同时用作 D 库,并且可能与使用相同技巧的其他库不兼容。
  • 不,它不要求你使用 dmd 作为你的链接器(它不能,因为 dmd 不能链接,它只是调用一个外部链接器来做它)。你只需要链接dfakemain.o。在我的 linux 示例中,gcc 被用作“链接器的调用者”。 是否有可以链接到的库来解决该问题? 是的。它是dfakemain.o。例如,它没有与 D 库 (dlibrary.o) 链接,也不应该。如果它使用一些 D 库,则每个可执行文件应该链接一次。
  • 啊,我看到我的答案实际上在您示例的 build.sh 中。我错过了解决方案的 -lrt -lphobos2 -lpthread -lm 部分。
【解决方案2】:

快速浏览compiler source code_Dmodule_ref是模块构造函数的链表。要解决此问题,请将其添加到您的 main.c

void* _Dmodule_ref;

程序现在链接并运行良好。

(至少,我认为它是这样工作的。)

【讨论】:

  • 我很确定您实际上必须调用来初始化 D 运行时,而不仅仅是修复链接器错误,但我以前从未真正这样做过,所以我不知道.我知道新闻组中的一些人一直在为 Windows GUI 应用程序做这件事,所以那里的有人确切地知道该做什么。我刚刚在 D.Learn 中发布了一个关于它的问题。希望有做过的人会在这里回复。
  • 是的,如果你想要像内存分配甚至静态构造函数这样的花哨的东西,那么你显然需要设置它:) 但如果你想将 D 用作更好的 C,这可以工作。
  • 这似乎确实适用于这种情况,但我想对其进行更彻底的调整。你知道这个符号应该做什么吗?
  • 据我所知,_Dmodule_ref是一个模块信息链表的头部。初始化时,模块将包含模块信息的结构添加到列表中,以便运行时初始化(内存管理等)完成后,运行时可以调用模块静态/共享构造函数。 (至少,我认为它是这样工作的。)
【解决方案3】:

如果 gcc 编译为 C++,则用于 extern 的默认链接将是 C++,而不是 C。试试这个吧:

extern "C" int foo(int x);

您的 D 语法似乎没有任何问题。这里有一段确认您的方法:http://www.digitalmars.com/d/2.0/interfaceToC.html

【讨论】:

  • 不,不编译为 C++。只是普通的旧 gcc -c main.c
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多