Notes

Programmes Projet Speedtouch Projet Snoopy Projet eciadsl Le site de Sabine La recette du pain Source Mage BeOS LinAC Mon CV Notes On nous prend pour des cons! Don
Programmes
Projet Speedtouch
Projet Snoopy
Projet eciadsl
Le site de Sabine
La recette du pain
Source Mage
BeOS
LinAC
Mon CV
Notes
On nous prend pour des cons!
Don
en fr

Construction d'un cross compilateur GNU

Benoît PAPILLAULT, 08/02/2005

Introduction

Un cross compilateur est comme un compilateur normal. Il prend en entrée un code source et produit en sortie un binaire exécutable. La seule différence est que le binaire résultant ne peut pas être exécuté sur la même machine. Par exemple, sur une machine x86, vous pouvez cross compiler des exécutables pour un processeur PowerPC®.

Ce document n'est pas un n-iéme document sur comment construire un cross compilateur. Il y a déjà des documents sur ce sujet, allez voir la section Références. Son but est d'expliquer quelles sont les étapes requises and comment cela doit fonctionner dans un monde idéal. Nous ne parlerons pas de patchs ici (ou juste pour référence). Bien sûr, LES INTRUCTIONS FOURNIES ICI NE FONCTIONNENT PAS.

Versions utilisées

  1. linux-libc-headers-2.6.8.1
  2. binutils-2.15
  3. glibc-2.3.4
  4. glibc-linuxthreads-2.3.4
  5. gcc-core-3.4.3
  6. gcc-g++-3.4.3
  7. tar-1.15.1

Etapes de construction

