Julien De Bona
Free Software, Cooking, and Everything


Création d'une toolchain pour la cross-compilation d'un système uClibc

Publié le 2006-10-14.

La Soekris utilise un processeur compatible x86 (et même Pentium), or ma seule machine un peu puissante est mon iBook (PowerPC G4). Si je veux préparer un système personnalisé, je vais donc devoir le cross-compiler, d'où cette page. Il existe certes des outils capables de faciliter cette tâche, comme buildroot ou scratchbox, mais aucun ne fonctionne sur PPC. Et puis, tout faire soi-même, c'est plus instructif. La création d'une toolchain de cross-compilation est une tâche délicate et complexe, et ce document pourra faire gagner un temps non négligeable. La procédure en bref

  • Décompresser et configurer un kernel Linux
  • Configurer uClibc en fonction de ce kernel et en installer les headers
  • Compiler les binutils
  • Compiler GCC
  • Compiler uClibc

Procédure détaillée

Pour généraliser un peu le code, je règle les variables suivantes. Il ne faut pas les mettre dans l'environnement car elles seraient passées implicitement aux makefiles, et dans un but didactique, je préfère le faire explicitement.

PREFIX=/home/julien/cross
BUILDDIR=/home/julien/build
ARCHIVEDIR=/home/julien/archives
ARCH=i386
TARGET=i386-linux-uclibc

Ainsi, j'installerai le cross-compilateur dans $PREFIX, téléchargerai le code source de la toolchain dans $ARCHIVEDIR et le compilerai dans $BUILDDIR. Configuration du kernel

Télécharger le source d'un kernel sur http://kernel.org (j'ai pris le dernier en date: le 2.6.17.11) et le placer dans $ARCHIVEDIR. Ensuite, le décompresser et le configurer en spécifiant l'architecture cible lors de la configuration:

cd $BUILDDIR
tar -xvjf $ARCHIVEDIR/linux-2.6.17.11.tar.bz2
cd linux-2.6.17.11
make ARCH=$ARCH menuconfig

Petit truc: à la place de menuconfig, on peut utiliser defconfig, qui va configurer le kernel avec les paramètres par défaut, ou copier le fichier .config d'une autre configuration et utiliser la cible oldconfig.

Installation des headers d'uClibc

Récupérer la dernière version d'uClibc depuis http://uclibc.org, l'extraire, la configurer et installer les headers:

cd $BUILDDIR
tar -xvjf $ARCHIVEDIR/uClibc-0.9.28.tar.bz2
cd uClibc-0.9.28
make menuconfig && make headers && make PREFIX=$PREFIX/ install_dev

Quelques options sont importantes lors du make menuconfig:

  • RUNTIME_PREFIX=/
  • DEVEL_PREFIX=/
  • KERNEL_SOURCE=$BUILDDIR/linux-2.6.17.11 (à taper en toutes lettres, sans passer par la variable $BUILDDIR)
  • DOPIC=y et ENABLE_SHARED=y (ces options se trouvent dans "General Library Settings" et permettent de créer des exécutables liés dynamiquement
  • CROSS_COMPILER_PREFIX=$PREFIX/bin/$TARGET-: le préfixe du cross-compilateur pour compiler uClibc (à taper en toutes lettres, et ne pas oublier le tiret à la fin.

Comme pour le kernel, on peut récupérer le fichier .config d'une précédente configuration et utiliser la cible oldconfig

Installation des binutils et de gcc

Aller sur http://ftp.gnu.org/gnu, télécharger les paquets gcc-core-4.1.0.tar.bz2 et binutils-2.16.1.tar.bz2, et les décompresser.

cd $BUILDDIR
tar -xvzf ../archives/binutils-2.17.tar.gz
tar -xvjf ../archives/gcc-core-4.1.1.tar.bz2

La procédure d'installation des binutils est documentée dans binutils/README une fois l'archive extraite. Une fois dans build-binutils, compiler et installer les binutils par:

cd $BUILDDIR
mkdir build-binutils
cd build-binutils
../binutils-2.17/configure --target=$TARGET --prefix=$PREFIX --disable-nls && make && make install

Ensuite, compiler GCC. L'option --enable-languages=c ne va compiler que le compilateur C et --with-headers va lui faire prendre en compte uClibc. Quant à libssp, il s'agit d'une fonctionnalité de protection contre certaines attaques, mais sa cross-compilation semble problématique. --enable-shared requiert un fichier crti.o qui sera créé par uClibc, et donc on utilise plutôt --disable-shared. Cela ne désactive pas la production de binaires liés dynamiquement, mais ne compile pas certaines bibliothèques de GCC en dynamique. Cette étape demande beaucoup de mémoire disponible. 512 ou 768 MB de RAM ne sont probablement pas de trop pour ne pas avoir de swap excessif. Ce qui est sûr, c'est que 256 MB sont vraiment trop étroits et provoquent énormément de swap, et que 768 MB sont suffisants et rendent compilation beaucoup plus courte.

cd $BUILDDIR
mkdir build-gcc
cd build-gcc
../gcc-4.1.1/configure --target=$TARGET --prefix=$PREFIX --disable-nls --enable-languages=c --with-headers=$PREFIX/include --disable-libssp --disable-shared
make PATH=$PREFIX/bin:$PATH all-gcc && make install

Compilation d'uClibc

uClibc a déjà été configuré, et maintenant qu'on a un compilateur, on peut le compiler:

cd $BUILDDIR/uClibc-0.9.28
make && make PREFIX=$PREFIX/$TARGET install

Le PREFIX lors de l'installation va placer les fichiers dans le répertoire où le compilateur attend ses bibliothèques.

Ca y est, la toolchain est prête à être utilisée; il suffit d'ajouter $PREFIX/bin dans le $PATH et de préfixer et d'utiliser $TARGET-gcc au lieu de gcc, $TARGET-strip au lieu de strip ...

Il est possible que la recompilation de gcc avec l'option --enable-shared permette de gagner un peu de place dans le système final, mais la situation actuelle me semble déjà satisfaisante.

Cross-compilation d'un kernel

La cross-compilation d'un kernel est un peu particulière, mais pas compliquée; il a déjà été configuré, il ne reste plus qu'à le compiler:

cd $BUILDDIR/linux-2.6.17.11
make ARCH=$ARCH CROSS_COMPILE=$PREFIX/bin/$TARGET-
make modules_install INSTALL_MOD_PATH=/chemin/vers/repertoire/vide

Etape suivante: compiler le reste du système ...


tags: linux, embarque, soekris

Quelques tags ...