9

我正在使用 VS 2017 在调试模式下构建我的应用程序。我已经在发布模式下构建了它所依赖和链接的第 3 方库。这是允许的还是报告错误的原因。

LNK2038 mismatch detected for 'RuntimeLibrary': value 'MT_StaticRelease' doesn't match value 'MTd_StaticDebug' in xxx.obj   my-application  <path-to>\libboost_filesystem-mt-s.lib(path_traits.obj) 1   

页面指出:

RuntimeLibrary 指示应用或库使用的 C++ 标准库和 C 运行时的版本。使用一个版本的 C++ 标准库或 C 运行时的代码与使用不同版本的代码不兼容。有关详细信息,请参阅 /MD、/MT、/LD(使用运行时库)。

我了解 DLL 运行时库不能与非 DLL 库混合使用。调试和发布库是否也是如此?

我在 Linux 上做同样的事情没有任何问题。

4

1 回答 1

5

不,您不能将调试和发布运行时库与 Visual Studio 2017 混合使用。它们与 ABI 不兼容。

在 C++ 运行时中有用于调试检查的额外检查和成员变量,并且内存分配例程会在调试模式下增加额外的空间和检查。

示例代码取自<xmemory0>( _Adjust_manually_vector_aligned)

    // Extra paranoia on aligned allocation/deallocation; ensure _Ptr_container is
    // in range [_Min_back_shift, _Non_user_size]
  #ifdef _DEBUG
    constexpr uintptr_t _Min_back_shift = 2 * sizeof(void *);
  #else /* ^^^ _DEBUG ^^^ // vvv !_DEBUG vvv */
    constexpr uintptr_t _Min_back_shift = sizeof(void *);
  #endif /* _DEBUG */
    const uintptr_t _Back_shift = reinterpret_cast<uintptr_t>(_Ptr) - _Ptr_container;
    _STL_VERIFY(_Back_shift >= _Min_back_shift && _Back_shift <= _Non_user_size, "invalid argument");

这里_DEBUG函数的变体分配了额外2 * sizeof(void*)的检查,而发布变体只使用sizeof(void*).

从这里很明显,由发布变体创建并由调试变体使用的指针(反之亦然)会触发各种混淆和错误检查。

因此,链接器错误可以防止这种情况发生。


也就是说,可以在特定情况下混合使用它们,尽管我不建议这样做。

您基本上必须创建两个分区,它们具有非常紧密和狭窄的界面。您必须确保除了POD 或完全不透明的数据类型之外没有任何类型的数据在“分区”之间传输。此外,您不能将调试库和发布库(因为 ABI 和符号冲突)静态链接到同一个二进制文件。

因此,您可以在“调试”例程中创建一个std::string,但不允许将其传递给“发布”例程。但是你可以将'std::string::c_str()'返回值传递给'Release'例程,因为那只是一个指向char的指针。

为此,您可以将所有“发布”二进制文件放在一个 DLL 中,并将此 DLL 与静态“发布”运行时静态链接,并将所有“调试”二进制文件放在另一个 DLL(或 EXE)中,并将其与“调试”运行时静态链接. 这样,运行时就完全隐藏在它们各自的 DLL 中,并且对外界不可见。

可以将一个或多个 DLL 与静态运行时链接,将其他 DLL 与动态运行时链接。但同样,我不推荐它)。

基本上,当您在 Windows 下运行“调试”应用程序时,就会发生这种情况。您不需要“调试”窗口来运行“调试”应用程序。您的“调试”应用程序在使用自己的“发布”运行时的“发布”Windows 上运行良好。只是 Windows 使用的“发布”运行时完全隐藏在您的“调试”发布时间之外。

于 2022-02-12T18:00:27.110 回答