C++ std library linking with different C++ standar

2019-02-10 07:22发布

问题:

I am compiling a project using Cygwin (GCC v4.5.0) and I'm having an odd linker problem. I am hoping somebody with some expertise can help.

Error: undefined reference to std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::basic_string<char, std::char_traits<char>, std::allocator<char> >&&)

However, the linking only fails when I compile with the gcc compiler flag: -std=c++0x It succeeds when I don't specify the standard.

Some notes:

  1. I am informing gcc to link the standard library manually with the compiler flag: -lstdc++
  2. The symbol dependency is originating from a Boost library header file (v.1.45.0): boost::units::detail::utility.hpp, function: std::string demangle(const char* name);
  3. The application compiles and links properly using MinGW gcc v4.5.0.

Questions:

  1. Does the compiled standard library usually contain different symbols for different C++ standards?
  2. Does the name mangling of symbols change with different C++ standards in GCC?
  3. Why can't the linker find the symbols for std::basic_string when I can guarantee that it can find libstdc++.a?

Thanks in advance everyone.

-JT

回答1:

Yes, both new revisions of the standard and technical reports make many changes to the content of the standard library. The function you referenced (std::string's move constructor) is newly added in C++0x's standard library.

The version of the standard does not affect name mangling, although the compiler version does, and newer compilers are needed for better C++0x support, so it could appear to be related.

You are probably using too old a version of libstdc++.

EDIT: Basic troubleshooting:

$ find /usr -name libstdc++.a
/usr/lib/gcc/i686-pc-cygwin/4.5.0/libstdc++.a

$ cygcheck -f /usr/lib/gcc/i686-pc-cygwin/4.5.0/libstdc++.a
libstdc++6-devel-4.5.0-1

$ nm -C /usr/lib/gcc/i686-pc-cygwin/4.5.0/libstdc++.a | grep basic_string | grep '&&'
00000000 T std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string&&)
00000000 T std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string&&)
00000000 T std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >::assign(std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >&&)
00000000 T std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >::basic_string(std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >&&)
00000000 T std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >::basic_string(std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >&&)
00000000 T std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >::operator=(std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >&&)

This does indeed look a little funny. The definitions for std::wstring (i.e. std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >) look correct, the narrow versions do not. The name std::string shouldn't ever have survived to the mangling stage, since it's just a typedef.

However, I get the same output on linux:

% find /usr -name libstdc++.a
/usr/lib64/gcc/x86_64-pc-linux-gnu/3.4.6/libstdc++.a
/usr/lib64/gcc/x86_64-pc-linux-gnu/3.4.6/32/libstdc++.a
/usr/lib64/gcc/x86_64-pc-linux-gnu/4.5.2/libstdc++.a
/usr/lib64/gcc/x86_64-pc-linux-gnu/4.5.2/32/libstdc++.a

% nm -C /usr/lib64/gcc/x86_64-pc-linux-gnu/4.5.2/libstdc++.a | grep basic_string | grep '&&'
0000000000000000 W std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string&&)
0000000000000000 W std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string&&)
0000000000000000 W std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >::assign(std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >&&)
0000000000000000 W std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >::basic_string(std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >&&)
0000000000000000 W std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >::basic_string(std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >&&)
0000000000000000 W std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >::operator=(std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >&&)