我有一个静态链接来自第三方供应商VENDOR1的库libfoo的X版本的应用程序。它还与来自不同第三方供应商VENDOR2的动态(共享)库libbar链接,该库将libfoo的Y版本与VENDOR1静态链接。
因此libbar.so包含libfoo.a的Y版本,而我的可执行文件包含libfoo.a的X版本 libbar仅在内部使用libfoo,并且没有libfoo对象从我的应用程序传递到libbar。
构建时没有错误,但在运行时app app出现故障。原因似乎是版本X使用的结构大小与版本Y不同,运行时链接器似乎混合起来,后者被使用了。
VENDOR1& VENDOR2是封闭源,所以我无法重建它们。
有没有办法构建/链接我的应用程序,以便它总是解析为版本X,而libbar总是解析为版本Y而两者永远不会混合?
答案 0 :(得分:15)
感谢所有回复。我有一个似乎有效的解决方案。 这是一个例子的详细问题。
在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.so并运行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
请注意,调用main.c中的bar版本,而不是链接到共享库的版本。
在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 :(得分:6)
尝试使用部分链接,以便使用libbar和libfoo-Y创建一个目标文件“partial.o”。使用带有“--localize-symbols”的objcopy在libfoo-Y local中创建partial.o中的符号。您应该能够通过在libfoo-Y上运行nm并按摩输出来生成。然后获取修改后的partial.o并将其链接到您的应用。
我在vxWorks上使用gcc工具链做了类似的事情,其中动态库不是复杂的,但是同一个库的两个版本需要干净地链接到单个应用程序。
答案 2 :(得分:2)
抱歉没有。我对Linux(以及可能是大多数* nixes)的方式的理解是不可能的。我能想到的问题唯一的“解决方案”是,如果您创建一个代理应用程序,它会以某些IPC的形式从libbar中公开您需要的内容。然后,您可以使用LD_LIBRARY_PATH
或类似的东西使该代理加载正确的版本。