我有一个我需要链接的闭源第三方共享库。不幸的是,第三方库的创建者并不打算限制导出和导出所有符号的符号。第三方库内部使用我在代码中使用的流行库的不兼容版本,但导出冲突的符号(谷歌的protobuf库)。当protobuffer库版本检查发现编译时间和库的运行时版本不兼容时,这会导致运行时错误。我可以通过恢复到与第三方库中使用的版本匹配的旧版本的protobufs 2.3来解决问题。但是,protbuf 2.3的性能问题使得我的应用程序无法使用它。我需要一种方法在我的代码中使用protobuf 2.4并让第三方库使用它自己的内部v 2.3。
有没有办法生成第三方库的新版本,该版本不会从仅在给定文件的内部使用的protobuf v 2.3库中导出符号?如果我有源,那将是一个更容易的问题。似乎像objcopy和strip这样的工具实际上无法修改动态符号表。到目前为止,我唯一的想法就是创建自己的填充程序库,通过将调用重定向到第三方库(可能用dlopen打开),只导出我需要的符号。
有更好的解决方案吗?
答案 0 :(得分:2)
我找到了一个有效的解决方案......我创建了一个shim库,可以将调用重定向到第三方库,允许库外的代码查看protbuf v2.4符号,而第三方库中的代码可以看到protobuf v2。 3个符号。此解决方法基于此处发布的想法:http://www.linuxjournal.com/article/7795
我必须修改dlopen标志以包含RTLD_LAZY | RTLD_LOCAL | RTLD_DEEPBIND。 RTLD_LOCAL标志使第三方库中的符号不会出现在填充程序库外部(防止符号泄漏)。 RTLD_DEEPBIND强制来自第三方库内部的调用仅查看符号的内部版本(防止符号泄漏)。
具体来说,这是我的垫片库的一个示例摘录。
#include <stdio.h>
#include <stdint.h>
#include <dlfcn.h>
#include "libhdfs/hdfs.h"
//#define PRINT_DEBUG_STUFF
// Helper function to retrieve a function pointer to a function from libMapRClient
// while isolating the symbols used internally from those already linked externaly
// to workaround symbol collision problem with the current version of libMapRClient.
void* GetFunc(const char* name){
#ifdef PRINT_DEBUG_STUFF
printf("redirecting %s\n", name);
#endif
void *handle;
char *error;
handle = dlopen("/opt/mapr/lib/libMapRClient.so", RTLD_LAZY | RTLD_LOCAL | RTLD_DEEPBIND);
if (!handle) {
fputs(dlerror(), stderr);
exit(1);
}
void* fp = dlsym(handle, name);
if ((error = dlerror()) != 0) {
fprintf(stderr, "%s\n", error);
exit(1);
}
return fp;
}
hdfsFS hdfsConnect(const char* host, tPort port) {
typedef hdfsFS (*FP) (const char* host, tPort port);
static FP ext = 0;
if (!ext) {
ext = (FP)GetFunc("hdfsConnect");
}
return ext(host, port);
}
int hdfsCloseFile(hdfsFS fs, hdfsFile file) {
typedef int (*FP) (hdfsFS fs, hdfsFile file);
static FP ext = 0;
if (!ext) {
ext = (FP)GetFunc("hdfsCloseFile");
}
return ext(fs, file);
}
...等等其他公共API函数
答案 1 :(得分:0)
更改传递给链接器的库的顺序可能会有所帮助。如果多个库导出相同的符号,则链接器应使用第一个库中的库。但是,并非所有链接器都是根据这一点,因此请查看其文档。