如何避免Windows上多个CRT版本的问题(dll地狱重访?)

How to avoid problems with multiple CRT versions on Windows (dll hell revisited?)

本文关键字:地狱 dll 问题 Windows 何避免 版本 CRT      更新时间:2023-10-16

我很感激以前也有人问过类似的问题,但阅读这些问题时,没有一个能完全解决我们的问题,所以我想我会寻求任何见解。

[TL;DR]版本:

是否可以/容易地为VS2005 CRT创建一个填充程序dll,然后将所有调用委派给VS2013 CRT?

降级VS2013版本以便使用VS2005 CRT是否更容易?

还是这两种想法都很疯狂?

我们的情况:

我们的C++应用程序是使用现代版本的C++编译器构建的(VS2013,gcc 4.8取决于目标平台)-我们使用的一些依赖项将需要现代版本,因为它们使用C++11。

我们的应用程序还使用运行时链接(.dll或.so)来打包各种应用程序组件。

在windows上,为了简化生活,我们使用/MD(或/MDd用于调试)进行编译,即使用多线程版本在dll中使用CRT-我们构建的任何依赖项都会重新编译为使用相同的CRT。

对所有依赖项使用相同的CRT(在单独的dll中)意味着,如果在一个dll中分配内存并在另一个dll释放内存,则可以避免问题,因为使用了相同的堆。

我们的问题

我们有一个依赖项,它是由第三方提供的(我不会在这里点名羞辱他们,但你知道你是谁!),作为预编译的dll/so,而不是作为源。

这是在Windows上使用VS2005(MSVC8)编译的,并使用MSVC8 crt。

他们以前版本的这种依赖关系运行良好。他们对这个依赖关系的api正确地处理了内存的分配和取消分配,所以即使它使用的是与我们应用程序的其他部分不同的CRT版本,它也没有问题。

不幸的是,他们的新版本("改进"!)在他们的api中大量使用了C++模板——这些模板在我们的调用代码中扩展,并导致试图从我们的调用码中删除在其dll中分配的内存。由于这两个区域使用不同的堆,这是非常有问题的。

可能的解决方案:

为了解决这个问题,我们可以看到以下可能的解决方案

1] 让供应商重写(我们已经要求过了,这是一个长期的解决方案,但在一段时间内不会发生)

2] 让供应商使用VS2013重新编译,这样我们双方都有相同的CRT(只是显然不会发生——已经要求了)。

3] 我们的所有代码都使用VS2005CRT(我们不能简单地使用VS2005来构建我们的代码,因为我们需要C++11支持)

4] 对第三方dll所期望的VS2005 CRT进行填隙,即构建看起来像VS2005 CRT但实际上使用的是VS2013 CRT的东西。

5] 包装第三方dll-即构建一个用VS2005编译的dll,其中包含对第三方依赖项的所有调用-并提供正确的内存处理,使其与我们的其他(使用VS2013 CRT的)dll 一起工作

最后是问题:

选项5]可能是工作量最大的(但成功的可能性最大)——基本上是选项1],但在我们的控制之下,所以我们不必等待第三方。

不过,在采用这条路线之前,我想我会问一下其他人是否做过类似于3]或4]的事情,或者其他我们没有想到的解决方案。

选项4](构建一个填充版本的CRT)似乎可能是最简单的,因为我认为VS2013 CRT中已经完成了许多向后兼容性工作——这只是一个找出细节并将2005版本的调用转发到2013版本的例子——在许多情况下,我认为甚至签名都是相同的,所以只是一个简单的条目。

然而,当我在谷歌上查看时,我找不到任何人为CRT版本不兼容问题构建填充程序dll的例子——所以这可能比我想象的要困难得多(或者我的谷歌功能严重缺乏)。

所以我想我会问是否有人做过类似的事情/知道为什么这是一个非常愚蠢的想法吗?

没有合理的方法可以实现匀场。

破坏交易的因素是STL实现发生了变化,而这些都是模板。几乎可以肯定的是,DLL混合了对VS2005STL的内联和非内联调用。如果将VS2005换成VS2013 CRT,则它们的DLL将混合使用内联VS2005和非内联VS2013调用。这无疑是一场灾难。这是假设VS2013CRT甚至具有所需的非内联版本。

也就是说,您可以在代码中提供自己的newdelete。这些可以转发到相应的VS2005版本,您可以在运行时通过GetProcAddress检索这些版本。这可能也许就足够了——没有保证。