C++ 如何从共享库调用函数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2538103/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to call a function from a shared library?
提问by Frank
What is the easiest and safest way to call a function from a shared library / dll? I am mostly interested in doing this on linux, but it would be better if there were a platform-independent way.
从共享库/dll 调用函数的最简单和最安全的方法是什么?我最感兴趣的是在 linux 上做这个,但如果有一种独立于平台的方式会更好。
Could someone provide example code to show how to make the following work, where the user has compiled his own version of foo
into a shared library?
有人可以提供示例代码来展示如何进行以下工作,其中用户已将自己的版本编译foo
为共享库?
// function prototype, implementation loaded at runtime:
std::string foo(const std::string);
int main(int argc, char** argv) {
LoadLibrary(argv[1]); // loads library implementing foo
std::cout << "Result: " << foo("test");
return 0;
}
BTW, I know how to compile the shared lib (foo.so
), I just need to know an easy way to load it at runtime.
顺便说一句,我知道如何编译共享库 ( foo.so
),我只需要知道一种在运行时加载它的简单方法。
回答by vladr
NOTE:You are passing C++ objects (in this case STL strings) around library calls. There is no standard C++ ABIat this level, so either try to avoid passing C++ objects around, or ensure that both your library and your program have been built with the same compiler (ideally the same compiler on the same machine, to avoid any subtle configuration-related surprises.)
注意:您正在围绕库调用传递 C++ 对象(在本例中为 STL 字符串)。有没有标准的C ++ ABI在这个水平,所以无论是尽量避免将C ++对象周围,或确保两个资料库和程序已建成具有相同的编译器(最好在同一台机器上相同的编译器,以避免任何微妙配置相关的惊喜。)
Do not forget to declare your exported methods extern "C"
inside your library code.
不要忘记在库代码中声明导出的方法extern "C"
。
The above having been said, here is some code implementing what you said you want to achieve:
上面已经说过,这里有一些代码实现了你所说的你想要实现的:
typedef std::string (*foo_t)(const std::string);
foo_t foo = NULL;
...
# ifdef _WIN32
HMODULE hDLL = ::LoadLibrary(szMyLib);
if (!hDll) { /*error*/ }
foo = (foo_t)::GetProcAddress(hDLL, "foo");
# else
void *pLib = ::dlopen(szMyLib, RTLD_LAZY);
if (!pLib) { /*error*/ }
foo = (foo_t)::dlsym(pLib, "foo");
# endif
if (!foo) { /*error*/ }
...
foo("bar");
...
# ifdef _WIN32
::FreeLibrary(hDLL);
# else
::dlclose(pLib);
# endif
You can abstract this further:
您可以进一步抽象:
#ifdef _WIN32
#include <windows.h>
typedef HANDLE my_lib_t;
#else
#include <dlfcn.h>
typedef void* my_lib_t;
#endif
my_lib_t MyLoadLib(const char* szMyLib) {
# ifdef _WIN32
return ::LoadLibraryA(szMyLib);
# else //_WIN32
return ::dlopen(szMyLib, RTLD_LAZY);
# endif //_WIN32
}
void MyUnloadLib(my_lib_t hMyLib) {
# ifdef _WIN32
return ::FreeLibrary(hMyLib);
# else //_WIN32
return ::dlclose(hMyLib);
# endif //_WIN32
}
void* MyLoadProc(my_lib_t hMyLib, const char* szMyProc) {
# ifdef _WIN32
return ::GetProcAddress(hMyLib, szMyProc);
# else //_WIN32
return ::dlsym(hMyLib, szMyProc);
# endif //_WIN32
}
typedef std::string (*foo_t)(const std::string);
typedef int (*bar_t)(int);
my_lib_t hMyLib = NULL;
foo_t foo = NULL;
bar_t bar = NULL;
...
if (!(hMyLib = ::MyLoadLib(szMyLib)) { /*error*/ }
if (!(foo = (foo_t)::MyLoadProc(hMyLib, "foo")) { /*error*/ }
if (!(bar = (bar_t)::MyLoadProc(hMyLib, "bar")) { /*error*/ }
...
foo("bar");
bar(7);
...
::MyUnloadLib(hMyLib);
回答by Frank
LoadLibraryis a Windows function for loading DLLs. You can check for symbol existence with GetProcAddress. On Linux/Unix you want dlopen/dlsym. To do this in cross platform, you could write a function that calls either of these methods using pre-processor, so, something like:
LoadLibrary是一个用于加载 DLL 的 Windows 函数。您可以使用GetProcAddress检查符号是否存在。在 Linux/Unix 上,您需要dlopen/ dlsym。要在跨平台中执行此操作,您可以编写一个使用预处理器调用这些方法之一的函数,例如:
int loadlibrary(char* library)
{
#ifdef _WIN32
/* do windows code */
#endif
#ifdef _LINUX
/* do linux code */
#endif
}
This is one way to achieve this sort of thing. You could also do it by including a different header in your own source tree for specific platform implementations of functions. This is probably a better way. In either case the idea is to abstract from the underlying API.
这是实现这种事情的一种方法。您也可以通过在您自己的源代码树中为特定平台的函数实现包含不同的头文件来实现。这可能是一个更好的方法。在任何一种情况下,想法都是从底层 API 中抽象出来。
回答by Frank
On Linux you need to use dlsym. See an example at the end of the page. On Window: GetProcAddress.
在 Linux 上,您需要使用dlsym。请参阅页面末尾的示例。在窗口上:GetProcAddress。