using older version of a shared linux library while compiling C - linux

I am trying to use libfann version 2.0.1 instead of the newest version 2.2.0, but could not figure out how to do so. Any thoughts on how to do that?
normally that works perfectly:
gcc fann_calculator.c -o run_fann_calculator -lfann -lm
where fann_calculator.c contains a program that calls a neural network.
Thanks

It depends upon where the two libraries sit. If they are installed in the same directory (e.g. both installed in /usr/lib/) you'll probably get the youngest one.
I suggest to carefully read the ld.so(8) and ldd(1) man pages. You certainly can trace what library is loaded (with e.g. the LD_DEBUG envirnonment variable). Don't forget to re-run ldconfig appropriately after library installation.
You could also play some LD_LIBRARY_PATH trick; for instance, set it to $HOME/lib:/usr/lib and install appropriate symlinks in your $HOME/lib/ to the precise library you want. For instance, you might do
ln -s /usr/lib/libfann.so.2.0.1 $HOME/lib/libfann.so.2
export LD_LIBRARY_PATH=$HOME/lib:/usr/lib:/lib
then check with ldd run_fann_calculator that you get the expected [version of the] libfann library.
Don't forget to read the Program Library Howto. You might want to pass appropriate flags to ld such as -rpath. You may need to pass them using gcc, perhaps with Gcc Link Options such as -Wl

Related

shared library not found during compilation

