我在 Windows 上遇到了 LoadLibrary 的一个奇怪问题。首先是一些背景。此应用程序依赖于 Qt,并且 Qt 被拆分为多个库。我正在尝试升级 Qt 的版本,但不会破坏任何人。较新的 Qt 库向后兼容旧的库。这意味着使用旧版本构建的应用程序可以在加载新版本时运行。反之则不然——如果加载了旧版本,使用新版本构建的应用程序将缺少符号。
Qt DLL 位于特定于版本的目录中(例如c:\qt\qt-4.5.2\lib
,c:\qt\qt-4.8.1\lib
作为示例)。大多数开发人员在他们的 PATH 中还有一个公共目录,其中包含我们使用的所有第三方库的“当前”版本(称为它c:\common\lib
)。这是运行应用程序时通常可以找到 Qt 库的地方。
我将新的 Qt 版本库放在公共位置,一切似乎都工作正常,除了一种情况。有问题的应用程序被拆分为多个库,其中一些是通过调用加载的LoadLibrary()
。其中一些运行时加载的 DLL 依赖于 Qt 库。在一种情况下,加载的 DLL 依赖于QtXml
,而后者本身又依赖于QtCore
.
这就是它变得奇怪的地方。应用程序依赖QtCore
并加载依赖于QtXml
. 应用程序和库是与旧版本的 Qt 链接构建的。如果此应用程序仅使用 PATH 中的公共目录运行,则一切正常,因为新的 Qt 版本 DLL 是从公共目录加载的。但是,如果 PATH 包含在公共目录之前存储旧 Qt 版本 DLL的目录,则加载运行时 DLL 会失败并丢失符号。
(在进行自动化单元测试时会出现这种情况,脚本显式设置 PATH 以使用特定的库版本。)
据我所知,应用程序正在加载旧版本,QtCore.dll
运行时加载的 DLL 正在(不知何故)加载新版本QtXml.dll
,因为已经加载QtCore
的没有它需要的符号,所以失败了。
但这似乎是不可能的,因为 PATH 类似于c:\qt\qt-4.5.2\lib;c:\common\lib
(加上其他不相关的路径)。如果我从公共 lib 目录中删除较新QtXml
的(不是用旧版本替换,只是删除它),然后LoadLibrary()
成功,因为它加载了所有 Qt 库的 4.5.2 版本。但这不是一个好的长期解决方案,因为在 PATH(常见)中没有 Qt 特定版本目录的情况下运行将无法找到QtXml
.
这怎么可能?如何LoadLibrary()
(或任何它递归调用以解决库的依赖项)从后面的PATH
? 我找不到任何表明公共库目录被特别考虑的东西(它不是一个设置的 DLL 目录)。在构建过程中没有提到它,它只是开发人员PATH
为了方便而拥有的东西。
顺便说一句,在 Linux 上存在类似的情况LD_LIBRARY_PATH
and dlopen()
,它在那里工作得很好。这是 Windows 正在做的不同的事情,我不明白。有没有人知道可能出了什么问题?