为什么我们不能将调试和发布版本与 MSVC 混合使用?



我有一个常见的问题,这次我不想解决它,而是想了解这种设计选择的好处。我有15年以上的Linux/C++开发经验,在构建Windows应用程序方面遇到了困难。

我有一个与专有组件(Intel OneApi和Basler Pylon(链接的应用程序。我想调试我的应用程序,但我无法在调试模式下编译代码,因为专有组件不为其库提供调试构建。

在Linux上,我可以混合使用任何库;发布和调试。我甚至可以混合使用不同编译器版本构建的库,只要ABI在不同版本之间不发生变化。

如果我不能在使用MSVC的Windows上以调试模式构建应用程序,那么我应该如何调试它们?

如果官方推荐是";只要写好代码";方法,那么这种限制有什么令人难以置信的好处呢?库的运行速度快2倍吗?它占用的存储空间是原来的10倍吗?

可笑的是,即使在Windows上,MinGW也允许混合调试和发布库,但专有库是用MSVC构建的。

感谢您的真知灼见。

在MSVC下,STL的ABI在发布模式和调试模式之间是不同的。一类区别是调试模式下类型中的附加私有成员,以添加各种运行时检查和元数据。但也存在其他类别的差异。(示例(

我甚至不希望我自己的类型在MSVC下的Release和Debug模式之间是ABI兼容的,除非我用一堆#pragma精细地控制布局(当然,我的头中没有使用STL(。这是因为我希望MSVC的设计者不必努力使调试和发布模式构建的ABI兼容,因为他们已经彻底破坏了STL的兼容性。

我很惊讶地听到你的报告,无论你在Linux下使用什么编译器,情况都不是这样。在像我这样的C++MSVC用户中,他们的理解是调试构建的一半意义在于额外的运行时检查和元数据。也许你在谈论C二进制文件,或者具有extern "C"接口的C++二进制文件——这两种IIRC在Linux上比具有C++ABI的二进制文件更常见?(当然,如果您通过不透明指针或其他尝试的解决方法发送STL类型,即使后者在与其他模式的二进制文件混合时也会在运行时爆炸。(

正如您可能知道的那样,除非工具链供应商明确表示不这样做,否则您无法安全地将二进制文件与由不同工具链(甚至是同一工具链的不同版本(生成的C++ABI链接起来。这是因为函数调用如何在布局和机器指令级别工作的细节从未像对C那样对C++进行过常规化。这就是为什么:

  • C是本地编程的通用语言
  • C++二进制文件的发布者通常通过extern "C"给它们一个C ABI

所以,我对你的问题感到惊讶的原因是,如果你在看一个带有C++ABI的二进制文件,通常你:

  • 已经可以访问其源代码,并且可以在您需要的任何模式下轻松生成新的构建(例如开源或您自己的二进制文件(;或
  • 发布者发布了其二进制文件的发布和调试模式版本,通常用于多个工具链(例如Qt(的多个版本

我见过的唯一例外是工程行业——我记得西门子发布了一些高级CAD软件,你只需要使用他们使用的MSVC的主要版本,这意味着当你升级到MSVC的新版本时,你必须升级到他们软件的新版本,反之亦然。

最新更新