Why shared library is linked by absolute path? - c++

I create an application by linking the libociei.so and libcustome.so
CC -o main main.cpp ../lib/libociei.so ../lib/libcustome.so
and copy libociei.so libcustome.so to /usr/lib
then I use ldd to check library, it shows:
main .....
libcustome.so ===> /usr/lib/libcustome.so
../lib/libociei.so
why libociei.so is not relocated to /usr/lib/libociei.so ?
ps : ld library path is /lib:/usr/lib and I do not add ../lib to ld library path

If you are on linux (say Ubuntu) then it is probably because you did not run:
sudo ldconfig
On other systems I am not so sure.

When you use readelf -d main does the NEEDED entries have the full path?
My guess is that ldd is seeking the libraries in the default path.

Related

Rpath/Runpath handle with dependent shared libraries in CMAKE

I will put you in context:
I have 2 third party shared libraries: libA.so and libB.so. My program contains only calls to libA.so symbols. The libA.so internaly needs to call to libB.so. If I readelf LibA.so it has a RunPath pointing to a path from the third party developer that doesn't exsist in my system.
My program builds with cmake. I use find_library(A) and find_libary(B) and then add them to my program executable target with target_link_libraries(my_executable PUBLIC A B)
With this setup the generated executable contains a correct RUNPATH for both libA.so and libB.so. The problem is that when running the executable the libB.so file is not found.
I need to keep the .so files in the place they are. Setting up LD_LIBRARY_PATH env variable or moving to a ldd valid folder is not an option. I have tried these solutions and they work btw.
How could I make the executable to find libB.so in this case.
Thanks in advance.
You can change RPATH with a tool named patchelf:
sudo apt install patchelf
patchelf --set-rpath \$ORIGIN libMyLibrary.so
Note that $ORIGIN here means "search in the folder where this library located". You can also combine values like this: \$ORIGIN:\$ORIGIN/../lib. This is convenient if you want to keep unix-like installation structure (executables in bin, libraries in lib).

g++ compiling: can I link to a directory with symlinked binaries?

The below compiles:
g++ -L../../lib -o my_prog my_prog.cpp -ltest1 -ltest2
where ../../lib contains symlinks to libtest1.so and libtest2.so
But I am getting an error when I run the program: "error while loading shared libraries: libtest1.so: cannot open shared object file: No such file or directory" and am not sure if symlinking is the culprit.
Option -L is for linker ld to find .a and .so during linking.
Option -Wl,-rpath= is for the dynamic linker ld.so to find .so when the application is run. You need to use -Wl,-rpath= when a required shared library is not in (standard system) directories specified in /etc/ld.so.conf.
Use $ORIGIN dynamic linker variable to make rpath relative to the path of your executable:
g++ -L../../lib -Wl,-rpath='${ORIGIN}/../../lib' -o my_prog my_prog.cpp -ltest1 -ltest2
Be careful to make sure ${ORIGIN} is not expanded by the shell or your makefile (this is why it is in single quotes).
${ORIGIN}:
$ORIGIN and rpath
ld.so understands the string $ORIGIN (or equivalently ${ORIGIN}) in an rpath specification (DT_RPATH or DT_RUNPATH) to mean the directory containing the application executable. Thus, an application located in somedir/app could be compiled with gcc -Wl,-rpath,'$ORIGIN/../lib' so that it finds an associated shared library in somedir/lib no matter where somedir is located in the directory hierarchy. This facilitates the creation of "turn-key" applications that do not need to be installed into special directories, but can instead be unpacked into any directory and still find their own shared libraries.
What happens at runtime is related to the rpath.
You may want (not really recommended, see this) to set your LD_LIBRARY_PATH appropriately before running your executable, or better yet you want to set the executable's rpath when linking it (e.g. by passing -Wl,--rpath $(realpath ../../lib/) to the g++ command doing the link.
Read Drepper's How to write shared libraries paper and the Program Library HowTo

How do you determine where the MySQLCPPConn library file is?

Consider the following Linux command to compile and run the MySQL Connector/C++ Example 1.
g++ test.cpp -lmysqlcppconn; ./a.out
I understand that the -l flag adds the specified library to the list of libraries to link, and the -L flag adds the specified directory to the list of directories to look in.
Q: Given that I did not specify the -L flag, how do I determine where mysqlcppconn is located?
My program compiles and runs without errors; however, I want to know where the MySQL Connector/C++ is installed. I've managed to find some MySQL headers in /usr/include/ and /usr/include/cppconn, and there is a directory called mysql in /usr/lib, but nothing named mysqlcppconn is inside.
Thank you! I am re-introducing myself to developing on a Linux environment, and have lots to re-learn and catch up on.
In Ubuntu or other debian derived system, you can use command dpkg with -L option to see installed files from deb package.
$ dpkg -L libmysqlcppconn7v5
/.
/usr
/usr/lib
/usr/lib/x86_64-linux-gnu
/usr/lib/x86_64-linux-gnu/libmysqlcppconn.so.7.1.1.9
/usr/share
/usr/share/doc
/usr/share/doc/libmysqlcppconn7v5
/usr/share/doc/libmysqlcppconn7v5/changelog.Debian.gz
/usr/share/doc/libmysqlcppconn7v5/copyright
/usr/lib/x86_64-linux-gnu/libmysqlcppconn.so.7
So the installation location for mysqlcppconn is /usr/lib/x86_64-linux-gnu/libmysqlcppconn.so
The library file is located in /usr/lib and called libmysqlcppconn. Both a static file and shared object file exist.
This answer is provided by πάντα ῥεῖ in the comment section.
The command ldd a.out will show what libraries the executable a.out is using.

