5.3. Note tecniche sulla Toolchain

Questa sezione prova a spiegare alcuni dei dettagli tecnici e logici dietro al metodo di costruzione complessivo. Non è importante che qui si comprenda ogni cosa immediatamente. Molto di questo avrà senso quando si sarà realizzata una compilazione. Questa sezione può essere ripresa in ogni momento durante il procedimento

Lo scopo complessivo del Capitolo 5 è di fornire un ambiente provvisorio in cui si possa accedere con chroot, e dal quale si possa produrre una costruzione pulita e priva di problemi del sistema LFS, obiettivo del Capitolo 6. Lungo la strada, ci si separa il più possibile dal sistema host, e nel farlo si costruisce una toolchain auto-contenuta che si auto-ospita. Bisogna notare che il processo di costruzione è stato pensato per minimizzare il rischio per i lettori nuovi e fornire un minimo valore didattico nello stesso tempo. In altre parole, potrebbero essere utilizzate tecniche più avanzate per costruire il sistema.

[Importante]

Importante

Prima di continuare bisogna essere certi del nome della propria piattaforma, a cui spesso si fa riferimento anche come tripletta target. Spesso, la tripletta target sarà probabilmente i686-pc-linux-gnu. Un modo semplice per determinare la propria piattaforma è quello di eseguire lo script config.guess fornito con i sorgenti di molti pacchetti. Scompattare i sorgenti delle Binutils ed eseguire lo script: ./config.guess e annotare l'output.

Bisogna anche essere a conoscenza del nome del linker dinamico, cui spesso si fa riferimento come dynamic loader (da non confondere con il linker standard ld che è parte delle Binutils). Il linker dinamico fornito da Glibc trova e carica le librerie condivise necessarie a un programma, prepara il programma all'esecuzione, e quindi lo esegue. Il nome del linker dinamico solitamente sarà ld-linux.so.2. Su piattaforme meno recenti, il nome potrebbe essere ld.so.1, e le nuove piattaforme a 64 bit potrebbero avere nomi completamente diversi. Il nome del linker dinamico della piattaforma può venire determinato guardando nella directory /lib sul sistema host. Un sistema per determinare il nome a colpo sicuro è di controllare un binario a caso del sistema host eseguendo: readelf -l <nome del binario> | grep interpreter e annotando l'output. Il riferimento autoritativo che copre tutte le piattaforme è nel file shlib-versions nella root dell'albero dei sorgenti di Glibc.

Alcuni punti tecnici su come funziona il metodo di costruzione del Capitolo 5:

Le binutils sono installate per prime perché il file ./configure eseguito sia da GCC che da Glibc effettua vari tipi di test sull'assemblatore e il linker per determinare quali caratteristiche del software abilitare e disabilitare. Ciò è molto più importante di quanto uno possa pensare inizialmente. Una configurazione scorretta di GCC o Glibc può portare a una toolchain corrotta, dove l'impatto di una tale corruzione potrebbe non evidenziarsi fin quasi al termine della costruzione dell'intera distribuzione. Grazie al cielo, un fallimento di una suite di test normalmente ci avvisa prima di aver perso troppo tempo.

Le Binutils installano il loro assemblatore e linker in due locazioni, /tools/bin e /tools/$TARGET_TRIPLET/bin. I tool in ogni locazione sono collegati stabilmente all'altra. Un aspetto importante del linker è il suo ordine di ricerca della libreria. Informazioni dettagliate si possono ottenere da ld passandogli il flag --verbose. Ad esempio, un ld --verbose | grep SEARCH illustrerà i percorsi di ricerca correnti e il loro ordine. Esso mostra quali file sono linkati da ld compilando un programma dummy e passando lo switch --verbose al linker. Ad esempio, gcc dummy.c -Wl,--verbose 2>&1 | grep succeeded mostrerà tutti i file aperti con successo durante la fase di link.

Il prossimo pacchetto installato è GCC. Un esempio di ciò che si può vedere durante la sua esecuzione di ./configure è:

checking what assembler to use... 
        /tools/i686-pc-linux-gnu/bin/as
checking what linker to use... /tools/i686-pc-linux-gnu/bin/ld

Ciò è importante per le ragioni sopra menzionate. Dimostra anche che lo script di configurazione di GCC non cerca le directory del PATH per trovare quali tool usare. Tuttavia, durante le attuali operazioni dello stesso gcc, non vengono necessariamente usati gli stessi percorsi di ricerca. Per scoprire quale linker standard sarà usato da gcc eseguire: gcc -print-prog-name=ld.

Informazioni dettagliate possono essere ottenute da gcc passandogli l'opzione da linea di comando -v quando compila un programma dummy. Ad esempio, gcc -v dummy.c mostrerà informazioni dettagliate riguardanti preprocessore, compilazione, e fase di assemblaggio, includendo i percorsi gcc di ricerca e il loro ordine.

