如果我有两个提供同名函数的库,我该怎么办?
13 回答
It is possible to rename symbols in an object file using objcopy --redefine-sym old=new file
(see man objcopy).
Then just call the functions using their new names and link with the new object file.
- 如果您控制一个或两个:编辑一个以更改名称并重新编译或等效地查看Ben和unknown的答案,这将在无需访问源代码的情况下工作。
- 如果您不控制其中任何一个,则可以将其中一个包裹起来。那就是编译另一个(静态链接!)库,除了重新导出原始符号之外的所有符号之外什么都不做,除了有问题的符号,这是通过具有备用名称的包装器到达的。真麻烦。
- 稍后添加:由于 qeek 说他在谈论动态库,因此Ferruccio和mouviciel建议的解决方案可能是最好的。(我似乎生活在很久以前静态链接是默认设置的时代。它影响了我的思考。)
适当的评论:通过“导出”,我的意思是使链接到库的模块可见——相当于extern
文件范围内的关键字。这是如何控制的取决于操作系统和链接器。这是我必须经常查找的东西。
Under Windows, you could use LoadLibrary() to load one of those libraries into memory and then use GetProcAddress() to get the address of each function you need to call and call the functions through a function pointer.
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);
would get the address of a function named bar in foo.dll and call it.
I know Unix systems support similar functionality, but I can't think of their names.
If you have .o files there, a good answer here: https://stackoverflow.com/a/6940389/4705766
Summary:
objcopy --prefix-symbols=pre_string test.o
to rename the symbols in .o file
or
objcopy --redefine-sym old_str=new_str test.o
to rename the specific symbol in .o file.
Here's a thought. Open one of the offending libraries in a hex editor and change all occurrences of the offending strings to something else. You should then be able to use the new names in all future calls.
UPDATE: I just did it on this end and it seems to work. Of course, I've not tested this thoroughly - it may be no more than a really good way to blow your leg off with a hexedit shotgun.
你不应该一起使用它们。如果我没记错的话,链接器会在这种情况下发出错误。
我没有尝试,但可能有一个解决方案,dlopen()
它允许您以编程方式处理动态库。如果您不需要同时使用这两个函数,您可以打开第一个库,使用第一个函数并关闭第一个库,然后再使用第二个库/函数。dlsym()
dlclose()
Assuming that you use linux you first need to add
#include <dlfcn.h>
Declare function pointer variable in proper context, for example,
int (*alternative_server_init)(int, char **, char **);
Like Ferruccio stated in https://stackoverflow.com/a/678453/1635364 , load explicitly the library you want to use by executing (pick your favourite flags)
void* dlhandle;
void* sym;
dlhandle = dlopen("/home/jdoe/src/libwhatnot.so.10", RTLD_NOW|RTLD_LOCAL);
Read the address of the function you want to call later
sym = dlsym(dlhandle, "conflicting_server_init");
assign and cast as follows
alternative_server_init = (int (*)(int, char**, char**))sym;
Call in a similar way than the original. Finally, unload by executing
dlclose(dlhandle);
发誓?据我所知,如果您有两个库公开了具有相同名称的链接点并且您需要链接这两个库,那么您无能为力。
这个问题是 c++ 有命名空间的原因。对于 2 个具有相同名称的第三方库,在 c 中并没有真正好的解决方案。
如果它是动态对象,您可能能够显式加载共享对象(LoadLibrary/dlopen/etc)并以这种方式调用它。或者,如果您不需要在同一代码中同时使用两个库,您可以使用静态链接来做一些事情(如果您有 .lib/.a 文件)。
当然,这些解决方案都不适用于所有项目。
You should write a wrapper library around one of them. Your wrapper library should expose symbols with unique names, and not expose the symbols of the non-unique names.
Your other option is to rename the function name in the header file, and rename the symbol in the library object archive.
Either way, to use both, it's gonna be a hack job.
The question is approaching a decade old, but there are new searches all the time...
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.
For Windows, dynamically loading the library is a solution and a permanent one like the dlopen alternative in Linux would be. However both dlopen() and LoadLibrary() add extra code that can be avoided if the only issue is duplicate names. Here the Windows solution is more elegant than the objcopy approach: Just tell the linker that the symbols in a library are known by some other name and use that name. There a few steps to doing it. You need to make a def file and provide the name translation in the EXPORTS section. See https://msdn.microsoft.com/en-us/library/hyx1zcd3.aspx (VS2015, it will eventually get replaced by newer versions) or http://www.digitalmars.com/ctg/ctgDefFiles.html (probably more permanent) for full syntax details of a def file. The process would be to make a def file for one of the libraries then use this def file to build a lib file and then link with that lib file. (For Windows DLLs, lib files only are used for linking, not code execution.) See How to make a .lib file when have a .dll file and a header file for the process of building the lib file. Here the only difference is adding the aliases.
For both Linux and Windows, rename the functions in the headers of the library whose names are being aliased. Another option that should work would be, in files referring to the new names, to #define old_name new_name, #include the headers of the library whose exports are being aliased, and then #undef old_name in the caller. If there are a lot of files using the library, an easier alternative is to make a header or headers that wraps the defines, includes and undefs and then use that header.
Hope this info was helpful!
我从未使用过 dlsym、dlopen、dlerror、dlclose、dlvsym 等,但我正在查看手册页,它提供了打开 libm.so 并提取 cos 函数的示例。dlopen 是否会经历寻找碰撞的过程?如果没有,OP 可以手动加载这两个库,并为他的库提供的所有功能分配新名称。
If it's a builtin function. for example, torch has range method(deprecated)and builtin has range method as well.
I was having some issues and all it took was adding __builtins__
before the function name.
range() => torch
builtins.range()