How Do Applications Resolve to Different Versions of Shared Libraries at Run Time

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 be libmy.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:

  1. Right Click on the Project => Properties => C/C++ Build => Settings
  2. 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



Leave a reply



Submit