Rpath/Runpath handle with dependent shared libraries in CMAKE - c++

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).

Related

Link libraries to linux biinary file in c++

I'm compiling a c++ program using g++ and i am using two libraries called libsdl2-dev and libsdl2-image-dev
I installed both these libraries in my ubuntu machine with the commands
apt install libsdl2-dev libsdl2-image-dev and when I compile the program everything works fine. Then I copied these libraries from /usr/lib/x86_64-linux-gnu/ to my working dir with the binary file to be able to give this folder to someone else.
The problem comes when the user that hasn't installed these libraries tries to open my program by writing ./main (the binary file). Since he hasn't installed these libraries he would get an error like "can't open shared object: no such file or directory".
This happens because the binary file looks for these libraries in /usr/lib etc...
What i need
I need that my binary file looks for these libraries in the same folder,and not in /usr/lib/x86 etc.., from what I read I have to do something like rpath
The IDE used is Sublime Text and the syntax used to compile all my files is this:
g++ -c src/*.cpp -std=c++14 -m64 -g -Wall -I include && g++ *.o -o bin/debug/main -lSDL2main -lSDL2 -lSDL2_image && ./bin/debug/main`
Structure of folders
I got the project dir with and inside that i got 4 more directories, each one called: bin (with the debug subdirectory, where we got the final compile), include (with hpp files), res (with all textures), and src with all cpp files to compile, the other files are project files and .o files
I'm using Ubuntu 20.04-2 LTS and the same is for the other user's PC
Thanks in advance for any help!
That's because the dynamic linker loading runtime dependencies looks for them in some specified locations, which are "by default" your system library directories (where those libraries got installed by apt).
The other user should ideally install those libraries too (which could be done "automatically" if you build a .deb package with proper dependencies)
Otherwise you would have to change the runpath of your program by adding -Wl,-rpath='$ORIGIN', which makes the dynamic linker look for dependencies just where the binary is located.
$ORIGIN here is a special variable meaning "this executable" which is what you wanted to achieve.
see rpath
and A description of RPATH $ORIGIN
I found a way to resolve!
I used the program patchelf to add an rpath to my directory (linked to the binary file) now everything works
use ldd ./bin/debug/main to check the library
export LD_LIBRARY_PATH =$LD_LIBRARY_PATH:"your library path"
run the program,if this is not work. use patchelf to change the rpath to you r library

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

Compiling a c++ code into a single package containing all dependencies

I have a cpp project that uses several libraries to which I have both *.so and *.a libraries. How should I compile my code to produce a self-containing library that doesn't require the user to install the dependencies ( and preferably hides dependencies from the user) ?
Let's assume code is c.cpp and libraries are liba.so and libb.so.
Goal to have a libc.so (or libc.a) with liba.so and libb.so transparent to the user.
What you need is static linking. Since you mention that you have the archive version of the library, it should work. Try using the -static flag with gcc for this.

Creating dummy shared object (.so) to depend on other shared objects

I'm trying to create a shared object (.so) that will make it so, by including one shared object with -lboost, I implicitly include all the boost libraries. Here's what I tried:
#!/bin/sh
BOOST_LIBS="-lboost_date_time-gcc43-mt -lboost_filesystem-gcc43-mt"
#truncated for brevity
g++ $BOOST_LIBS -shared -Wl,-soname,libboost.so.1 -o libboost.so.1.0
ln -si libboost.so.1.0 libboost.so.1
ln -si libboost.so.1 libboost.so
After placing all 3 created files (libboost.so libboost.so.1 libboost.so.1.0) in the same directory as all the boost libraries, I tried compiling a test program with it (which depends on -lboost_date_time-gcc43-mt):
g++ -lboost test.cpp
Doing this, I got the same undefined reference message as not having -lboost. Having -lboost_date_time-gcc43-mt works, but that's too wordy :) How do I get -lboost to automatically bring in the other shared libraries?
You don't. Not really, anyway.
The linker is stripping out all of the symbol dependencies because the .so doesn't use them.
You can get around this, perhaps, by writing a linker script that declares all of the symbols you need as EXTERN() dependencies. But this implies that you'll need to list all of the mangled names for the symbols you need. Not at all worth the effort, IMO.
I don't have a solution for creating a dummy '.so', but I do have something that will simplify your life... I highly suggest that you try using cross-platform make (CMake). In CMake, linking against those libraries is easy:
FIND_PACKAGE(Boost 1.37 COMPONENTS date_time filesystem REQUIRED)
ADD_EXECUTABLE(myexecutable ${myexecutable_SRCS})
TARGET_LINK_LIBRARIES(myexecutable ${Boost_LIBRARIES})
The commands above, if placed in a "CMakeLists.txt" file, is all you need to:
Verify that Boost 1.37 or later is installed, with the "date_time" and "filesystem" libraries installed.
Create an executable named "myexecutable" from the sources listed in the corresponding variable.
Link the executable "myexecutable" against the boost "date_time" and "filesystem" libraries.
See also: Why the KDE project switched to CMake.
Actually, making one .so depend on all boost .so files is quite possible (but might not actually help you). I've just tried this:
$ export BOOST_ROOT=/home/ghost/Work/Boost/boost-svn
$ g++ -shared -Wl,-soname,libboost.so -o libboost.so $BOOST_ROOT/stage/lib/libboost_program_options.so
$ g++ -L . -I $BOOST_ROOT first.cpp -lboost -Wl,-R$BOOST_ROOT/stage/lib
$ LD_LIBRARY_PATH=.:$BOOST_ROOT/stage/lib ./a.out
And it did work. However, note that dancing with -R and LD_LIBRARY_PATH. I don't know an way how you can include the path to Boost .so inside your libboost.so so that they are used both for linking and actually running the application. I can include rpath inside libboost.so just fine, but it's ignored when resolving symbols for the application.

How to install and use libtool shared library (.lo files)?

So after I ran libtool and got out a libfoo.lo and foo.o file from my library source, how do I convert the libfoo.lo file into a normal Linux shared library, like libfoo.so.1.0.0 so I can install and link to it on my target system?
From the outputs mentioned in the question, it looks like you ran libtool with --mode=compile mode. You will need to run libtool again with --mode=link to produce .a and .so libraries.
libtool is just a simple wrapper for gcc, ln ar and ranlib which is needed to produce libraries. All it does is run gcc adding the necessary options to ensure that your static and shared libraries are created correctly.
When compiling libtool inserts the -fPIC tag to ensure the necessary generation of position independent code needed for shared libraries. The .o files are normal object files that can be archived into a static .a file. The .lo files are object files with position independent code which can now be linked into a .so file.
When linking libtool will run ar to create a static library or ln to link the objects files into a .so shared library.
libtool also can install the library when desired using the --mode=install.
See http://www.gnu.org/software/libtool/manual/libtool.html for more info.
Please remember that when building an executable there are always two stages, compiling and linking.