3. Librerie condivise

Le librerie condivise sono librerie che vengono caricate all'avvio dei programmi. Una volta che una libreria condivisa è stata correttamente installata, tutti i programmi successivamente eseguiti ne faranno automaticamente uso. Il funzionamento è in realtà molto più flessibile e sofisticato di quanto detto, infatti l'approccio usato da Linux permette di:

3.1. Convenzioni

Affinché le librerie condivise supportino tutte queste caratteristiche è necessario attenersi ad un certo numero di convenzioni e linee guida. Occorre a questo scopo che risulti chiara la differenza tra i nomi con cui è possibile fare riferimento ad una libreria, in particolare i suoi "soname" e "nome vero" (e in che relazione questi siano tra di loro). Deve inoltre essere chiaro dove queste debbano essere poste nel filesystem.

3.1.1. Nomi delle librerie condivise

Ogni libreria condivisa ha uno speciale nome chiamato "soname". Il soname è caratterizzato dal prefisso "lib", dal nome della libreria, dalla particella ".so", seguita da un punto e da un numero di versione che viene incrementato ogni qualvolta avvengano delle modifiche all'interfaccia (una eccezione particolare è rappresentata dalle librerie di più basso livello del C, il cui nome non comincia per "lib"). Un soname completamente qualificato include come prefisso la directory in cui è posto; in un sistema funzionante al soname completamente qualificato corrisponde semplicemente un link simbolico al "nome vero" della libreria condivisa.

Ogni libreria condivisa ha anche un "nome vero", che corrisponde al nome del file che contiene effettivamente il codice di libreria. Il nome vero aggiunge al soname un punto, un numero di versione secondario, un ulteriore punto e il numero di release. L'ultimo punto ed il numero di release sono opzionali. Il numero di versione secondario ed il numero di release sono di supporto al controllo di configurazione, consentendo di sapere esattamente quale o quali versioni della libreria siano state installate. Si noti che questi numeri potrebbero non coincidere con quelli utilizzati per descrivere la libreria nella documentazione, anche se quando coincidono le cose certamente si semplificano.

In aggiunta a questi, esiste inoltre il nome utilizzato dal compilatore nel momento in cui fa richiesta di una particolare libreria (in seguito riferito come il "nome per il linker"), il quale coincide semplicemente con il soname privato di qualunque numero di versione.

La chiave della gestione delle librerie condivise consiste nella distinzione fra questi nomi. I programmi, nell'elencare internamente le librerie condivise di cui hanno bisogno, dovrebbero indicarne solo il soname. Al contrario, quando si crea una libreria condivisa, si crea solo la libreria stessa, con uno specifico nome di file (quindi con maggiore dettaglio sulle informazioni relative alla versione). Quando si installa una nuove versione di una libreria, la si copia in una posizione scelta fra un limitato insieme di speciali directory e quindi si esegue il programma ldconfig(8). ldconfig esamina i file esistenti e crea i soname come link simbolici ai nomi veri e, allo stesso tempo, aggiorna il file di cache /etc/ld.so.cache (descritto più avanti).

ldconfig non predispone i nomi per il linker; questo viene tipicamente fatto durante l'installazione della libreria ed il nome per il linker viene semplicemente creato come un link simbolico al "più recente" soname o al più recente nome vero. Raccomanderei la scelta di predisporre il nome per il linker come link simbolico al soname, dal momento che nella maggior parte dei casi se viene aggiornata una libreria la si vorrà probabilmente utilizzare automaticamente quando si esegue il link dei programmi. Ho chiesto a H. J. Lu il motivo per cui ldconfig non configuri automaticamente i nomi per il linker. La sua spiegazione è stata sostanzialmente che si potrebbe voler eseguire del codice utilizzando la versione più aggiornata della libreria, ma si potrebbe al contrario volere che lo sviluppo fosse collegato ad una versione più vecchia (ed eventualmente non compatibile). Quindi, ldconfig non fa assunzioni a proposito di cosa si voglia utilizzare in fase di link dei programmi e, di conseguenza, chi installa una libreria deve specificamente modificare i link simbolici per aggiornare la versione della libreria utilizzata dal linker.

Così, /usr/lib/libreadline.so.3 è un soname completamente qualificato, che ldconfig predisporrebbe come link simbolico ad un qualche nome vero come /usr/lib/libreadline.so.3.0. Dovrebbe inoltre essere presente un nome per il linker, /usr/lib/libreadline.so che potrebbe essere un link simbolico che fa riferimento a /usr/lib/libreadline.so.3.

