【问题标题】:Prevent mixing debug and release libraries防止混合调试和发布库
【发布时间】:2011-10-12 08:59:11
【问题描述】:

作为库开发人员,我想防止我的库用户(Windows、MSVC)链接到错误的配置(不要将调试库链接到他们的发布程序,反之亦然)。

是否可以在编译时警告用户他应该链接到库的正确配置?

编辑

调试和发布版本都应该可用,以允许 Windows 开发人员调试他们的应用程序。所以我的库的调试和发布版本都应该可用。

我之所以问这个问题,是因为对 Windows 初学者开发人员的很多支持是由于他们混合调试和发布代码,以及出现难以调试的运行时错误。

【问题讨论】:

  • 您为什么希望您的客户调试您的库?你提供源代码吗?设计您的 API,使编译器设置无关紧要。 COM ABI 就是一个很好的例子。
  • 如果您创建静态库而不是 dll,则必须以任何方式添加调试版本。否则根本没有人能够创建调试版本。

标签: c++ visual-c++


【解决方案1】:

好问题,我一直认为使用我的库的开发人员会链接到正确的版本。现在我想了想,你为什么还要向公众发布你的调试库呢?为什么它们的调试版本和发布版本都不应该链接到您的发布库?

无论如何,我看到了一种通过在每个配置中导出一些符号来做到这一点的方法:

//header:
class DLLIMPEXP Dummy
{
   static int x;
   virtual void dummy();
}
//cpp
#ifdef DEBUG
int Dummy::x = 0;
void Dummy::dummy()
{
}
#endif

如您所见,只有在 DEBUG 中编译您的模块时,您的符号才会被导出。尝试从第三个模块以发布模式链接 lib 将导致链接器错误。对于相反的情况,你可以有类似的东西。

我不建议你这样做,我宁愿记录它或只分发我的模块的发布版本。

【讨论】:

  • 很有趣。你让我想到了:添加将在库中的非内联函数 IsReleaseVersion()。并在构造函数中添加内联检查(将包含在应用程序端)以检查其版本。
  • 我刚刚编辑了这个问题来回答你的一些问题。只有当用户尝试在自己的代码中使用该符号时,这才会触发链接错误。此外,我希望用户得到一个明确的信息,告诉他们“你没有链接到正确的库”。
  • @Mourad:您可以将缺少的符号命名为 PleaseUseReleaseVersionOfXxxLibrary,也可以命名为 PleaseUseDebugVersionOfXxxLibrary。
  • @Mourad 静态成员呢?那行得通吗?您无法收到明确的消息,但您可以将成员重命名为“heyManQuitUsingTheDebugLibraryForTheReleaseVersion”...
【解决方案2】:

这里有两个不同的方面:

  • 不兼容问题
  • 性能问题

如果是性能问题,那么选择仍然应该是他们的,他们可能希望调试。

如果是不兼容的问题,一件简单的事情是更改调试版本的命名空间,以便对符号进行不同的修改。

#ifdef NDEBUG
  namespace project {
#else
  namespace project { namespace debug {
#endif

// content

#ifdef NDEBUG
  }
#else
  }
  using namespace debug;
  }
#endif

通过嵌套在 debug 命名空间中,您可以更改符号的排列方式(即使在编译方面,它不会改变任何内容)。这实际上可以防止链接针对调试版本编译的库与发布版本(从而尽早解决不兼容问题,而不是神秘地崩溃)。

但是,我强烈建议您将其保留给一组非常具体的课程(它很重)。

通常应该能够在调试和发布模式下提供兼容的接口,以便客户端可以在加载时进行热插拔。

【讨论】:

    【解决方案3】:

    您可以添加#warning 指令,但我强烈建议您不要这样做。 您最好使用两个不同的名称交付到不同版本的库。

    这里是您的问题的另一个提示:

    myLib.h  // Release Version
    myLibd.h // Debug Version
    

    这样做会迫使用户在使用您的库设置应用程序时小心(因为设置必须是手动的)。

    您还可以在 README 或 INSTALL 中添加注释,大多数用户在想要在 MSVC 上设置链接时都会阅读它。

    您还可以检查程序中的 DEBUG 和 NDEBUG 宏值。 (在库初始化期间使用断言。

    【讨论】:

      【解决方案4】:

      将此代码添加到您的库的标题中

      不同类型的不同名称

      #ifndef _DLL
      // C runtime as dll
      #  ifdef _DEBUG
      #    pragma comment(lib, "MyLibD.lib")
      #  else
      #    pragma comment(lib, "MyLib.lib")
      #  endif
      #else
      // C runtime statically
      #  ifdef _DEBUG
      #    pragma comment(lib, "MyLibSD.lib")
      #  else
      #    pragma comment(lib, "MyLibS.lib")
      #  endif
      #endif
      

      不同类型的不同路径

      #ifndef _DLL
      // C runtime as dll
      #  ifdef _DEBUG
      #    pragma comment(lib, "debug/dynamic/MyLib.lib")
      #  else
      #    pragma comment(lib, "release/dynamic/MyLib.lib")
      #  endif
      #else
      // C runtime statically
      #  ifdef _DEBUG
      #    pragma comment(lib, "debug/static/MyLib.lib")
      #  else
      #    pragma comment(lib, "debug/static/MyLib.lib")
      #  endif
      #endif
      

      之后,您只需将 lib 的路径添加到链接器中,您就无法再将其混淆。

      【讨论】:

      • 这通常不是好的做法(在代码中指定库),但它是一个解决方案,所以我不会反对。
      • 如果你开发的是静态库而不是 dll,我总是更喜欢这个。有这么多优点和避免的错误,我不会因为哲学原因而在意。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-03
      • 2019-09-09
      • 2011-05-07
      • 2012-07-24
      • 2013-06-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多