linker can not find symbols but they're there?

9.2k Views Asked by At

Trying to compile this 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

But clearly those symbols are there:

$ 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

Unlike other similar problems on SO, this is NOT about linking order, as there is only one object file being linked. Anything I'm missing??

1

There are 1 best solutions below

3
On BEST ANSWER

But clearly those symbols are there:

Clearly, they're not. Take a closer look and you will see that there are no matches between the signatures reported by your linker as undefined and those reported from the library by nm.

The Standard header <string> defines std::string as typedef for:

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

The GCC implementation of <string>, as of the cxx11 ABI (GCC 4.7.0) defines std::string as a typedef for:

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

The std::__cxx11 name space encloses types whose binary implementations are compliant with the cxx11 ABI.

That type definition means that C++ translation unit that includes the Standard header <string> won't compile, with GCC >= 4.7, into object code containing a symbol that demangles as std::string.

If a binary - like your libcfgparser.so - contains a symbol that demangles as std::string, then whatever that symbol might have referred to in the sources from which it was built, it does not refer to std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char>>, and cannot be linked with other binaries that were compiled with that definition of std::string.

Your libcfgparser.so is the one installed by libcfgparser0_1.1.2_amd64.deb from the cfgparser Sourceforce project (which was last updated three years ago). I guess this from that the fact that I get your linkage error with same example.cc program linked against the library that is installed by that package.

The explanation for the error is revealed by:

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

which tells us that this library was built with GCC 4.3.2 - pre the cxx11 ABI.

The std::string that appears in your nm output is a pre-cxx11 demangling abbreviation of std::basic_string<char, std::char_traits<char>, std::allocator<char>>.

This libcfgparser.so is ABI-incompatible with your current GCC, so you can't link it with programs that you build with that compiler. What you can do is build libcfgparser from the source package, libcfgparser-1.1.2.tar.bz2, with your current compiler and then link your programs with the library you have built yourself.

That works, but not effortlessly. First you'll need to fix the broken and antiquated autotooling of the source package to create a working ./configure script.

Which doesn't give a reassuring impression of the proficiency of the package maintainer. Plus the source code of the package, copyright 2008, is of amateur quality. If what you are after is a C++ parser for INI-style files, then boost::property_tree::ini_parser would be the goto solution. See this answer