使用DEF文件而不是LIB文件链接DLL?

3

我了解到您可以:

  • 将.DLL文件转换为包含其导出函数的.DEF文件
    (注:这在许多约定中不起作用)
  • .DEF文件转换为.LIB文件,以便您可以使用它来链接到DLL

为什么(大多数)链接器不能仅使用.DEF文件而不是.LIB文件来链接DLL?

4个回答

5
最终的答案是“因为没有人真正需要它,而且它并没有真正帮助到任何事情”。 DEF文件是创建DLL导入库的输入文件。然后,当另一个链接使用DLL时,导入库本身就是一个输入。从外部看,导入库似乎是特殊的东西,但是当你看到里面时,它实际上只是一个具有对象的稍微特殊的库。修改链接器以直接接受DEF文件(或DLL)是完全可能的。但是,链接器的设计中心是将对象作为输入,并输出PE可执行文件。因此,将DEF或DLL作为输入超出了设计模式。除此之外,这将是毫无意义的 - 允许链接器以DEF文件或DLL作为输入既不会启用任何重要的新场景,也不会阻止任何事情。将您拥有的DEF文件(即使没有实际的DLL)转换为可用的导入库只需几分钟的工作(只需为每个DEF条目创建虚假的空函数并进行链接)。因此,没有理由添加直接链接DEF文件的功能。

确认你的观点,MinGW/GCC确实支持直接链接DLL。 (http://sources.redhat.com/binutils/docs-2.21/ld/WIN32.html) - Lumi

3
就MSVC而言,.lib文件始终是静态库。它们与所有已编译的.c/.cpp文件一起链接为编译单元,因此库中的所有代码都包含在最终的可执行文件中。
然而,某些.lib文件(特别是大多数Windows系统文件)仅包含存根,告诉操作系统在加载时加载所需的DLL,然后存根将函数调用路由到DLL。但是,这些存根确实被静态链接到您的可执行文件中。您的程序将使用DLL(并获得其中的所有优点和缺点),但由于它所需的命名DLL函数位于.lib中(因此实际上位于可执行文件本身中),因此您的代码不必知道它正在使用DLL(具体来说是使用declspec(dllimport))。
.def文件仅在创建.dll文件期间用作“设置”或“配置”文件,以指定文件应导出哪些函数。它不能链接,因为它并没有描述链接器理解的任何内容。

2
你不能将dll转换成DEF文件。DEF仅指示哪些dll函数可从外部访问,即被导出。
来自文档
DLL文件的布局与.exe文件非常相似,但有一个重要区别——DLL文件包含导出表。导出表包含DLL导出到其他可执行文件的每个函数的名称。这些函数是DLL的入口点;只有导出表中的函数可以被其他可执行文件访问。DLL中的任何其他函数都是私有的。使用DUMPBIN工具的/EXPORTS选项可以查看DLL的导出表。
您可以使用两种方法从DLL中导出函数:
创建模块定义(.def)文件,并在构建DLL时使用.def文件。如果想按序号而不是按名称从DLL导出函数,则使用此方法。
在函数定义中使用关键字__declspec(dllexport)。
使用任一方法导出函数时,请确保使用__stdcall调用约定。
使用提供的链接了解有关从dll中导出的更多信息。
我认为你被投票否决,是因为你的观点不是很清晰,至少对我来说不是。还要检查这个。它解释了如何选择导出方法。

+1 谢谢你提供的信息;然而,你认为“你不能将dll文件转换成DEF文件”并不总是正确的。我有时会这样做(我也见过其他人这样做),有时是因为DLL文件没有可用的LIB文件。你可以争论说一开始就不应该使用DLL,但有时情况就是这样。 - user541686

1
Mehrdad,这并不总是关于如何链接到DLL的问题,因为我个人从未使用过.def文件来链接DLL。我所做的是获取别人的DLL,并非常费力地构建了一个头文件,或者说是函数原型,以便我可以在C中使用LoadLibrary(),在VB中使用Declare Function ... Lib "Foo.dll" Alias "OrdinalName",在C#中使用[DllImport()]
当然,这很少这样做,因为如果您正在使用DLL进行某些操作,通常您有权限这样做,并且作者会提供.lib和与二进制DLL文件配套的头文件。

我从未使用过你所说的确切技术,将 .DEF 转换为 .LIB 等等... 但是,我想从一个库或 DLL 中导出 .DEF 应该很容易。这个我实际上做过,在一个项目中,DLL 代码是用 vbScript 构建的,它从主项目中获取代码,并将所有现有、已编译和测试过的代码创建成 API。之所以要进行这种复杂的操作,是因为我不知道 DLL 中会有哪些函数,因为主项目随时可能发生变化,因此静态的 .DEF 文件永远不起作用。因此,我必须先构建 DLL,捕获 dimpbin /exports,取消装饰函数,然后构建 .DEF 文件并重新链接 DLL。

如果你发现自己处于这种情况下,也许你需要重新思考你的原始设计,并从那里解决问题...

至于 .LIB 文件,通常只有在需要静态链接时才需要,但当 .H 文件可用时,它们也会被使用,这通常使调试变得更加方便...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接