Scrivere programmi in C/C++ usando la toolchain GCC è, in genere, piacevole e produttivo. A patto di conoscere alcune questioni che, a prima vista, possono sembrare di lana caprina.
La questione di lana caprina
Ad esempio, una cosa importante da sapere è che, a differenza di quando si linka un eseguibile, quando si fa il link di una libreria condivisa (file lib*.so), lo GNU linker (invocato direttamente con il comando ld, oppure indirettamente tramite il compilatore GCC) non dà alcun errore se ci sono simboli irrisolti. L’idea è quella di consentire comunque la creazione della libreria, rimandando la risoluzione dei simboli al momento in cui si farà il link di un eseguibile che ne faccia uso.
Facciamo un esempio concreto: supponiamo di realizzare la libreria libdinamica.so, che usa al suo interno la funzione richiesta() presa dalla libreria condivisa libdipendenza.so. Il comando di link per libdinamica.so sarà qualcosa del genere:
$ g++ -shared -o libdinamica.so oggetto1.o oggetto2.o oggetto3.o
che non contiene riferimenti alla libreria libdipendenza.so e non dà messaggi di errore. Un eventuale eseguibile che fa uso della libreria libdinamica.so dovrà essere linkato con il comando
$ g++ -o pincopallino oggetto4.o oggetto5.o -L. -ldinamica -ldipendenza
, ossia specificando entrambe le librerie (qui si suppone che tutti i file si trovino nella cartella corrente).
Se, invece, si fosse linkata la libreria con il comando
$ g++ -shared -o libdinamica.so oggetto1.o oggetto2.o oggetto3.o -L. -ldipendenza
il comando per linkare l’eseguibile avrebbe potuto essere
$ g++ -o pincopallino oggetto4.o oggetto5.o -L. -ldinamica
che è molto più logico perché, in generale, i file oggetto4.o e oggetto5.o possono essere del tutto agnostici riguardo alla libreria libdipendenza.so.
Il comportamento virtuoso
Un modo per costringerci ad adottare il “comportamento virtuoso” (quello di linkare libdipendenza.so con libdinamica.so, e non con l’eseguibile) è quello di richiedere al linker di lamentarsi dei simboli irrisolti anche durante la costruzione delle librerie condivise. L’opzione per attivare questo comportamento del linker è --no-undefined (che diventa -Wl,--no-undefined se invocata dal compilatore).
Con l’opzione --no-undefined, la prima versione del comando ha questo esito:
$ g++ -Wl,--no-undefined -shared -o libdinamica.so oggetto1.o oggetto2.o oggetto3.o oggetto1.o: In function `usa_richiesta()': oggetto1.cpp:(.text+0x13): undefined reference to `richiesta()' collect2: ld returned 1 exit status $
mentre l’unica forma che funziona sarà
$ g++ -Wl,--no-undefined -shared -o libdinamica.so oggetto1.o oggetto2.o oggetto3.o -L. -ldipendenza
