为什么 LINK.EXE 需要一个 .EXP 文件来适应 .DLL 文件之间的循环依赖?

Why does LINK.EXE need a .EXP file to accommodate circular dependencies among .DLL files?

注意: .LIB 的所有情况都指的是 link.exe 导入库,而不是目标文件集合。

我花了很长时间弄清楚如何适应 Windows 中 .DLL 文件之间的循环依赖关系。这是因为我正在使用一个 makefile,它在循环依赖的共享库中有未解决的外部问题。我认为我需要更多地了解 linker...

我要回顾一下,因为它很容易忘记。不仅如此,我对 linking in Windows 的理解很有可能存在问题。任何更正都会有所帮助。

为了这个问题,我有3个文件:exec.objone.objtwo.obj.

场景:

  1. one.obj 包含在 two.obj 中定义的符号,并由 [ 处理=85=] 作为.DLL。
  2. two.obj 包含在 one.obj 中定义的符号,并由 [ 处理=85=] 作为.DLL。
  3. exec.obj 包含在 one.obj[=88= 中定义的符号] 并由 link.exe 作为 .EXE 处理。

一个常见的循环依赖问题:

当one.obj被link.exe处理时,会创建one.dll和one.lib(导入库)。 one.lib 的目的是描述在 one.dll.

中找到的导出符号的位置

在当前这个时间点,one.dll 无法从 two.obj 导入符号,因为 two.obj 还没有被 link.exe 处理,所以 two.lib (导入库)还不存在。因此,one.dll 包含对 two.obj 中定义的符号的未解析引用。

就像one.obj一样,当two.obj被link.exe处理时,它会创建一个导入库(two.lib)和two.dll。但是,two.obj 实际上可以通过查看 one.lib 内部找到它自己未解析的引用。此时,one.dll 有未解析的引用,而 two.dll 没有。无论哪种方式,exec.obj 在处理时都会有未解析的引用。

常见的循环依赖解决方案:

问题是,每当您尝试将 link one.obj 作为 .DLL 时,它会搜索未解析的引用,将 one.obj 转换为 .DLL 并创建相应的 one.lib(导入库)都在同一个步骤中。该步骤完成后,再搜索任何其他未解析的引用就太晚了,因为 one.obj 现在是 one.dll.

解决方案是分解步骤。创建相应的导入库(one.lib)而不将one.obj变成one.dll。这将允许 one.obj 稍后由 link.exe 处理,因此当 two.obj 最终被 linked 时不会禁用它使用 two.lib 的能力。

问题:

当使用 lib.exe 在它自己的单个步骤中创建相应的导入库 (one.lib) 时,会创建另一个名为 one.exp 的文件。我不明白为什么有必要。如果 one.obj 仍然存在,它可以在处理 two.obj 时在 two.lib 中找到它的未解析引用。但是,根据我的阅读,有必要在最后一步中包含 one.exp 。 不仅要处理 one.obj 并让它找到 two.lib,one.exp 还必须添加到 link.exe 的文件列表中。为什么? two.lib 已经描述了 one.obj 所需的符号,而 two.exp 从来不需要处理 two.obj。

您必须将时钟倒回到 80 年代后期,回到使用 linker 的 /DEF 或 /EXPORT 选项指定导出的时候。他们使第二个 link 的步骤变得脆弱 one.dll,当你不使用 exact 相同的选项时,你会大吃一惊。通过 linking one.exp 和省略选项来避免,现在不再可能弄错它们并且 linker 不会重写 one.lib

不再很相关,现在几乎每个人都使用 __declspec(dllexport) 属性来指定导出。在那种情况下,当你没有 link one.exp 时,我看不到明显的失败场景,除了 one.lib 文件日期比 two.dll 更新并导致重建不必要地。不太确定,我从来没有像这样陷入困境。