Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Linking with multiple versions of a library

I have an application that statically links with version X of a library, libfoo, from thirdparty vendor, VENDOR1. It also links with a dynamic (shared) library, libbar, from a different thirdparty vendor, VENDOR2, that statically links version Y of libfoo from VENDOR1.

So libbar.so contains version Y of libfoo.a and my executable contains version X of libfoo.a libbar only uses libfoo internally and there are no libfoo objects passed from my app to libbar.

There are no errors at build time but at runtime the app seg faults. The reason seems to be that version X uses structures that have a different size they version Y and the runtime linker seems to be mixing up which get used by which.

Both VENDOR1 & VENDOR2 are closed source so I cannot rebuild them.

Is there a way to build/link my app such that it always resolves to version X and libbar alway resolves to version Y and the two never mix?

like image 295
YerBlues Avatar asked Jul 12 '10 22:07

YerBlues


People also ask

What is linking static library?

Static Linking and Static Libraries is the result of the linker making copy of all used library functions to the executable file. Static Linking creates larger binary files, and need more space on disk and main memory. Examples of static libraries (libraries which are statically linked) are, . a files in Linux and .

How shared library are linked?

Shared libraries (also called dynamic libraries) are linked into the program in two stages. First, during compile time, the linker verifies that all the symbols (again, functions, variables and the like) required by the program, are either linked into the program, or in one of its shared libraries.

Are shared libraries the same as dynamic libraries?

Dynamic and shared libraries are usually the same. But in your case, it looks as if you are doing something special. In the shared library case, you specify the shared library at compile-time. When the app is started, the operating system will load the shared library before the application starts.

What is dynamic link library and static library?

A static library must be linked into the final executable; it becomes part of the executable and follows it wherever it goes. A dynamic library is loaded every time the executable is executed and remains separate from the executable as a DLL file.


3 Answers

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.

like image 125
YerBlues Avatar answered Sep 30 '22 11:09

YerBlues


Try a partial link so that you have an object file "partial.o" with libbar and libfoo-Y. Use objcopy with "--localize-symbols " to make the symbols in partial.o from libfoo-Y local. You should be able to generate by running nm on libfoo-Y and massaging the output. Then take the modified partial.o and link it to your app.

I've done something similar with gcc toolchain on vxWorks where dynamic libs are not a complication but two versions of the same lib needed to link cleanly into a monolithic app.

like image 42
bstpierre Avatar answered Sep 30 '22 12:09

bstpierre


Sorry no. My understanding of the way that Linux (and possibly most *nixes) is that that is not possible. The only 'solution' for your problem I can think of, is if you create a proxy app, which exposes what you need from libbar in the form of some IPC. You can then make that proxy load the correct version using LD_LIBRARY_PATH or something simmilar.

like image 33
Gianni Avatar answered Sep 30 '22 10:09

Gianni