loading a shared library from any directory - linux

I'm playing with shared library linking and loading procedures, and trying to learn about different ways to tackle the loading error:
error while loading shared libraries: ... : cannot open shared object file: No such file or directory
I managed to solve it by using LD_LIBRARY_PATH and by using rpath. I now try to comprehend the usage of ldconfig and how it can solve it, too [some of my web sources: 1, 2, 3 ]
So, I've got the following source files: test.c func1.c func2.c. Here's what I do:
Compiling them into PIC .obj files:
$ gcc -Wall -fPIC -c *.c
Creating a shared library from the object files, naming it 'libshared.so', and using 'soname':
$ gcc -shared -Wl,-soname,libshared.so -o libshared.so *.o
Linking with a shared library by telling GCC where to find the shared library (the ... is just an abbreviation for my personal shared library path):
$ gcc -L/home/.../my_shared_library -Wall -o mytest test.c -lshared
Now, I try running it, and get the loading error:
./mytest: error while loading shared libraries: libshared.so: cannot open shared object file: No such file or directory
So I try telling the loader to search my private directory for the shared library file:
ldconfig -n home/.../my_shared_library
(I also tried it with: ldconfig -n .-L when my working directory is home/.../my_shared_library)
and tried running it once again, but I still get the same error. What am I doing wrong?

Use GNU Libtool to simplify the process and avoid such errors.
Also use -fPIC option when you build your library.

Read Program Library HowTo & Drepper's paper: How to Write Shared Libraries
You probably want to set the rpath. See this question.
You might load your plugin at runtime with dlopen(3). Notice that shared object paths without any / are handled specially.

Related

How do I use a .lib with the "Visual C++ for linux" plugin?

I'm using the Visual C++ for Linux plugin. I can run a basic Hello world without problems. My actual project uses a .lib. It compiles fine but I get an error during linking (this is copied from Visual Studio's output pane):
ClCompile:
Starting remote build
Compiling sources:
Invoking g++
g++ -c -x c++ /home/devbox/projects/LinuxProgServ/LinuxProgServ/main.cpp -I /home/devbox/projects/LinuxProgServ/include/libuv -I /home/devbox/projects/LinuxProgServ/../include/lubuntu -I "/home/devbox/projects/LinuxProgServ/../include/lubuntu/x86_64-linux-gnu" -g2 -gdwarf-2 -o "/home/devbox/projects/LinuxProgServ/obj/x64/Debug/main.o" -Wall -Wswitch -W"no-deprecated-declarations" -W"empty-body" -Wconversion -W"return-type" -Wparentheses -W"no-format" -Wuninitialized -W"unreachable-code" -W"unused-function" -W"unused-value" -W"unused-variable" -O0 -fno-strict-aliasing -fno-omit-frame-pointer -fthreadsafe-statics -fexceptions -frtti -std=c++11
main.cpp
Done compiling '/home/devbox/projects/LinuxProgServ/LinuxProgServ/main.cpp'
Link:
Linking objects
Invoking ld
g++ -o "/home/devbox/projects/LinuxProgServ/bin/x64/Debug/LinuxProgServ.out" -Wl,--no-undefined /home/devbox/projects/LinuxProgServ/obj/x64/Debug/main.o -llibuv.lib
/usr/bin/ld: cannot find -llibuv.lib
collect2: error: ld returned 1 exit status
libuv.lib is specified in Project Properties>Linker>Input>Library Dependencies. I tried the following without success:
Copy the lib to /home/devbox/projects/lib and add that directory to
the linker command with -L, both using Visual Studio's additional
library folder field and directly in the Additional command line
options field. This results in the same final command.
Copy the lib to the output directory and set it to be copied
Add the local Windows path to Visual Studio's additional library folders
Add the linux path from #1 to Visual Studio's additional library folders
Try with another library
I made the same project but for Windows just to be sure and it works.
Am I missing something? Obviously I could just run the commands myself or use any variant of *make but that's not the point.
When you pass a library to g++ with -l, g++ helpfully prefixes the name you give with lib then looks for a file of that name with a .so or .a extension on the library search path. By convention, shared libraries (dlls) have the .so extension and static libraries the .a extension.
The route of least resistance would be to build your library with the .a extension, i.e. libuv.a then specify it to the VCLinux project library dependencies as uv. And specify the library search path with -L, as you do in your step 1.
Alternatively, you can put the full path of the library on the g++ link command line, without -l prefix, i.e. /home/devbox/projects/lib/libuv.lib and g++ will use it in the same way it uses other object files. Set via Linker/All Options/Additional Options.
Update: on reflection, this second approach won't work. Although g++ (gcc) will accept the library as an input when specified with its fully qualified path, the library must appear after the program object files for references to be resolved. Unfortunately there is no control over positioning of Additional Options in VCLinux which always puts them at the front of the parameter list on the g++ command line, i.e. before the object file(s). :(
And, at the risk of stating the obvious, the library must be built on Linux with g++ and be located on a path visible to g++ when linking your program.

