如何使用基于 Qt 的依赖项来组织 Qt DLL

Posted

技术标签:

【中文标题】如何使用基于 Qt 的依赖项来组织 Qt DLL【英文标题】:How to organize Qt DLLs with Qt-based dependency 【发布时间】:2013-10-29 19:09:20 【问题描述】:

我有一个使用 Qt 4.8.5 的 Qt 应用程序。此应用程序依赖于使用 Qt 4.6.0 构建的 DLL。我们称之为“MyDLL.dll”。

我无法重建 MyDLL.dll 以将其更新到更新的 Qt 版本。由于我的应用程序和 MyDLL 都需要 QtCore 和其他 DLL,并且版本不同,我如何组织我的文件以使它们不冲突?

MyDLL 在启动时是必需的,所以我不能使用任何延迟加载方法。

编辑:需要明确的是,出现这个问题是因为 MyDll.dll 是使用来自修改后的源的自定义 Qt 4.6.0 构建的,而我的应用程序使用的是 4.8.5 的自定义构建。两个版本的修改不一定相同,所以我不想假设我仍然可以使用 4.8.5 DLL。原来在这种情况下它成功了,但问题仍然存在。

【问题讨论】:

Qt 在次要版本中保持二进制兼容性,因此您应该能够将 MyDLL.dll 与 Qt 4.8.5 一起使用。你试过了吗? 我没有,实际上,你说得对,应该有二进制兼容性——这是 Qt 最棒的事情之一。我想我过分简化了我的问题。它完全让我感到困惑,Windows 不允许可执行文件指向特定的 DLL 子目录。 Windows 确实允许这样做。首先它在可执行文件的目录中搜索 DLL,然后是当前工作目录,然后依次搜索系统目录和 PATH(参见msdn.microsoft.com/en-us/library/vstudio/7d83bc18.aspx)。如果您需要覆盖 PATH 中的 DLL 版本,请将它们放在与可执行文件相同的目录中,或者在运行程序之前将当前工作目录设置为 DLL 所在的任何子目录(例如,在快捷方式中),但是您无论如何都不需要这样做。你会没事的,这里没有“DLL Hell”或其他任何事情。 在资源管理器 GUI 中,当您创建快捷方式时,如果您右键单击并选择“属性”,“启动目录”设置会指定初始工作目录。要自动执行此操作,这取决于您的安装程序(例如,Nullsoft 的 NSIS 安装程序系统具有创建应用程序快捷方式的命令,快捷方式的工作目录是参数之一)。可以通过编程方式创建快捷方式 (msdn.microsoft.com/en-us/library/windows/desktop/…),最简单的选择是使用您的安装程序。 但是,请注意,如果将 DLLs 放在可执行文件的目录中不够,并且您发现自己不得不对当前工作目录和 PATH 进行一些技巧,则可能存在一个更大的问题,您应该先退后一步检查。只有在非常奇怪或不幸的情况下,您才有理由将自动加载 DLL 放置在不寻常的地方。您使用 Qt 和您的自定义 DLL 描述的情况既不奇怪也不不幸。保持简单。 【参考方案1】:

您应该没有任何问题。 Qt 在次要版本和补丁版本上保持二进制兼容性(请参阅http://qt-project.org/wiki/Qt-Version-Compatibility),并且使用 4.6.x 构建的应用程序/DLL 在绑定到 4.8.x 运行时时可以正常运行。

您使用 4.6.0 构建的 MyDLL.dll 将与 4.8.5 运行时 DLL 一起运行。 使用 4.8.5 构建的应用程序将使用 4.8.5 运行时 DLL 运行。 只要您使用一直以来使用的同一个界面,您的应用程序就可以通过 MyDLL.dll 正常运行。

如果您发现问题是因为其他原因,您需要明确说明您遇到了什么问题。

如果您没有发现问题而只是先发制人地询问,那么 1) 照常进行,没有特殊考虑,2) 您应该先尝试一下!

【讨论】:

我本身并没有遇到任何错误,而是预料到混合 Qt 版本可能导致的问题。我也讨厌在我的 bin 目录中有大量 DLL,并希望有办法解决它,因为我在 MyDLL 之上还有其他几个依赖项。 只要你不混合主要版本就不会有问题(例如 Qt 4.x 和 5.x 不会混合 - 你被锁定到 4 .x). 我认为这是我问题的正确答案。尽管另一个答案以更详细的方式解决了 DLL Hell 的问题,但这不是当前的问题。【参考方案2】:

欢迎来到 DLL 地狱! :(

这在 Microsoft Windows 下是一个大问题,因为标准不是将版本信息构建到 DLL 文件名中(就像 Linux .so 文件一样)。

如果您直接链接到“MyDLL.dll”,您将无法完成您所追求的目标,因为它将寻找 QT DLL(如 QtCore、QtGui 等)。库存的 Qt DLL 在文件名中不包含版本修饰,因此在加载哪个版本时会有冲突。此外,您可能一开始就无法正确链接(由于冲突。Qt 不能很好地与旧版本配合使用)。

唯一的可能性可能是创建一个单独的可执行文件链接到 Qt 4.6.0 和 MyDLL,并在您的主应用程序和服务器之间使用一些进程外通信。 COM 在这种情况下可能会起作用,但这在很大程度上取决于您的 dll 实际执行的操作。

唯一的其他做法是降级您的主应用程序并将其修复到 Qt 4.6.0。

【讨论】:

两件事:.so 文件有同样的问题(通常是共享库的结果),Windows 只是鼓励通常糟糕的 DLL 组织。版本信息嵌入在 DLL 中,并且通常由供应商作为 DLL 中的函数提供,只是通常被应用程序忽略。但无论如何,Qt 保持跨版本的二进制兼容性,OP 不应该有任何问题。 确实,DLL 中内置了版本信息,但如果您使用导入库进行链接并且没有动态加载 dll,这对您没有多大帮助。但是,关于向后兼容性的好处。看看他实际收到了什么错误消息会很有趣。 顺便说一下,Qt 出于这个原因在 DLL 文件名中嵌入了主要版本号。您描述的问题是有效的,但不适用于 Qt 运行时或 OP 的问题。你知道这一点,我只是指出它是因为我不希望 OP 走上 DLL 偏执狂的道路。 :) 我们需要更多关于他所看到的问题的信息;理论上应该没有任何问题。 是的,它嵌入了主要版本 (4),但没有嵌入次要版本或发行版,目前这对他没有帮助。我同意我们需要更多信息。 次要版本和发布版本是二进制兼容的,这就是它只嵌入主要版本的原因。 Qt for Windows 的开发人员提供的保护与许多(但不是全部)开发人员在他们的 .so 中提供的保护完全相同。【参考方案3】:

Jason C 的回答是正确的。还要注意以下几点:

    MyDll.dll 必须使用与应用程序其余部分相同的编译器版本进行编译。

    用于构建 MyDll.dll 的 Qt 版本应该与您当前使用的 Qt 版本具有相同的主要配置标志。 Qt 命名空间、QThread 支持等都必须相同。

【讨论】:

以上是关于如何使用基于 Qt 的依赖项来组织 Qt DLL的主要内容,如果未能解决你的问题,请参考以下文章

如何用Qt自动拷贝exe依赖的dll

C++、Qt - 如何摆脱 dll 依赖项?

如何判断一个 exe 是不是依赖于某些 Qt 图像格式的 dll?

如何使用 .dll 注入覆盖 Qt 成员函数

在非 Qt 应用程序中使用基于 Qt 的 DLL

QT5程序发布dll依赖