gpt4 book ai didi

c++ - 使用Visual Studios C++ list 文件

转载 作者:IT老高 更新时间:2023-10-28 12:41:45 25 4
gpt4 key购买 nike

我已经编写了一些代码,这些代码利用开源库来完成一些繁重的工作。这项工作是在Linux上完成的,并进行了单元测试和cmake,以帮助将其移植到Windows。要求它在两个平台上都可以运行。

我喜欢Linux,喜欢cmake,也喜欢我可以自动生成Visual Studio文件。就像现在一样,在Windows上,所有内容都将编译并链接,并生成测试可执行文件。

但是,为了达到这一点,我不得不与Windows斗争了几天,学习了有关 list 文件和可再发行软件包的所有知识。

据我了解:

借助VS 2005,Microsoft创建了并排dll。这样做的动机是,以前,多个应用程序将安装同一dll的不同版本,从而导致以前安装且正在运行的应用程序崩溃(即“Dell Hell”)。并排dll解决了此问题,因为现在在每个可执行文件/dll后面附加了一个“ list 文件”,用于指定应执行哪个版本。

这一切都很好。应用程序应该不再神秘地崩溃。然而...

Microsoft似乎在每个Visual Studio版本中都发布了一组新的系统dll。另外,正如我前面提到的,我是一个尝试链接到第三方库的开发人员。通常,这些东西以“预编译的dll”的形式分发。现在,当使用一个版本的Visual Studio编译的预编译dll链接到使用另一个版本的Visual Studio的应用程序时会发生什么?

根据我在互联网上阅读的内容,发生了坏事。幸运的是,我从没走过这么远-运行可执行文件时,我一直遇到“MSVCR80.dll not found”问题,因此开始涉足整个 list 问题。

我最后得出的结论是,使它起作用的唯一方法(除了静态链接所有内容之外)是,所有第三方库都必须使用相同版本的Visual Studio编译-即,不要使用预编译的dll-下载源代码,建立一个新的dll并改用它。

这是真的吗?我错过了什么?

此外,如果确实如此,那么我不禁会以为Microsoft出于恶意原因是故意这样做的。

它不仅会破坏所有预编译的二进制文件,从而使使用预编译的二进制文件变得不必要地困难,如果您碰巧在使用第三方专有库的软件公司工作,那么每当它们升级到Visual Studio的最新版本时,您的公司都必须现在做同样的事情,否则代码将不再运行。

顺便说一句,Linux如何避免这种情况?尽管我说我更喜欢开发它,并且了解链接的机制,但是我还没有维护足够长的应用程序来遇到这种低级共享库版本控制问题。

最后,总结一下:是否可以在这种新的 list 方案中使用预编译的二进制文件?如果是的话,我的错误是什么?如果不是,Microsoft是否诚实地认为这使应用程序开发更容易?

更新-一个更简洁的问题: Linux如何避免使用Manifest文件?

最佳答案

应用程序中的所有组件必须共享相同的运行时。如果不是这种情况,则会遇到一些奇怪的问题,例如对delete语句进行断言。

在所有平台上都是一样的。这不是微软发明的东西。

通过了解运行时可能在何处咬回,可以解决“仅一个运行时”问题。
这主要是在您在一个模块中分配内存,然后在另一个模块中释放内存的情况下。

a.dll
dllexport void* createBla() { return malloc( 100 ); }

b.dll
void consumeBla() { void* p = createBla(); free( p ); }

当a.dll和b.dll链接到不同的rumtime时,这会崩溃,因为运行时函数实现了自己的堆。

您可以通过提供destroyBla函数轻松地避免此问题,该函数必须被调用以释放内存。

在某些情况下,您可能会遇到运行时问题,但是可以通过包装这些构造来避免大多数问题。

以供引用 :
  • 不要在模块边界上分配/释放内存/对象
  • 不要在dll界面中使用复杂的对象。 (例如std::string,...)
  • 不要跨dll边界使用复杂的C++机制。 (typeinfo,C++异常,...)
  • ...

  • 但这不是 list 的问题。

    list 包含模块使用的运行时的版本信息,并由链接程序嵌入到二进制文件(exe/dll)中。加载应用程序并解决其依赖项时,加载程序将查看exe文件中嵌入的 list 信息,并使用WinSxS文件夹中相应版本的运行时dll。您不能仅将运行时或其他模块复制到WinSxS文件夹。您必须安装Microsoft提供的运行时。 Microsoft提供了MSI软件包,可以在将软件安装到测试/最终用户计算机上时执行。

    因此,在使用应用程序之前安装运行时,您将不会遇到“缺少依赖项”错误。

    (已更新为“Linux如何避免使用 list 文件”问题)

    什么是 list 文件?

    引入 list 文件将歧义消除信息放置在现有的可执行文件/动态链接库旁边或直接嵌入到此文件中。

    这是通过指定启动应用程序/加载依赖项时要加载的dll的特定版本来完成的。

    (您还可以对 list 文件执行其他几项操作,例如,某些元数据可能会放在此处)

    为什么要这样做?

    由于历史原因,该版本不是dll名称的一部分。因此,“comctl32.dll”在所有版本中都以此方式命名。 (因此Win2k下的comctl32与XP或Vista中的comctl32不同)。要指定您真正想要(并经过测试)的版本,请将版本信息放入“appname.exe.manifest”文件中(或嵌入此文件/信息)。

    为什么这样做?

    许多程序将其dll安装到systemrootdir的system32目录中。这样做是为了使共享库的错误修正可以轻松地为所有相关应用程序部署。在内存有限的日子里,当多个应用程序使用相同的库时,共享库减少了内存占用。

    当所有程序员将所有dll安装到此目录时,此概念被许多程序员滥用。有时会用较旧的库覆盖新版本的共享库。有时,库的行为会悄无声息地发生变化,从而使依赖的应用程序崩溃。

    这导致了“在应用程序目录中分发所有dll”的方法。

    为什么这么糟?

    当出现错误时,必须更新分散在多个目录中的所有dll。 (gdiplus.dll)在其他情况下,这甚至是不可能的(Windows组件)

    list 方法

    这种方法解决了以上所有问题。您可以将dll安装在程序员可能不会干预的中央位置。在这里,可以更新dll(通过更新WinSxS文件夹中的dll),然后加载程序加载“正确的” dll。 (版本匹配由dll加载程序完成)。

    Linux为什么没有这种机制?

    我有几个猜测。 (这实际上只是猜测...)
  • 大多数事情都是开源的,因此对于目标用户来说,重新编译错误修复程序不是问题
  • 因为只有一个“运行时”(gcc运行时),所以不会发生运行时共享/库边界的问题,因此
  • 经常出现
  • 许多组件在接口(interface)级别使用C,如果正确使用
  • ,就不会发生这些问题
  • 在大多数情况下,库的版本嵌入在其文件名中。
  • 大多数应用程序都静态绑定(bind)到它们的库,因此可能不会发生dll-hell。
  • GCC运行时保持非常稳定的ABI,因此不会发生这些问题。
  • 关于c++ - 使用Visual Studios C++ list 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/588712/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com