Linker d2:从外部库以不同的名称导入函数它最初是导出的

Linker d2:从外部库以不同的名称导入函数它最初是导出的,linker,static-linking,d,Linker,Static Linking,D,我正在将用C编写的第三方库API翻译成D。该库导出了许多名为libname\u foofunc、libname\u barfunc等函数,这是C库防止全局命名空间膨胀的预期。由于D比C更模块化,我想提供更多的D'ish接口并去掉函数前缀,因此函数看起来像libname.C.foofunc和libname.C.barfunc 由于库不知道我的“改进”,我必须以某种方式将libname.c.foofunc转换为libname\u foofunc,同时保留正确的外部链接、目标名称损坏和调用约定 假设有

我正在将用C编写的第三方库API翻译成D。该库导出了许多名为
libname\u foofunc
libname\u barfunc
等函数,这是C库防止全局命名空间膨胀的预期。由于D比C更模块化,我想提供更多的D'ish接口并去掉函数前缀,因此函数看起来像
libname.C.foofunc
libname.C.barfunc

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

假设有方法(我也不知道)告诉链接器,外部未解析符号
\uuu imp\uuu D1c7foofuncFZi
对应于
\u libname\u foofunc
libname>_foofunc@0
(尽管我不得不用手弄脏姓名),但告诉D什么是呼叫约定仍然有问题

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

那么,在D中是否有方法以与导出时不同的名称导入外部函数?

我曾经考虑过在函数的原始名称下“按原样”导入函数,然后将它们别名为无前缀的类似物,但这似乎相当笨拙。

您可以使用

alias libname_foofunc foofunc;

这将使
libname\u foofunc
保持可见,但允许您使用
foofunc
,编译器将其转换为
libname\u foofunc
,考虑到OT的最后一段,答案是否定的。没有其他语言也可以这样做,就像您描述的那样,而且不应该这样做。如果API设计人员希望以您喜欢的方式拥有函数名,他们会以这种方式公开它们

现在想象一下,A组的开发者更喜欢
someFunction()
,B组的开发者更喜欢
someFunction()
,C组的开发者更喜欢
someFunction()


别名是必须的,无论您使用的是D还是其他。应该是这样的。API应该简单、简洁、易于理解。

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

  • 为D代码中的函数设置别名。您可以将别名放在列出符号的任何模块中(因为您必须在D中声明它们)。然后,您的代码可以使用原始名称或别名。我看不出有什么笨拙的地方

  • 创建包装函数(C或D),并让您的D代码使用它们

  • 化名肯定会更好。它们不引入任何开销,也不太复杂


    但是不管怎样,当使用D中的C库时,通常要做的就是使用C函数名。您正在调用C函数,这一事实不应该被隐藏。它们不是D函数,行为也不一样(即使它们很相似)——特别是当涉及到谁拥有传递给函数的内容的内存时。更名它们的好处值得商榷。通常情况下,当编写一个D包装器来为API提供一个更干净、更像D的API(而不仅仅是更改名称)时,C函数就不再直接使用了。在火卫一中,一个很好的例子是etc.c.curl与std.net.curl。etc.c.curl纯粹是c API,不尝试重命名任何东西。它不会创建任何别名来使符号匹配火卫一的命名约定或使它们更像D。它本质上只是curl头文件的D版本。另一方面,std.net.curl构建在它之上,以提供更像D的API和抽象。它不仅仅是重命名C函数。

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

    struct libname
    {
        struct C
        {
            static int libname_foofunc();
            alias libname_foofunc foofunc;
        }
    
        static C c;
    }
    
    void main()
    {
        libname.c.foofunc();
    }
    

    我在问题的最后一段提到了这种临时解决方法。哦,这个技巧看起来很巧妙——我可以将它声明为静态结构,所以在
    静态C
    中就不需要了。。。非常好,谢谢!是的,我没想过让定义是静态的。我不知道这是什么时候开始起作用的。另外,gshared应该是静态的,gshared不会对函数声明做任何类似的操作。