如果两个库提供相同名称的函数会产生冲突,我该怎么办?
如果我有两个提供相同名称的函数库,我该怎么办?
- 如果你控制一个或两个:编辑一个改变名称和重新编译或等价地看到本和未知的答案将无法访问的源代码工作。
- 如果你不控制他们中的任何一个,你可以把他们中的一个包起来。 这是编译另一个 ( 静态链接 !)库,除了重新导出原始的所有符号,除了有问题的一个,通过一个替代名称的包装到达之外,什么也不做。 真是麻烦
- 后来补充:既然qeek说他正在谈论dynamic库, Ferruccio和mouviciel提出的解决scheme可能是最好的。 (我似乎活在很久以前的时候,静态链接是默认的,它使我思考。
apropos的意见:通过“出口”我的意思是使模块链接到库可见 – 相当于文件范围外的extern
关键字。 这是如何控制的,取决于操作系统和链接器。 这是我总是要查的东西。
可以使用objcopy --redefine-sym old=new file
(参见man objcopy)重命名对象文件中的符号。
然后,只需使用新名称调用函数,并链接到新的对象文件。
在Windows下,您可以使用LoadLibrary()将其中一个库加载到内存中,然后使用GetProcAddress()获取您需要调用的每个函数的地址,并通过函数指针调用函数。
例如
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系统支持类似的function,但我想不出他们的名字。
这是一个想法。 在hex编辑器中打开其中一个有问题的库,并将所有出现的有问题的string更改为其他内容。 那么你应该可以在以后的所有通话中使用新的名字。
更新: 我只是这样做,它似乎工作。 当然,我还没有彻底地testing过 – 这可能不过是一个用hexedit霰弹枪把你的腿踢掉的好方法。
你不应该一起使用它们。 如果我没有记错,链接器会在这种情况下发出错误。
我没有尝试,但解决scheme可能与dlopen()
, dlsym()
和dlclose()
,它们允许您以编程方式处理dynamic库。 如果您不需要同时使用这两个函数,则可以打开第一个库,使用第一个函数并在使用第二个库/函数之前closures第一个库。
发誓? 据我所知,如果您有两个库显示具有相同名称的链接点,并且您需要链接两个链接点,则可以做的事情不多。
这个问题是c ++有命名空间的原因。 对于具有相同名称的2个第三方库,c并不是很好的解决scheme。
如果它是一个dynamic对象,你可以显式地加载共享对象(LoadLibrary / dlopen / etc)并以此方式调用它。 或者,如果在同一代码中不需要同时使用两个库,那么也可以使用静态链接(如果有.lib / .a文件)。
当然,这些解决scheme都不适用于所有项目。
假设你使用linux,你首先需要添加
#include <dlfcn.h>
在适当的上下文中声明函数指针variables,例如,
int (*alternative_server_init)(int, char **, char **);
就像Ferruccio在https://stackoverflow.com/a/678453/1635364中说的那样,通过执行加载你想要使用的库(select你喜欢的标志);
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);
你应该围绕其中的一个写封装库。 你的包装库应该公开具有唯一名称的符号,并且不公开非唯一名称的符号。
您的其他选项是重命名头文件中的函数名称,并重命名库对象归档中的符号。
无论哪种方式,使用这两个,这将是一个黑客工作。
我从来没有使用dlsym,dlopen,dlerror,dlclose,dlvsym等,但是我正在查看man page,并给出了打开libm.so并提取cos函数的示例。 dlopen是否经历了寻找碰撞的过程? 如果没有,OP可以手动加载这两个库,并为其库提供的所有function分配新名称。
如果你有.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文件中的特定符号。
问题已经接近十年了,但是总是有新的search……
正如已经回答的那样,使用–redefine-sym标志的objcopy在Linux中是一个不错的select。 有关完整的文档,请参阅https://linux.die.net/man/1/objcopy 。 这是有点笨重,因为你基本上是在进行更改时拷贝整个库,每次更新都需要重复这个工作。 但至less它应该工作。
对于Windows来说,dynamic加载库是一个解决scheme,并且像Linux中的dlopen替代品一样是永久性的。 然而,如果唯一的问题是重复名称,dlopen()和LoadLibrary()都会添加额外的代码,这些代码可以避免。 在这里,Windows解决scheme比objcopy方法更优雅:只要告诉链接器库中的符号被其他名称所知并使用该名称即可。 有几个步骤来做到这一点。 您需要创build一个def文件并在EXPORTS部分提供名称转换。 见https://msdn.microsoft.com/en-us/library/hyx1zcd3.aspx(VS2015 ,它最终将被更新的版本取代)或http://www.digitalmars.com/ctg/ctgDefFiles.html (可能更永久性)的def文件的完整语法细节。 这个过程将是为其中一个库创build一个def文件,然后使用这个def文件构build一个lib文件,然后与该lib文件链接。 (对于Windows DLL,lib文件仅用于链接,而不是代码执行。)请参阅如何在构buildlib文件的过程中有.dll文件和头文件时创build.lib文件。 这里唯一的区别是添加别名。
对于Linux和Windows,都要重命名名称为别名的库的标题中的函数。 另一个应该工作的选项是,在引用新名称的文件中,将#define old_name new_name,#include导出为别名的库的标头,然后在调用方中包含#undef old_name。 如果使用该库的文件很多,则更简单的方法是制作包装定义的头文件或头文件,然后使用include和undefs然后使用该头文件。
希望这个信息是有帮助的!