Dans ces explications, nous allons essayer de construire un cross compilateur PowerPC® (powerpc-unknown-linux-gnu) sur une machine x86 (i686-pc-linux-gnu). Nous allons essayer de construire un chroot PowerPC® dans un répertoire nommé $SYSROOT (/opt/powerpc-unknown-linux-gnu-root ici) et un cross compilateur PowerPC® dans un autre répertoire nommé $PREFIX (/opt/powerpc-unknown-linux-gnu-gcc ici).

  • $BUILD sera le système de compilation, i.e. le système sur lequel nous allons compilé, ici i686-pc-linux-gnu
  • $HOST sera le système hôte, i.e. le système sur lequel nous allons exécuter les exécutables produits, ici powerpc-unknown-linux-gnu
  1. Installation des en-têtes du noyau Linux®

    Les en-têtes du noyau Linux® sont nécessaires pour compiler la glibc. Cependant, nous avons besoin des mêmes en-têtes que celles qui seraient sur le système hôte. Par exemple, le lien symbolique asm doit pointer vers le répertoire approprié. Une autre façon de régler cette situation et qui est nécessaire sur un système multi-arch est d'avoir des en-têtes du noyau Linux® multi-arch.

    Comme nous utilisons déjà des en-têtes du noyau Linux® multi-arch, cette étape est une simple copie de répertoire.

    mkdir -p $SYSROOT/usr/include &&
    cp -a /usr/include/asm* /usr/include/linux $SYSROOT/usr/include
    
  2. Installation de binutils

    binutils fournis deux outils importants : l'assembleur GNU et l'éditeur de liens GNU qui sont tout les deux utilisés comme backend du compilateur C GNU. Nous avons ici besoin de cross binutils, i.e. un assembleur GNU et un éditeur de liens GNU qui seront exécutés sur le système de compilation et qui produiront des binaires corrects pour le système hôte.

    L'option --with-sysroot est assez importante. Elle sera codée en dur dans l'exécutable résultant, i.e. $HOST-ld. Cette option est utilisée au moment de l'exécution pour localiser les bibliothéques lorsque le chemin de recherche des bibliothéques inclus un chemin commençant par le signe =. C'est le cas pour les chemins de recherche des bibliothéques par défaut, qui est : =/usr/local/lib:=/lib:=/usr/lib. Ceci peut sembler assez complexe de prime abord, mais cela permet aux bibliothéques d'être trouvées par l'éditeur de liens comme si nous compilions sur le système hôte lui-même.

    tar jxf binutils-2.15.tar.bz2 &&
    mkdir binutils-build &&
    cd binutils-build &&
    ../binutils-2.15/configure --prefix=$PREFIX \
      --target=$HOST \
      --with-sysroot=$SYSROOT &&
    make all &&
    make install
    
  3. Installation des en-têtes glibc

    Nous avons besoin des en-têtes glibc pour construire gcc. Nous avons utilisé l'add-on linuxthreads au lieu de nptl car ce dernier ne fonctionnait pas dans cette étape. Nous spécifions à la fois le système de compilation et le système hôte sur la ligne de commande configure pour forcer la cross compilation. La valeur de BUILD peut-être déterminé en exécutant le script config.guess dans les sources de binutils.

    tar jxf glibc-2.3.4.tar.bz2 &&
    (cd glibc-2.3.4 &&
      tar jxf glibc-linuxthreads-2.3.4.tar.bz2) &&
    mkdir glibc-build &&
    cd glibc-build &&
    ../glibc-2.3.4/configure --prefix=/usr \
      --build=$BUILD --host=$HOST \
      --with-headers=$SYSROOT/usr/include \
      --without-cvs --disable-profile --disable-debug --without-gd \
      --enable-add-ons=linuxthreads --with-tls --without-__thread \
      --enable-kernel=2.4 &&
    make install-headers install_root=$SYSROOT
    
  4. Installation d'un premier gcc

    Dans cet étape, nous pouvons compiler un premier cross compilateur. Il ne sera pas capable de produire des bibliothéques dynamiques car les bibliothéques dynamiques ont besoin des bibliothéques dynamiques de glibc.

    Comme pour binutils, l'option --with-sysroot est assez importante aussi. Cette option sera utilisé au moment de l'exécution pour gérer le chemin par défaut de recherche des en-têtes comme si nous compilions sur le système hôte. Le chemin par défaut de recherche des en-têtes est : /usr/local/include:/usr/include. Quelques répertoires internes à gcc peuvent également s'y ajouter ($PREFIX/lib/gcc/$HOST/3.4.3/include ici).

    tar jxf gcc-core-3.4.3.tar.bz2 &&
    mkdir gcc-build &&
    cd gcc-build &&
    ../gcc-3.4.3/configure --prefix=$PREFIX \
      --target=$HOST \
      --with-sysroot=$SYSROOT --with-headers=$SYSROOT/usr/include \
      --disable-threads --disable-shared --enable-language=c &&
    make &&
    make install
    
  5. Installation de glibc

    Nous avons maintenant un premier cross compilateur/assembleur/éditeur de liens. Nous allons l'utiliser pour construire une glibc hôte. Nous avons besoin d'ajouter le répertoire correct à PATH afin que le script configure trouve notre cross compilateur.

    export PATH=$PREFIX/bin:$PATH &&
    tar jxf glibc-2.3.4.tar.bz2 &&
    (cd glibc-2.3.4 &&
      tar jxf glibc-linuxthreads-2.3.4.tar.bz2) &&
    ../glibc-2.3.4/configure \
      --prefix=/usr \
      --build=$BUILD --host=$HOST \
      --with-headers=$SYSROOT/usr/include \
      --without-cvs --disable-profile --disable-debug --without-gd \
      --enable-add-ons=linuxthreads --with-tls --without-__thread \
      --enable-kernel=2.4 &&
    make &&
    make install install_root=$SYSROOT &&
    
  6. Installation de gcc

    Maintenant que nous avons une glibc hôte, nous pouvons reconstruire notre cross compilateur pour inclure le support du C++ (ceci requiert la construction d'une bibliothéque dynamique et ne pouvait pas être fait à une étape précédente).

    tar jxf gcc-core-3.4.3.tar.bz2 &&
    tar jxf gcc-g++-3.4.3.tar.bz2 &&
    mkdir gcc-build &&
    cd gcc-build &&
    ../gcc-3.4.3/configure --prefix=$PREFIX \
      --target=$HOST \
      --with-sysroot=$SYSROOT --with-headers=$SYSROOT/usr/include \
      --enable-threads=posix --enable-languages=c,c++ &&
    make &&
    make install
    

Tests

  1. Un exemple simple: compilons Hello World!

    Nous allons utilisé le programme C suivant pour tester si notre cross compilateur fonctionne. C'est un programme trés simple.

    int main()
    { printf("Hello World!\n"); return 0; }
    

    Nous le compilons par:

    $HOST-gcc -o main main.c
    
    Nous pouvons maintenant le fichier main sur le système hôte et l'exécuter!
  2. Un exemple plus complexe: compilons tar

    Nous allons maintenant utiliser la syntaxe correcte de configure pour activer la cross compilation. DESTDIR est l'argument correct à utiliser pour make install avec tout les logiciels utilisant automake, ce qui est le cas de tar.

    tar zxvf tar-1.15.1.tar.gz &&
    cd tar-1.15.1 &&
    ./configure --prefix=/usr --host=$HOST &&
    make &&
    make install DESTDIR=$SYSROOT
    

    D'autres logiciels peuvent utiliser la même convention, même s'ils n'utilisent pas automake. Si aucune convention n'a été utilisé, nous pouvons utiliser make install prefix=$SYSROOT/usr à la place, mais ceci ne fonctionnera pas pour les chemins qui ont été passés sur la ligne de commande de configure. Voici un exemple plus complexe que nous utiliserons dans ce cas:

    ./configure --prefix=/usr \
    			--sysconfdir=/etc \
    			--localstatedir=/var \
    			--mandir="\${prefix}/share/man" \
    			--infodir="\${prefix}/share/info" &&
    make &&
    make install prefix="${SYSROOT}/usr" \
                 sysconfdir="${SYSROOT}/etc" \
                 localstatedir="${SYSROOT}/var"
    

Références

  1. Le site principal pour construire un cross compilateur GNU est http://kegel.com/crosstool/. Ce site fournit un script sympa qui peut être utilisé pour produire un cross compilateur qui marche. Ce script inclus aussi divers patchs qui ont été collectés et qui s'appliquent automatiquement
  2. Le manuel Autoconf 2.57 explique comme utiliser les options de e./configure pour activer correctement la cross compilation. Les détails sont dans la section 15.6.3.
  3. Le manuel Autobook explique comment le cadre fournit par autoconf/automake peut être utilisé pour simplifier la cross compilation, surtout lorsque le logiciel a besoin de compiler des outils qui s'exécuteront sur la machine de compilation. Les détails sont dans la section 26.4.6.2.
  4. Un script qui marche et qui implémente ce qui a été dit ici: mk-cross-gcc. It can also be used to build an x86_64 bi-arch cross compiler (not described here).
  5. Un patch pour glibc-2.3.4 patch nécessaire au script précédent: glibc-2.3.4-libeh-kludge.patch

Mentions légales

  • Linux® est une marque déposée de Linus Torvalds.
  • PowerPC® est une marque déposée d'International Business Machines Corporation
Valid HTML 4.01! Valid CSS!
Benoit PAPILLAULT