我正在努力实现的长篇故事
我正在开发一个将 DLL 作为插件动态加载的程序。我正在使用 Microsoft Visual C++ 2008 编译程序。不过,我们假设应该支持 Qt 使用的任何 Visual C++ 版本。程序目录布局如下:
| plugins/
| plugin1.dll
| plugin2.dll
| QtCore4.dll
| QtGui4.dll
| program.exe
program.exe
发现所有插件 DLL 文件,对其执行 LoadLibrary() 并调用某个签名函数来确定它是否真的是插件。这在安装了 vcredist for MSVC90 的计算机上运行良好。自然,为了使程序在所有计算机上运行,我必须使用 msvc*.dll 文件和适当的清单文件重新分发它。Qt DLL 也需要 redist 才能运行。
现在,我已经将 cmake 设置为根据所选的 Visual Studio 版本自动复制适当的 redist DLL 和清单。为了简单起见,让我们继续假设我正在使用 MSVC90。当 redist 被复制到程序目录时,布局如下所示:
| plugins/
| plugin1.dll
| plugin2.dll
| QtCore4.dll
| QtGui4.dll
| msvcm90.dll
| msvcp90.dll
| msvcr90.dll
| Microsoft.VC90.CRT.manifest (I'm also aware that this file is bugged in VS2008)
| program.exe
关于清单文件中的错误:http ://www.cmake.org/pipermail/cmake/2008-September/023822.html
问题
具有这种布局的程序现在可以在没有安装 redist 的计算机上运行,但插件没有被加载。为了让插件加载,我必须执行以下操作之一:
- 将清单文件复制到
plugins/
目录。从清单文件中删除对 msvc*.dll 文件的所有引用。这行得通,但不是很好,因为我必须支持不同版本的已编辑清单文件,具体取决于使用的 MSVC 的版本。另外,我不知道这是否不会与 2008 年以外的 Visual Studio 中断。 - 将整个 redist 复制到
plugins/
目录。这不需要对清单文件进行任何修改,但现在program.exe
愚蠢地尝试加载 msvc*.dll 文件,认为它们是插件。自然,这会优雅地失败,因此不会造成太大的伤害。另一个缺点是程序包的大小增加了 1 MB 以上。不过,这两个问题都是我可以忍受的。 - 使用 /MT 开关编译插件。简短的测试表明这确实有效,但我不确定如果 Qt 和
program.exe
都是 /MD 将来它是否不会破坏任何东西。
问题
最好的解决方案是什么?什么是正确的解决方案?如果有多个正确的解决方案,那么最佳实践是哪个?我是第一个尝试这样做的人吗?
更新 1(2012 年 11 月 18 日)
虽然这个问题仍未得到解答,但我决定走最不让人头疼的路线。到目前为止,我一直在使用第 1 号解决方案,我决定坚持使用它。如果 CMake 检测到用户使用的 MSVC 版本与 2008 不同,它将显示一条警告消息,指出不完全支持自动打包。