Potrebbe anche essere necessario assicurarsi di non dipendere dalla glibc dinamica. Esegui ldd
sull'eseguibile risultante e prendi nota di eventuali dipendenze dinamiche (libc/libm/libpthread sono soliti sospetti).
Un esercizio aggiuntivo sarebbe la creazione di una serie di esempi C++ 11 coinvolti utilizzando questa metodologia e provando effettivamente i binari risultanti su un vero sistema 10.04. Nella maggior parte dei casi, a meno che tu non faccia qualcosa di strano con il caricamento dinamico, saprai subito se il programma funziona o si blocca.
Quel post sul blog è piuttosto impreciso.
Per quanto ne so, le modifiche all'ABI C++ sono state introdotte con tutte le principali versioni di GCC (ovvero quelle con diversi componenti del numero di prima o seconda versione).
Non vero. Le uniche modifiche all'ABI C++ introdotte da GCC 3.4 sono state compatibili con le versioni precedenti, il che significa che l'ABI C++ è rimasto stabile per quasi nove anni.
A peggiorare le cose, la maggior parte delle principali distribuzioni Linux utilizza istantanee GCC e/o corregge le loro versioni GCC, rendendo praticamente impossibile sapere esattamente con quali versioni GCC potresti avere a che fare quando distribuisci i binari.
Le differenze tra le versioni con patch di GCC delle distribuzioni sono minori e non cambiano l'ABI, ad es. Fedora 4.6.3 20120306 (Red Hat 4.6.3-2) è ABI compatibile con le versioni upstream di FSF 4.6.x e quasi certamente con qualsiasi 4.6.x di qualsiasi altra distribuzione.
Su GNU/Linux le librerie di runtime di GCC usano il versioning dei simboli ELF così è facile controllare le versioni dei simboli necessarie per oggetti e librerie, e se hai un libstdc++.so
che fornisce quei simboli funzionerà, non importa se si tratta di una versione con patch leggermente diversa da un'altra versione della tua distribuzione.
ma nessun codice C++ (o qualsiasi codice che utilizza il supporto di runtime C++) può essere collegato dinamicamente se questo deve funzionare.
Anche questo non è vero.
Detto questo, collegamento statico a libstdc++.a
è un'opzione per te.
Il motivo per cui potrebbe non funzionare se carichi dinamicamente una libreria (usando dlopen
) è che i simboli libstdc++ da cui dipende potrebbero non essere stati necessari alla tua applicazione quando l'hai collegata (staticamente), quindi quei simboli non saranno presenti nel tuo eseguibile. Ciò può essere risolto collegando dinamicamente la libreria condivisa a libstdc++.so
(che è comunque la cosa giusta da fare se dipende da questo.) L'interposizione di simboli ELF significa che i simboli presenti nel tuo eseguibile verranno utilizzati dalla libreria condivisa, ma altri non presenti nel tuo eseguibile verranno trovati in qualsiasi libstdc++.so
si collega a. Se la tua applicazione non utilizza dlopen
non devi preoccuparti di questo.
Un'altra opzione (e quella che preferisco) è distribuire il nuovo libstdc++.so
accanto alla tua applicazione e assicurati che venga trovata prima del sistema predefinito libstdc++.so
, che può essere fatto forzando il linker dinamico a cercare nel posto giusto, usando $LD_LIBRARY_PATH
variabile di ambiente in fase di esecuzione o impostando un RPATH
nell'eseguibile in fase di collegamento. Preferisco usare RPATH
poiché non si basa sull'impostazione corretta dell'ambiente affinché l'applicazione funzioni. Se colleghi la tua applicazione con '-Wl,-rpath,$ORIGIN'
(notare le virgolette singole per impedire alla shell di tentare di espandere $ORIGIN
) quindi l'eseguibile avrà un RPATH
di $ORIGIN
che dice al linker dinamico di cercare le librerie condivise nella stessa directory dell'eseguibile stesso. Se inserisci il nuovo libstdc++.so
nella stessa directory dell'eseguibile si troverà in fase di esecuzione, problema risolto. (Un'altra opzione è mettere l'eseguibile in /some/path/bin/
e il più recente libstdc++.so in /some/path/lib/
e link con '-Wl,-rpath,$ORIGIN/../lib'
o qualsiasi altra posizione fissa relativa all'eseguibile, e imposta l'RPATH relativo a $ORIGIN
)
Un'aggiunta all'eccellente risposta di Jonathan Wakely, perché dlopen() è problematico:
A causa del nuovo pool di gestione delle eccezioni in GCC 5 (vedere PR 64535 e PR 65434), se si apre e si chiude una libreria che è collegata staticamente a libstdc++, si otterrà ogni volta una perdita di memoria (dell'oggetto pool). Quindi, se c'è qualche possibilità che userai mai dlopen, sembra davvero una pessima idea collegare staticamente libstdc++. Si noti che si tratta di una vera e propria fuga di notizie rispetto a quella benigna menzionata in PR 65434.