从共享库/ DLL调用函数最简单和最安全的方法是什么? 我最感兴趣的是在linux上这样做,但如果有一个平台无关的方式会更好。
有人可以提供示例代码来展示如何进行以下工作,用户将自己的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; }
顺便说一句,我知道如何编译共享库( foo.so
),我只需要知道一个简单的方法来加载它在运行时。
注意:您正在库调用周围传递C ++对象(在本例中为STL字符串)。 在这个级别上没有标准的C ++ ABI ,所以要么避免传递C ++对象,要么确保库和程序都是用同一个编译器(理想情况下是同一台机器上的同一个编译器)构建的,以避免任何微妙的配置相关的惊喜。)
不要忘记在库代码中声明你的导出方法extern "C"
。
上面已经说过了,下面是一些代码实现你所说的你想实现的 :
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
你可以进一步抽象 :
#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);
LoadLibrary是一个用于加载DLL的Windows函数。 您可以使用GetProcAddress检查符号是否存在。 在Linux / Unix上,你需要dlopen / dlsym 。 要在跨平台上做到这一点,你可以使用预处理器编写一个调用这些方法的函数,如下所示:
int loadlibrary(char* library) { #ifdef _WIN32 /* do windows code */ #endif #ifdef _LINUX /* do linux code */ #endif }
这是实现这种事情的一种方法。 您也可以通过在您自己的源代码树中包含不同的头文件来实现特定的函数平台实现。 这可能是一个更好的方法。 无论哪种情况,这个想法都是从底层的API中抽象出来的。
在Linux上,您需要使用dlsym 。 查看页面末尾的示例。 在窗口上: GetProcAddress 。