2009-01-30 32 views
135

Questo è un seguito di Dynamic Shared Library compilation with g++.Libreria condivisa dinamica C++ su Linux

Sto provando a creare una libreria di classi condivisa in C++ su Linux. Sono in grado di compilare la libreria e posso chiamare alcune delle funzioni (non di classe) utilizzando le esercitazioni che ho trovato here e here. I miei problemi iniziano quando provo ad usare le classi che sono definite nella libreria. Il secondo tutorial che ho collegato mostra come caricare i simboli per creare oggetti delle classi definite nella libreria, ma si ferma a breve di usando gli oggetti per eseguire qualsiasi lavoro.

Qualcuno sa di un tutorial più completo per la creazione di librerie di classi C++ condivise che mostra anche come utilizzare quelle classi in un file eseguibile separato? Un tutorial molto semplice che mostra la creazione di oggetti, l'uso (getter e setter semplici andrebbero bene), e la cancellazione sarebbe fantastica. Un link o un riferimento ad un codice open source che illustri l'uso di una libreria di classi condivise sarebbe altrettanto valido.


Anche se le risposte da codelogic e nimrodm funzionano, volevo solo aggiungere che ho preso in mano una copia di Beginning Linux Programming poiché questa domanda, e il suo primo capitolo ha codice di esempio C e buone spiegazioni per la creazione e l'utilizzo di entrambe le librerie statiche e condivise. Questi esempi sono disponibili tramite Google Ricerca Libri nello an older edition of that book.

+0

Non sono sicuro di capire cosa intendi per "utilizzarlo", una volta che viene restituito un puntatore all'oggetto, potresti usarlo come se tu usassi qualsiasi altro puntatore a un oggetto. – codelogic

+0

L'articolo che ho collegato a mostra come creare un puntatore a funzione di una funzione di fabbrica oggetto utilizzando dlsym. Non mostra la sintassi per la creazione e l'utilizzo di oggetti dalla libreria. –

+1

Avrete bisogno del file di intestazione che descrive la classe. Perché pensi di dover usare "dlsym" invece di lasciare che il sistema operativo trovi e collega la libreria al momento del caricamento? Fammi sapere se hai bisogno di un semplice esempio. – nimrodm

risposta

119

MyClass.h

#ifndef __MYCLASS_H__ 
#define __MYCLASS_H__ 

class MyClass 
{ 
public: 
    MyClass(); 

    /* use virtual otherwise linker will try to perform static linkage */ 
    virtual void DoSomething(); 

private: 
    int x; 
}; 

#endif 

myclass.cc

#include "myclass.h" 
#include <iostream> 

using namespace std; 

extern "C" MyClass* create_object() 
{ 
    return new MyClass; 
} 

extern "C" void destroy_object(MyClass* object) 
{ 
    delete object; 
} 

MyClass::MyClass() 
{ 
    x = 20; 
} 

void MyClass::DoSomething() 
{ 
    cout<<x<<endl; 
} 

class_user.cc

#include <dlfcn.h> 
#include <iostream> 
#include "myclass.h" 

using namespace std; 

int main(int argc, char **argv) 
{ 
    /* on Linux, use "./myclass.so" */ 
    void* handle = dlopen("myclass.so", RTLD_LAZY); 

    MyClass* (*create)(); 
    void (*destroy)(MyClass*); 

    create = (MyClass* (*)())dlsym(handle, "create_object"); 
    destroy = (void (*)(MyClass*))dlsym(handle, "destroy_object"); 

    MyClass* myClass = (MyClass*)create(); 
    myClass->DoSomething(); 
    destroy(myClass); 
} 

In Mac OS X, compilare con:

g++ -dynamiclib -flat_namespace myclass.cc -o myclass.so 
g++ class_user.cc -o class_user 

Su Linux, la compilazione con:

g++ -fPIC -shared myclass.cc -o myclass.so 
g++ class_user.cc -ldl -o class_user 

Se questo fosse per un sistema di plugin, si usa MyClass come classe base e definire tutte le funzioni necessarie virtuale. L'autore del plug-in verrebbe quindi derivato da MyClass, sovrascrive i virtual e implementa create_object e destroy_object. La tua applicazione principale non dovrebbe essere modificata in alcun modo.

+6

Sono in procinto di provare questo, ma solo avere una domanda È strettamente necessario utilizzare void * o la funzione create_object può restituire MyClass *? Non ti sto chiedendo di cambiare questo per me, vorrei solo sapere se c'è un motivo per usarne uno sull'altro. –

+0

Può essere MyClass *, nessun motivo per essere annullato *, l'ho aggiornato. – codelogic

+1