3.1.2. Posizionamento nel filesystem

Le librerie condivise devono essere poste in qualche locazione nel filesystem. La maggior parte del software open source tende a seguire gli standard GNU; per maggiori informazioni si faccia riferimento alla documentazione disponibile presso info:standards#Directory_Variables. Gli standard GNU raccomandano, per la distribuzione di software accompagnato dai sorgenti, di utilizzare come locazione predefinita delle librerie /usr/local/lib (mentre tutti i comandi dovrebbero andare in /usr/local/bin). Essi stabiliscono inoltre le convenzioni per la ridefinizione di queste locazioni e per l'attivazione delle procedure di installazione.

Il Filesystem Hierarchy Standard (FHS) discute cosa dovrebbe andare a far parte di una distribuzione e dove (vedasi http://www.pathname.com/fhs). Secondo l'FHS, la maggior parte delle librerie dovrebbero essere installate in /usr/lib, tranne le librerie necessarie all'avvio che dovrebbero essere in /lib; infine, le librerie che non sono parte del sistema dovrebbero essere in /usr/local/lib.

Non esiste un reale conflitto fra questi due documenti; gli standard GNU raccomandano un comportamento predefinito per gli sviluppatori di codice sorgente, mentre l'FHS raccomanda il comportamento per chi distribuisce i programmi (che in maniera selettiva ridefinisce il comportamento prestabilito nel codice sorgente, di solito per mezzo del sistema di gestione dei pacchetti della distribuzione). Nella pratica tutto questo funziona bene: il codice sorgente "più aggiornato" (ed eventualmente bacato!) che si è scaricato dalla rete si installa automaticamente nella directory "locale" (/usr/local), e, una volta che il codice ha raggiunto uno stadio maturo, i gestori dei pacchetti possono banalmente ridefinire il comportamento predefinito per posizionare il codice in una locazione standard per la distribuzione. Si noti che se una libreria invoca programmi che possono essere richiamati unicamente da librerie, tali programmi dovrebbero essere posti in /usr/local/libexec (che diventa /usr/libexec in una distribuzione). Una complicazione è rappresentata dal fatto che i sistemi derivati da distribuzioni Red Hat non includono /usr/local/lib nel percorso predefinito per la ricerca delle librerie; per ulteriori informazioni si veda anche la discussione che segue a proposito di /etc/ld.so.conf. L'insieme delle directory comunemente utilizzate include /usr/X11R6/lib per le librerie del sistema X-windows. Si noti che /lib/security viene utilizzato per i moduli PAM (Pluggable Authentication Modules), ma questi sono di solito gestiti come librerie a caricamento dinamico (anche queste discusse più avanti).

3.2. Come le librerie vengono utilizzate

Nei sistemi basati sulle GNU glibc, inclusi quindi tutti i sistemi Linux, l'avvio di un eseguibile binario in formato ELF attiva l'esecuzione del caricatore di programma. Nei sistemi Linux, questo caricatore ha nome /lib/ld-linux.so.X (dove X è il numero di versione). Tale caricatore, a sua volta, localizza e carica in memoria tutte le librerie condivise utilizzate dal programma.

La lista delle directory su cui effettuare la ricerca è contenuta nel file /etc/ld.so.conf. Molte distribuzioni derivate da Red Hat non includono normalmente /usr/local/lib nel file /etc/ld.so.conf. Personalmente lo considero un baco e aggiungere /usr/local/lib in /etc/ld.so.conf rappresenta un tipico "rimedio" necessario per eseguire molti programmi su sistemi derivati da Red Hat.

Se si vuole forzare l'utilizzo di poche specifiche funzioni in alternativa a quelle normalmente rese disponibili da una libreria, ma mantenere valido il resto della libreria stessa, si possono inserire i nomi di queste librerie sostitutive (file .o) in /etc/ld.so.preload; queste librerie di "preloading" avranno la precedenza su quelle standard. Questo file di preloading viene tipicamente utilizzato per le correzioni di emergenza alla configurazione del sistema; una distribuzione di solito non includerà un simile file quando viene rilasciata.

La ricerca attraverso tutte queste directory all'avvio del programma risulterebbe gravemente inefficiente, di conseguenza in realtà si utilizza un meccanismo di cache. Il normale comportamento del programma ldconfig(8) consiste nel leggere il file /etc/ld.so.conf, configurare gli appropriati link simbolici nelle directory (così che questi seguiranno le convenzioni standard) e infine scrivere una cache nel file /etc/ld.so.cache che viene quindi utilizzato dagli altri programmi. Questo velocizza enormemente l'accesso alle librerie. La conseguenza è che ldconfig deve essere eseguito ogni volta che una DLL viene aggiunta, quando una DLL viene rimossa o quando cambia l'insieme delle directory in cui effettuare la ricerca delle librerie; spesso quando viene installata una libreria uno dei compiti effettuati dai gestori di pacchetti consiste nell'esecuzione di ldconfig. All'avvio di un programma, quindi, il caricatore dinamico in realtà utilizza il file /etc/ld.so.cache e carica quindi le librerie di cui necessita.

Ad ogni modo, FreeBSD utilizza nomi di file leggermente diversi per questa cache. Sotto FreeBSD, la cache per il formato ELF è /var/run/ld-elf.so.hints e la cache per il formato a.out è /var/run/ld.so.hints. Questi file sono comunque aggiornati da ldconfig(8), di conseguenza questa differenza di collocazione nel filesystem dovrebbe assumere una qualche importanza solo in rare, "esotiche", situazioni.

3.3. Variabili di ambiente

Diverse variabili d'ambiente permettono di controllare il processo di gestione delle librerie condivise ed esistono variabili d'ambiente che consentono di modificarne il funzionamento predefinito.

3.3.1. LD_LIBRARY_PATH

È possibile utilizzare, per una specifica esecuzione di un programma, una libreria differente. Sotto Linux, la variabile d'ambiente LD_LIBRARY_PATH costituisce una sequenza di directory, separate da doppi punti, dove le librerie dovrebbero essere inizialmente cercate, prima che venga cioè preso in esame l'insieme delle directory di sistema; questo risulta utile quando si sta sottoponendo a dubug una nuova libreria o quando si voglia utilizzare una libreria non standard per uno scopo particolare. La variabile d'ambiente LD_PRELOAD elenca le librerie condivise con funzioni che si sostituiscono a quelle predefinite, allo stesso modo di quanto avviene per /etc/ld.so.preload. L'utilizzo di queste variabili è implementato nel caricamento delle librerie da /lib/ld-linux.so. Si deve inoltre notare che, per quanto LD_LIBRARY_PATH funzioni per molte delle varianti di Unix, non funziona per tutte; per esempio, questa funzionalità è disponibile sotto HP-UX ma come variabile d'ambiente SHLIB_PATH, mentre sotto AIX la variabile è LIBPATH (con la medesima sintassi, una lista separata da doppi punti).

LD_LIBRARY_PATH risulta comoda per lo sviluppo e le operazioni di test, ma non dovrebbe venire modificata nel corso di una procedura di installazione al fine di essere utilizzata dai comuni utenti; si veda "Why LD_LIBRARY_PATH is Bad" al link http://www.visi.com/~barr/ldpath.html per una illustrazione dei motivi. Ciononostante, oltre ad essere utile per lo sviluppo e le operazioni di test, l'uso di questa variabile permette talvolta di aggirare problemi che non potrebbero essere risolti diversamente. Se non si desidera intervenire sulla variabile d'ambiente LD_LIBRARY_PATH, sotto Linux si può eventualmente invocare direttamente il caricatore di programma passandogli degli argomenti. Per esempio, il seguente comando utilizza il PERCORSO fornito in sostituzione al contenuto della variabile LD_LIBRARY_PATH ed avvia l'ESEGUIBILE indicato:
  /lib/ld-linux.so.2 --library-path PERCORSO ESEGUIBILE
L'esecuzione di ld-linux.so senza argomenti fornisce ulteriori informazioni sul suo utilizzo, ma, ancora una volta, non è consigliabile ricorrere a questo metodo se non per operazioni di debug.

3.3.3. Altre variabili di ambiente

Esiste in realtà un certo numero di ulteriori variabili d'ambiente che controllano il processo di caricamento; i nomi di tali variabili cominciano con i prefissi LD_ o RTLD_. La maggior parte di queste si utilizzano nel debug di basso livello del processo di caricamento o per l'implementazione di particolari comportamenti. Queste variabili sono per lo più scarsamente documentate; se si ha necessità di conoscerne le caratteristiche, il modo migliore di imparare qualcosa è leggere il codice sorgente del caricatore (che fa parte della distribuzione del compilatore gcc).

Permettere il controllo a livello utente sul caricamento di librerie a collegamento dinamico sarebbe disastroso per programmi con setuid/setgid se non venissero prese adeguate precauzioni. Di conseguenza, nel funzionamento del caricatore GNU (che carica il resto del programma all'avvio dello stesso), se il programma è setuid o setgid queste variabili (e altre variabili simili) vengono ignorate o fortemente limitate nei loro effetti. Il caricatore determina se un programma è setuid o setgid controllandone gli attributi; se l'uid e l'euid differiscono, o se il gid e l'egid differiscono, il caricatore presume che si stia trattando di un programma con setuid/setgid (o discendente di uno che lo sia) e quindi limita fortemente le possibilità di controllarne il collegamento. Leggendo il codice sorgente della libreria GNU glibc è possibile verificarlo; in particolare si vedano ad esempio i file elf/rtld.c e sysdeps/generic/dl-sysdep.c. Questo significa che facendo coincidere uid e gid con l'euid e l'egid e quindi chiamando un programma, queste variabili avranno un effetto completo. Altri sistemi Unix gestiscono questa situazione in modo differente, ma per la stessa ragione: un programma con setuid/setgid non dovrebbe essere indebitamente influenzato dalla configurazione delle variabili d'ambiente.

3.4. Creare una libreria condivisa

Creare una libreria condivisa è facile. Innanzitutto, si devono creare i file oggetto che andranno a far parte della libreria condivisa utilizzando le opzioni -fPIC o -fpic di gcc. Le opzioni -fPIC e -fpic abilitano la generazione di codice non dipendente dalla posizione ("position independent code"), un requisito per le librerie condivise; si veda oltre per le differenze fra le due opzioni. Il soname viene passato attraverso l'opzione -Wl di gcc. L'opzione -Wl inotra opzioni al linker (in questo caso -soname è quindi un'opzione per il linker); le virgole dopo -Wl non sono un errore di stampa e non si dovrebbero mai includere spazi (a meno di indicarli tramite una sequenza di escape) nel corpo di questa opzione. Si crea quindi una libreria condivisa utilizzando questo formato:

gcc -shared -Wl,-soname,mio_soname \
    -o nome_della_libreria elenco_dei_files elenco_delle_librerie

Ecco un esempio in cui si creano due file oggetto (a.o e b.o) e successivamente si crea una libreria condivisa che li contiene entrambi. Si noti che questa modalità di compilazione comprende le informazioni di debug (-g) e genererà eventuali warning (-Wall); tale modalità non rappresenta un requisito nella creazione di una libreria condivisa, ma è una pratica consigliata. La compilazione genera i file oggetto (utilizzando -c), ed include la necessaria opzione -fPIC:

gcc -fPIC -g -c -Wall a.c
gcc -fPIC -g -c -Wall b.c
gcc -shared -Wl,-soname,libmialibreria.so.1 \
    -o libmialibreria.so.1.0.1 a.o b.o -lc

Ci sono alcuni punti degni di nota:

Durante lo sviluppo, esiste il potenziale problema di modificare una libreria che è utilizzata anche da molti altri programmi -- e che non si voglia che altri programmi utilizzino la libreria "di sviluppo", tranne solamente un particolare programma tramite il quale si effettuano procedure di test. Un'opzione di link che si potrebbe usare è l'opzione "rpath" di ld, che specifica il percorso di ricerca delle librerie a tempo di esecuzione per il particolare programma che si sta compilando. Da gcc, è possibile definire tale opzione specificandola nel modo seguente:
 -Wl,-rpath,$(DEFAULT_LIB_INSTALL_PATH)
Se si utilizza questa opzione nel creare il programma che utilizza la libreria non è necessario preoccuparsi di LD_LIBRARY_PATH (si veda anche oltre) a parte verificare che non crei conflitti, o utilizzare altre tecniche per nascondere la versione di sviluppo della libreria al resto del sistema.

3.5. Installare ed utilizzare una libreria condivisa

Una volta creata una libreria condivisa, la si vorrà installare. L'approccio semplice consiste nel copiare la libreria in una delle directory standard (ad esempio, /usr/lib) ed eseguire ldconfig(8).

Innanzitutto, sarà necessario aver creato da qualche parte la libreria condivisa. Successivamente si dovranno creare i necessari link simbolici, in particolare un link dal soname al nome vero (come anche da un soname privo di versione, vale a dire, un soname che termina in ".so" per gli utenti che non specificano alcun numero di versione). L'approccio più semplice consiste nell'eseguire:
 ldconfig -n directory_con_librerie_condivise

Infine, nel compilare i programmi, si dovrà informare il linker di tutte le librerie condivise e statiche che si vogliono utilizzare. Si usino a questo scopo le opzioni -l e -L.

Se non si può o non si vuole installare la libreria in una locazione standard (ad esempio se non si dispone dei privilegi per modificare /usr/lib), sarà necessario cambiare approccio. In questo caso, la si dovrà installare da qualche parte e quindi fornire il programma di informazioni sufficienti così che il programma possa localizzare la libreria... ed esistono molti modi per farlo. Nei casi semplici si può utilizzare il flag -L di gcc. Si può utilizzare l'approccio basato su "rpath" (descritto precedentemente), in particolare quando solo uno specifico programma utilizza la libreria che si sta installando in una locazione "non standard". Si può anche regolare il funzionamento dei programmi tramite le variabili d'ambiente. In particolare, si può assegnare opportunamente LD_LIBRARY_PATH, che è una lista di directory separata da doppi punti (:) in cui avviene la ricerca delle librerie condivise prima che vengano prese in considerazioni le usuali directory di installazione. Si si sta utilizzando una shell bash è possibile invocare mio_programma nel modo seguente:

LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH  mio_programma

Se si vuole utilizzare una libreria sostituendone solo alcune funzioni, è possibile farlo creando un file oggetto e assegnando LD_PRELOAD; le funzioni in questo file oggetto si sostituiranno a quelle già presenti nella libreria (lasciando le altre invariate).

Solitamente è possibile aggiornare le librerie senza troppe preoccupazioni; se ci sono state variazioni a livello di API, si suppone che il creatore della libreria ne abbia cambiato il soname. In questo modo, differenti versioni di una singola libreria possono coesistere in uno stesso sistema e quella corretta viene selezionata per ogni programma. Comunque, se un programma smette di funzionare in seguito all'aggiornamento di una libreria che ha mantenuto lo stesso soname, è possibile forzarlo ad utilizzare la vecchia versione di libreria facendo una copia della vecchia libreria da qualche parte, rinominando il programma (ad esempio con il vecchio nome seguito da ".orig"), e quindi sostituendolo con un breve script ("wrapper") che riassegna la libreria da utilizzare prima di chiamare il vero programma (precedentemente rinominato). Si può porre la vecchia libreria in una particolare locazione, se preferibile, anche se le convenzioni sulla numerazione permettono, in generale, la coesistenza di versioni differenti in una medesima directory. Lo script potrebbe avere un aspetto simile al seguente:
  #!/bin/sh
  export LD_LIBRARY_PATH=/usr/local/mia_lib:$LD_LIBRARY_PATH
  exec /usr/bin/mio_programma.orig $*
È comunque raccomandabile non fare affidamento su questa possibilità quando si scrive il proprio codice; si cerchi piuttosto di accertarsi che le proprie librerie siano retrocompatibili o che si sia incrementato il numero di versione nel soname ogni volta che sia stata inserita una incompatibilità. Questo è solo un approccio di "emergenza" adatto ad affrontare problemi che si verificano nel peggiore dei casi.

È possibile visualizzare l'elenco delle librerie condivise utilizzate da un programma usando ldd(1). Ad esempio, si possono elencare le librerie condivise usate da ls digitando il comando:
  ldd /bin/ls
Generalmente verrà mostrato un elenco dei soname da cui il programma dipende assieme alle directory dove questi nomi vengono risolti. Nella quasi totalità dei casi si osserveranno almeno due dipendenze:

Attenzione: non si esegua ldd su un programma di cui non ci si fida. Come chiaramente affermato nel manuale di ldd(1), ldd funziona (in alcuni casi) assegnando una particolare variabile d'ambiente (per oggetti in formato ELF si tratta di LD_TRACE_LOADED_OBJECTS) e successivamente eseguendo il programma. Può risultare possibile per un programma forzare l'utente di ldd ad eseguire un arbitrario segmento di codice (invece che semplicemente mostrare le informazioni che ldd produce). Quindi, per ragioni di sicurezza, non si usi ldd su programmi che non ci si fiderebbe ad eseguire.

3.6. Librerie incompatibili

Quando una nuova versione di una libreria diventa incompatibile a livello binario con la precedente, il soname deve cambiare. In C esistono quattro principali motivi per cui una libreria cessa di essere compatibile a livello binario:

  1. il comportamento di una funzione cambia così da non corrispondere più alle specifiche originali,

  2. ci sono variazioni nelle strutture dati esportate (un'eccezione: aggiungere attributi opzionali in fondo a strutture può essere accettabile a condizione che tali strutture vengano allocate unicamente all'interno della libreria stessa),

  3. viene rimossa una funzione precedentemente esportata,

  4. l'interfaccia di una funzione esportata viene modificata.

Se si possono evitare questi motivi risulta allora possibile mantenere la compatibilità binaria delle librerie. Detto in altri termini, è possibile mantenere compatibile l'interfaccia binaria verso le applicazioni (ABI - Application Binary Interface) se si evitano simili modifiche. Per esempio, si potrebbe voler aggiungere delle nuove funzioni, ma non eliminare quelle vecchie. Si possono aggiungere elementi alle strutture, ma solo accertandosi che i vecchi programmi non saranno sensibili al cambiamento aggiungendoli solo in fondo alle strutture preesistenti, permettendo solo alla libreria (e non alle applicazioni) l'allocazione di tali strutture, rendendo opzionale l'uso dei termini aggiunti (o facendo in modo che sia la libreria ad assegnarli opportunamente) e così via. Attenzione: probabilmente non è possibile espandere delle strutture se gli utenti le stanno utilizzando negli array.

Per il C++ (e altri linguaggi che supportano la compilazione di codice in forma di template e/o meccanismi di risoluzione delle chiamate di metodi determinati in fase compilazione) la situazione è più complessa. Risultano validi tutti gli argomenti già citati ai quali se ne aggiungono numerosi altri. La ragione risiede nel fatto che alcune informazioni vengono inserite nel codice compilato in maniera non direttamente visibile allo sviluppatore, risultando in dipendenze che possono non essere ovvie se non si ha presente come il C++ viene tipicamente implementato. Di fatto, non si tratta di problematiche "nuove", è solo che il codice C++ compilato può farle emergere in modi che possono risultare inaspettati. Quella che segue è una lista (probabilmente incompleta) di cose che non si possono fare in C++ mantenendo la compatibilità binaria, come riportata da Troll Tech's Technical FAQ:

  1. aggiungere reimplementazioni di funzioni virtuali (a meno che non sia possibile per le applicazioni esistenti continuare a chiamare l'implementazione originale), dato che ClasseBase::funzioneVirtuale() viene valutata in fase di compilazione (e non in fase di link).

  2. aggiungere o rimuovere funzioni membro virtuali, dato che questo modificherebbe la dimensione e la struttura della vtbl di ogni sottoclasse.

  3. modificare il tipo di un qualunque dato membro o spostare un qualunque dato membro a cui si ha accesso tramite funzioni membro dichiarate inline.

  4. modificare l'albero di una gerarchia di classi, eccetto per aggiungere nuove foglie.

  5. aggiungere o rimuovere dati membro privati, dato che questo modificherebbe dimensione e struttura di ogni sottoclasse.

  6. rimuovere funzioni membro pubbliche o protette a meno che non siano dichiarate inline.

  7. rendere inline una funzione membro pubblica o protetta.

  8. modificare il comportamento di una funzione inline, a meno che la vecchia versione non continui a funzionare.

  9. modificare i privilegi di accesso (vale a dire pubblico, protetto o privato) di una funzione membro in un programma che intenda mantenere una certa portabilità in quanto alcuni compilatori inseriscono i privilegi di accesso nella decorazione del nome di funzione.

Data la lunga lista, gli sviluppatori di librerie in C++ dovranno pianificare lo sviluppo con particolare attenzione se vorranno minimizzare gli aggiornamenti che ne possano compromettere la compatibilità a livello binario. Fortunatamente, nei sistemi di tipo Unix (Linux incluso) si possono caricare ed utilizzare contemporaneamente differenti versioni di una stessa libreria, così che, anche se con qualche penalizzazione in termini di occupazione dello spazio disco, gli utenti possono continuare ad eseguire "vecchi" programmi che richiedono le vecchie librerie.