What should I do if two libraries provide a function with the same name generating a conflict?

如果有两个库提供具有等效名称的函数,我应该怎么做?

59459 次浏览

发誓?据我所知,如果有两个库公开同名的链接点,并且需要针对这两个链接点进行链接,那么您就无能为力了。

如果我没记错的话,链接器在这种情况下会发出一个错误。

我没有尝试,但解决方案可能是使用 dlopen()dlsym()dlclose(),它们允许您以编程方式处理动态库。如果不需要同时使用这两个函数,可以打开第一个库,使用第一个函数,并在使用第二个库/函数之前关闭第一个库。

  • 如果您控制一个或两个: 编辑一个改变名称和重新编译或等效地看到 未知的回答,这将工作 没有访问源代码。
  • 如果你不能控制他们中的任何一个,你可以把他们中的一个包起来。这就是编译 另一个(statically linked!)这个库除了重新导出原始符号之外什么也不做,只是重新导出冒犯者的符号,而冒犯者是通过另一个名称的包装器到达的。真麻烦。
  • 后来又补充说: 既然 qeek 说他在谈论动态库,那么 费鲁奇奥Mouviciel提出的解决方案可能是最好的。(我似乎生活在很久以前,那时静态链接是默认的。它影响了我的思维。)

关于注释: 通过“ export”我的意思是使链接到库的模块可见——相当于文件作用域中的 extern关键字。如何控制这一点取决于操作系统和链接器。这是我 一直都是必须查找的东西。

这个问题就是 c + + 拥有名称空间的原因。对于两个同名的第三方库,在 c 中没有一个很好的解决方案。

如果它是一个动态对象,那么您可以显式地加载共享对象(LoadLibrary/dlopen/etc)并以这种方式调用它。或者,如果您不需要在同一代码中同时使用两个库,那么可以使用静态链接(如果您有。解放军/。文件)。

当然,这些解决方案都不适用于所有项目。

我从来没有使用过 dlsym、 dlopen、 dlerror、 dlclose、 dlvsym 等等,但是我查看了手册页,它给出了一个打开 libm.so 并提取 cos 函数的示例。Dlopen 是否经历了寻找碰撞的过程?如果没有,OP 可以手动加载这两个库,并为库提供的所有函数指定新的名称。

You should write a wrapper library around one of them. 包装程序库应公开具有唯一名称的符号,而不应公开非唯一名称的符号。

另一种选择是重命名头文件中的函数名,并重命名库对象归档中的符号。

不管怎样,要同时使用这两种方法,都会是一次黑客行动。

我有个想法。在十六进制编辑器中打开一个有问题的库,并将所有出现的有问题的字符串更改为其他内容。然后,您应该能够在以后的所有调用中使用新名称。

更新: 我刚刚在这边做了,看起来很有效。当然,我还没有彻底测试过这个-它可能不过是一个真正的好方法,打掉你的腿与己方猎枪。

可以使用 objcopy --redefine-sym old=new file重命名对象文件中的符号(参见 man objeccopy)。

然后使用这些函数的新名称调用它们,并链接到新的目标文件。

在 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 系统支持类似的功能,但我想不出它们的名字。

假设您使用的是 linux,那么首先需要添加

#include <dlfcn.h>

在适当的上下文中声明函数指针变量,例如,

int (*alternative_server_init)(int, char **, char **);

Like Ferruccio stated in https://stackoverflow.com/a/678453/1635364 , 通过执行(选择您喜欢的标志)显式加载您想要使用的库

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);

如果那里有.o 文件,这里有一个很好的答案: https://stackoverflow.com/a/6940389/4705766

摘要:

  1. objcopy --prefix-symbols=pre_string test.o重命名.o 文件中的符号

或者

  1. objcopy --redefine-sym old_str=new_str test.o to rename the specific symbol in .o file.

这个问题已经有十年历史了,但是新的搜索一直在出现..。

As already answered, objcopy with the --redefine-sym flag is a good choice in Linux. See, for example, https://linux.die.net/man/1/objcopy for full documentation. It is a little clunky because you are essentially copying the entire library while making changes and every update requires this work to be repeated. But at least it should work.

对于 Windows 来说,动态加载库是一种解决方案,类似 Linux 中的 dlopen 替代方案的永久解决方案是。但是 dlopen ()和 LoadLibrary ()都添加了额外的代码,如果唯一的问题是重复名称,则可以避免这些代码。在这里,Windows 解决方案比对象复制方法更优雅: 只需告诉链接器库中的符号以其他名称命名,并使用该名称。有几个步骤可以做到这一点。您需要创建一个 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 文件的过程,请参见 当有一个.dll 文件和一个头文件时,如何创建一个.lib 文件。这里唯一的区别是添加别名。

对于 Linux 和 Windows,重命名名称被别名的库标题中的函数。另一个可行的选项是,在引用新名称的文件中,定义 old _ name new _ name,# 包含导出为别名的库的头,然后在调用者中定义 # undef old _ name。如果有很多文件使用这个库,一个更简单的替代方法是创建一个或多个头文件来包装定义、包含和取消定义,然后使用这个头文件。

希望这些信息对你有所帮助!

如果这是一个内置的功能。 例如,火炬有测距法(不推荐) ,内置有测距法。

我遇到了一些问题,只需要在函数名之前添加 __builtins__ 。 射程() = > 火炬 内建 . range ()