d2:从最初导出的不同名称导入外部库中的函数

时间:2012-04-05 13:34:37

标签: linker static-linking d

我正在将用C编写的第三方库API转换为D.该库导出了许多名为libname_foofunclibname_barfunc等的函数,这对C库来说可以防止膨胀全局命名空间。由于D比C更模块化,我想提供更多D'ish接口并摆脱函数前缀,因此函数看起来像libname.c.foofunclibname.c.barfunc

由于库不知道我的“改进”,我必须以某种方式将libname.c.foofunc转换为libname_foofunc并保留正确的外部链接,目标名称修改和同时调用约定。

假设有方法(我也不知道)告诉链接器外部未解析的符号__imp__D1c7foofuncFZi对应_libname_foofunclibname_foofunc@0(尽管我必须做名字)手工碾磨),仍然有问题告诉D什么是召唤惯例。

如果我在extern(C) int foofunc()中明确指定libname/c.di,则不再存在调用约定问题,但名称会转换为_foofunc,这也与预期不同。

那么,在D中导入外来函数的方式是否与导出的名称不同?

我虽然在原始名称下“按原样”导入功能,然后将它们别名为无前缀的类似物,但这似乎非常笨拙。

4 个答案:

答案 0 :(得分:3)

你可以使用

alias libname_foofunc foofunc;

这会使libname_foofunc可见,但允许您使用foofunc,编译器会将其转换为libname_foofunc

答案 1 :(得分:2)

考虑到旧约的最后一段,答案是否定的。没有其他语言能够像你描述的那样去做,也不应该这样做。如果API设计者希望以您喜欢的方式拥有函数名称,那么他们会以这种方式公开它们......

现在想象一下那些喜欢some_function(),然后B组喜欢someFunction()的开发者的A组和喜欢SomeFunction()的C组......

无论你使用D还是其他东西,别名都是必须的。它应该是那样的。 API应该简单,简洁,易于理解。

答案 2 :(得分:2)

就链接而言,符号实际上是C的东西,因为我们讨论的是C链接器。 D与链接和导出符号的情况基本上与C ++中的情况相同,这就是为什么有错误的名称等。您将不得不使用其原始名称在D中为它们创建声明,因为这是链接器所期望的。 D没有做任何不同或神奇的事情会改变这一点。只有两种方法可以使用不同的名称。

  1. 为D代码中的函数添加别名。您可以将别名放在任何模块中列出符号(因为您必须在D中声明它们)。然后您的代码可以使用原始名称或别名。我没有看到任何笨拙的事情。

  2. 创建包装函数 - 使用C或D - 并让D代码使用它们。

  3. 别名肯定会更好恕我直言。它们不会引入任何开销,也不那么复杂。

    但无论如何,从D使用C库时,正常的做法就是使用C函数名。你正在调用C函数,不应该隐藏这个事实。它们不是D函数,并且不是相同的(即使它们是相似的) - 特别是当涉及到拥有你传递给函数的内存的东西时。重命名它们的好处值得商榷。通常在编写D包装器时,为API提供更清晰,更像D的API(而不仅仅是更改名称),不再直接使用C函数。 Phobos的一个很好的例子是etc.curl vs std.net.curl。 etc.c.curl纯粹是C API,不会尝试重命名任何东西。它不会创建任何别名来使符号与Phobos的命名约定相匹配或使它们更像D。它本质上只是curl头文件的D版本。另一方面,std.net.curl构建在它之上,以提供更像D的API和抽象。它远不止重命名C函数。

答案 3 :(得分:1)

如果您不想将这些函数放入模块中,可以将它们保存在结构体中并模拟某种命名空间。例如。你可以这样做:

struct libname
{
    struct C
    {
        static int libname_foofunc();
        alias libname_foofunc foofunc;
    }

    static C c;
}

void main()
{
    libname.c.foofunc();
}