I am trying to generate a c++ library using the g++ compiler. My library has another C library as dependency and I have compiled it in order to obtain the .so files.
I have the following structure:
src:
include/linux:
libcustom.a
libcustom.la
libcustom.so
libcustom.so.0
libcustom.so.0.0.0
Now, when I have all the .o files of my cpp classes, and I want to link the library, I execute the following command:
g++ -shared -L/usr/lib/R/lib -Wl,-Bsymbolic-functions -Wl,-z,relro -o mylibrary.so File1.o File2.o File3.o -L./include/linux -lc++ -lutil -lm -lcustom -Wl,-rpath='$ORIGIN/include/linux' -L/usr/lib/R/lib -lR
But it throws me the error:
libcustom.so.0: cannot open shared object file: No such file or directory
I am executing the command from the src directory.
I know it could be fixed editing the LD_LIBRARY_PATH, but the idea it is someone can use my library without the need of configuring anything, so I am trying to do that with the c++'s -rpath flag.
Any idea how can I fix it, or the reason for the error?
The error message you got seems to come from the run-time loader ld.so instead of the linker ld (I know the names are confusing). You have to distinguish between finding so's at link-time and at run-time. The -L flag you give at link-time has nothing to do with localizing the library at run-time.
Your rpath=./include/linux value is not correct, because dot is not recognized by the ld as relative path. Relative searching path should be given like
-Wl,-rpath='$ORIGIN/include/linux'
where the $ORIGIN represents the folder where your executable (not mylibrary.so) locates. Make sure to use single quote and not double quote because the string $ORIGIN should be passed to the linker literally and hard coded into the executable file.
More details goes
how to link to shared lib from shared lib with relative path
ld: Using -rpath,$ORIGIN inside a shared library (recursive)
Related
The book Advanced Linux Programming contains:
The system searches only /lib and /usr/lib, by default. If a shared library that is linked into your program is installed outside those directories, it will not be found, and the system will refuse to run the program.
One solution to this problem is to use the -Wl, -rpath option when linking the program. Another solution to this problem is to set the LD_LIBRARY_PATH environment variable when running the program.
So from information above, I assume adding path to $LD_LIBRARY_PATH is equivalent to passing argument to linker when compiling something like -Wl,-rpath,SOME_PATH until I hit this problem:
I am trying to generate a shared library and this shared library depends on some .so files somewhere at my system. Here's the command for compilation:
g++ -fPIC -shared -Wl,-soname,libA.so -o libA.so SRC.cpp -L PATH_A -I PATH_B -Wl,-rpath,PATH_C:PATH_D:PATH_E -la -lb -lc
After I compile, I use ldd to check if there's any dependency issue and something unexpected to me happens:
Some of dependency are found and some of them are not (libA.so => not found), however all the paths it needs (PATH_C PATH_DPATH_E) have been passed to argument -Wl,-rpath.
So it seems -Wl,-rpath does not work for this case , the only solution to make it work is to add the path to libA.so to $LD_LIBRARY_PATH and ldd returns that all the dependency are found.
I would like to know why -Wl,-rpath fails in, what's the difference between adding the path to $LD_LIBRARY_PATH and passing an argument to -Wl,-rpath?
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
I was using gpgpu-sim, a GPU simulator, to conduct researches. There are several .so files in my own folder:
And there are some alternatives .so in Nvidia's cudart lib folder:
And there are some .o files and need to be linked with libcudart.so, when I type in the command:
g++ -L "Path/to/MyFolder" -l cudart *.o
I hope the generated a.out would link to libcudart.so, but it just linked to a strange so file:
libcudart_gpgpu-sim_git-commit-6443f21d433f1b642003867e56fe1f54efae55e3_modified_0.so => not found
And when I typed this code:
g++ -L "Path/to/NvidiaFolder" -l cudart *.o
The program can sussessfully find libcudart.so.9 in my LD_LIBRARY_PATH folder,but it shows that the version can't match!:
./a.out: /path/to/myFolder/libcudart.so.9.0: version `libcudart.so.9.0'not found (required by ./a.out)
Can anybody tell me how ld works and how to solve those problems?
I finally find out the reason.
if you use this code to link objects to generate a shared library:
g++ -shared -Wl,-soname,libNAME_A.so -o libNAME_B.so
then, if some on is trying to link NAME_B.so using:
g++ <INPUT> -lNAME_B -o <OUTPUT>
the output will finally look for libNAME_A.so.
refer to g++ man page:
-Wl,option
Pass option as an option to the linker. If option contains commas,
it is split into multiple options at the commas. You can use this
syntax to pass an argument to the option. For example,
-Wl,-Map,output.map passes -Map output.map to the linker. When
using the GNU linker, you can also get the same effect with
-Wl,-Map=output.map.
and for ld man page:
-soname=name
When creating an ELF shared object, set the internal DT_SONAME
field to the specified name. When an executable is linked with a
shared object which has a DT_SONAME field, then when the executable
is run the dynamic linker will attempt to load the shared object
specified by the DT_SONAME field rather than the using the file
name given to the linker.
There is nothing to do with CUDA here, it's just a linking and runtime environment setup problem.
The ld linker searches for objects and library archives following the order specified by -L option parameters, and only after into default system directories. The linker will link the object code that first match this search.
At runtime, if you linked against dynamic libraries (.so files) you will need to properly define the LD_LIBRARY_PATH environment variable with a list of paths to look for dynamic libraries, separated by colon (:).
So if you link to your objects using libraries from your local path (assuming you are looking for libcudart.so):
g++ -o myprogram *.o -L "/Path/to/myFolder" -lcudart
you need to set LD_LIBRARY_PATH as follows before running your program:
export LD_LIBRARY_PATH="/Path/to/myFolder:$LD_LIBRARY_PATH"
./myprogram
I hope this help and clarify your understanding. Frankly I don't understand the origin of your libcudart_gpgpu-sim_git-commit match
I use MinGW32 more specifically TDM-GCC-32. I have very simple project I link to one custom library but this error pops out:
>g++ -D_WIN32 -D_MINGW -lgdi32 -lgdiplus -Linterception/x86 -linterception main.cpp -o interceptor.exe
interception/x86/libinterception.a(dgnes00125.o):(.text+0x0): multiple definitio
n of `atexit'
C:/TDM-GCC-32/bin/../lib/gcc/mingw32/5.1.0/../../../crt2.o:crt1.c:(.text+0x2c0):
first defined here
interception/x86/libinterception.a(dgnes00109.o):(.text+0x0): multiple definitio
n of `_onexit'
C:/TDM-GCC-32/bin/../lib/gcc/mingw32/5.1.0/../../../crt2.o:crt1.c:(.text+0x2d0):
first defined here
C:/TDM-GCC-32/bin/../lib/gcc/mingw32/5.1.0/../../../../mingw32/bin/ld.exe: C:/TD
M-GCC-32/bin/../lib/gcc/mingw32/5.1.0/../../../crt2.o: bad reloc address 0x20 in
section `.eh_frame'
collect2.exe: error: ld returned 1 exit status
Commands I use to build the library:
gcc -DINTERCEPTION_EXPORT -D_WIN32 -D_MINGW -shared -o interception.dll interception.c
dlltool -z interception.def --export-all-symbol interception.dll
dlltool -d interception.def -l libinterception.a
I guess I have to use different options for compiling the library to avoid redefinitions..
The dlltool method I believe is currently deprecated. I can't fault you here though, as most of the available documentation still says to do it this way.
Gcc will link directly against .dll files, making .a files obsolete (at least for dealing with dll's - the only current reason to use a .a file is for static linking). You don't even have to specify the dll with the -l flag, although you have to specify the path of the dll if it's not in your current directory
C:\Users\burito>gcc main.o opengl32.dll -o main.exe
gcc: error: opengl32.dll: No such file or directory
C:\Users\burito>gcc main.o c:\Windows\system32\opengl32.dll -o main.exe
C:\Users\burito>
Ok, opengl32.dll is perhaps not a great example, but I hope I've given you the general idea.
I believe MSVC still needs its .lib files to use a .dll, for which there are several ways of making them if the library doesn't come with one.
In your specific case, the command that should work would be...
g++ -D_WIN32 -D_MINGW -lgdi32 -lgdiplus interception/x86/interception.dll main.cpp -o interceptor.exe
If for whatever reason you really do need to create a .a file from a .dll, the command that has worked for me is...
gendef interception.dll
dlltool -l interception.a -d interception.def -k -A
As the repository you linked does provide .dll files in its releases, you shouldn't have to build them yourself
I am writing a C++ program in Linux with NetBeans. I am having difficulty setting it up to use external sources/shared objects. I have the .so files from the compiled external package and the source files that go with it.
So far I have:
specified for the project to include all the source and header file directories (under Project properties->Build->C++ Compiler)
specified the .so files that correspond to the external source code (under Project properties->Build-Linker)
When I try to declare an object defined in the external sources NetBeans does not give me any syntax errors and even auto-completes the object name for me. However, when I build the program I get an error saying "undefined reference to" that object.
Am I doing something horribly wrong?
EDIT:
In response to quamrana's question, this is one of the output lines in the console when it attempts to build.
g++ -o dist/Debug/GNU-Linux-x86/JAUSTester build/Debug/GNU-Linux-x86/MainScreen.o build/Debug/GNU-Linux-x86/main.o build/Debug/GNU-Linux-x86/moc_MainScreen.o -L/usr/lib -Wl,-rpath /usr/local/lib/active /usr/local/lib/active/libcxutils.so -Wl,-rpath /usr/local/lib/active/libjauscore.so -Wl,-rpath /usr/local/lib/active/libjausextras.so -Wl,-rpath /usr/local/lib/active/libjausmobility.so -Wl,-rpath /usr/local/lib/active/libtinyxml.so -lQtGui -lQtCore -lpthread
The .so files I want to include are the ones specified there in /usr/local/lib/active/.