Il pacchetto installato successivamente è Glibc. Le considerazioni più importanti per costruire Glibc riguardano il compilatore, i tool binari e gli header del kernel. Il compilatore normalmente non è un problema perché Glibc userà sempre il gcc trovato in una directory del PATH. I tool binari e gli header del kernel possono essere un po' più complicati. Pertanto non si prendano rischi e si utilizzino gli switch di configurazione disponibili per forzare le selezioni corrette. Dopo 'esecuzione di ./configure, verificare i contenuti del file config.make nella directory glibc-build per tutti i dettagli importanti. Notare l'uso di CC="gcc -B/tools/bin/" per controllare quali tool binari sono usati e l'uso dei flag -nostdinc e -isystem per controllare il percorso di ricerca dell'include del compilatore. Queste cose evidenziano un importante aspetto del pacchetto Glibc: è molto autosufficiente nel suo motore di costruzione e generalmente non fa riferimento ai default della toolchain.

Dopo l'installazione di Glibc, apportare alcuni aggiustamenti per garantire che ricerca e collegamento prendano posto solo nel prefisso /tools. Installare un ld aggiustato, che ha un percorso di ricerca incluso in esso limitato a /tools/lib. Quindi correggere il file specs di gcc per farlo puntare al nuovo linker dinamico in /tools/lib. Questo ultimo passo è vitale per l'intero processo. Come citato in precedenza, un percorso fisso verso un linker dinamico è incluso in ogni eseguibile Executable and Link Format (ELF) condiviso. Ciò può essere controllato eseguendo: readelf -l <nome del binario> | grep interpreter. Correggendo il file specs di gcc si garantisce che ogni programma compilato da qui alla fine di questo capitolo usi il nuovo linker dinamico in /tools/lib.

La necessità di usare il nuovo linker dinamico è anche la ragione per cui la patch Specs è applicata per il secondo passo di GCC. Non fare questo significa far sì che gli stessi programmi GCC abbiano il nome del linker dinamico dalla directory del sistema host /lib incluso in essi, cosa che vanificherebbe l'oiettivo di allontanarci dall'host.

Durante il secondo passo di Binutils, si può utilizzare lo switch di configurazione --with-lib-path per controllare il percorso di ricerca delle librerie di ld. Da questo punto in poi, la toolchain principale è auto-contenuta e si auto-ospita. I rimanenti pacchetti del Capitolo 5 si costruiscono tutti con la nuova Glibc in /tools.

Una volta entrati nell'ambiente chroot nel Capitolo 6, il primo grosso pacchetto che si installa è Glibc, per via della sua natura auto-sufficiente cui si è accennato prima. Una volta installato Glibc in /usr, si realizza un rapido cambio dei default della toolchain, e quindi si procede alla vera costruzione del resto del sistema LFS.

5.3.1. Note sui collegamenti statici

Molti programmi devono fare, oltre al loro compito specifico, molte operazioni piuttosto comuni e talvolta complesse. Tra queste ci sono allocazione di memoria, ricerca nelle directory, lettura e scrittura file, manipolazione di stringhe, confronti, aritmetica e molte altre operazioni. Invece di obbligare ogni programma a reinventare la ruota, il sistema GNU fornisce tutte queste funzioni di base in librerie pronte all'uso. La più grossa ed importante libreria in ogni sistema Linux è Glibc.

Ci sono due principali modi di collegare le funzioni da una libreria a un programma che la usa: staticamente o dinamicamente. Quando un programma è collegato staticamente, il codice della funzione utilizzata è incluso nell'eseguibile, e il risultato è un programma piuttosto gonfiato. Quando un programma è collegato dinamicamente, vi è incluso un riferimento al collegamento dinamico, il nome della libreria, e il nome della funzione, e il risultato è un programma più snello. Un terzo modo è di usare l'interfaccia di programmazione del linker dinamico (si veda la pagina man di dlopen per maggiori informazioni).

Il collegamento dinamico è il default in Linux, ed ha tre grandi vantaggi rispetto a quello statico. Primo, c'è bisogno di una sola copia del codice eseguibile della libreria sul proprio disco rigido, invece di avere più copie dello stesso codice incluse in un intero insieme di programmi, il che salva spazio sul disco. Secondo, quando più programmi usano la stessa funzione della libreria nello stesso momento, è necessaria solo una copia del codice della funzione in memoria, il che salva spazio in memoria. Terzo, quando viene fissato un bug in una funzione della libreria o questa è comunque migliorata, bisogna ricompilare solamente questa libreria, invece di dover ricompilare tutti i programmi che fanno uso della funzione migliorata.

Se il collegamento dinamico ha diversi vantaggi, perché colleghiamo staticamente i primi due pacchetti in questo capitolo? Le ragioni sono tre: storica, didattica, e tecnica. Storica, perché le prime versioni di LFS collegavano staticamente ogni programma in questo capitolo. Didattica, perché sapere la differenza è utile. Tecnica, perché così facendo si guadagna un elemento di indipendenza dal sistema. Tuttavia, è bene sapere che LFS può essere costruita con successo anche con i primi due pacchetti collegati dinamicamente.