Old GCC can not automatically find the new version libstdc++? - c++

I'm trying to use the 3rd-party lib, called DocToText, with gcc 4.4.7.
I compiled the program with:
g++ -I./doctotext/ -L./doctotext/ -Wl,-rpath=./doctotext -ldoctotext -o example test_doctotext.cpp
In the beginning, it returned libstdc++.so.6: version GLIBCXX_3.4.15 not found
I manually downloaded the newer version, and re-linked, here is the result
[root#mail]~xian# find / -name "libstdc++.so.6"
/lib64/libstdc++.so.6
/usr/lib64/libstdc++.so.6
[root#mail]~xian# strings /lib64/libstdc++.so.6 | grep GLIBCXX_3.4.15
GLIBCXX_3.4.15
[root#mail]~xian# strings /usr/lib64/libstdc++.so.6 | grep GLIBCXX_3.4.15
GLIBCXX_3.4.15
But when I compiled again, it returned:
[root#mail]~xian# g++ -I./doctotext/ -L./doctotext/ -Wl,-rpath=./doctotext -ldoctotext -o example test_doctotext.cpp
./doctotext//libdoctotext.so: undefined reference to `std::__detail::_List_node_base::swap(std::__detail::_List_node_base&, std::__detail::_List_node_base&)#GLIBCXX_3.4.15'
./doctotext//libdoctotext.so: undefined reference to `std::__detail::_List_node_base::_M_transfer(std::__detail::_List_node_base*, std::__detail::_List_node_base*)#GLIBCXX_3.4.15'
./doctotext//libdoctotext.so: undefined reference to `std::__detail::_List_node_base::_M_unhook()#GLIBCXX_3.4.15'
./doctotext//libdoctotext.so: undefined reference to `std::__detail::_List_node_base::_M_hook(std::__detail::_List_node_base*)#GLIBCXX_3.4.15'
collect2: ld returned 1 exit status
I also tried
g++ -I./doctotext/ -L./doctotext/ -L/lib64/ -Wl,-rpath=./doctotext,-rpath=/lib64 -ldoctotext -lstdc++ -o example test_doctotext.cpp
, and I got the same errors (undefined reference).
libdoctotext.so indeed link to /lib64/libstdc++.so.6
[root#mail]~xian# ldd doctotext/libdoctotext.so | grep libstdc++.so.6
libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007f96c7ab4000)
Fortunately, I found two method to solve this problem:
use newer gcc:
I used gcc 9.1.1 (with scl), then g++ -I./doctotext/ -L./doctotext/ -Wl,-rpath=./doctotext -ldoctotext -o example test_doctotext.cpp directly works.
specify the path to libstdc++.so.6 with gcc 4.4.7:
g++ -I./doctotext/ -L./doctotext/ -Wl,-rpath=./doctotext -ldoctotext /lib64/libstdc++.so.6 -o example test_doctotext.cpp
But I'm really curious about why my gcc 4.4.7 can not link to that libstdc++ under the system default path?
Is the version of libstdc++ be tightly coupled to the version of gcc in someway?
===============================================================================
Eventually, I found gcc would use
[root#mail]/usr/lib64# find / -name "libstdc++.so"
/opt/rh/devtoolset-9/root/usr/lib/gcc/x86_64-redhat-linux/9/32/libstdc++.so
/opt/rh/devtoolset-9/root/usr/lib/gcc/x86_64-redhat-linux/9/libstdc++.so
/usr/lib/gcc/x86_64-redhat-linux/4.4.4/32/libstdc++.so
/usr/lib/gcc/x86_64-redhat-linux/4.4.4/libstdc++.so
[root#mail]/usr/lib64# ll /usr/lib/gcc/x86_64-redhat-linux/4.4.4/libstdc++.so
lrwxrwxrwx. 1 root root 37 Aug 21 15:22 /usr/lib/gcc/x86_64-redhat-linux/4.4.4/libstdc++.so -> ../../../../lib64/libstdc++.so.6.0.13
6.0.13 doesn't have GLIBCXX_3.4.15
I re-link this to libstdc++.so.6.0.17, problem solved

Every GCC release is accompanied by its very own libstdc++ release.
The C++ standard library (and support libraries like libsupc++) often rely on specific implementation details in the compiler, including bugs, and specific changes in behaviour due to defect reports etc.
Sometimes even a new GCC release also needs a matching binutils (linker) release, as the way the code is generated changed to use a specific feature only available in the newer linker.
You can explicitly link it to the system libstdc++ by passing that path to the compiler/linker, but I don't recommend it, as the ABI may have changed in an incompatible way.

Related

GCC not linking against libstdc++?

I'm receiving C++ build errors on Ubuntu 16.04 (g++ 5.4) that I don't understand:
The linker errors are (taken a few of them and run them through c++filt)
undefined reference to symbol 'std::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> >::str() const##GLIBCXX_3.4'
undefined reference to symbol 'std::condition_variable::notify_one()##GLIBCXX_3.4.11'
The command lanks I'm using are: gcc -std=c++11 -m64 -fPIC -std=c++11 ... (the ... has all the libs, etc.)
I assume I'm trying to link against /usr/lib/x86_64-linux-gnu/libstdc++.so.6. When I run strings against it, I see GLIBCXX_3.4 and GLIBCXX_3.4.11 (but I really don't know what this is indicating.)
nm shows me that the symbols (at least the condition_variable one is defined)
$ nm -DA /usr/lib/x86_64-linux-gnu/libstdc++.so.6 | c++filt | grep condition_variable::notify_one
/usr/lib/x86_64-linux-gnu/libstdc++.so.6:00000000000b3930 T std::condition_variable::notify_one()
I've run readelf on all the libraries I'm attempting to link, and they all appear to be built for the same ABI (GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609)
Update
I noticed that the first error is resolved by explicitly linking against libstd++.so (i.e. I added stdc++ to my target_link_libraries in CMake). I was under the impression that I should never have to do this?
tl;dr: Invoke g++ rather than gcc to avoid this problem
(based on #SergeyA's comment)
GCC behaves differently depending on whether you run it as the gcc or the g++ binary. Specifically, it apparently won't automatically link against its bundled C++ standard library, libstdc++. I'm guessing it will link against its C standard library - which doesn't help you much.
So just use the appropriate binary for your language; specifying --std=c++whatever isn't enough.

Which version of glibc should be used when release my *.so file?

I'm working on a shared library which support SSL connection and transmission. I want to release it as a *.so file. After compiling it in my Ubuntu14.04(64bit Desktop) with g++ 4.8.2, it can not work in the CentOS5.8.
The First Round
I compile the shared library with following command:
g++ -v -shared -Wl,-soname,libmyssl.so.1,-o libmyssl.so.1.0 myssl.o -lz -lssl -lcrypto
I use command objdump -p libmyssl.so.1.0|grep NEEDED to know it depends on following libraries:
NEEDED libz.so.1
NEEDED libssl.so.1.0.0
NEEDED libcrypto.so.1.0.0
NEEDED libstdc++.so.6
NEEDED libc.so.6
Then I write a demo to use libmyssl.so.1.0.
g++ -D UNIX64 -o ssldemo ssldemo.cpp ./libmyssl.so.1.0 -lz -lssl -lcrypto
I compile the demo in Ubuntu14.04(the same version), it works fine.
I compile the demo in CentOS(openssl 0.9.8e), it linked failed because invalid openssl's version
The Second Round
I removed the "-lz lssl -lcrypto", so the command as following
g++ -v -shared -Wl,-soname,libmyssl.so.1,-o libmyssl.so.1.0 myssl.o
I use command objdump -p libmyssl.so.1.0|grep NEEDED to know it depends on following libraries:
NEEDED libstdc++.so.6
NEEDED libc.so.6
I use the libmyssl.so.1.0 in above demo code in the same way:
g++ -D UNIX64 -o ssldemo ssldemo.cpp ./libmyssl.so.1.0 -lz -lssl -lcrypto
I compile the demo in Ubuntu14.04(the same version), it works fine.
I compile the demo in CentOS(openssl 0.9.8e), it didn't report ssl linked errors, but it report glibc linked errors as follows:
undefined reference to `memcpy#GLIBC_2.14'
After updating CertOS's glibc, the demo work fine.
The Third Round
I try to remove the depends to "libc.so.6" and "libstdc++.so.6", so I added option "-nodefaultlibs" to the compile command:
g++ -nodefaultlibs -v -shared -Wl,-soname,libmyssl.so.1,-o libmyssl.so.1.0 myssl.o
I use command objdump -p libmyssl.so.1.0|grep NEEDED only get empty string.
I use command ldd libmyssl.so.1.0 get result "statically linked", no sure why it said "statically linked".
I use the libmyssl.so.1.0 in above demo code in the same way:
g++ -D UNIX64 -o ssldemo ssldemo.cpp ./libmyssl.so.1.0 -lz -lssl -lcrypto
It always report following error both in Ubuntu14.04 and CentOS5.8:
Ubuntu:
hidden symbol `atexit' in /usr/lib/x86_64-linux-gun/libc_nonshared.a(atexit.oS) is referenced by DSO
/usr/bin/ln: final link failed: Bad value
CentOS:
hidden symbol `atexit' in /usr/lib64/libc_nonshared.a(atexit.oS) is referenced by DSO
/usr/bin/ln: final link failed: Nonrepresentable section on output
Questions:
Which version of GLIBC should be linked when I compile my *.so file so that it can work fine in as many as possible Linux?
Do have a way to avoid the dependency to the GLIBC? I tried it in The Third Round but failed.
Any other suggestions ?
Which version of GLIBC should be linked when I compile my *.so file
so that it can work fine in as many as possible Linux?
You should select the oldest distro that you want to target and build on this one. This would ensure that your library would require the minimum possible Glibc version. So simply select the distro with oldest Glibc and build there.
Version of your Glibc is usually encoded in libc.so name (e.g. /lib64/libc-2.12.so) but you can also do
$ strings //lib64/libc-2.12.so | grep GLIBC
GLIBC_2.2.5
GLIBC_2.2.6
...
GLIBC_2.12
GLIBC_PRIVATE
Do have a way to avoid the dependency to the GLIBC? I tried it in The Third Round but failed.
Writing entirely Glibc-independent library sounds like an overkill (you'll need to re-implement IO, memcpy, etc., with lower quality/performance compared to Glibc). Are you sure you want to go down this path?
Any other suggestions ?
For complete applications two common solutions are
static linking
bundling them together with stdlibs they were linked against (they'll of course need to be run with special LD_LIBRARY_PATH or -Wl,-rpath)
But in your case (isolated shared library) targeting the lowest supported Glibc seems to be the only option.

Cygwin G++ linker (ld.exe) on Windows 7 cannot find libc.so.6 and other library files

I am using g++ in a cygwin terminal to link several c object files and c++ object files together into a single shared executable. The linker tells me that there are several libraries it cannot find. However, I can list them, using the locations where the linker states that it is looking for them:
g++ -g -o myProg.so *.o -shared
c:/cygwin/bin/../lib/gcc/x86_64-vityan-linux-gnu/4.6.0/../../../../x86_64-vityan-linux-gnu/bin/ld.exe: *cannot find /lib/libc.so.6*
c:/cygwin/bin/../lib/gcc/x86_64-vityan-linux-gnu/4.6.0/../../../../x86_64-vityan-linux-gnu/bin/ld.exe: *cannot find /x86_64-vityan-linux-gnu/lib/libc_nonshared.a*
c:/cygwin/bin/../lib/gcc/x86_64-vityan-linux-gnu/4.6.0/../../../../x86_64-vityan-linux-gnu/bin/ld.exe: *cannot find /lib/ld-linux-x86-64.so.2*
collect2: ld returned 1 exit status
$ ls /lib/libc.so.6
/lib/libc.so.6
$ ls /x86_64-vityan-linux-gnu/lib/libc_nonshared.a
/x86_64-vityan-linux-gnu/lib/libc_nonshared.a
$ ls /lib/ld-linux-x86-64.so.2
/lib/ld-linux-x86-64.so.2
I have tried renaming the .so files to .dll with no success.
I have tried to use the g++ switch '--sysroot' ( --sysroot=/cygdrive/c/cygwin/) with no success.
I have tried adding the g++ switch '-B /cygdrive/c/cygwin/lib/' with no success.
The thing that's really got me confused is that I did this same thing on a similar project about 6 months ago - no issues. And, the system clearly shows that the libraries are there.
What is missing that ld.exe needs to find these files?
I ran a quick analysis of what packages I had installed in Cygwin. I had several of the mingw g++ toolchain packages as well (which don't get used), and a bunch of other stuff. I only use Cygwin for a few specific projects, so I reinstalled: removed all of the other g++ toolchain items, and just installed the cygwin gcc 64 bit toolchain packages. Project now compiles without issue. Closing question.

Install gcc 4.7 but cannot run program sucessfully

I need to use C++ 11, so I updated my GCC from 4.1 to 4.7. I compile the source code and make install it. gcc -version will show 4.7.0 (everything looks good). I compiled my program using:
g++ -O2 -std=c++11 -o wdSer wdSer.cpp
After that I run my program ./wdSer, there are some information as follows:
./wdSer: /usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.9' not found (required by ./wdSer)
./wdSer: /usr/lib64/libstdc++.so.6: version `CXXABI_1.3.5' not found (required by ./wdSer)
./wdSer: /usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.10' not found (required by ./wdSer)
./wdSer: /usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.11' not found (required by ./wdSer)
Who can tell me how to solve it?
First try this:
LD_LIBRARY_PATH=/usr/local/lib64:$LD_LIBRARY_PATH ./wdSer
/usr/local/lib64 is the default library directory for a 64bit build of gcc .
Setting LD_LIBRARY_PATH to contain that directory tells the linker to look in that directory for library files.
If that does not work, look at the output of g++ -v
On my system, I get this:
$ g++ -v
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/local/gcc-4.8.2/libexec/gcc/x86_64-unknown-linux-gnu/4.8.2/lto-wrapper
Target: x86_64-unknown-linux-gnu
Configured with: ../gcc-4.8.2/configure --prefix=/usr/local/gcc-4.8.2 --with-isl=/usr/local/isl-0.12.2 --with-cloog=/usr/local/cloog-0.18.1
Thread model: posix
gcc version 4.8.2 (GCC)
In this output, you are looking for a directory following --prefix. Add /lib64 to the end of that prefix, and you'll have your library directory.
On my system, it's /usr/local/gcc-4.8.2 , so I need the linker to look in /usr/local/gcc-4.8.2/lib64 to find my libstdc++ .
So I run programs like this:
LD_LIBRARY_PATH=/usr/local/gcc-4.8.2/lib64:$LD_LIBRARY_PATH ./a.out
If you don't want to set your LD_LIBRARY_PATH before running your programs, you should build them with -Wl,-rpath= , like this:
$ g++ -std=c++11 -o wdSer -Wl,-rpath=/usr/local/lib64/ wdSer.cc
You can use ldd on a program to see where the shared libraries it is linked to are found:
$ ldd a.out
linux-vdso.so.1 => (0x00007fff8a506000)
libstdc++.so.6 => /usr/local/gcc-4.8.2/lib64/libstdc++.so.6 (0x00007fa3c6aaf000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fa3c6811000)
libgcc_s.so.1 => /usr/local/gcc-4.8.2/lib64/libgcc_s.so.1 (0x00007fa3c67fa000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa3c646f000)
/lib64/ld-linux-x86-64.so.2 (0x00007fa3c6bbc000)
Here, a.out is a program I built with the option -Wl,-rpath=/usr/local/gcc-4.8.2/lib64 , so the linker looks there first, and finds the libstdc++ that goes with my gcc 4.8.2 install.
Please see the documention for the -v flag: http://gcc.gnu.org/onlinedocs/gcc-4.8.2/gcc/Overall-Options.html#Overall-Options (and search for -v )
the -Wl flag : http://gcc.gnu.org/onlinedocs/gcc-4.8.2/gcc/Link-Options.html#Link-Options (and scroll down to the bottom)
and the -rpath flag: https://sourceware.org/binutils/docs-2.24/ld/Options.html#Options (and search for -rpath)

Compiling PARDISO linear solver test case with GCC

I am trying to compile a linear system solver using PARDISO.
The test case (pardiso_sym.c) also downloaded from the same website above.
I have the following files inside the directory:
[gv#emerald my-pardiso]$ ls -lh
total 1.3M
-rw-r--r-- 1 gv hgc0746 1.3M Aug 7 11:59 libpardiso_GNU_IA64.so
-rw-r--r-- 1 gv hgc0746 7.2K Nov 13 2007 pardiso_sym.c
Then I try to compile it with the following command:
[gv#emerald my-pardiso]$ gcc pardiso_sym.c -o pardiso_sym -L . -llibpardiso_GNU_IA64.so -L/home/gv/.boost/include/boost-1_38 -llapack
But it gives this error:
/usr/local/lib/gcc/x86_64-unknown-linux-gnu/4.3.2/../../../../x86_64-unknown-linux-gnu/bin/ld:
cannot find -llibpardiso_GNU_IA64.so
collect2: ld returned 1 exit status
What's wrong with my compilation method?
This is the additional info of my system:
[gv#emerald my-pardiso]$ uname -a
Linux gw05 2.6.18-92.1.13.el5 #1 SMP Wed Sep 24 19:32:05 EDT 2008
x86_64 x86_64 x86_64 GNU/Linux
[gv#emerald my-pardiso]$ gcc --version
gcc (GCC) 4.3.2
Update:
The library is recognized using Dave Gamble's suggestion. But now it gives different
error:
$ gcc pardiso_sym.c -o pardiso_sym -L . -lpardiso_GNU_IA64 -L/home/gv/.boost/include/boost-1_38 -llapack
./libpardiso_GNU_IA64.so: undefined reference to `s_stop'
./libpardiso_GNU_IA64.so: undefined reference to `s_wsfe'
./libpardiso_GNU_IA64.so: undefined reference to `e_wsfe'
./libpardiso_GNU_IA64.so: undefined reference to `z_abs'
./libpardiso_GNU_IA64.so: undefined reference to `s_cat'
./libpardiso_GNU_IA64.so: undefined reference to `s_copy'
./libpardiso_GNU_IA64.so: undefined reference to `do_fio'
EDIT: I read the pardiso manual. Here's the fix:
gcc pardiso_sym.c -o pardiso_sym -L . -lpardiso_GNU_IA64 -L/home/gv/.boost/include/boost-1_38 -llapack
Here I've removed the "lib" from the start and the ".so" from the end of -lpardiso_GNU_IA64
EDIT:
For new errors you'll need -lg2c after -lapack (fortran compatibility library)
EDIT2:
Also add -lgfortran and anything else you might need. Googling for a missing symbol usually finds mentions of library it contains. Keep adding libraries one by one untill all dependencies are satisfied.
So in your case routine is like this:
linked lapack -- got unresolved symbol from g2c
added g2c -- got symbols from gfortran
added gfortran -- got some other symbols, look them up and add libs one by one.
Libray order matters, if you include g2c before lapak for example, linker will throw away all its symbols before it knows they are needed for lapak (MS linker does 2 passes to fix that). So if you see a missing symbol that is in a lib you already include, look at which library needs it and move the lib with the symbol to be after it.