shared object library not found when running program, but it's linked during compiling

Update: issue is solved. The library was Made for Armv7a CPUs but it was "soft float" Not "hard float". It seems like my machine is HF and Not SF compatible
My program depends on an externally build .so library called libMyLib.so. When I compile the program like this:
$ g++ -std=c++11 main.cpp -o run -pthread
it reports that there are a lot of undefined references, obviously because i didn't include libMyLib.so when compiling. So the compiler knows what he needs to compile the program. When i compile the program like this:
$ g++ -std=c++11 main.cpp -o run -pthread -lMyLib
it doesn't report any errors and creates the file "run". Notice that libMyLib.so is already in /usr/local/lib and it looks like it is linked when compiling since the references are defined now and the "run" file is created. But as i run the file, this happens:
$ ./run
./run: error while loading shared libraries: libMyLib.so: cannot open shared object file: No such file or directory
I've checked with ldd and it shows me this:
$ ldd run
...
libMyLib.so => not found
...
So ldd doesn't find the library on execution, but it finds it while compiling. I'm quite new to Linux and linking libraries so i don't know what to do.
Also, running ldd on the .so file returns this:
$ ldd /usr/local/lib/libMyLib.so
not a dynamic executable
I've already checked an this message may occur when running a .so file on the wrong platform. But i've checked, the library is compiled for arm (I'm running on a raspberry pi -> arm):
$ objdump -f /usr/local/lib/libMyLib.so | grep ^architecture
architecture: arm, flags 0x00000150:
I also update the linker:
$ sudo ldconfig -v
...
/usr/local/lib:
libwiringPi.so -> libwiringPi.so.2.44
libwiringPiDev.so -> libwiringPiDev.so.2.44
libMyLib.so -> libMyLib.so.1
...
I really have no clue why this might still happen. Can anyone help me?
/usr/local/lib is one of the directories that the linker searches by default
for libraries specified with the -l option, so your linkage succeeds.
At runtime however, the program loader by default searches for the linked
libraries in:-
/lib, /usr/lib and among the libraries whose names and locations have been cached in the ldconfig cache, /etc/ld.so.cache.
The directories listed in the value of the environment variable LD_LIBRARY_PATH,
in the current shell.
The ldconfig cache is only updated when ldconfig is run. See man ldconfig.
The loader fails to find libMyLib.so at runtime because you have not
run ldconfig since you placed that library in /usr/local/lib and
neither have you correctly added /usr/local/lib to the LD_LIBRARY_PATH
in the same shell in which you try to run the program.
It is inconvenient and otherwise undesirable to require a special setting of
LD_LIBRARY_PATH to enable a program to run.
To enable the loader to find your library, run ldconfig as root. This
will succeed provided that /usr/local/lib is listed in /etc/ld.so.conf,
or in one of the files included by /etc/ld.so.conf. If it's not, then
you can explicitly cache the shared libraries from /usr/local/lib by running
ldconfig /usr/local/lib, as root.
First check LD_LIBRARY_PATH variable is having the path to your library directory
$ echo $LD_LIBRARY_PATH
If not there then update the library path.
$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path/to/library
Use strace to debug.
strace -f ./run

Building Chilkat with a .sh file

I downloaded chilkat and I need to build it... I got 2 .sh files. The README says:
To build the C and C++ samples, first edit the c_sampleBuild.sh and
linkSample.sh scripts and set the "-L" option's path for the system libraries.
LinkSample.sh:
g++ -Wl,--enable-auto-import linkSample.cpp -o"linkSample.exe" -L. -libchilkat-9.5.0 -L/c/MinGW/lib -lcrypt32 -lws2_32 -ldnsapi
c_sampleBuild.sh:
#!/bin/bash -ev
gcc -c c_Sample.c -o"c_Sample.o"
g++ c_Sample.o -o"c_Sample.exe" -L. -lchilkat-9.5.0 -L/c/MinGW/lib -lcrypt32
-lws2_32 -ldnsapi
It's now clear how I should make that.... Help please :) Thanks
You haven't said what platform you are building on. But if you are using Windows + MinGW then:
The libraries for crypt32, ws2_32 and dnsapi can be downloaded from: here
For the g++ command, the -l (lowercase) option tells g++ which additional libraries you want to link against, and the -L (uppercase) option is used to tell g++ where to look for the libraries.
If you have a library file called libbar.a in the current folder (.) then you add the option (-L. -lbar)
Or, if you have a library in /path/to/foo/libbar.a then you add (-L/path/to/foo -lbar).
You will need to check the MinGW documentation for the locations of the system libraries, they are likely to be found in /lib or /usr/lib.