[ << ]
[ < ]
[ Home ]
[ > ]
[ >> ]
2. Creare un Cross-Compilatore
Indice:
2.a. Prologo
La prima cosa da sapere sulla creazione di una toolchain è che certe versioni di
alcuni suoi componenti non funzionano assieme. Sapere quali siano le esatte
combinazioni problematiche è un dato che è in costante mutamento a seconda di
come si sviluppa l'albero di portage. L'unico modo sicuro per determinare se una
certa combinazione funziona è eseguire crossdev, specificando le versioni dei
vari componenti secondo necessità, finché non viene completata con successo la
compilazione dell'intera toolchain. Anche a quel punto, la cross toolchain
potrebbe generare binari non funzionanti sul sistema di destinazione. Solo
avendo pazienza e procedendo per tentativi ed errori si potrà ottenere una
combinazione favorevole di tutti i fattori.
Tutti i pacchetti della toolchain sono pensati in modo tale da esser totalmente
isolati in base all'architettura di destinazione, per cui non c'è modo che
interferiscano con l'ambiente nativo di compilazione. Questo permette di
installare cross-compilatori per qualunque architettura si desideri senza
intaccare il resto del sistema.
Tuttavia, ci sono alcuni scenari, anche se in diminuzione ogni giorno che
passa, che fanno sì che portage richieda o influenzi dei cambiamenti alla root
reale. Per mantenere pulita la propria installazione di Gentoo, si raccomanda
caldamente che l'installazione di crossdev e tutte le attività di
cross-compilazione avvengano dentro ad un chroot di uno stage3 di Gentoo. (È lo
stesso chroot usato per installare Gentoo.)
2.b. crossdev
Introduzione
Generare a mano un cross-compilatore era un processo lungo e tedioso. Per questo
è stato integrato totalmente in Gentoo! Tramite un'interfaccia chiamata
crossdev (installabile con emerge crossdev) emerge verrà
eseguito con tutte le variabili d'ambiente valorizzate correttamente ed
installerà tutti i pacchetti corretti per generare qualunque tipo di
cross-compilatore di cui si ha bisogno. Per prima cosa bisogna installare
crossdev.
Codice 2.1: Installare crossdev |
# emerge crossdev
|
È consigliabile installare la versione instabile (~arch) di crossdev per
ottenere tutte le più recenti correzioni.
Nota:
Se si sta effettuando un aggiornamento da una vecchia versione di crossdev, e
c'è crossdev-wrappers installato, assicurarsi prima di disinstallare
crossdev-wrappers. Le cross-toolchain esistenti rimarranno intatte.
|
In questo documento verrà coperto solamente l'utilizzo basilare di crossdev,
tuttavia questo strumento può personalizzare adeguatamente il processo per la
maggior parte delle necessità. Eseguire crossdev --help per ottenere
alcune indicazioni su come usare crossdev. Ecco alcune delle modalità d'uso più
comuni:
Codice 2.2: Opzioni di crossdev utili |
# crossdev --g [gcc version] --l [(g)libc version] --b [binutils version] --k
[kernel headers version] -P -v -t [tuple]
# crossdev -S -P -v -t [tuple]
|
Installazione
Il primo passo consiste nel selezionare la corretta stringa per
il sistema di destinazione. Prendiamo ad esempio che si voglia generare
un cross-compilatore per il processore SH4 (SuperH) con supporto alle
glibc per Sistema Operativo Linux. Il tutto partendo da una macchina
PowerPC.
Codice 2.3: Generazione del cross-compilatore per SH4 |
# crossdev --target sh4-unknown-linux-gnu
-----------------------------------------------------------------------------------------------------
* Host Portage ARCH: ppc
* Target Portage ARCH: sh
* Target System: sh4-unknown-linux-gnu
* Stage: 4 (C/C++ compiler)
* binutils: binutils-[latest]
* gcc: gcc-[latest]
* headers: linux-headers-[latest]
* libc: glibc-[latest]
* PORTDIR_OVERLAY: /usr/local/portage
* PORT_LOGDIR: /var/log/portage
* PKGDIR: /usr/portage/packages/powerpc-unknown-linux-gnu/cross/sh4-unknown-linux-gnu
* PORTAGE_TMPDIR: /var/tmp/cross/sh4-unknown-linux-gnu
_ - ~ - _ - ~ - _ - ~ - _ - ~ - _ - ~ - _ - ~ - _ - ~ - _ - ~ - _
* Forcing the latest versions of {binutils,gcc}-config/gnuconfig ... [ ok ]
* Log: /var/log/portage/cross-sh4-unknown-linux-gnu-binutils.log
* Emerging cross-binutils ... [ ok ]
* Log: /var/log/portage/cross-sh4-unknown-linux-gnu-gcc-stage1.log
* Emerging cross-gcc-stage1 ... [ ok ]
* Log: /var/log/portage/cross-sh4-unknown-linux-gnu-linux-headers.log
* Emerging cross-linux-headers ... [ ok ]
* Log: /var/log/portage/cross-sh4-unknown-linux-gnu-glibc.log
* Emerging cross-glibc ... [ ok ]
* Log: /var/log/portage/cross-sh4-unknown-linux-gnu-gcc-stage2.log
* Emerging cross-gcc-stage2 ... [ ok ]
|
Nota:
Al momento non è possibile assegnare a PORTAGE_CONFIGROOT una directory
predisposta per l'architettura di destinazione prima di invocare
crossdev, bisogna invece usare la propria configurazione. Se si vogliono
usare FLAG use specifiche per architettura, come altivec su
un'architettura non powerpc, bisogna smascherare la flag use in
/usr/portage/base/use.mask, o cambiare temporaneamente il proprio
profilo.
|
Test Veloce
Se tutto è andato come previsto, si dovrebbe avere un compilatore nuovo
fiammante sulla propria macchina. Facciamo una prova!
Codice 2.4: test del cross-compilatore per SH4 |
$ sh4-unknown-linux-gnu-gcc --version
sh4-unknown-linux-gnu-gcc (GCC) 4.2.0 (Gentoo 4.2.0 p1.4)
Copyright (C) 2007 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ echo 'int main(){return 0;}' > sh4-test.c
$ sh4-unknown-linux-gnu-gcc -Wall sh4-test.c -o sh4-test
$ file sh4-test
sh4-test: ELF 32-bit LSB executable, Renesas SH, version 1 (SYSV), for GNU/Linux 2.6.9, dynamically linked (uses shared libs), not stripped
|
Se il comando crossdev fallisse, saranno comunque a disposizione i
log per analizzare il problema che si è verificato. Se non si è in
grado di risolvere il problema, aprite pure un bug sul bugzilla di Gentoo.
Per maggiori informazioni visitare la pagina
dei Contatti.
Disinstallazione
Per disinstallare una toolchain, è sufficiente usare l'opzione --clean.
Se la sysroot è stata modificata a mano, vi verrà domandato se cancellarne il
contenuto, per cui potreste volere mettere in pipe yes | al comando.
Codice 2.5: disinstallare il cross-compiler |
# crossdev --clean sh4-unknown-linux-gnu
|
Nel caso non lo si abbia già notato, cancellare tutti i file contenuti nella
directory /usr/CTARGET/ è completamente sicuro.
Opzioni
Ovviamente crossdev può fare molte altre cose, per scoprirle, basta lanciare
crossdev --help.
2.c. I dettagli della Cross-Compilazione
Avvertenza:
Questa sezione è inclusa per i posteri, nella speranza che possa essere utile ad
altri. I lettori a cui è dedicata sono coloro che (per una ragione o per
l'altra) vogliono crearsi a mano, tutto da soli, il proprio cross-compilatore
usando binutils/(glibc|uclibc)/gcc . Questa sezione non è intesa per
illustrare/documentare/quelchevolete la miriade di errori di compilazione che
quasi sicuramente si incontreranno lungo la via. Se avete bisogno di tale
supporto, leggete la sezione Ampliare le
proprie Conoscenze del Manuale, ma non lamentatevi con l'autore o chiunque
altro all'interno di Gentoo.
|
Avvertenza:
Se state ancora leggendo, dovreste controllare il progetto CrossTool (fate
riferimento alla sezione Ampliare le proprie
Conoscenze) che fornisce un metodo generico adatto ad ogni distribuzione
per generare un cross-compilatore. Pur essendo, a giudizio dell'autore, poco
più che un accrocchio, è sicuramente la migliore, nonché l'unica, via
percorribile per ottenere un cross-compilatore.
|
Introduzione
Generalmente ci sono due strade percorribili per generare il proprio
compilatore. La via "maestra" e l'oscura scorciatoia.
La via "maestra" è:
- binutils
- header del kernel
- header delle libc
- gcc stage1 (solo c)
- libc
- gcc stage2 (c/c++/etc...)
L'oscura scorciatoia invece è:
- binutils
- header del kernel
- gcc stage1 (solo c)
- libc
- gcc stage2 (c/c++/etc...)
Molte persone seguono la scorciatoia perche la generazione degli header delle
libc richiede molto tempo, specie su macchine lente. Inoltre installare gli
header del kernel e/o delle libc senza un cross-compilatore funzionante potrebbe
esser una scocciatura. Ricordate però che se si cerca aiuto sui
cross-compilatori, il progetto upstream non vi offrirà supporto se avrete
utilizzato la scorciatoia.
La scorciatoia inoltre richiede uno stage1 "menomato". Dal momento che si sta
compilando senza gli header, non è possibile abilitare le varie opzione della
sysroot né è possibile compilare correttamente le librerie del gcc. Questa
situazione può essere accettabile solo se si usa lo stage1 per compilare la
libreria C e il kernel, per tutto il resto sarà necessario un compilatore basato
su sysroot.
Di seguito verrà descritta solo la via "riconosciuta", i passi da fare comunque
sono praticamente gli stessi. Per la scorciatoia sarà sufficiente applicare
qualche patch supplementare al gcc.
Sysroot
La cross-compilazione avverrà usando il metodo della sysroot. Ma cosa si intende
precisamente quando si parla di sysroot ?
Dalla documentazione del gcc:
Dice al GCC di considerare dir come la radice (NdT. root) di un'alberatura
contenente il filesystem di root del sistema operativo di destinazione. Gli
header del sistema di destinazione, le librerie e gli oggetti a run-time saranno
ricercati al suo all'interno.
La directory radice solitamente viene posizionata in /usr/$CTARGET .
Codice 3.1: tipico layout di una sysroot |
/usr/$CTARGET/
|-- bin/
|-- lib/ librerie di runtime critiche (libc/ldso/etc...)
`-- usr/
|-- include/ header per lo sviluppo
| |-- linux/ come il kernel linux
| `-- asm/ come le dir. specifiche per ogni architettura
`-- lib/ librerie di runtime / sviluppo non critiche
|
Come si può notare, è una configurazione analoga alla / , solo che si trova in
/usr/$CTARGET. Questa scelta non è ovviamente accidentale, ma pensata di
proposito così da rendere semplice la migrazione di applicazioni e/o librerie da
/usr/$CTARGET alla / sull'architettura di destinazione. volendo, è possibile
utilizzare /usr/$CTARGET come NFS root pronta all'uso!
Nota:
Note pre sysroot:
Il vecchio metodo per cross-compilare imponeva l'uso di --prefix=/usr/$CTARGET.
Se si stanno usando versioni di binutils/gcc antecedenti al supporto al sysroot,
ci si potrebbe trovar a dover agire come sopra indicato. Non sarà però qui
illustrato il come, in quanto (1) non si dovrebbero usare versioni così
datate/arrugginite/bacate di tali componenti e (2) sarebbe molto più scomodo e
problematico in confronto a sysroot.
|
Binutils
Prelevare l'ultima versione del pacchetto binutils e scompattarlo.
L'opzione di configurazione --disable-werror è usata per evitare che la
compilazione delle binutils fallisca per via dei warning. Caratteristica molto
utile per gli sviluppatori, molto problematica invece per gli utenti.
Codice 3.2: configurazione e compilazione delle binutils |
$ ./configure \
--target=$CTARGET \
--prefix=/usr \
--with-sysroot=/usr/$CTARGET \
--disable-werror
$ make
$ make install DESTDIR=$PWD/install-root
|
Il motivo per cui le binutils vengono installate nella directory
install-root è per permettere la rimozione di componenti di cui non
si ha bisogno. Ad esempio, una normale installazione creerà
/usr/lib/libiberty.a che non deve però far parte del sistema in uso.
Va perciò fatta prima un po' di pulizia:
Codice 3.3: ripuliamo le binutils |
$ rm -rf install-root/usr/{info,lib,man,share}
|
Installare quindi quanto rimasto :
Codice 3.4: installazione delle binutils |
# cp -a install-root/* /
|
Header del kernel
Prelevare l'ultimo pacchetto del kernel e scompattarlo. Gli header possono
essere installati in 2 modi: ripuliti o grezzi. La prima è chiaramente migliore
(richiede però una versione recente del kernel Linux), ma verranno illustrate
brevemente entrambe.
Nota:
Ricordarsi di sostituire $ARCH con un valore sensato per la propria
architettura.
|
Codice 3.5: Compilazione/installazione degli header grezzi |
$ yes "" | make ARCH=$ARCH oldconfig prepare
# mkdir -p /usr/$CTARGET/usr/include
# cp -a include/linux include/asm-generic /usr/$CTARGET/usr/include/
# cp -a include/asm-$ARCH /usr/$CTARGET/usr/include/asm
|
Codice 3.6: compilazione/installazione degli header ripuliti |
# make ARCH=$ARCH headers_install INSTALL_HDR_PATH=/usr/$CTARGET/usr
|
Header delle libc di sistema
Prelevare l'ultimo pacchetto delle glibc e scompattarlo. Le Glibc sono piuttosto
esigenti, per questo andranno compilate in una directory differente da quella
dei sorgenti.
Codice 3.7: compilazione/installazione degli header delle glibc |
$ mkdir build
$ cd build
$ ../configure \
--host=$CTARGET \
--prefix=/usr \
--with-headers=/usr/$CTARGET/usr/include \
--without-cvs \
--disable-sanity-checks
# make -k install-headers install_root=/usr/$CTARGET
|
Purtroppo le glibc non sono perfette e richiedono che alcune operazioni siano
fatte a mano:
Codice 3.8: diamo una mano alle glibc |
# mkdir -p /usr/$CTARGET/usr/include/gnu
# touch /usr/$CTARGET/usr/include/gnu/stubs.h
# cp bits/stdio_lim.h /usr/$CTARGET/usr/include/bits/
|
GCC Stage 1 (solo C)
Prima di tutto bisogna fare in modo che il gcc trovi gli header delle libc.
Codice 3.9: diamo una mano al gcc |
# ln -s usr/include /usr/$CTARGET/sys-include
|
Quindi prelevare l'ultima versione del pacchetto gcc e scompattarlo.
Codice 3.10: compilazione del gcc stage 1 |
$ mkdir build
$ cd build
$ ../configure \
--target=$CTARGET \
--prefix=/usr \
--with-sysroot=/usr/$CTARGET \
--enable-languages=c \
--disable-shared \
--disable-checking \
--disable-werror \
--disable-libmudflap \
--disable-libssp \
--disable-libgomp \
--disable-libssp
$ make
$ make install DESTDIR=$PWD/install-root
|
Come le binutils, anche il gcc crea dei file che non ci interessano.
Codice 3.11: ripuliamo il gcc stage 1 |
$ rm -rf install-root/usr/{info,include,lib/libiberty.a,man,share}
|
Installare poi quanto rimasto (tutto dovrebbe finire nelle directory del
CTARGET specificato, senza sovrascrivere alcun file del sistema in uso):
Codice 3.12: installazione del gcc stage 1 |
# cp -a install-root/* /
|
Libc di Sistema
Eliminare la vecchia cartella di compilazione del gcc e ricrearla.
Codice 3.13: compilazione/installazione delle glibc |
$ rm -rf build
$ mkdir build
$ cd build
$ ../configure \
--host=$CTARGET \
--prefix=/usr \
--without-cvs
$ make
# make install install_root=/usr/$CTARGET
|
GCC Stage 2 (Tutti i frontend)
È giunta l'ora di compilare un GCC completo. Scegliere i frontend al
compilatore d'interesse; per semplicità si selezioneranno solo C e C++.
Codice 3.14: compilare/installare il gcc stage 2 |
$ ./configure \
--target=$CTARGET \
--prefix=/usr \
--with-sysroot=/usr/$CTARGET \
--enable-languages=c,c++ \
--enable-shared \
--disable-checking \
--disable-werror
$ make
# make install
|
File Core Runtime
Ci sono diversi file core runtime casuali di cui si vorrebbe conoscerne la
funzione. Ecco una breve spiegazione.
| File forniti dalle glibc |
| File | Funzione |
| crt0.o |
Vecchio stile del runtime code iniziale ? Nessuno lo genera più.
|
| crt1.o |
Nuovo stile del runtime code iniziale. Contiene il simbolo _start che
configura l'ambiente con argc/argv/libc_init/libc_fini prima di passare al
main della libc. Le glibc chiamano questo file 'start.S'.
|
| crti.o |
Definisce la funzione prolog; _init nella sezione .init e _fini nella
sezione .fini. Le glibc chiamano questo file 'initfini.c'.
|
| crtn.o |
Definisce la funzione epilog. Le glibc chiamano questo file 'initfini.c'.
|
| Scrt1.o |
Usato al posto di crt1.o quando si creano eseguibili PIE. |
| gcrt1.o |
Usato al posto di crt1.o quando si crea codice con informazioni per il
profiling. Compila con -pg. Produce in output dei file adatti al
programma gprof.
|
| Mcrt1.o |
Come gcrt1.o, ma è usato con il programma prof. Dal momento che è inutile
sui sistemi linux, le glibc ne installano una versione fittizia.
|
| File forniti dal GCC |
| File |
Funzione |
| crtbegin.o |
Usato dal GCC per trovare l'inizio dei costruttori. |
| crtbeginS.o |
Usato al posto di crtbegin.o quando si creano shared objects o eseguibili
PIE.
|
| crtbeginT.o |
Usato al posto di crtbegin.o quando si creano eseguibili statici.
|
| crtend.o |
Usato dal GCC per trovare l'inizio dei distruttori.
|
| crtendS.o |
Usato al posto di crtend.o quando si creano shared objects o eseguibili PIE.
|
L'ordine generale in fase di linking:
Codice 3.15: ordine generale in fase di linking |
... crt1.o crti.o crtbegin.o [-L paths] [user objects] [gcc libs] [C libs] [gcc libs] crtend.o crtn.o
|
[ << ]
[ < ]
[ Home ]
[ > ]
[ >> ]
I contenuti di questo documento sono rilasciati sotto la licenza Creative
Commons - Attribution / Share Alike.
|