So I got several shared libraries that I am trying to permanently install on my Ubuntu system but I am having some difficulty with it.
I want to install the libraries and the headers in a separate folder under /usr/local/lib and /usr/local/include (for example a folder named agony) so it would be clean and removing them would just require that I delete those folders. so it looks something like this:
/usr/local/lib/agony/libbtiGPIO.so
/usr/local/lib/agony/libbtiDSP.so
...
/usr/local/include/agony/GPIO.h
/usr/local/include/agony/DSP.h
...
And I added a file here /etc/ld.so.conf.d/agony.conf which include a line describing the path to the library folder:
$ cat /etc/ld.so.conf.d/agony.conf
/usr/local/lib/agony
and I perform sudo ldconfig to update the library database.
So to double check if the library is found I do ldconfig -p | grep bti* and
I see the following result:
$ ldconfig -p | grep bti
...
libbtiGPIO.so (libc6,x86-64) => /usr/local/lib/agony/libbtiGPIO.so
libbtiDSP.so (libc6,x86-64) => /usr/local/lib/agony/libbtiDSP.so
...
At this point I should be able to use the libraries without specifying the library path. But When I attempt to compile an application without providing the library path (-L) it fails. However, when I supply gcc with the library path ex:
gcc source.c -L /usr/local/lib/agony output -lbtiGPIO -lbtiDSP
it works!!
I don't want to use LD_LIBRARY_PATH environment variable because this library is going to be used everywhere on the system and I don't want other compilers to worry about providing LD_LIBRARY_PATH.
What am I doing wrong here?
At this point I should be able to use the libraries without specifying the library path
Here lies the confusion.
You have built your shared library libbtiGPIO.so (just sticking with that one),
placed it in /usr/local/lib/agony, and updated the ldconfig database accordingly.
The effect of that is when you run a program that has been linked with libbtiGPIO
then the dynamic linker (/lib/x86_64-linux-gnu/ld-2.21.so, or similar) will know where to look
to load that library into the process and you will not need to tell it by setting an LD_LIBRARY_PATH in the environment.
However, you haven't done anything that affects the list of default library
search directories that are hardwired into your build of gcc, that it passes to
the linker (/usr/bin/ld) when you link a program with libbtiGPIO in the first place.
That list of default search directories is what you will find if your do a verbose
build of your program - gcc -v ... - and then pick out the value of LIBRARY_PATH
from the output, e.g.
LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/5/:\
/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/:\
/usr/lib/gcc/x86_64-linux-gnu/5/../../../../lib/:\
/lib/x86_64-linux-gnu/:\
/lib/../lib/:\
/usr/lib/x86_64-linux-gnu/:\
/usr/lib/../lib/:\
/usr/lib/gcc/x86_64-linux-gnu/5/../../../:\
/lib/:\
/usr/lib
/usr/local/lib/agony is not one of those and to make it one of those you
would have to build gcc from source yourself. Hence, in order to link your
program with libbtiGPIO you still need to tell ld where to find it with
-L/usr/local/lib/agony -lbtiGPIO.
man, you misunderstand the procedure of complier and link.
First, libbtiGPIO.so is a shared link library not a static link library. it is important to know those difference .
Then you need to know something else. changing ld.so.conf.d/*.conf and run sudo ldconfig, it affects the procedure of link. in other words, if you don't add agony.conf and sudo ldconfig, you will receive a error when you run ./a.out rather than gcc source.c -L ...., the gcc command can run successfully even thougth you don't ldconfig.
Finally,if you don't pollute the LD_LIBRARY_PATH environment variable, you have to add -L ... options in your gcc command. What'more, if you don't want to input too many words in your shell frequently, you can learn to use Makefile.

Use private C++ runtime library on linux

In Windows, the dynamic loader always looks for modules in the path of the loaded executable first, making it possible to have private libraries without affecting system libraries.
The dynamic loader on Linux only looks for libraries in a fixed path, in the sense that it is independent on the chosen binary. I needed GCC 5 for its overflow checked arithmetic functions, but since the C++ ABI changed between 4.9 and 5, some applications became unstable and recompiling them solved the issue. While waiting for my distro [kubuntu] to upgrade the default compiler, is it possible to have newly compiled application linking to the new runtime, while packaged application still links to the old library, either by static linkage, or something that mimics the Windows behavior?
One way of emulating it would be to create a wrapper script
#!/bin/bash
LD_LIBRARY_PATH=$(dirname $(which your_file)) your_file
And after the linking step copy the affected library but it is sort of a hack.
You can use rpath.
Let's say your "new ABI" shared libraries are in /usr/local/newapi-libs.
gcc -L/usr/local/newapi-libs
-Wl,-rpath,/usr/local/newapi-libs
program.cpp -o program -lsomething`
The -rpath option of the linker is the runtime counterpart to -L. When a program compiled this way is run, the linker will first look in /usr/local/newapi-libs before searching the system library paths.
More information here and here.
You can emulate the Windows behavior of looking in the executable's directory by specifying -Wl,-rpath,.
[edit] added missing -L parameter and dashes before rpath.

How to see which static libraries were used for gcc/g++ compilation from the generated binary?

Context: I'm using a linux toolchain (includes g++, other build tools, libs, headers, etc) to build my code with statically linked libraries. I want to ensure that I'm using ONLY libraries/headers from my toolchain, not the default ones on the build machine. I can use strace to see what g++ is doing (which libraries it is using) while it is compiling which would be helpful in a normal scenario - but my build system has many wrappers around g++ that hide all of the output.
Question: is there a way to obtain from a statically-linked binary any useful information regarding the library and header files which were used to create the binary? I've taken a look at the objdump tool but I'm not sure if it will help much.
Just pass -v to g++ or gcc at link time. It will show all the linked libraries. Perhaps try make CC='gcc -v' CXX='g++ -v'
More generally, -v passed g++ or gcc shows you the underlying command with its arguments because gcc or g++ is just a driver program (starting cc1, ld or collect2, as, ...)
By passing the -H flag to GCC (i.e. g++ or gcc) you can see every included header. So you can check that only the heanders you expect are included.
You cannot see what static library has been linked, because linking a static library just means linking the relevant object file members in it, so a static library can (and usually is) linked in only partly.
You could use the nm command to find names from such libraries.
If you can simply recompile, then there are ways (using some of the techniques that Basile explained) to get the headers and libraries (static or dynamic) but, unfortunately, there is no way to know which libraries were used after the compilation is complete.

compiling glibc from source with debug symbols

I need to compile glibc from source with debug symbols .
Where do i specify the '-g' option for this
How do i later make a sample code link to this particular glibc rather than the one installed on my system?
I need to compile glibc from source with debug symbols
You will have hard time compiling glibc without debug symbols. A default ./configure && make will have -g on compile line.
How do i later make a sample code link to this particular glibc rather than the one installed on my system?
This is somewhat tricky, and answered here.
It is probably a matter of configure tricks. First, try configure --help and then, either configure --enable-debug or perhaps configure CC='gcc -g' or even configure CFLAGS='-g'
For your sample code, perhaps consider playing LD_LIBRARY_PATH or LD_PRELOAD tricks (assuming linking to dynamic library).
But be very careful, since the Glibc is the cornerstone of Gnu/Linux like systems.

How to cheat *.so library into using missing #GLIBC_2.6 function?

I need to run relatively new package on not-so-new RHEL 5.6.
I have 3rd party library (lib3rdparty.so) which is compiled against glibc 2.6 while RHEL 5.6 have only 2.5 installed. But in the library there is only a couple of references to sched_getcpu##GLIBC_2.6. I've checked it like this
readelf -s lib3rdparty.so | egrep "#GLIBC_2.[6-9]"
to find references to something newer than GLIBC_2.5 which is installed. The output is
0 FUNC GLOBAL DEFAULT UND sched_getcpu#GLIBC_2.6 (62)
0 FUNC GLOBAL DEFAULT UND sched_getcpu##GLIBC_2.6
So, I have only one function from GLIBC_2.6. Now I want to make library think, that I have this function. For that purpose I forged small library (libcheat.so) like it mentioned here. Now I have libcheat.so file which, if run through readelf, will show this string:
10 FUNC GLOBAL DEFAULT 11 sched_getcpu##GLIBC_2.6
With this library I managed to succesfully build executable which is dynamically linked with lib3rdparty.so. Without this library I can't build anything, because ld can't find reference to sched_getcpu.
But the problem is with running this file: when I try to run it I have a following error:
./hello_world: version `GLIBC_2.6' not found (required by ./lib3rdparty.so)
So, I believe there is one last step to make it work, but I don't know what to do. I've tried to use /etc/ld.conf.preload and exporting LD_LIBRARY_PATH so it would point to my library to load before others. But it won't run. Tried to run it through strace but have no meaningful output.
Any ideas?
I'm not sure if the workaround you picked up is the best way to go. Why not supplying a newer glibc for the application? You can try to pass it over using the LD_PRELOAD environment variable. For best binary compatibility, you can obtain a glibc binary from a newer distribution version, or rebuild a newer glibc version for RHEL 5.6.
Also, try to fiddle with the LD_DEBUG environment variable to see what the dynamic linker does.
Ok, I believe I should mention "last step" which in my case included patching of binary 3rd party libraries.
Using objdump I found an address where lib3rdparty.so searches for GLIBC_2.6
Using hexedit I replaced this address with the one where GLIBC_2.5 was exported (you should search for bytes in reversed order). Also I replaced symbol with 2.5.
Using objdump I've checked that all references now using GLIBC_2.5
I needed to rebuild libcheat.so as sched_getcpu now was referencing GLIBC_2.5, so I used sched_getcpu##GLIBC_2.5 as assembler inline
After that I put libcheat.so near lib3rdparty.so, set LD_LIBRARY_PATH to . and my binary started to work. I'm not sure that this stuff will work totally correct, but if you stumbled into this kind of problem, this question and answer might be of some help.

Resources