Building of shared libs which depend on each other (Linux)

I have a very complex bunch of libs and executables taken over (Linux). The whole system was developed using static libraries in the past, then a couple years ago the libs are migrated to be shared libraries (-fPIC etc). Checking the dependencies I found out, that there are two shared libs: libA and libB:
libA calls some functions from libB
libB calls some functions from libA
I would like to build the libs having proper dependencies: libA depends on libB and libB depends on libA. But I can't give "-llibB" to the linker, because the lib is not yet existing at the build time of libA
If I build libA without the dependancy of libB (creating unresolved symbols), I have to keep in mind if I use libA I have to link libB also, because of undefined symbols in libA. That's annoing!
What I'm looking for is a possibility to build libA and telling to the linker to create dependancy to libB WITHOUT having libB at this time, is that possible?
How can I solve my problem without merging libA and libB together?
Regards,
peters
Edit:
I found out, that I can directly generate an empty lib (without writing a source code):
gcc -shared -Wl,-soname,libB.so.$(MAJOR) -o libB.so
then I can build libA adding: -lB to the build command. After that I removed the libB.so.
Finally, after installation the libB refers to libA and libA refers to libB.
Of course the MAJOR number must match the MAJOR of the libB, this is so, because the major number is common for all libs.
I'm just asking myself if there is more suitable way to do it?
Dependencies between shared libraries aren't resolved until load time, so you can link with the following line:
gcc -shared -Wl,-soname,libA.so.$(AMAJOR) -o libA.so
gcc -shared -Wl,-soname,libB.so.$(BMAJOR) -o libB.so
and then
gcc -o myProgram a.o b.o c.o libA.so libB.so
when you load(run) myProgram, the dynamic loader will follow the unsatisfied dependencies and look for the symbols in both shared objects. The -shared option is actually a non-complaint-about-unresolved-symbols flag that allows to construct an ELF file without all resolved symbols.
Another thing that can be happening here is that the libreries are not installed. You are trying to execute them without the proper paths and get unresolved symbols (from myProgram) when executing it. One solution is to run myProgram with:
LD_LIBRARY_PATH=. myProgram
or
export LD_LIBRARY_PATH=/path/to/libraries
myProgram
In linux, libraries are cached in a system database, so loading of shared libraries is fast. Database is indexed by soname, and to regenerate the database you have to use command ldconfig(8) as root
ldconfig
Other environments may not use ldconfig(8) at all (solaris being an example)

Do permanent linking to other shared libraries

