La differenza principale è che includi librerie collegate statiche con la tua app. Sono collegati quando crei la tua app. Le librerie dinamiche sono collegate in fase di esecuzione, quindi non è necessario includerle nell'app. In questi giorni le librerie dinamiche vengono utilizzate per ridurre le dimensioni delle app avendo molte librerie dinamiche sul computer di tutti.
Le librerie dinamiche consentono inoltre agli utenti di aggiornare le librerie senza ricreare le app client. Se viene trovato un bug in una libreria che usi nella tua app ed è collegata staticamente, dovrai ricostruire la tua app e rilasciarla nuovamente a tutti i tuoi utenti. Se viene rilevato un bug in una libreria collegata dinamicamente, tutti i tuoi utenti devono solo aggiornare le proprie librerie e la tua app non ha bisogno di un aggiornamento.
Quando un programma C++ viene compilato. Deve avere riferimenti alle funzioni e al codice della libreria C++ (diciamo ad esempio il codice per la libreria).
Supponiamo di avere un'ipotetica libreria condivisa chiamata libdyno.so
. Alla fine sarai in grado di sbirciare al suo interno usando objdump
o nm
.
objdump --syms libdyno.so
Puoi farlo oggi sul tuo sistema con qualsiasi libreria condivisa. objdump
su un MAC si chiama gobjdump
e viene fornito con brew nel binutils
pacchetto. Provalo su un Mac...
gobjdump --syms /usr/lib/libz.dylib
Ora puoi vedere che i simboli sono contenuti nell'oggetto condiviso. Quando fai link
con l'oggetto condiviso di solito usi qualcosa come
g++ -Wall -g -pedantic -ldyno DynoLib_main.cpp -o dyno_main
Nota il -ldyno
in quel comando. Questo sta dicendo al compilatore (in realtà il linker ld) di cercare un file oggetto condiviso chiamato libdyno.so
ovunque li cerchi normalmente. Una volta trovato quell'oggetto, può trovare i simboli di cui ha bisogno. Non c'è alcuna dipendenza circolare perché lo sviluppatore ha richiesto il caricamento della libreria dinamica specificando -l
bandiera.
Come e quando useresti una libreria dinamica? Come ne fai uno? Come in qual è il comando di compilazione specifico utilizzato per produrre tale file da un file .cpp standard
Crea un file chiamato DynoLib.cpp
#include "DynoLib.h"
DynamicLib::DynamicLib() {}
int DynamicLib::square(int a) {
return a * a;
}
Crea un file chiamato DynoLib.h
#ifndef DYNOLIB_H
#define DYNOLIB_H
class DynamicLib {
public:
DynamicLib();
int square(int a);
};
#endif
Compilali per essere una libreria condivisa come segue. Questo è specifico per Linux...
g++ -Wall -g -pedantic -shared -std=c++11 DynoLib.cpp -o libdyno.so
Ora puoi ispezionare questo oggetto usando il comando che ho dato prima, cioè
objdump --syms libdyno.so
Ora crea un file chiamato DynoLib_main.cpp che verrà collegato con libdyno.so
e usa la funzione che abbiamo appena definito al suo interno.
#include "DynoLib.h"
#include <iostream>
using namespace std;
int main(void) {
DynamicLib *lib = new DynamicLib();
std::cout << "Square " << lib->square(1729) << std::endl;
return 1;
}
Compilalo come segue
g++ -Wall -g -pedantic -L. -ldyno DynoLib_main.cpp -o dyno_main
./dyno_main
Square 2989441
Puoi anche dare un'occhiata al binario principale usando nm
. Di seguito vedo se c'è qualcosa con la stringa square
in esso c'è il simbolo di cui ho bisogno da libdyno.so
in alcun modo referenziato nel mio binario.
nm dyno_runner |grep square
U _ZN10DynamicLib6squareEi
La risposta è si. Il U
maiuscolo significa indefinito ma questo è il nome del simbolo per il nostro metodo quadrato nella classe DynamicLib che abbiamo creato in precedenza. Il nome dall'aspetto strano è dovuto alla manipolazione del nome che è il suo stesso argomento.
Come faccio a sapere a quali collegarmi staticamente come farei con un file regular.o e a quali dovrebbero essere collegati dinamicamente?
Non hai bisogno di saperlo. Si specifica con cosa si desidera collegare e si lascia che il compilatore (e il linker ecc.) facciano il lavoro. Nota il -l
flag denomina la libreria e il -L
gli dice dove cercare. C'è una descrizione decente su come il compilatore trova le cose qui
Opzione di collegamento gcc -L:modi alternativi per specificare il percorso della libreria dinamica
Oppure dai un'occhiata a man ld
.
A cosa servono i flag -L e -l? Cosa significa specificare ad esempio un flag -lusb sulla riga di comando?
Vedere il collegamento sopra. Questo è da man ld
..
-L searchdir
Aggiungere path searchdir all'elenco dei percorsi che ld cercherà nelle librerie di archivio e negli script di controllo ld. Puoi usare questa opzione qualsiasi numero di volte. Le directory vengono cercate nell'ordine in cui sono specificate sulla riga di comando. Le directory specificate sulla riga di comando vengono cercate prima delle directory predefinite. Tutte le opzioni -l si applicano a tutte le opzioni -l, indipendentemente dall'ordine in cui appaiono le opzioni. Le opzioni -L non influenzano il modo in cui ld cerca un linkerscript a meno che non sia specificata l'opzione -T.`
Se sei riuscito ad arrivare qui paga i dividendi per conoscere il linker ie ld. Svolge un ruolo importante ed è fonte di molta confusione perché la maggior parte delle persone inizia a trattare con un compilatore e pensa che compiler == linker
e questo non è vero.