如果我有两个提供等效名称功能的库,我该怎么办?
答案 0 :(得分:42)
适用评论:通过“导出”,我的意思是使链接到库的模块可见 - 相当于文件范围内的extern
关键字。如何控制它取决于操作系统和链接器。这是我总是必须要查找的内容。
答案 1 :(得分:41)
可以使用objcopy --redefine-sym old=new file
重命名目标文件中的符号(参见man objcopy)。
然后只需使用新名称调用函数并链接到新的目标文件。
答案 2 :(得分:12)
在Windows下,您可以使用LoadLibrary()将其中一个库加载到内存中,然后使用GetProcAddress()获取需要调用的每个函数的地址,并通过函数指针调用函数。
e.g。
HMODULE lib = LoadLibrary("foo.dll");
void *p = GetProcAddress(lib, "bar");
// cast p to the approriate function pointer type (fp) and call it
(*fp)(arg1, arg2...);
FreeLibrary(lib);
将获取foo.dll中名为bar的函数的地址并调用它。
我知道Unix系统支持类似功能,但我想不出他们的名字。
答案 3 :(得分:8)
这是一个想法。在十六进制编辑器中打开其中一个违规库,并将所有出现的违规字符串更改为其他内容。然后,您应该可以在以后的所有呼叫中使用新名称。
更新:我刚刚做到这一点似乎有效。当然,我没有彻底测试过这个问题 - 它可能只是一个非常好的方法来吹你的腿使用hexedit霰弹枪。
答案 4 :(得分:6)
你不应该一起使用它们。如果我没记错的话,链接器会在这种情况下发出错误。
我没有尝试过,但可以使用dlopen()
,dlsym()
和dlclose()
的解决方案,它允许您以编程方式处理动态库。如果您不需要同时使用这两个函数,则可以在使用第二个库/函数之前打开第一个库,使用第一个函数并关闭第一个库。
答案 5 :(得分:6)
假设您使用linux,首先需要添加
#include <dlfcn.h>
在适当的上下文中声明函数指针变量,例如
int (*alternative_server_init)(int, char **, char **);
像https://stackoverflow.com/a/678453/1635364中所说的Ferruccio一样, 通过执行(选择你最喜欢的标志)显式加载你想要使用的库
void* dlhandle;
void* sym;
dlhandle = dlopen("/home/jdoe/src/libwhatnot.so.10", RTLD_NOW|RTLD_LOCAL);
阅读稍后要调用的函数的地址
sym = dlsym(dlhandle, "conflicting_server_init");
分配和转换如下
alternative_server_init = (int (*)(int, char**, char**))sym;
以与原始方式类似的方式拨打电话。最后,通过执行
卸载dlclose(dlhandle);
答案 6 :(得分:4)
这个问题是c ++具有命名空间的原因。对于具有相同名称的2个第三方库,c实际上并不是一个很好的解决方案。
如果它是动态对象,您可以显式加载共享对象(LoadLibrary / dlopen / etc)并以这种方式调用它。或者,如果您在同一代码中不需要同时使用这两个库,则可以使用静态链接执行某些操作(如果您有.lib / .a文件)。
当然,这些解决方案都不适用于所有项目。
答案 7 :(得分:3)
宣誓?据我所知,如果你有两个库可以公开具有相同名称的链接点而你需要链接两者,那么你就无法做到。
答案 8 :(得分:3)
如果你有.o文件,那么这里有一个很好的答案:https://stackoverflow.com/a/6940389/4705766
要点:
objcopy --prefix-symbols=pre_string test.o
重命名.o文件中的符号或
objcopy --redefine-sym old_str=new_str test.o
重命名.o文件中的特定符号。答案 9 :(得分:2)
你应该在其中一个周围写一个包装器库。 您的包装器库应该公开具有唯一名称的符号,而不是公开非唯一名称的符号。
您的另一个选择是重命名头文件中的函数名称,并重命名库对象存档中的符号。
无论哪种方式,要使用两者,这将是一项黑客工作。
答案 10 :(得分:0)
我从未使用过dlsym,dlopen,dlerror,dlclose,dlvsym等,但是我正在查看手册页,它给出了打开libm.so并提取cos函数的示例。 dlopen是否经历了寻找碰撞的过程?如果没有,OP可以手动加载两个库,并为其库提供的所有函数分配新名称。
答案 11 :(得分:0)
这个问题已接近十年之久,但一直有新的搜索......
正如已经回答的那样,带有--redefine-sym标志的objcopy在Linux中是一个不错的选择。例如,请参阅https://linux.die.net/man/1/objcopy以获取完整文档。它有点笨重,因为您实际上在进行更改时复制整个库,每次更新都需要重复此工作。但至少它应该有用。
对于Windows,动态加载库是一种解决方案,而像Linux中的dlopen替代方案那样是永久性的。但是,dlopen()和LoadLibrary()都会添加额外的代码,如果唯一的问题是重复的名称,则可以避免这些代码。这里的Windows解决方案比objcopy方法更优雅:只需告诉链接器库中的符号已被其他名称所知并使用该名称。这样做有几个步骤。您需要创建一个def文件并在EXPORTS部分中提供名称翻译。有关def文件的完整语法详细信息,请参阅https://msdn.microsoft.com/en-us/library/hyx1zcd3.aspx(VS2015,最终将被更新版本替换)或http://www.digitalmars.com/ctg/ctgDefFiles.html(可能更长久)。该过程将为其中一个库创建一个def文件,然后使用此def文件构建一个lib文件,然后链接到该lib文件。 (对于Windows DLL,lib文件仅用于链接,而不是代码执行。)有关构建lib文件的过程,请参阅How to make a .lib file when have a .dll file and a header file。这里唯一的区别是添加别名。
对于Linux和Windows,重命名名称为别名的库的标题中的函数。另一个应该起作用的选项是,在引用新名称的文件中,#define old_name new_name,#include包含其出口别名的库的标题,然后在调用者中使用#undef old_name。如果有很多文件使用该库,则更容易的替代方法是创建包含定义,包含和undef的头或标题,然后使用该标头。
希望这些信息有用!