Gentoo Logo

1.  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.)

1.  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 1.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 1.1: Opzioni di crossdev utili

(Usare delle versioni specifiche dei pacchetti)
# crossdev --g [gcc version] --l [(g)libc version] --b [binutils version] --k
[kernel headers version] -P -v -t [tuple]
(Usare solamente la versione stabile)
# 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 1.1: 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 1.1: 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 1.1: 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.

1.  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" è:

  1. binutils
  2. header del kernel
  3. header delle libc
  4. gcc stage1 (solo c)
  5. libc
  6. gcc stage2 (c/c++/etc...)

L'oscura scorciatoia invece è:

  1. binutils
  2. header del kernel
  3. gcc stage1 (solo c)
  4. libc
  5. 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 1.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 1.1: 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 1.1: ripuliamo le binutils

$ rm -rf install-root/usr/{info,lib,man,share}

Installare quindi quanto rimasto :

Codice 1.1: 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 1.1: 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 1.1: 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 1.1: 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 1.1: 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 1.1: diamo una mano al gcc

# ln -s usr/include /usr/$CTARGET/sys-include

Quindi prelevare l'ultima versione del pacchetto gcc e scompattarlo.

Codice 1.1: 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 1.1: 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 1.1: installazione del gcc stage 1

# cp -a install-root/* /

Libc di Sistema

Eliminare la vecchia cartella di compilazione del gcc e ricrearla.

Codice 1.1: 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 1.1: 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 1.1: 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

Aggiornato il 13 aprile 2010

Oggetto: Creare un cross-compilatore sulla propria macchina!

Donate to support our development efforts.

Copyright 2001-2014 Gentoo Foundation, Inc. Questions, Comments? Contact us.