Delphi链接器和C++链接器的区别

Posted

技术标签:

【中文标题】Delphi链接器和C++链接器的区别【英文标题】:Difference between Delphi linker and C++ linker 【发布时间】:2012-10-12 06:35:20 【问题描述】:

我来自 Delphi 世界,在那里静态导入 DLL 函数非常容易。您需要做的就是指定函数名称和模块,如下所示:

function GetTickCount : DWORD; stdcall; external 'Kernel32.dll';

为什么在 C++ 中我必须使用kernel32.lib 来导入函数?为什么我不能像在 Delphi 中那样简单地告诉链接器导入该函数?

我知道这对你们中的许多人来说可能听起来很无聊,但是从 Delphi 进入 C++ 世界确实会让人感到困惑。

【问题讨论】:

这真的是历史。在 C 和 C++ 世界中,它总是这样做的。用于从 DLL 导入函数的 .lib 文件包含导入存根。 Delphi 方法让编译器生成这些存根。实际上,根据您接受的答案,它与序数与命名导入绝对无关。一些简单的实验可以证实这一点。 这里有一个类似的问题:***.com/questions/6957061/… 事实上它几乎是这个的重复 欢迎来到 C 世界,一切都比需要的复杂得多 【参考方案1】:

C++ 工具链需要几个步骤来完成 Delphi 可以一步完成的工作。在 C++ 中声明外部 DLL 函数时,没有(标准)方法来指示该函数实际上可以在哪个命名的 DLL 中找到。就编译器而言,声明的函数只是 extern 并且必须有一个链接器可以在某处找到的定义。

要将命名函数连接到可以在其中找到它的 DLL,C++ 工具链需要一个“导入库”,其中包含链接器知道如何处理的导入存根。当找到由导入存根定义的函数时,链接器为相应 DLL 中的特定函数名称创建一个 DLL 函数引用(由导入存根指示)。

在 Delphi 中,语言设计者允许程序员直接在源代码中指定关联的 DLL。 Delphi 编译器可以直接生成对外部 DLL 的引用,而无需使用导入存根步骤。

【讨论】:

我猜 C++ 确实需要对此进行更新 :)。谢谢你启发我。 @opc0de:作为独立于平台的语言标准,C++ 本身并不能做太多事情。 Delphi 始终是特定于平台的(包括 Linux 和 Windows)。 @phresnel 看看 free pascal 它是跨平台的 @opc0de:尽管必须将“Windows”和“Unix”以及其他操作系统添加到 C++ ISO 标准中。我猜,GameBoy 上的 Free Pascal 不会有 DLL 文件。更应该责备的是编译器供应商,他们必须使用#pragma 之类的东西来了解平台细节,而不是 C++ 本身:) @DavidHeffernan:感谢您的提醒,我已经尝试修改答案了。【参考方案2】:

您的问题实际上只是 Microsoft C++ 编译器 (MSVC) 的问题,它需要使用“导入库”作为将符号(即函数名称)绑定到动态链接库。这本身不是 C++ 问题。可以说这只是 MSVC 编译器的另一个烦人的怪癖,但我对这种方案的动机知之甚少,无法评论它是否应该或可以改变。如果我没记错的话,C++Builder 编译器也可以使用这种机制,模仿 MSVC。

大多数其他编译器在链接和二进制接口方面与 GCC 的工作方式(GNU 编译器集合)保持一致。而那些不需要这个额外的“导入库”,您只需将有问题的 DLL 指定为库的一部分即可与您的可执行文件链接。

顺便说一句,当谈到 C++ 链接器和 Delphi 链接器之间的差异时,您指出的这个问题只是冰山一角。它们在更深层次上是非常不同的。 C++ 标准几乎要求链接器相当简单(由于“单独的编译模型”),只是连接点,可以这么说,而在 Delphi 中,链接器与编译器的联系更加紧密,并且通常更智能(并且更快)。

【讨论】:

我正在将 Qt 与 MinGW 一起使用,我仍然需要以这种方式链接。也许有一种方法,我不知道。我会做一些研究。谢谢 @Mikael 你有什么文件可以支持吗?我对 gcc/g++ 的 Windows 端口的经验是,您仍然需要使用 MS 格式的 .lib 导入库。 @DavidHeffernan 在 MinGW 中,在处理 MS 生成的 DLL 时,您只需要 MS 样式机制,反之亦然(为 MinGW DLL 生成 MSVC 友好的库)。有像dlltoolreimp 这样的工具可以进行导入库的转换/创建。无论如何,链接不使用相同 C++ ABI 的 DLL 和 EXE 是一个非常糟糕的主意。使用与 C 兼容的 DLL 或来自 GCC / ICC / Clang 的 C++ DLL,链接器可以在没有导入库的情况下处理它们(参见 mingw.org/wiki/CreateImportLibraries)。 GCC 像处理类 Unix 操作系统中的共享对象一样处理 DLL。【参考方案3】:

我刚刚向 QC 提交了以下功能请求:

QC #109493: Add a compiler extension to import DLL functions without needing an import .lib file

【讨论】:

你把QC报告放在了现场测试版下吗? 不,我是在 XE3 RTM 下提交的,我不知道为什么它被标记为私有。

以上是关于Delphi链接器和C++链接器的区别的主要内容,如果未能解决你的问题,请参考以下文章

CSS系列之后代选择器子选择器和相邻兄弟选择器

在调试信息压缩标志的各种组合下,汇编器和链接器之间的压缩调试信息如何流动?

元素和选择器 伪类 选择器的优先级

链接问题 C++、glew 和 SDL

未命名的命名空间和 Visual C++ 链接器性能

后代选择器和子元素选择器的区别