链接器无法找到符号,但它们在那里?

问题描述:

试图编译这个cfgparser example链接器无法找到符号,但它们在那里?

$ g++ example.cc -lcfgparser 
: In function `main': 
example.cc:(.text+0x6b): undefined reference to `ConfigParser_t::readFile(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)' 
example.cc:(.text+0x160): undefined reference to `ConfigParser_t::getValue(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*) const' 
example.cc:(.text+0x2d9): undefined reference to `ConfigParser_t::getValue(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int*) const' 
example.cc:(.text+0x43c): undefined reference to `ConfigParser_t::getValue(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, double*) const' 
example.cc:(.text+0x5b1): undefined reference to `ConfigParser_t::getValue(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool*) const' 
example.cc:(.text+0x78c): undefined reference to `ConfigParser_t::getValue(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >*) const' 
example.cc:(.text+0xa15): undefined reference to `ConfigParser_t::getValue(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*) const' 
example.cc:(.text+0xba2): undefined reference to `ConfigParser_t::getValue(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*) const' 
example.cc:(.text+0xd15): undefined reference to `ConfigParser_t::getValue(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*) const' 
example.cc:(.text+0xe7f): undefined reference to `ConfigParser_t::getValue(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*) const' 
collect2: error: ld returned 1 exit statu 

但显然这些符号有:

$ nm -gC /usr/lib/libcfgparser.so 
000000000003710 T ConfigParser_t::readFile(std::string const&) 
0000000000004880 T ConfigParser_t::ConfigParser_t(std::string const&) 
00000000000024c0 T ConfigParser_t::ConfigParser_t() 
0000000000004ad0 T ConfigParser_t::ConfigParser_t(std::string const&) 
00000000000024a0 T ConfigParser_t::ConfigParser_t() 
0000000000004d20 T ConfigParser_t::getOptions(std::string const&) const 
00000000000028d0 T ConfigParser_t::getSections() const 
0000000000002ff0 T ConfigParser_t::getValue(std::string, std::string, bool*) const 
0000000000002de0 T ConfigParser_t::getValue(std::string, std::string, double*) const 
0000000000002bd0 T ConfigParser_t::getValue(std::string, std::string, int*) const 
00000000000027d0 T ConfigParser_t::getValue(std::string, std::string, std::string*) const 
0000000000003500 T ConfigParser_t::getValue(std::string, std::string, std::vector<std::string, std::allocator<std::string> >*) const 

不像上的其他类似的问题,这是不是链接顺序,因为只有一个目标文件被链接。我错过了什么?

+1

我的猜测是,这两个模块的构建方式使得'std :: string'对他们意味着不同的东西。可能与不同风格的C++运行时库链接? –

+0

如果您复制了示例代码,则问题可能是您包含'stdio.h'而不是'cstdio'。这将匹配与char相关的东西断开的链接。其他的事情要检查:你的'libcfgparser.so'是用'std :: string'构建的,它支持'wchar_t'? – starturtle

+0

我有同样的问题确保ABI兼容性,确保-m32/-m64与您的库/可执行文件版本匹配。 – ceorron

但显然这些符号有:

显然,他们不是。仔细看一下,你会发现 由你的 链接器报告的特征与未报告的特征之间没有任何匹配,从 nm报告的特征之间没有匹配。

标准头<string>std::string定义为的typedef:

std::basic_string<char, std::char_traits<char>, std::allocator<char>> 

的GCC实现的<string>,作为cxx11 ABI(GCC 4.7.0) std::string定义为一个typedef的:

std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>> 

std::__cxx11名称空间包含的二进制实现符合cxx1的 类型1 ABI。

这类型定义是指C++翻译单元,其包括标准头<string>不会 编译,用GCC> = 4.7,到含有该demangles作为std::string一个符号的目标代码。

如果二元 - 就像你libcfgparser.so - 包含一个符号,demangles为std::string,然后 无论该符号可能在从它被建造的消息人士称,它并不是指std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, 而不能与其他编译了std::string定义的二进制文件相链接。

libcfgparser.so是一个从 cfgparser Sourceforce project (这是最后更新三年前)由libcfgparser0_1.1.2_amd64.deb安装。我想这是因为我 得到您的链接错误,与链接相同的example.cc程序与该程序包安装的库链接。 - 前期cxx11 ABI

/usr/lib$ strings -a libcfgparser.so | grep "GCC: (" 
GCC: (Debian 4.3.2-1.1) 4.3.2 
... 

它告诉我们这个图书馆建与GCC 4.3.2:

了错误的解释被发现。

出现在您nm输出的std::string是预先cxx11 demangling的std::basic_string<char, std::char_traits<char>, std::allocator<char>>缩写 。

这个libcfgparser.so是与您当前的GCC ABI不兼容的,所以您的 不能将它与您使用该编译器构建的程序链接。你可以做的是 建立libcfgparser从源代码包,libcfgparser-1.1.2.tar.bz2, 与您当前的编译器,然后链接您的程序与你自己建立的库 。

这有效,但不是毫不费力。首先,您需要修复损坏的 和源代码包的过时自动工具,以创建一个工作的./configure 脚本。

这并没有给出包装维护者熟练程度的令人放心的印象。 加上该软件包的源代码,版权2008,是业余质量。如果 你以后是用于INI风格文件的C++解析器,那么boost::property_tree::ini_parser将是 转到解决方案。请参阅this answer

+0

谢谢!你的回答非常有帮助和教育。我在猜测类似的原因,但我不能总结可能是因为“'nm'输出中出现的'std :: string'是'std :: basic_string ,std :: allocator >'''''''''''''''''''''''''''''''''''''''''''''我不知道怎么正确地去缩写'std :: string'。 – qweruiop

+0

同样使用'boost :: property_tree :: ini_parser'是一个很好的调用 – qweruiop

+0

@qweruiop不客气,'std :: string'(demangled)='Ss'(mangled)是pre-cxx11 GCC名称中的一个* hardcoded *缩写,它不是逻辑,而是方便。可以指望的是,二进制文件中的符号(无论是破坏的还是去结构的),* *不同*与链接器* *不同,'因为它们是链接器所看到的。 –