2010-03-29 42 views
13

Qual è il modo più semplice e sicuro per chiamare una funzione da una libreria/dll condivisa? Sono principalmente interessato a farlo su Linux, ma sarebbe meglio se esistesse un modo indipendente dalla piattaforma.Come chiamare una funzione da una libreria condivisa?

Qualcuno potrebbe fornire codice di esempio per mostrare come eseguire il seguente lavoro, in cui l'utente ha compilato la propria versione di foo in una libreria condivisa?

// 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, so come compilare il lib condivisa (foo.so), ho solo bisogno di sapere un modo semplice per caricarlo in fase di esecuzione.

risposta

25

NOTA: Si stanno passando oggetti C++ (in questo caso stringhe STL) attorno alle chiamate di libreria. C'è senza C++ ABI standard a questo livello, quindi cerca di evitare di passare oggetti C++, o assicurati che sia la tua libreria sia il tuo programma siano stati costruiti con lo stesso compilatore (idealmente lo stesso compilatore sulla stessa macchina, per evitare eventuali sorprese relative alla configurazione.)

Non dimenticare di dichiarare i metodi esportati extern "C" all'interno del codice della libreria.

Quanto sopra premesso, qui è qualche codice che implementa quello che hai detto che si vuole raggiungere:

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 

È possibile abstract questa ulteriore:

#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

Se lei ha citato, che header da includere su Unix/Linux ... –

+0

Fatto nel secondo blocco di codice. – vladr

+0

Che dire del nome della funzione mangling in C++, non complicherebbe le cose? Inoltre, hai sbagliato a digitare le finestre qui '#include ' – sbk

0

Su Linux è necessario utilizzare dlsym. Guarda un esempio alla fine della pagina. sulla finestra: GetProcAddress.

1

LoadLibrary è una funzione di Windows per il caricamento di DLL. È possibile verificare la presenza di simboli con GetProcAddress. Su Linux/Unix si desidera dlopen/dlsym. Per fare questo in cross-platform, si potrebbe scrivere una funzione che chiama uno di questi metodi che utilizzano pre-processore, quindi, qualcosa di simile a:

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

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

#endif 
} 

Questo è un modo per raggiungere questo genere di cose. Puoi farlo anche includendo un'intestazione diversa nel tuo albero dei sorgenti per implementazioni di funzioni specifiche della piattaforma. Questo è probabilmente un modo migliore. In entrambi i casi l'idea è di astrarre dall'API sottostante.

Problemi correlati