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??
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.
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.
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With