【发布时间】:2012-06-19 12:24:46
【问题描述】:
我在使用 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,而 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(加上其他不相关的路径)。如果我删除较新的QtXml 从公共 lib 目录(不替换为旧版本,只需将其删除),那么 LoadLibrary() 成功,因为它加载了所有的 4.5.2 版本Qt 库。但这不是一个好的长期解决方案,因为在 PATH(常见)中没有 Qt 特定版本目录的情况下运行将无法找到 QtXml。
这怎么可能? LoadLibrary()(或任何它递归调用以解决库的依赖项)如何从PATH 中的稍后 加载库?我找不到任何表明公共库目录被特别考虑的东西(它不是一个设置的 DLL 目录)。在构建过程中没有提到它,只是为了方便开发人员在他们的PATH 中提供的。
顺便说一句,LD_LIBRARY_PATH 和 dlopen() 在 Linux 上也存在类似的情况,它在那里工作得很好。这是 Windows 正在做的不同的事情,我不明白。有没有人知道可能出了什么问题?
【问题讨论】:
-
每个 DLL Hell 问题都是在您将 DLL 存储在一个公共目录中时产生的,在您开始依赖 PATH 环境变量时长大,并在您开始混合版本时使您的房子着火。不要共享 DLL。
-
在已安装的系统中,这不会是问题,因为构建版本将与应用程序位于同一位置。这实际上只是一个开发问题,可以同时使用多个版本的第三方库。
标签: c++ windows loadlibrary