Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

linker can not find symbols but they're there?

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??

like image 541
qweruiop Avatar asked Dec 14 '16 03:12

qweruiop


People also ask

How do linkers resolve symbols?

The linker resolves symbol references by associating each reference with exactly one symbol definition from the symbol tables of its input relocatable object files. Symbol resolution is straightforward for references to local symbols that are defined in the same module as the reference.

What is a symbol linker?

Linker symbols have a name and a value. The value is a 32-bit unsigned integer, even if it represents a pointer value on a target that has pointers smaller than 32 bits. The most common kind of symbol is generated by the compiler for each function and variable.

What linker does GCC use?

GNU linker. But gcc does not link object files. Instead it uses collect2 which is just wrapper for the GNU ld linker: ~$ /usr/lib/gcc/x86_64-linux-gnu/4.9/collect2 --version collect2 version 4.9.


1 Answers

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

like image 92
Mike Kinghan Avatar answered Jan 04 '23 15:01

Mike Kinghan