如果我有两个提供名称相同的函数的库,该怎么办?
vorbis_...
,sf_...
,sdl_...
)。本质上,这就是C ++对命名空间函数的符号名称所做的事情。
如果我有两个提供名称相同的函数的库,该怎么办?
vorbis_...
,sf_...
,sdl_...
)。本质上,这就是C ++对命名空间函数的符号名称所做的事情。
Answers:
适当地加上注释:“导出”是指使链接到库的模块可见-等效extern
于文件范围内的关键字。如何控制它取决于OS和链接器。这是我始终必须查找的内容。
可以使用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系统支持类似的功能,但是我想不出它们的名字。
dlopen
dlsym
和dlclose
。但是,Unix上的封装可能不如Windows上的有效。
这是一个想法。在十六进制编辑器中打开一个有问题的库,然后将所有出现的有问题的字符串更改为其他内容。然后,您应该可以在以后的所有呼叫中使用新名称。
更新: 我只是在这方面做到了,它似乎起作用了。 当然,我还没有对它进行彻底的测试-这可能仅仅是用hexedit shot弹枪击退腿部的好方法。
假设您使用linux,首先需要添加
#include <dlfcn.h>
在适当的上下文中声明函数指针变量,例如,
int (*alternative_server_init)(int, char **, char **);
就像Ferruccio在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);
您不应该一起使用它们。如果我没记错的话,链接器会在这种情况下发出错误。
我没有尝试,但溶液可以用dlopen()
,dlsym()
而且dlclose()
它允许您以编程方式处理动态库。如果您不需要同时使用两个函数,则可以在使用第二个库/函数之前打开第一个库,使用第一个函数并关闭第一个库。
如果那里有.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文件中的特定符号。此问题是c ++具有名称空间的原因。对于两个具有相同名称的第三方库,在c中并没有很好的解决方案。
如果它是动态对象,则可以显式加载共享对象(LoadLibrary / dlopen / etc)并以这种方式调用它。或者,如果您不需要在同一代码中同时使用两个lib,则可以使用静态链接(如果有.lib / .a文件)执行某些操作。
当然,这些解决方案都不适用于所有项目。
发誓?据我所知,如果有两个库公开了具有相同名称的链接点,并且您需要针对两者进行链接,那么您将无能为力。
您应该围绕其中之一编写包装器库。包装器库应公开具有唯一名称的符号,而不公开非唯一名称的符号。
您的另一个选择是重命名头文件中的函数名称,并重命名库对象归档中的符号。
无论哪种方式,使用这两种方法都是一项艰巨的工作。
这个问题已经接近十年了,但一直都有新的搜索...
正如已经回答的那样,带有--redefine-sym标志的objcopy在Linux中是一个不错的选择。有关完整的文档,请参见例如https://linux.die.net/man/1/objcopy。这有点笨拙,因为在进行更改时您实际上是在复制整个库,并且每次更新都需要重复这项工作。但至少应该可以。
对于Windows,动态加载库是一种解决方案,而永久性的解决方案就像Linux中的dlopen替代方案一样。但是,dlopen()和LoadLibrary()都添加了额外的代码,如果唯一的问题是重复的名称,则可以避免这些代码。在这里,Windows解决方案比objcopy方法更为优雅:只需告诉链接程序其他名称即可知道库中的符号,并使用该名称。要做一些步骤。您需要制作一个def文件,并在EXPORTS部分中提供名称转换。请参阅https://msdn.microsoft.com/zh-cn/library/hyx1zcd3.aspx(VS2015,它最终将被较新版本取代)或http://www.digitalmars.com/ctg/ctgDefFiles.html(可能更永久)以获取def文件的完整语法详细信息。该过程将为其中一个库创建一个def文件,然后使用该def文件构建一个lib文件,然后与该lib文件链接。(对于Windows DLL,lib文件仅用于链接,而不用于代码执行。)有关构建lib文件的过程,请参见在具有.dll文件和头文件时如何制作.lib文件。这里唯一的区别是添加别名。
对于Linux和Windows,请重命名其别名为别名的库头中的函数。另一个可行的选择是,在引用新名称的文件中,#define old_name new_name,#include要对其别名进行导出的库的头,然后在调用方中#undef old_name。如果使用该库的文件很多,一个更简单的选择是制作一个包含定义,包含和未定义的头文件,然后使用该头文件。
希望此信息对您有所帮助!