Grazie, ho provato questo e ha funzionato come è su Linux dalla riga di comando (una volta ho apportato la modifica suggerita nei commenti del codice). Apprezzo il tuo tempo. –

48

Quanto segue mostra un esempio di libreria di classi condivise condivisa. [H, cpp] e un modulo main.cpp che utilizza la libreria. È un esempio molto semplice e il makefile potrebbe essere migliorato molto meglio. Ma funziona e può aiutare a:

shared.h definisce la classe:

class myclass { 
    int myx; 

    public: 

    myclass() { myx=0; } 
    void setx(int newx); 
    int getx(); 
}; 

shared.cpp definisce le GetX/setx funzioni:

#include "shared.h" 

void myclass::setx(int newx) { myx = newx; } 
int myclass::getx() { return myx; } 

main.cpp utilizza la classe,

#include <iostream> 
#include "shared.h" 

using namespace std; 

int main(int argc, char *argv[]) 
{ 
    myclass m; 

    cout << m.getx() << endl; 
    m.setx(10); 
    cout << m.getx() << endl; 
} 

e il makefile che genera libshared.so e collega principale con la libreria condivisa:

main: libshared.so main.o 
    $(CXX) -o main main.o -L. -lshared 

libshared.so: shared.cpp 
    $(CXX) -fPIC -c shared.cpp -o shared.o 
    $(CXX) -shared -Wl,-soname,libshared.so -o libshared.so shared.o 

clean: 
    $rm *.o *.so 

per l'esecuzione effettiva 'main' e legame con libshared.so si avrà probabilmente bisogno di specificare il percorso di carico (o metterlo in/usr/local/lib o simili).

Di seguito specifica la directory corrente come percorso di ricerca per le biblioteche e corre principale (sintassi bash):

export LD_LIBRARY_PATH=. 
./main 

di vedere che il programma è collegato con libshared.so si può provare LDD:

LD_LIBRARY_PATH=. ldd main 

Stampe sulla mia macchina:

~/prj/test/shared$ LD_LIBRARY_PATH=. ldd main 
    linux-gate.so.1 => (0xb7f88000) 
    libshared.so => ./libshared.so (0xb7f85000) 
    libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0xb7e74000) 
    libm.so.6 => /lib/libm.so.6 (0xb7e4e000) 
    libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0xb7e41000) 
    libc.so.6 => /lib/libc.so.6 (0xb7cfa000) 
    /lib/ld-linux.so.2 (0xb7f89000) 
+1

Questo appare (per il mio occhio non molto allenato) per collegare staticamente libshared.so al tuo eseguibile, piuttosto che usare il collegamento dinamico in fase di esecuzione. Ho ragione? –

+9

No. Questo è il collegamento dinamico standard Unix (Linux). Una libreria dinamica ha l'estensione ".so" (Oggetto condiviso) ed è collegata con l'eseguibile (principale in questo caso) al momento del caricamento - ogni volta che viene caricato il main. Il collegamento statico avviene al momento del collegamento e utilizza le librerie con l'estensione ".a" (archivio). – nimrodm

+8

Questo è collegato dinamicamente a _build_ time. In altre parole, è necessaria una conoscenza preliminare della libreria a cui stai collegando (ad esempio, il collegamento a 'dl' per dlopen). Questo è diverso da dynamically _loading_ una libreria, in base a dire, un nomefile specificato dall'utente, in cui non è necessaria la conoscenza precedente. – codelogic

8

in sostanza, si dovrebbe includere i clas s 'il file di intestazione nel codice in cui si desidera utilizzare la classe nella libreria condivisa. Quindi, quando si collega, use the '-l' flag per collegare il codice con la libreria condivisa. Ovviamente, ciò richiede che sia .so dove si trova il sistema operativo.Vedi 3.5. Installing and Using a Shared Library

L'utilizzo di dlsym è utile quando non si conosce in fase di compilazione quale libreria si desidera utilizzare. Non sembra che sia il caso qui. Forse la confusione è che Windows chiama le librerie caricate dinamicamente sia che si esegua il collegamento in fase di compilazione sia in fase di esecuzione (con metodi analoghi)? Se è così, allora puoi pensare a dlsym come l'equivalente di LoadLibrary.

Se è davvero necessario caricare dinamicamente le librerie (vale a dire, sono plug-in), quindi this FAQ dovrebbe essere d'aiuto.

+1

Il motivo per cui ho bisogno di una libreria dinamica condivisa è che lo chiamerò anche dal codice Perl. Potrebbe essere un malinteso completo da parte mia che devo anche chiamarlo in modo dinamico da altri programmi C++ che sto sviluppando. –

+0

Non ho mai provato perl e C++ integrati, ma penso che sia necessario usare XS: http://www.johnkeiser.com/perl-xs-c++.html –

Problemi correlati