2010-03-29 6 views
13

Was ist der einfachste und sicherste Weg, eine Funktion aus einer gemeinsam genutzten Bibliothek/DLL aufzurufen? Ich bin hauptsächlich an Linux interessiert, aber es wäre besser, wenn es einen plattformunabhängigen Weg gäbe.Wie ruft man eine Funktion von einer gemeinsam genutzten Bibliothek auf?

Kann jemand Beispielcode zur Verfügung stellen, um zu zeigen, wie die folgende Arbeit funktioniert, wenn der Benutzer seine eigene Version von foo in eine gemeinsam genutzte Bibliothek kompiliert hat?

// 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, ich weiß, wie das gemeinsame lib (foo.so) kompilieren, ich muß nur eine einfache Art und Weise weiß, dass es zur Laufzeit zu laden.

Antwort

25

Hinweis: Sie übergeben C++ - Objekte (in diesem Fall STL-Zeichenfolgen) um Bibliotheksaufrufe. Es gibt kein Standard C++ ABI auf dieser Ebene, also entweder versuchen, C++ Objekte zu vermeiden, oder sicherstellen, dass sowohl Ihre Bibliothek und Ihr Programm mit dem gleichen Compiler (idealerweise der gleiche Compiler auf dem gleichen Computer, um zu vermeiden) gebaut wurden alle subtilen konfigurationsbezogene Überraschungen.)

Sie auf erklären Ihre exportierten Methoden extern "C" in Ihrer Bibliothek Code nicht vergessen.

Die oben having been said, hier ist einige Code Umsetzung dessen, was Sie sagten, Sie erreichen wollen:

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 

können Sie abstrakt diese weiter:

#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); 
+0

Wenn Sie erwähnt die Header unter Unix/Linux zu enthalten ... –

+0

Fertig in den zweiten Codeblock. – vladr

+0

Was ist mit Funktionsnamen Mangling in C++, würde das nicht kompliziert? Auch Sie falsch geschriebene Fenster hier '#include ' – sbk

0

Unter Linux müssen Sie dlsym verwenden. Siehe ein Beispiel am Ende der Seite. Am Fenster: GetProcAddress.

1

LoadLibrary ist eine Windows-Funktion zum Laden von DLLs. Mit GetProcAddress können Sie prüfen, ob ein Symbol vorhanden ist. Unter Linux/Unix möchten Sie dlopen/dlsym. Um dies zu tun in Cross-Plattform, können Sie eine Funktion schreiben, die eine dieser Methoden unter Verwendung von Pre-Prozessor ruft, so etwas wie:

int loadlibrary(char* library) 
{ 
#ifdef _WIN32 
    /* do windows code */ 

#endif 
#ifdef _LINUX 
    /* do linux code */ 

#endif 
} 

Dieser Weg ist, diese Art der Sache zu erreichen. Sie können dies auch tun, indem Sie für bestimmte Plattformimplementierungen von Funktionen eine andere Kopfzeile in Ihrer eigenen Quellstruktur einfügen. Dies ist wahrscheinlich ein besserer Weg. In jedem Fall besteht die Idee darin, von der zugrunde liegenden API zu abstrahieren.

Verwandte Themen