Talvolta uno sviluppatore può trovarsi nella posizione di dover caricare una libreria (ed usare le funzioni ivi contenute) a runtime; questo accade il più delle volte quando si sta sviluppando un plug-in di qualche tipo o un programma disegnato con una architettura modulare.
In C caricare una libreria è estremamente semplice (è sufficiente
invocare le funzioni dlopen
, dlsym
e
dlclose
), mentre in C++ l'operazione è leggermente
più complessa. Le difficoltà insite nel caricare dinamicamente una libreria C++
sono in parte dovute al processo di decorazione dei simboli di linking
comunemente chiamato name mangling, ed in
parte dovute al fatto che l'interfaccia di dlopen
è stata
implementata pensando in C e, conseguentemente, non offre una maniera
appropriata di caricare classi.
Prima di illustrare come si caricano dinamicamente le librerie in C++, è appropriato analizzare il processo di name mangling in maggior dettaglio. Si continui la lettura, la spiegazione del processo di decorazione dei simboli è importante nel comprendere le ragioni del problema e come risolverle.
In ogni programma C++ (o libreria, o object file), tutte le funzioni non dichiarate come static sono rappresentate nel file binario da simboli. Questi simboli sono speciali stringhe di testo che identificano unicamente una funzione nel programma, la libreria o l'object file.
In C il simbolo e il nome della funzione corrispondono: il simbolo della
funzione strcpy
è appunto
strcpy, e così per ogni altro simbolo.
Questo è possibile perché in C due funzioni non dichiarate come static
devono necessariamente avere nomi distinti.
Siccome il linguaggio C++ permette l'overloading di una funzione
(diverse versioni di una funzione avente il medesimo nome ma una differente
lista di argomenti) ed include svariate funzionalità non presenti in C - come classi,
funzioni che fanno parte di dette classi, la specifica di eccezioni - non è semplicemente
possibile impiegare il solo nome della funzione come unico simbolo. Per risolvere
questo problema, il C++ utilizza il cosiddetto meccanismo di
name mangling, che trasforma il nome della funzione e
tutte le informazioni necessarie (come il numero e la dimensione degli argomenti)
in una stringa di testo così ingarbugliata che solo il compiler riesce a comprenderla.
Il simbolo risultante per la funzione foo
potrebbe ad esempio
essere foo@4%6^ - o potrebbe non
includere nemmeno la parola "foo".
Uno dei problemi risultanti dal processo di name mangling è che lo
standard C++ (currently [ISO14882]) non definisce come
i simboli debbano essere codificati. Di conseguenza, ogni compiler "decora"
i simboli in maniera diversa, alcuni compiler hanno addirittura cambiato l'algoritmo di
name mangling tra diverse release (famoso il caso di g++ 2.x e 3.x). Anche se aveste
studiato i dettagli del processo di name mangling del vostro compiler (e quindi sareste
in grado di caricare funzioni per mezzo di dlsym
), questa
soluzione risulterebbe funzionare solamente con quel particolare compiler, ed il
meccanismo potrebbe non funzionare già con la prossima versione del medesimo.
Un altro problema dell'interfaccia definita da dlopen
è la limitazione inerente nel fatto che la libreria supporta solamente il caricamento di
funzioni. Ma in C++ una libreria spesso espone la definizione
di classi da utilizzare nei nostri programmi. Ovviamente, per poter utilizzare queste ultime
si deve essere in grado di istanziare le medesime, ma questo non è facilmente fattibile.