How do applications resolve to different versions of shared libraries at run time?
Versioning of shared objects works as follows:
When you create a shared object, you give it both a real name and an soname
. These are used to install the shared object (which creates both the object and a link to it).
So you can end up with the situation:
pax> ls -al xyz*
-rw-r--r-- 1 pax paxgroup 12345 Nov 18 2009 xyz.so.1.5
lrwxrwxrwx 1 pax paxgroup 0 Nov 18 2009 xyz.so.1 -> xyz.so.1.5
lrwxrwxrwx 1 pax paxgroup 0 Nov 18 2009 xyz.so -> xyz.so.1
with xyz.so.1.5
possessing the SONAME
of xyz.so.1
.
When the linker links in xyz.so
, it follows the links all the way to xyz.so.1.5
and uses its SONAME
of xyz.so.1
to store in the executable. Then, when you run the executable, it tries to load xyz.so.1
which will point to a specific xyz.so.1.N
(not necessarily version 1.5).
So you could install xyz.so.1.6
and update the xyz.so.1
link to point to it instead and already-linked executables would use that instead.
One advantage of this multi-layer method is that you can have multiple potentially incompatible libraries of the same name (xyz.so.1.*
, xyz.so.2.*
) but, within each major version, you can freely upgrade them since they're supposed to be compatible.
When you link new executables:
- Those linking with
xyz.so
will get the latest minor version of the latest major version. - Others linking with
xyz.so.1
will get the latest minor version of a specific major version. - Still others linking with
xyz.so.1.2
will get a specific minor version of a specific major version.
Now keep that last paragraph in mind as we examine your comment:
Now lets say I compile another version of the same library with the following real-name,
libmy.so.2.0
. The SONAME by guidelines would belibmy.so.2.0
.
No, I don't believe so. The soname
would be more likely to be libmy.so.2
so that you can make minor updates to the 2.x
stream and get the latest behaviour.
Linking with multiple versions of a library
Thanks for all the responses. I have a solution that seem to be working.
Here's the problem in detail with an example.
In main.c we have:
#include <stdio.h>
extern int foo();
int bar()
{
printf("bar in main.c called\n");
return 0;
}
int main()
{
printf("result from foo is %d\n", foo());
printf("result from bar is %d\n", bar());
}
In foo.c we have:
extern int bar();
int foo()
{
int x = bar();
return x;
}
In bar.c we have:
#include <stdio.h>
int bar()
{
printf("bar in bar.c called\n");
return 2;
}
Compile bar.c and foo.c:
$ gcc -fPIC -c bar.c
$ gcc -fPIC -c foo.c
Add bar.o to a static library:
$ ar r libbar.a bar.o
Now create a shared library using foo.o and link with static libbar.a
$ gcc -shared -o libfoo.so foo.o -L. -lbar
Compile main.c and link with shared library libfoo.so
$ gcc -o main main.c -L. -lfoo
Set LD_LIBRARY_PATH to find libfoo.so and run main:
$ setenv LD_LIBRARY_PATH `pwd`
$ ./main
bar in main.c called
result from foo is 0
bar in main.c called
result from bar is 0
Notice that the version of bar in main.c is called, not the version linked into the shared library.
In main2.c we have:
#include <stdio.h>
#include <dlfcn.h>
int bar()
{
printf("bar in main2.c called\n");
return 0;
}
int main()
{
int x;
int (*foo)();
void *handle = dlopen("libfoo.so", RTLD_GLOBAL|RTLD_LAZY);
foo = dlsym(handle, "foo");
printf("result from foo is %d\n", foo());
printf("result from bar is %d\n", bar());
}
Compile and run main2.c (notice we dont need to explicitly link with libfoo.so):
$ gcc -o main2 main2.c -ldl
$ ./main2
bar in bar.c called
result from foo is 2
bar in main2.c called
result from bar is 0
Now foo in the shared library calls bar in the shared library and main calls bar in main.c
I don't think this behaviour is intuitive and it is more work to use dlopen/dlsym, but it does resolve my problem.
Thanks again for the comments.
How to specify the library version to use at link time in eclipse?
I coworker helped me to solve this:
- Right Click on the Project => Properties => C/C++ Build => Settings
- Under GCC C++ Linker => Miscellaneous: Write the full name of your library, including the library path. Similar to the indications on this post for building with GCC.
Linux accommodates multiple versions of a shared library but what about includes?
Include-files are handled differently from shared libraries:
With shared libraries, there will be one name for development packages to use when linking, which is a symbolic link to a file which has a specific
soname
(name plus version). After linking, a program has a reference to that file which is used whenever running the program.Include-files can be distinguished by the
-I
option for include-paths. When there are multiple useful versions of a library, some developers may package the versions using different directory names for holding the related header files. That way, changing just the-I
option when compiling makes the build scripts able to work with a specific version of the headers. But unlike shared libraries, the header files are used only when building the program which uses a library.
Related Topics
Error on Execution -Version 'Qt_5' Not Found Required By
How to Search for Files Containing Dos Line Endings (Crlf) with Grep on Linux
How to Kill All Linux Processes That Are Older Than a Certain Age
How to Pass a Wildcard Parameter to a Bash File
View Tabular File Such as CSV from Command Line
Linux Vi Arrow Keys Broken in Insert Mode
Bash Capturing Output of Awk into Array
Setting Creation or Change Timestamps
How to Convert Linux 32-Bit Gcc Inline Assembly to 64-Bit Code
How to Modify the Source of Buildroot Packages for Package Development
Linux: Remove File Extensions for Multiple Files
Docker-Compose Up and User Inputs on Stdin
Remove a Symlink to a Directory