Why does ldd fail to find libstdc++ in /usr/local/lib64 without LD_LIBRARY_PATH? - gcc

I would like to run a program compiled with gcc-11 on a raspberry pi 4b without having to specify LD_LIBRARY_PATH or having to link with the library path.
At the moment, if I have to specity the path to the new libstdc++ in LD_LIBRARY_PATH, otherwise ld fails to load the correct library:
pi#cm4:~ $ ./rckam-server --version
./rckam-server: /lib/aarch64-linux-gnu/libstdc++.so.6: version `CXXABI_1.3.13' not found (required by ./rckam-server)
./rckam-server: /lib/aarch64-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.29' not found (required by ./rckam-server)
./rckam-server: /lib/aarch64-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.26' not found (required by ./rckam-server)
pi#cm4:~ $ LD_LIBRARY_PATH=/usr/local/lib64 ./rckam-server --version
rckam-server version 0.2021.08.23-a5d7a165
pi#cm4:~ $
I am running Raspberry Pi OS 64 bits (debian 10.11). After building and installing gcc 11.2.0, I have created /etc/ld.so.conf.d/gcc-11.2.0.conf:
pi#cm4:/etc $ cat ld.so.conf.d/gcc-11.2.0.conf
/usr/local/libexec/gcc/aarch64-unknown-linux-gnu/11.2.0
/usr/local/lib64
pi#cm4:/etc $
After running ldconfig I verified that the cache contains the relevant libraries:
pi#cm4:/etc $ ldconfig -p | grep libstdc++
libstdc++.so.6 (libc6,AArch64) => /lib/aarch64-linux-gnu/libstdc++.so.6
libstdc++.so.6 (libc6,AArch64) => /usr/local/lib64/libstdc++.so.6
libstdc++.so (libc6,AArch64) => /usr/local/lib64/libstdc++.so
pi#cm4:/etc $ ldconfig -p | grep liblto
liblto_plugin.so (libc6,AArch64) => /usr/local/libexec/gcc/aarch64-unknown-linux-gnu/11.2.0/liblto_plugin.so
pi#cm4:/etc $
This is the compiler:
pi#cm4:/etc $ gcc-11 -v
Using built-in specs.
COLLECT_GCC=gcc-11
COLLECT_LTO_WRAPPER=/usr/local/libexec/gcc/aarch64-unknown-linux-gnu/11.2.0/lto-wrapper
Target: aarch64-unknown-linux-gnu
Configured with: ../gcc-11.2.0/configure -v --enable-languages=c,c++ --program-suffix=-11 --with-cpu=cortex-a72
Thread model: posix
Supported LTO compression algorithms: zlib
gcc version 11.2.0 (GCC)
What else should I do to enable ld to find the appriopriate libraries in /usr/local/lib64?

Simply make sure that the newer version of libstdc++ is considered before the old one. This is exactly what happens when LS_LIBRARY_PATH is specified.
The output of "ldconfig -p | grep libstdc++" lists /usr/local/lib64/libstdc++.so.6 after /lib/aarch64-linux-gnu/libstdc++.so.6 and that is where the problem lies. It happens because the file /etc/ld.so.conf.d/aarch64-linux-gnu.conf is processed by ldconfig before /etc/ld.so.conf.d/gcc-11.0.2.conf.
There are several ways to control the order in which the directories are processed by ldconfig. The first one is the old fashioned method: listing the directories in the desired order directly in /etc/ld.so.conf instead of using gcc-11.2.0.conf. Something like this:
/usr/local/libexec/gcc/aarch64-unknown-linux-gnu/11.2.0
/usr/local/lib64
include /etc/ld.so.conf.d/*.conf
The file gcc-11.2.0.conf can be explicitly included before the generic include (it doesn't matter if a file is included twice):
include /etc/ld.so.conf.d/gcc-11.2.0.conf
include /etc/ld.so.conf.d/*.conf
When using files in /etc/ld.so.conf.d, it is also possible to control the order of the includes with numeric prefixes. In this specific case, renaming the file to /etc/ld.so.conf/00-gcc-11.2.0.conf would force ldconfig to process it before any other file in the directory.

Related

Why does the program which is compiled against the installed glibc not run normally?

Thanks in advance.
my development environment:
$ cat /proc/version
Linux version 5.4.0-66-generic (buildd#lgw01-amd64-016) (gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04)) #74~18.04.2-Ubuntu SMP Fri Feb 5 11:17:31 UTC 2021
$ ld --version
GNU ld (GNU Binutils for Ubuntu) 2.30
Copyright (C) 2018 Free Software Foundation, Inc.
$ getconf GNU_LIBC_VERSION
glibc 2.27
$ #my glibc source version is 2.32.9000-development
$ cat ./version.h
/* This file just defines the current version number of libc. */
#define RELEASE "development"
#define VERSION "2.32.9000"
For some reasons, I need to modify and test glibc. I follow the steps of this website(https://sourceware.org/glibc/wiki/Testing/Builds#Compile_against_glibc_in_an_installed_location) to modify glibc and write test programs.
compile glibc.(confgure and make)
install glibc.(make install to a directory)
...other steps in the website above.
I successfully modified some pthread functions and passed the test (the test program I wrote can compiled against the install glibc and ran successfully). ldd the program.
$ ldd ./exec/1-1.out
linux-vdso.so.1 (0x00007ffcbf367000)
libpthread.so.0 => /home/cjl-target/gnu/install/lib64/libpthread.so.0 (0x00007fcadcea9000)
libc.so.6 => /home/cjl-target/gnu/install/lib64/libc.so.6 (0x00007fcadcaed000)
/home/cjl-target/gnu/install/lib64/ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2 (0x00007fcadd2ca000)
As shown above, the shared libraries that the program depends on all point to the glibc installation path.
But when I compiled message-queue's test program(test mq_unlink) and ran it, failed as bellow:
./exec/1-1.out: symbol lookup error: /lib/x86_64-linux-gnu/libpthread.so.0: undefined symbol: __libc_vfork, version GLIBC_PRIVATE
check the library that is depended by the program:
$ ldd ./exec/1-1.out
linux-vdso.so.1 (0x00007ffce3f72000)
librt.so.1 => /home/cjl-target/gnu/install/lib64/librt.so.1 (0x00007f0a389a2000)
libc.so.6 => /home/cjl-target/gnu/install/lib64/libc.so.6 (0x00007f0a385e6000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f0a383c7000)
/home/cjl-target/gnu/install/lib64/ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2 (0x00007f0a38dac000)
As shown above, the shared libraries libpthread.so.0 points to the system library. Why?
my compile script is(from the website above):
# dobuild.sh
SYSROOT=/home/xxx/xxx/xxx #the glibc's installation path
(set -x; \
gcc \
-L${SYSROOT}/usr/lib64 \
-I${SYSROOT}/usr/include \
--sysroot=${SYSROOT} \
-Wl,-rpath=${SYSROOT}/lib64 \
-Wl,--dynamic-linker=${SYSROOT}/lib64/ld-linux-x86-64.so.2 \
-Wall $*
)
when I compile the pthread's test program:./dobuild 1-1.c -pthread -Wall
when I compile the mq's test program:./dobuild 1-1.c -lrt -Wall
In addition, it is confusing that when invoke the pthread_create in the mq_unlink's test program, compiling it ./dobuild 1-1.c -lrt -pthread, the ldd result shows that all dependent libraries point to the installed glibc.
I've tried multiple variations of this, but none of them seem to work. Any ideas?
First, you should stop using ldd -- in the presence of multiple GLIBCs on a host, ldd is more likely to mislead than to illuminate.
If you want to see which libraries are really loaded, do this instead:
LD_TRACE_LOADED_OBJECTS=1 ./exec/1-1.out
Second, you should almost never use $* in shell scripts. Use "$#" instead (note: quotes are important). See this answer.
Third, the behavior you are observing is easily explained. To understand it, you need to know the difference between DT_RPATH and DT_RUNPATH, described here.
You can verify that your binaries are currently using RUNPATH, like so:
readelf -d 1-1.out | grep 'R.*PATH'
And you can verify that everything starts working as you expect by adding -Wl,--disable-new-dtags to the link command (which would cause the binary to use RPATH instead).
To summarize:
RUNPATH affects the search for the binary itself, but not for any libraries the binary depends on.
RPATH affects the search path for the binary and all libraries it depends on.
with RUNPATH, expected libpthread.so.0 is found only when the binary depends on it directly, but not when the dependency on libpthread is indirect (via librt).
with RPATH, expected libpthread.so.0 is found regardless of whether the dependency is direct or indirect.
Update:
If I want to use DT_RUNPATH, how to set the library runpath for librt?
You would need to link librt.so with -rpath=${SYSROOT}/lib64.
You could edit the rt/Makefile, or build with:
make LDFLAGS-rt.so='-Wl,--enable-new-dtags,-z,nodelete,-rpath=${SYSROOT}/lib64'
You would need to do the same for any other library that may bring transitive dependency on other parts of GLIBC. I don't know of a general way to do this, but setitng LDFLAGS-lib.so='-Wl,-rpath=${SYSROOT}/lib64' and rebuilding everything might do the trick.

Overriding MacOS High Sierra /usr/lib (or how to static link)

I have a program I'm compiling that requires a new version of Curl. Mac default Curl is in /usr/bin and /usr/lib. I have compiled a newer version of curl and compiled using:
gcc mypgm.c -I ./curl-7.58.0/include/curl -I ./cJSON-master -L ./cJSON-master/build ./libcjson.1.7.1.dylib ./libcurl.4.dylib -o mypgm
When I run mypgm I get the error:
Incompatible library version: mypgm requires version 10.0.0 or later, but libcurl.4.dylib provides version 7.0.0
Running otool I found that the libcurl in my build dir is correct, but it seems to be wanting to use the /usr/lib version, which can't be deleted (without disable SIP, delete, reenable, which I don't want to do in case some future version reinstalls).
So my question is two-fold.
I want to know if it is possible like with $PATH to change the way macOS finds libraries (I read something about LD_LIBRARY_PATH and DYLD_LIBRARY_PATH being ignored), and
How should I redo the gcc line to static link those libraries?
This worked after coping the libraries into the /usr/local/lib folder.
gcc -I ./curl-7.58.0/include/curl -I ./cJSON-master /usr/local/lib/libcjson.1.7.1.dylib /usr/local/lib/libcurl.4.dylib mypgm.c -o mypgm
I think the relative path (./) for the libraries rather then absolute path is the key.

omp.h not found, OS X Yosemite not using newest gcc version

I am trying to build GraphChi on OS X Yosemite but get the following error:
fatal error: 'omp.h' file not found
From this question - How to include omp.h in OS X? - I learned that Yosemite uses Clang instead of gcc, which does not include omp.h.
$ which gcc
/usr/bin/gcc
$ gcc -v
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 6.0 (clang-600.0.56) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin14.1.0
Thread model: posix
Next, I installed gcc via Homebrew
$ brew info gcc
gcc: stable 4.9.2 (bottled)
http://gcc.gnu.org
/usr/local/Cellar/gcc/4.9.2_1 (1092 files, 177M)
Built from source with: --without-multilib
and updated $PATH to include the path to the new gcc version
$ echo $PATH
/usr/local/Cellar/gcc/4.9.2_1:usr/local/bin:/opt/local/bin:/opt/local/sbin:/usr/bin:/bin:/usr/sbin:/sbin
however, gcc -v and which gcc still point to the old version, and building GraphChi still doesn't work due to the missing omp.h file
Does anyone know what else I need to do?
Update
locate omp.h returned:
/usr/local/Cellar/apple-gcc42/4.2.1-5666.3/lib/gcc/i686-apple-darwin11/4.2.1/include/omp.h
/usr/local/Cellar/gcc/4.9.2_1/lib/gcc/4.9/gcc/x86_64-apple-darwin14.1.0/4.9.2/include/omp.h
/usr/local/Cellar/gfortran/4.8.2/gfortran/lib/gcc/x86_64-apple-darwin13.0.0/4.8.2/include/omp.h
my ~/.profile:
export PATH=/usr/local/Cellar/gcc/4.9.2_1/lib/gcc/4.9/gcc/x86_64-apple-darwin14.1.0/4.9.2/include:/usr/local/Cellar/gcc/4.9.2_1/bin:usr/local/bin:/opt/local/bin:/opt/local/sbin:$PATH
I solved this with installing gcc with homebrew:
brew install gcc --without-multilib
and then building the source code with
CC=gcc-5 CXX=g++-5 cmake ..
CC=gcc-5 CXX=g++-5 make -j7
Once you have installed gcc-4.9 with homebrew, it will automatically be in your path. To use OpenMP, you just need to make sure you are using the newly installed gcc-4.9, and it will be able to find omp.h.
In the case of GraphChi, you will have to go change line 3 of the Makefile to be gcc-4.9. From there, running make should just work. They describe this in their README, but at least the version they describe is out of date https://github.com/GraphChi/graphchi-cpp#problems-compiling-on-mac.
clang does not support OpenMP yet. Also gcc by default links to Apple's LLVM clang compiler (not the GCC installed from brew).
Instead gcc-4.9 would link to GCC. I think if -fopenmp is specified omp.h is included automatically.
It is possible to manually build a version of clang with OpenMP support, see http://clang-omp.github.io
You shouldn't add the include path to PATH; instead, specify it as CFLAGS, including the -I option. You can export the CFLAGS variable, or set it on the fly.
Depending on how you compile things, you could do
CFLAGS=-I/usr/local/Cellar/gcc/4.9.2_1/lib/gcc/4.9/gcc/x86_64-apple-darwin14.1.0/4.9.2/include/omp.h gcc <whatever>
Of course, in this case you can specify it directly on the gcc command (as -I/usr/local/....), but the CFLAGS variable also works with configure (as configure often won't have an option to specify where it should look for specific include files); probably with make, or even for those installing a Python package: CFLAGS=-I... pip install <some-package>.
Other flags to consider are
CXXFLAGS: C++ specific pre-processor flags
LDFLAGS: linker specific flags (e.g. LDFLAGS=-L/some/path/... for linking with dynamic libraries).
CC: specify the C compiler to use. This is an easy way to avoid the built-in gcc alias for clang on OS X. Just use CC=/usr/local/bin/gcc-4 make or similar.
CXX: specify the C++ compiler to use.

Linking with libtcmalloc ubuntu

I had installed the package libtcmalloc-minimal0
but when I try to compile my program with flag
-ltcmalloc-minimal0
I am getting error
/usr/bin/ld: cannot find -ltcmalloc_minimal0
I had checked /usr/lib and the library is there
More Info
dpkg gives following o/p
dpkg -L libtcmalloc-minimal0
/.
/usr
/usr/lib
/usr/lib/libtcmalloc_minimal.so.0.0.0
/usr/lib/libtcmalloc_minimal_debug.so.0.0.0
/usr/share
/usr/share/doc
/usr/share/doc/libtcmalloc-minimal0
/usr/share/doc/libtcmalloc-minimal0/TODO
/usr/share/doc/libtcmalloc-minimal0/AUTHORS
/usr/share/doc/libtcmalloc-minimal0/copyright
/usr/share/doc/libtcmalloc-minimal0/changelog.gz
/usr/share/doc/libtcmalloc-minimal0/README.gz
/usr/share/doc/libtcmalloc-minimal0/changelog.Debian.gz
/usr/lib/libtcmalloc_minimal.so.0
/usr/lib/libtcmalloc_minimal_debug.so.0
and I am compiling for 64 bit mode
and library is also 64 bit
file /usr/lib/libtcmalloc_minimal.so.0.0.0
/usr/lib/libtcmalloc_minimal.so.0.0.0: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, stripped
You can't link simply to a file with -l if it doesn't end exactly with .so, since the linker assumes a particular naming convention (lib*.so).
You have several choices:
Install libtcmalloc-minimal0-dev if it exists, which should provide the .so dynamic link.
Create the symlink yourself: cd /usr/lib; ln -s libtcmalloc_minimal.so.0.0.0 libtcmalloc_minimal.so; cd -
Link directly to the library without the symlink by using gcc test.c /usr/lib/libtcmalloc_minimal.so.0.0.0
Link using the -l option using the full name: -l:libtcmalloc_minimal.so.0.0.0
Running dpkg -L libtcmalloc-minimal0 will show you that the library is /usr/lib/libtcmalloc_minimal.so.0 so the correct option should be -ltcmalloc_minimal without any digit

GLIBCXX_3.4.9 not found

I have a problem concerning libstdc++.so.
I installed a new version of gcc and tried to compile C++ code. The compiling worked, but when I try to execute the binary (m5.opt is its name) I've got the following error:
build/ALPHA_SE/m5.opt: /usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.9' not found (required by build/ALPHA_SE/m5.opt).
Do I need to replace libstdc++.so? And if so, where can I download the version I want? On the GCC-website they say libstdc++ is a part of gcc now.
Details
GCC:
I had gcc 4.1.2 before, but I downloaded gcc 4.2.4. From the untarred gcc-directory I executed ./configure; make; sudo make install`.
When I tried to use gcc or g++ to compile, it's default version was still 4.1.2. To overcome this I replaced some links:
mv /usr/bin/gcc /usr/bin/gcc_bak
ln -s /usr/local/bin/gcc gcc
mv /usr/bin/g++ /usr/bin/g++_bak
ln -s /usr/local/bin/g++ g++
GLIBC(++) -- libstdc++:
/usr/lib64/libstdc++.so.6 -> libstdc++.so.6.0.8
/usr/local/lib/libstdc++.so -> libstdc++.so.6.0.9
/lib/libc.so.6 -> libc-2.5.so -> libc-2.5.so
Linux-version:
uname -a gives:
Linux madmax 2.6.18-128.4.1.el5 #1 SMP Tue Aug 4 12:51:10 EDT 2009 x86_64 x86_64 x86_64 GNU/Linux
The problem is that you built your new GCC incorrectly: on Linux you should use
./configure --prefix=/usr
The default installation prefix is /usr/local, which is why make install put gcc and g++ binaries into /usr/local/bin, etc.
What's happening to you now is that you compile and link using the new (symlinked) GCC 4.2.4, but at runtime your program binds to the old /usr/lib64/libstdc++.so.6 (version 6.0.8, instead of required 6.0.9). You can confirm that by running ldd build/ALPHA_SE/m5.opt: you should see that it uses /usr/lib64/libstdc++.so.6.
There are several fixes you could do.
env LD_LIBRARY_PATH=/usr/local/lib64 ldd build/ALPHA_SE/m5.opt
should show you that setting LD_LIBRARY_PATH is sufficient to redirect the binary to correct library, and
LD_LIBRARY_PATH=/usr/local/lib64 build/ALPHA_SE/m5.opt
should just run. You could "bake" this path into m5.opt binary by relinking it with -Wl,-rpath=/usr/local/lib64.
A more permanent solution is to fix the libraries the same way you fixed the binaries:
cd /usr/lib64 && mv libstdc++.so.6 libstdc++.so.6_bak &&
ln -s /usr/local/lib64/libstdc++.so.6 .
An even better solution is to reconfigure the new GCC with --prefix=/usr, and then make all install.
I know this is a very old question, but ...
It's not usually a good idea to replace the system compiler (i.e. the one in /usr) because the entire system will have been built with it and depend on it.
It's usually better to install the new compiler to a separate location and then see the libstdc++ FAQ How do I insure that the dynamically linked library will be found? and Finding Dynamic or Shared Libraries in the manual for how to ensure the correct libstdc++.so is found at runtime.
The other answers here should be fine, but the 'quick and easy' solution if you do happen to have gcc installed to /usr/local/ is to just add the new libs to the LD_LIBRARY_PATH
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib64
You can also check the to see if you have the right versions of GLIBC installed using
strings /usr/lib/libstdc++.so.6 | grep GLIBC
strings /usr/local/lib64/libstdc++.so.18 | grep GLIBC
I got this last tip from another forum so credits due where credits due!

Resources