currently I'm creating a shared library "libmylib.so" using libtool with statements like this:
libtool --mode=compile g++ -Wall -fPIC -shared $(CFLAGS) $(LFLAGS) $(LSTATIC)
libtool --mode=link g++ -shared -export-symbols-regex beam_ -rpath /usr/lib -lotherlib
The library created with this depends on an other (non-static) library "libotherlib.so", that's why I'm using the statement "-lotherlib".
Now when I build an executable that links against libmylib.so something strange happens: I have to link against libotherlib.so again, means I have to add a statement "-lotherlib" for this executable too.
So it seems former linking of libotherlib.so when building libmylib.so does not to be persistent. But how can I change this? How can I build libmylib.so so that it implicitely knows about its dependency to shared library libotherlib.so?
Thanks!
The answer seems to be the same like for this question: Link a static library to a shared one during build?
Big difference: when shared objects are specified for linking instead of static ones they are not included but the generated shared library remembers its dependnecy to these so's.

Link a static library to a shared one during build?

I have a problem building a shared library with GCC/Linux. Currently this shared library is created with GCC/libtool option "-shared" and everything is fine.
Now there are two additional, static libraries (.a-files) that have to be added to this shared one since they provide some functionality that is required by the shared one. Adding these static libraries with option "-l" does not help, afterwards they are not part of the .so file.
So how can I force GCC/libtool to really add the code of these static libraries to the shared library?
Thanks!
You need --whole-archive linker option in this case to command the linker to include whole static libs' content into the shared lib.
g++ -shared sample.o -o libSample.so -Wl,-whole-archive -lmylib1.a -lmylib2.a -Wl,-no-whole-archive
From man ld:
For each archive mentioned on the command line after the --whole-archive option, include every object file in the archive in the link, rather than searching the archive for the required object files. This is normally used to turn an archive file into a shared library, forcing every object to be included in the resulting shared library. This option may be used more than once.
Two notes when using this option from gcc: First, gcc doesn't know about this option, so you have to use -Wl,-whole-archive. Second, don't forget to use -Wl,-no-whole-archive after your list of archives, because gcc will add its own list of archives to your link and you may not want this flag to affect those as well.
You only need the --whole-archive parameter to force the linker to include the library, but it should be able to infer its own needs from unmatched symbols.
Ensure that any static libraries on the command-line come after their dependent object-files e.g.:
g++ -Wl,-E -g -pipe -O2 -pipe -fPIC myobjectfile.o mystaticlibrary.a -shared -o mylib.so

Any way to make LD record shared library name only, no subdirs?

I am linking a Linux executable referencing a shared library:
g++ Debug/file.o Debug/MyLib.so -o Debug/MyApp -Wl,--rpath='$ORIGIN'
The problem is that the generated MyApp file references "Debug/MyLib.so" so if I run it from the Debug directory, it does not find it. Thus, specifying -Wl,--rpath='$ORIGIN' does not help.
Is there a way to tell the GNU LD to use the 'Debug/MyLib.so' file, but record it as just 'MyLib.so' inside the executable?
If don't want to change the name of your library, you can use the soname option when
you create it.
For example:
build the library
$> g++ -fpic -c mylib.cpp
$> g++ -shared -o subdir/mylib.so mylib.o -Wl,-soname=mylib.so
build the program
g++ -o subdir/main main.cpp -Lsubdir -l:mylib.so -Wl,-rpath='$ORIGIN'
(Don't forget the colon after the -l option)
You're linking inappropriately for a shared library. You should rename the library to libMyLib.so, and link your executable using:
g++ Debug/file.o -o Debug/MyApp -Wl,--rpath='$ORIGIN' -LDebug -lMyLib
What the -LDebug says is search in the Debug directory for libraries at link time, and then the -lMyLib says look for a library called libMyLib.so (or libMyLib.a) in the paths that -L specifies, plus the standard library search path.
The standard naming convention for libraries under linux/unix is libLibraryName, and the linker knows when you ask to link to a library using -l, that it should look for a file prefixed lib thatname
When you used it in the prior form, it actually recorded the absolute library that was used when linking, rather than the normal mechanism of just recording the name of the library, and relying on the runpath to resolve the path to the library.

Resources