2010-07-12 64 views
26

我有一个应用程序与来自第三方供应商VENDOR1的库libfoo的版本X静态链接。它还与来自另一个第三方供应商VENDOR2的动态(共享)库libbar链接,该静态链接来自VENDOR1的libfoo版本Y.与多个版本的库链接

因此,libbar.so包含版本Y的libfoo.a和我的可执行文件包含libfoo.a的版本X libbar只在内部使用libfoo,并且没有从我的应用程序传递给libbar的libfoo对象。

构建时没有错误,但在运行时应用程序段出现故障。原因似乎是,版本X使用的结构具有不同的大小,它们的版本为Y,并且运行时链接程序似乎正在混合,哪些会被哪些使用。

两个供应商1 &供应商2是闭源的,所以我不能重建它们。

是否有建立/链接我的应用程序,使得它始终解析版本X和libbar的送花儿给人解析到版本Y和两个从未混合的方法吗?

+0

你可以让你的应用动态链接到VENDOR1吗? – 2010-07-12 23:31:32

+0

不以任何方式与语言无关。这对于编译器链接器和操作系统来说非常具体,它们是如何一起工作的。最简单的方法是通过电子邮件向供应商和他们如何解决这个问题。 – 2010-07-12 23:31:43

+0

我们目前的想法是,至少在linux上,使用libbar.so上的dlopen()和RTLD_DEEPBIND标志。另一种可能性是将libfoo.a的应用程序分离到共享库中,libbaz.so将libfoo.a封装起来,然后将应用程序dlopen libbaz.so和libbar.so与RTLD_LOCAL分离,我们认为这可能会保留所有重复的符号在内部。这可能适用于Linux,但我们需要它,因此也适用于Solaris,AIX和HPUX。 – YerBlues 2010-07-13 00:05:42

回答

11

感谢您的所有回复。我有一个似乎正在工作的解决方案。 下面是一个例子的详细问题。

main.c中,我们有:

#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()); 
} 

在foo.c的有:

extern int bar(); 

int foo() 
{ 
    int x = bar(); 
    return x; 
} 

在bar.c,我们有:

#include <stdio.h> 

int bar() 
{ 
    printf("bar in bar.c called\n"); 
    return 2; 
} 

编译bar.c和foo.c的:

$ gcc -fPIC -c bar.c 
$ gcc -fPIC -c foo.c 

添加文件bar.o到静态库:

$ ar r libbar.a bar.o 

现在创建使用文件foo.o并链接与静态共享库搜索libbar.a

$ gcc -shared -o libfoo.so foo.o -L. -lbar 

编译main.c中与共享库链接libfoo.so

$ gcc -o main main.c -L. -lfoo 

设置LD_LIBRARY_PATH以查找libfoo。所以并运行主:

$ 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 

请注意,在main.c中栏的版本叫做,没有连接到共享库的版本。

在main2.c我们:

#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()); 
} 

编译和运行main2.c(注意我们不需要明确地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 

现在foo的共享共享库中的库调用栏和main.c中的主要调用栏。我不认为这种行为是直观的,使用dlopen/dlsym更多的工作,但它确实解决了我的问题。

再次感谢您的评论。

1

对不起没有。我对Linux(也可能是大多数* nixes)的方式的理解是不可能的。我能想到的唯一解决问题的方法是创建一个代理应用程序,它以一些IPC的形式公开您需要从libbar获得的内容。然后,您可以使用LD_LIBRARY_PATH或类似的东西使该代理加载正确的版本。

+0

“可能大多数* nixes” - 除AIX外。在AIX上,这实际上是可行的,而默认的链接器行为恰好是问题所在。 – Dummy00001 2010-07-13 00:07:55

+0

OS X也可以优雅地处理这个问题。每个.so/.dylib都有自己的链接表/参考。我说*多数*正是因为我知道这不是全部。无论如何,Linux不会这样做,AFAIK。 – Gianni 2010-07-13 00:29:38

5

尝试的部分链接,让你有一个目标文件“partial.o”与libbar的和libfoo的-Y。将objcopy与“--localize-symbols”一起使用,以使libfoo-Y local.part中的符号成为partial.o。您应该能够通过在libfoo-Y上运行nm并按摩输出来生成。然后采取修改partial.o并将其链接到您的应用程序。

我已经做了VxWorks的gcc工具类似的东西在那里动态库不是一个复杂而干净地连接成一个整体的应用程序所需要的相同的lib的两个版本。