STL和发布/调试库混乱

时间:2011-01-21 21:37:35

标签: c++ linux gcc shared-libraries

我正在使用第三方。我正在使用它的共享库版本,因为库很大(~60MB)并且被多个应用程序使用。

在应用程序启动时是否有办法发现库的发行版/调试版分别用于我的应用程序的发布/调试版本?

更长的说明

公开C ++接口的库。其中一种API方法返回std::vector<std::string>

在调试模式下编译应用程序时的问题,应该使用库的调试版本。同样的发布。如果使用了不正确的库版本,应用程序将崩溃。

根据gcc(见http://gcc.gnu.org/onlinedocs/libstdc++/manual/bk01pt03ch17s04.html

  

但使用混合模式标准库   这可能是使用调试模式   或release-mode basic_string对象,   事情变得更复杂

P.S。 1

看起来Timbo的提议是一种可能的解决方案 - 使用不同的soname来调试和发布库。那么,应该将什么传递给./configure脚本来更改库的名字?

P.S。 2

我的问题不是在链接时,而是在运行时。

P.S。 3

Here是我正面临的问题。

4 个答案:

答案 0 :(得分:7)

引用here的调试模式 nothing 与应用程序的调试或发布版本有关。 STL调试模式使用-D_GLIBCXX_DEBUG激活,是一种特殊的检查模式。

第三方库实际上不太可能使用STL检查模式进行编译,但如果是,则很可能会很快提及您的代码也应该使用-D_GLIBCXX_DEBUG进行编译。

如果第三方库没有使用检查STL构建,那么无论您是在进行优化还是调试构建,它都与您的代码兼容。

由于您声明与第3方库的优化版本链接的代码的调试版本导致崩溃,因此该崩溃很可能是由代码中的错误引起的(或者可能是第3方库中的错误)。

Valgrind和GDB是你的朋友。

答案 1 :(得分:5)

我认为您误读了您提供的链接中的文档。特别是,您误解了其目的 - 该部分名为“目标”,并描述了C ++调试库的一些假设设计以及这些设计的后果,以便解释所做出的实际设计选择。您引用的行后面的文本位描述了由假设实现产生的混乱,该实现具有针对发布模式和调试模式字符串的单独设计。它继续说:

  

因此,我们无法轻松地为std :: basic_string类模板提供安全的迭代器,因为它存在于整个C ++标准库中。

(或者,改写一下,提供一个特殊的“调试”版本的字符串迭代器是不可能的。)

  

...

     

使用libstdc ++调试模式的设计,我们无法有效地隐藏用户的调试和释放模式字符串之间的差异。未能隐藏差异可能会导致不可预测的行为,因此我们选择仅执行不需要ABI更改的basic_string更改。对用户的影响预计会很小,因为有简单的替代方案(例如__gnu_debug :: basic_string),并且我们从混合调​​试和发布编译的翻译单元的能力中获得的可用性好处是巨大的。

换句话说,GCC的libstdc ++中的调试和发布模式的设计已经拒绝了这个假设的实现,并对字符串进行了单独的设计,特别是为了允许您担心如何避免的那种类型的跨模式链接

因此,如果没有-D_GLIBCXX_DEBUG(或者由于某种原因,如果您愿意的话)编译库,并且将其与应用程序的任一模式相关联,那么您应该没有问题。如果你确实有问题,那是因为某个地方出现了错误。 [但请看下面的编辑!这是std::string特有的,而不是其他容器!]

修改:在接受此答案后,我在std::vector<std::string> crash处回答了后续问题,并意识到此答案的结论不正确。 GCC的libstdc ++使用字符串来巧妙地支持“Per-use recompilation”(其中给定容器对象的所有使用必须使用相同的标志进行编译,但是在程序中使用相同的容器类不需要使用相同的方法编译flags),但这与提供所需交叉链接能力的完整“单元编译”不同。特别是,文档说明了这种交联能力,

  

我们认为,如果我们打算提供安全的迭代器,保持程序语义不变,并且在发布模式下不会降低性能,那么这种重新编译水平实际上是不可能的。

因此,如果您在库接口上传递容器,需要两个单独的库。老实说,对于这种情况,我发现最简单的解决方案就是将两个库安装到不同的目录中(每个变量一个 - 并且您希望两者都与主库目录分开)。或者,您可以重命名调试库文件,然后手动安装。

作为进一步的建议 - 你可能不经常在调试模式下运行它。可能只需要将调试版本静态编译并链接到您的应用程序中,因此您不必担心安装多个动态库并在运行时保持它们直接。

答案 2 :(得分:1)

为DLL的调试版和发行版提供不同的名称,并通过库依赖关系链接正确的版本。除非找到正确的DLL,否则您的应用程序将无法启动。

答案 3 :(得分:0)

这是您应该在构建系统中进行的检查。在您的构建脚本中,

  • 如果您正在构建发布版,则链接到发布库。
  • 如果您正在构建调试,则链接到调试库。

例如,如果您使用的是make:

release: $(OBJ)
    $(CC) $(CXXFLAGS_RELEASE) $(foreach LIB,$(LIBS_RELEASE),-l$(LIB))
debug: $(OBJ)
    $(CC) $(CXXFLAGS_DEBUG) $(foreach LIB,$(LIBS_DEBUG),-l$(LIB))