Accueil

 

Petit mémento à l'usage des Linuxiens férus d'embarqué :

 

Nous allons détailler la conception d'une chaine de compilation croisée "From Scratch".

Le but de cette page web est de comprendre la méthode de conception d'une chaine d'un point de vue pédagogique.

Il existe des moyens beaucoup plus simples pour obtenir une chaines de compilation croisée avec notament les projets:

Crosstool-ng, Buildroot, Openembedded et j'en passe...

1.1  Génération d'une chaîne de compilation croisée

Le noyau Linux est multi-plateforme. Il convient donc de l'adapter en fonction de l'architecture dans laquelle il sera exécuté. En effet, un microprocesseur d'architecture x86 est conçu différemment d'un microprocesseur ARM. Ainsi, le jeu d'instructions (ensemble d'opérations élémentaires qu'un microprocesseur est capable de réaliser) est différent. La construction d'un système embarqué commence par la conception du noyau (et de ses modules si besoin) pour l'architecture cible. Puis vient la conception du système de fichiers et le développement des programmes prévus pour la carte électronique. Il faut donc adapter tous ces derniers pour l'architecture cible. Nous allons approfondir le concept de chaîne de compilation croisée. Nous présenterons également les différentes étapes de la compilation d'un programme. Nous exposerons ensuite les différentes façons d'obtenir une chaîne de compilation croisée depuis les sources jusqu'aux différents programmes la générant automatiquement.

1.2  Les différentes étapes de la vie d'un programme

La compilation d'un programme passe par différentes étapes successives avant d'aboutir à un exécutable (binaire). GCC de GNU/Linux n'est rien d'autre qu'un compilateur capable de traduire un programme écrit dans un langage de haut niveau (langage C) vers le langage machine (binaire) en respectant la sémantique propre à l'architecture de la machine dans laquelle il doit s'exécuter. Le compilateur GCC est pourvu de trois sous-programmes qui sont
Le rôle de cc1 est de produire un fichier assembleur d'extension ".s" et d'effectuer un premier travail de "preprocessing" consistant à remplacer les différentes lignes de directive (les lignes commençant par "#include" en début de code d'un programme C).
L'assembleur, as, a pour rôle de transformer le fichier texte assembleur en son équivalent binaire. Le fichier obtenu est un fichier objet au format ELF portant l'extension ".o". Le format ELF (Executable and Linkable Format) est une norme du format binaire exécutable adopté par tous les systèmes d'exploitation actuels sauf par celui de Microsoft. Le système d'exploitation GNU/Linux l'utilise de manière exclusive. Les fichiers objets contiennent des informations codées en binaires. Les principales choses qui leur manquent sont l'adressage mémoire des fonctions utilisées et la fonction main.
L'éditeur de lien, ld, a un rôle de finalité. Il assemble tous les fichiers objets entre eux et les réorganise en un même type. L'éditeur de liens organise également l'adressage mémoire des fonctions utilisées (définies dans les bibliothèques) ou appelées en dehors du programme (voir plus loin la section bibliothèques statiques/dynamiques). Il adresse la fonction principale main pour transformer les fichiers objets finaux en un unique exécutable.
GCC va donc fournir à ces différents sous-programmes différents fichiers lors des différentes étapes de la compilation d'un programme. Détaillons les différentes étapes de la compilation à travers un exemple. Soit le programme C nommé helloworld.c qui affiche dans le terminal "Hello World!". Son code est :
#include <stdio.h>
{
int main(void)
printf("Hello world!n");
return 0;
}
Pour lancer la compilation, il suffit de taper dans le terminal :
gcc helloworld.c -o helloworld
Nous obtenons l'exécutable helloworld pour notre machine x86.
Cette commande est équivalente à ces deux commandes successives:
Nous lançons la compilation du fichier helloworld.c, cela génère le fichier objet helloworld.o :
gcc -c helloworld.c -o helloworld.o
Puis le compilateur lie le fichier objet helloworld.o avec les bibliothèques du système pour finalement produire l'exécutable helloworld :
gcc helloworld.o -o helloworld
Nous avons vu que le compilateur GCC est comme un "manageur" pour ces trois tâches présentées.
Nous avons vu à travers cet exemple qu'un exécutable compilé depuis une machine de type x86 ne pourra pas s'exécuter sur une carte pourvue d'un c?ur ARM. Les jeux d'instructions n'étant pas les mêmes, il convient de compiler le programme source pour l'architecture cible.
La carte électronique utilisée est d'architecture ARM. Elle n'est pas faite pour compiler du code pour son architecture car le compilateur, le "linkeur" et l'assembleur prendraient une place mémoire bien trop importante sur la carte. De plus le temps nécessaire à la compilation serait bien plus important sur une carte non dédiée que sur un PC hôte bien plus puissant.
Il nous faut donc un programme capable de générer du code pour une architecture ARM depuis un PC hôte sur une architecture x86. Le programme servant de traducteur entre les deux architectures s'appelle : la chaîne de compilation croisée.

1.3  Bibliothèques statiques/dynamiques

Pour pouvoir compiler, un programme a besoin de bibliothèques qui contiennent la définition des fonctions utilisées. Il existe deux types de bibliothèques : les bibliothèques statiques et les bibliothèques dynamiques. Typiquement les bibliothèques dynamiques sont de la forme lib***.so et les bibliothèques statiques lib***.a.
La différence majeure entre ces deux types de bibliothèque est l'inclusion (bibliothèques statiques) ou non (bibliothèques dynamiques) des définitions des fonctions utilisées dans l'exécutable. Ces deux types de bibliothèques ont chacun leurs inconvénients et leurs avantages. Pour une bibliothèque dynamique:
Pour une bibliothèque statique:
Il convient de bien prendre en compte le fait que l'utilisation d'une bibliothèque dynamique offre l'avantage d'être utilisée par d'autres exécutables en même temps ou non. En revanche, si cette bibliothèque est exclusivement utilisée par un seul programme, il faut songer à l'utiliser de manière statique. Dans le monde de l'embarqué, les bibliothèques système sont en général dynamiques alors que celles des applications développées sont souvent statiques car souvent développées de manière exclusive.

1.4  L'obtention d'une chaîne

Il existe plusieurs méthodes pour obtenir une chaîne de compilation croisée. Nous présenterons d'abord la méthode la plus fastidieuse qui nécessite de compiler une à une les sources. Cette méthode est couramment appelée "From Scratch". Puis nous obtiendrons une nouvelle chaîne de compilation avec un outil nommé Crosstool. Il existe une nouvelle génération de cet outil appelé Crosstool-ng. Il est maintenu et géré par un Français. Il existe des chaînes de compilation croisée toutes faites et téléchargeables sur le site Internet de l'entreprise Allemande DENX Software Engineering 1. Enfin, il existe également des outils de création de distribution Linux complète (noyau + système de fichiers) tels que Buildroot, OpenEmbedded, PTXdist... qui sont capables de compiler et d'installer une chaîne de compilation croisée automatiquement. Bien souvent, ces chaînes de compilation croisée sont propres à l'outil de création de la distribution. Une chaîne de compilation croisée se compose de différents éléments comme suit: Tous ces éléments sont indispensables pour générer une chaîne de compilation. Leurs différentes combinaisons peuvent générer une chaîne de compilation croisée avec l'aide de quelques patchs ou bien ne pas être du tout compatible entre eux. Il convient de faire plusieurs essais avec des versions différentes de chacun des éléments avant d'aboutir à une chaîne sans trop de difficulté. La bibliothèque utilisée dans les exemples suivants est la glibc. Elle est principalement utilisée dans le monde Linux. Cette bibliothèque contient la bibliothèque C principale du système. Glibc fournit un ensemble de routines (ouverture/fermeture de fichiers; allocation de mémoire etc...) indispensables au bon fonctionnement du système GNU reposant sur un noyau Linux. Elle joue le rôle d'interface entre le noyau et le système d'exploitation grâce à ces appels système qu'elle fournit. Cependant, il existe d'autres bibliothèque C qui sont bien plus légères et plus adaptées pour les systèmes embarqués comme, par exemple, la bibliothèque uClibc, la bibliothèque dietlibc ou la bibliothèque newlib.

1.5  Éléments indispensables à savoir ou à posséder

Pour obtenir une chaîne de compilation croisée pleinement fonctionnelle, il convient, bien évidemment, d'avoir: Quelle que soit la méthode de conception de la chaîne de compilation croisée, il convient aussi d'avoir au préalable le programme Autoconf installé dans sa machine hôte. Ce programme est chargé de produire un fichier (nommé make) capable d'automatiser la compilation de l'ensemble des sources d'un paquet. Pour générer un tel fichier, le script configure a pour mission d'inspecter le système afin de vérifier que les sources pourront trouver toutes les dépendances prévues sur le système afin de permettre de compiler correctement les sources. Il convient également d'éclaircir quelques termes passés en paramètre au script configure: Dans tous les cas de figure d'obtention d'une chaîne de compilation croisée, la dénomination de la chaîne finale sera du type arm-none-linux-gnueabi). Les quatre valeurs désignent:

1.6  Les différentes étapes communes de la création d'une chaîne

  1. Bien évidemment l'obtention des sources est indispensable. Le téléchargement de celles-ci depuis un site officiel peut se faire soit à la main (utilisation systématique de la commande wget pour chaque paquet), soit automatiquement par script (c'est le cas de Crosstool et Crosstool-ng). Il est possible de télécharger les sources par CVS (Concurrent Versions System). Ce dernier est un système de contrôle de versions client-serveur permettant à plusieurs personnes de travailler simultanément sur un même ensemble de fichiers. Cette méthode permet d'avoir la dernière version à jour des sources. Dans notre cas, vu que l'on va travailler avec des paquets un peu anciens et dont les changements sont inclus dans les versions postérieures, le CVS ne sera pas utilisé ici.
  2. Le premier paquet à être compilé est binutils car le compilateur GCC dépend des outils de celui-ci pour créer des exécutables. En effet, c'est binutils qui assemble les fichiers objets générés par GCC en une image exécutable,
  3. Nous avons besoin des fonctions d'en-tête du noyau Linux spécifique pour l'architecture ARM. Elles contiennent des fonctions indispensables telles les appels système pour interagir avec le noyau. Ces en-têtes sont utilisées pour produire la bibliothèque C (glibc) pour ARM,
  4. Nous allons générer un compilateur GCC appauvri en fonctions basiques. Souvent appelé "bootstrap GCC", ce compilateur est néanmoins capable de produire une bibliothèque Glibc pour ARM grâce aux fonctions d'en-tête du noyau de l'étape précédente,
  5. Nous utilisons notre "bootstrap GCC" pour produire les fichiers d'en-tête de la bibliothèque Glibc,
  6. Nous obtiendrons une bibliothèque C fonctionnelle pour ARM.
  7. Nous avons tous les outils pour commencer la conception de notre prochain GCC pour ARM.
  8. Nous compilons les bibliothèques mathématiques GMP et MPFR pour ARM.
  9. Finalement, nous compilons le GCC final avec les bibliothèques précédentes.

1.7  A partir des sources

Voici sans doute la manière la plus délicate pour obtenir une chaîne de compilation croisée. Nous allons d'abord télécharger toutes les sources indispensables pour mettre au point notre chaîne. Les différentes modifications dans le code de chacun des composants sera précisé tout le long du processus de création de la chaîne. Cette procédure est inspirée de l'ouvrage "Pro Linux Embedded Systems" de Gene Sally aux éditions Apress. Les paquets indispensables pour obtenir une compilation sans erreur seront précisés au fur et à mesure du déroulement du processus de la création de la chaîne.
Tout au long du processus de création de la chaîne, nous allons créer un répertoire spécifique à chaque paquet dans lequel l'appel du script configure mettra tous les paramètres indispensables à la compilation. Nous pouvons nous interroger sur la nécessité d'un tel procédé. En fait, à chaque appel du script configure les variables ou les paramètres passés sont souvent différents pour un même paquet. Le fichier généré make est également différent. Pour éviter des "traces" dues à l'ancienne compilation et leurs effets néfastes sur la nouvelle compilation, nous supprimerons à chaque fois le répertoire créer précédemment pour en créé un nouveau.

1.7.1  Téléchargement des sources

Les différents composants sont téléchargeables aux adresses suivantes: Toutes les sources sont dans le répertoire /root/chaîne/sources. La décompression et le dépaquetage des sources se fait avec la commande tar xjvf le_nom_du_paquet.tar.bz2
Chaque paquet contenant les sources est décompressé dans son répertoire respectif, exception faite pour le paquet glibc-ports-2.9.tar.bz2 qui est décompressé et dépaqueté dans le répertoire glibc-2.9:
cd glibc-2.9
tar xjvf ../glibc-ports-2.9.tar.bz2
Le répertoire /opt/arm accueille la chaîne de compilation croisée. Nous y créons également le répertoire /sysroot et le sous-répertoire /usr que nous utiliserons pendant la création de la chaîne de compilation:
mkdir -p /opt/arm/sysroot/usr

1.7.2  Les variables d'environnement

Pour des raisons de commodité, nous allons utiliser deux terminaux pour générer notre chaîne de compilation croisée. Ces terminaux sont nommés respectivement T1 (pour terminal 1) et T2 (pour terminal 2). Ces deux terminaux ont des variables d'environnement semblables. Cependant, le terminal T2 a davantage de variables d'environnement pour faciliter la compilation. Dans chacun des terminaux, entrons les variables d'environnements communes suivantes:
export SRCDIR=/root/chaine/sources
Ce répertoire accueille toutes les sources téléchargées.
export BUILDDIR=/root/chaine/build
C'est dans ce répertoire que seront compilés tous les paquets sources.
export TARGETMACH=arm-none-linux-gnueabi
Cette variable spécifie le type d'architecture cible.
export BUILDMACH=x86_64-pc-linux-gnu
Cette variable spécifie le type d'architecture dans lequel le paquet est compilé.
export INSTALLDIR=/opt/arm
Cette variable renseigne sur le répertoire accueillant la chaîne de compilation croisée.
export SYSROOTDIR=/opt/arm/sysroot
Cette variable renseigne sur le répertoire accueillant les bibliothèques et les fichiers d'en-tête du noyau du système cible.
Pour T2 ajoutons en plus les variables d'environnement suivantes :
export CROSS=arm-none-linux-gnueabi
Indique que nous utilisons la variable CROSS comportant les champs arm-none-linux-gnueabi expliqués plus haut.
export CC=${CROSS}-gcc
Indique que nous utilisons le compilateur GCC pour l'architecture ARM.
export LD=${CROSS}-ld
Indique que nous utilisons la bibliothèque dynamique de l'architecture ARM.
export AS=${CROSS}-as
Indique que nous utilisons l'assembleur de l'architecture ARM.

1.7.3  Binutils

Le premier paquet a être compilé est Binutils. Sa compilation ne pose aucun problème et est rapide. Depuis le terminal T1, tapons les lignes suivantes:
mkdir $BUILDDIR/binutils
cd $BUILDDIR/binutils
../../sources/binutils-2.20/configure
--disable-werror
--build=$BUILDMACH
--prefix=$INSTALLDIR
--with-sysroot=$SYSROOTDIR
--target=$TARGETMACH
make
make install
Le tableau suivant expose les options passées en paramètres et leur significations:
Paramètres Fonction
--disable-werror Désactivation des "warning" : évite de bloquer la compilation.
--build=$BUILDMACH Architecture du PC hôte qui fait la compilation.
--prefix=$INSTALLDIR Répertoire d'accueil des exécutables.
--with-sysroot=$SYSROOTDIR Répertoire d'accueil des libraires.
--target=$TARGETMACH Architecture cible.
Table 1.1: Les options Binutils

1.7.4  Fichiers d'en-tête du noyau

La compilation des fichiers d'en-tête du noyau génère une erreur due au nom d'une fonction réutilisée lors de la compilation. Ouvrons le fichier linux-2.6.28.3/script/unifdef.c par un éditeur comme vim. Changeons le nom de la fonction en supprimant la lettre ë" du nom de la fonction getline() en getlin(). Il est possible de réaliser l'opération en appliquant directement un patch téléchargeable ICI :
Il suffira de copier ce patch dans le répertoire linux-2.6.28.3/script/ et de l'appliquer en tapant: patch -i unifdef.patch
Désormais, la compilation et l'installation se fait sans embûche.
Depuis le terminal T1, tapons les lignes suivantes:
cd $SRCDIR/linux-2.6.28.3
make mrproper
make ARCH=arm kb9202_defconfig
make ARCH=arm headers_check
make ARCH=arm INSTALL_HDR_PATH=$INSTALLDIR/sysroot/usr headers_install
L'option ARCH=arm précise, bien entendu, le type d'architecture cible. Nous allons utiliser cette chaîne pour la carte (un peu âgée, je le reconnais) KwikByte KB9202C qui n'est, malheureusement, plus en vente sur le site du constructeur http://www.kwikbyte.com
C'est pourquoi nous précisions son utilisation par l'entrée kb9202_defconfig. Ce fichier rassemble toutes les options du noyau Linux pour la carte. Pour une carte de type ARM générique: l'option integrator_defconfig rassemble l'ensemble des options communes du noyau pour toutes les architectures ARM. Dans le répertoire du noyau linux-2.6.28.3/arch/configs/, nous pouvons voir toutes les cartes prises en comptes nativement par le noyau.

1.7.5  Amorce GCC - Bootstrap GCC

Avant de procéder à la compilation et à l'installation de l'amorce GCC (bootstrap GCC), vérifiez que les bibliothèques mathématiques GMP et MPFR sont bien installées dans votre système Linux. La bibliothèque GMP 2 contient des fonctions arithmétiques à multi-précisions. Elle est utilisée principalement en cryptographie et en recherche algébrique. GMP se définit sous une distribution Debian/Ubuntu sous la forme de paquets à télécharger/installer via le gestionnaire de paquets Synaptic. Les paquets sont: La bibliothèque MPFR 3 contient des fonctions mathématiques capables d'effectuer des calculs multi-précision à virgule flottante avec des arrondis précis. Elle est maintenue par Laurent Fousse4, maître de conférences à Grenoble. La bibliothèque est téléchargeable et installable, sous une distribution Debian/Ubuntu, sous la forme de paquets via Synaptic:
Depuis le terminal T1, tapons les lignes suivantes:
mkdir $BUILDDIR/amorce-gcc
cd $BUILDDIR/amorce-gcc
../../sources/gcc-4.3.3/configure
--build=$BUILDMACH
--host=$BUILDMACH
--target=$TARGETMACH
--prefix=$INSTALLDIR
--without-headers
--enable-bootstrap
--enable-languages=c
--disable-threads
--enable-__cxa_atexit
--disable-libmudflap
--with-gnu-ld
--with-gnu-as
--disable-libssp
--disable-libgomp
--disable-nls
--disable-shared
make all-gcc install-gcc
Cette commande précédente crée le compilateur de base et l'installe dans le répertoire renseigné par la variable $INSTALLDIR
Nous lançons à présent la construction d'une bibliothèque de base utilisée par GCC pour produire du code. Cette bibliothèque doit être construite avant la finale car elle dépend entièrement de celle-ci :
make all-target-libgcc install-target-libgcc
Nous forçons la conception de la bibliothèque de la chaîne de compilation en statique par le lien symbolique suivant:
ln -s /opt/arm/lib/gcc/arm-none-linux-gnueabi/4.3.3/libgcc.a
/opt/arm/lib/gcc/arm-none-linux-gnueabi/4.3.3/libgcc_sh.a
Voici les explications des options:
La plupart des paramètres entrés en ligne de commande désactivent un certain nombre d'entre eux non nécessaires à la conception d'une bibliothèque standard.
Paramètres Fonction
--without-headers Compilation sans les en-têtes du noyau compilateur
--enable-bootstrap GCC produit sous forme de "BootStrap"
--enable-languages=c Seul le langage C est nécessaire (le C++ est possible)
--disable-threads Désactivation des fichiers d'inclusion multi-thread
--enable-__cxa_atexit Option décrivant l'implémentation de la fonction atexit()
--disable-libmudflap bibliothèque utilisée pour le débogage
--with-gnu-ld Compilation avec linker natif
--with-gnu-as Compilation avec assembleur natif
--disable-libssp Désactivation de la bibliothèque spécialisée dans le dépassement mémoire
--disable-libgomp Désactivation de l'API OpenMP
--disable-nls Désactivation de tous les langages locauxd sauf l'anglais
--disable-shared Le compilateur ne supportera pas les bibliothèques dynamiques
Table 1.2: Les options d'Amorce GCC

1.7.6  Création des fichiers d'en-tête de la Glibc

Ces fichiers d'en-tête servent de définition des fonctions créées par le compilateur installé sur le système cible (notre fameux Bootstrap GCC). Avant de procéder à la compilation et à l'installation des fichiers d'en-tête de la Glibc, il convient de patcher deux fichiers. Le premier patch change le numéro de version supporté par la Glibc et est configure.patch (à appliquer dans la racine du répertoire glibc-2.9). Le second résout un problème de backslash avec sed et est gen-sorted.awk.patch ( à appliquer dans le répertoire glibc-2.9/scripts/).
Depuis le terminal T2, tapons les lignes suivantes:
mkdir $BUILDDIR/libc-header
cd $BUILDDIR/libc-header
echo "libc_cv_forced_unwind=yes" > config.cache
echo "libc_cv_c_cleanup=yes" >> config.cache
export PATH=$INSTALLDIR/bin:$PATH
../../sources/glibc-2.9/configure
--build=$BUILDMACH
--host=$TARGETMACH
--prefix=$SYSROOTDIR/usr
--with-headers=$SYSROOTDIR/usr/include
--config-cache
--enable-add-ons=glibc-ports-2.9,nptl
--enable-kernel=2.6.0
make -k install-headers cross_compiling=yes install_root=$SYSROOTDIR
ln -s /opt/arm/lib/gcc/arm-none-linux-gnueabi/4.3.3/libgcc.a
/opt/arm/lib/gcc/arm-none-linux-gnueabi/4.3.3/libgcc_eh.a
Les explications aux diverses options et commandes:
Paramètres Fonction
--prefix=$SYSROOTDIR/usrRépertoire d'accueil des exécutables
--with-headers=$SYSROOTDIR/usr/include Utilisation des en-têtes du noyau de l'étape 4.6.4
--config-cache Force l'exécutable configure à lire
les instructions du fichier config.cache
--enable-add-ons=glibc-ports-2.9,nptl Utilisation de la bibliothèque supplémentaire glibc-ports
pour ARM (notre cas). Egalement valable pour MIPS et
PowerPC.
--enable-kernel=2.6.0 Conception de la bibliothèque pour noyau Linux type 2.6.0.
Table 1.3: Les options de la conception des fichiers d'en-tête de la Glibc
Commandes Explications
echo "libc_cv_forced_unwind=yes" > config.cache Le fichier config.cache
echo "libc_cv_c_cleanup=yes" >> config.cache contient ces 2 lignes
qui empêchent l'exécution
du code compilé
pour ARM avec la chaîne de
compilation croisée installée
sur le host (x86)
make -k install-headers cross_compiling=yes Les fichiers d'entêtes sont
install_root=$SYSROOTDIR cross-compilés et
installés dans le répertoire
$SYSROOTDIR
ln -s /opt/arm/lib/gcc/arm-none-linux-gnueabi/4.3.3/libgcc.a Même chose ici: par ce lien
/opt/arm/lib/gcc/arm-none-linux-gnueabi/4.3.3/libgcc_eh.a symbolique, nous forçons
la conception de la
bibliothèque de la
chaîne de compilation
en statique
Table 1.4: Les commandes de la conception des fichiers d'en-tête de la Glibc

1.7.7  Création de la Glibc

Voilà, nous y sommes, nous avons tous les éléments dans le répertoire $INSTALLDIR pour pouvoir concevoir notre Glibc pour ARM. Vous remarquerez que les commandes sont très similaires par rapport à l'étape précédente. Remarque: la compilation prend beaucoup de temps et tous les paramètres ont déjà été expliqués.
Depuis le terminal T2, tapons les lignes suivantes:
Nous pouvons créer le répertoire /glibc depuis $BUILDDIR
mkdir $BUILDDIR/glibc
cd $BUILDDIR/glibc
Très ressemblant avec les commandes précédentes:
echo "libc_cv_forced_unwind=yes" > config.cache
echo "libc_cv_c_cleanup=yes" >> config.cache
../../sources/glibc-2.9/configure
--build=$BUILDMACH
--host=$TARGETMACH
--prefix=/usr
--with-headers=$SYSROOTDIR/usr/include
--config-cache
--enable-add-ons=glibc-ports-2.9,nptl
--enable-kernel=2.6.0
make -k install-headers cross_compiling=yes install_root=$SYSROOTDIR
make
make install_root=$SYSROOTDIR install

1.7.8  Construction du nouveau GCC

Après cette étape, le compilateur GCC généré est capable de compiler du code statique. Vous pouvez vous arrêter après cette étape si vous développez des applications utilisant des bibliothèques statiques.
Depuis le terminal T1, tapons les lignes suivantes:
Nous pouvons créer le répertoire /gcc depuis $BUILDDIR
cd $BUILDDIR/gcc
echo "libc_cv_forced_unwind=yes" > config.cache
echo "libc_cv_c_cleanup=yes" >> config.cache
export CC=gcc
../../sources/gcc-4.3.3/configure
--build=$BUILDMACH
--target=$TARGETMACH
--prefix=$INSTALLDIR
--with-sysroot=$SYSROOTDIR
--enable-languages=c
--with-gnu-as
--with-gnu-ld
--disable-multilib
--with-float=soft
--disable-sjlj-exceptions
--disable-nls
--enable-threads=posix
--enable-long-longx
make all-gcc
make install-gcc
Commandes Explications
export CC=gcc La variable d'environnement oblige la
compilation du GCC pour ARM par le compilateur du host
--disable-multilib Les différentes variantes de bibliothèques
pour architectures différentes ne sont pas conçues
--with-float=soft Support des nombres à virgule flottante
émulé par le soft car les ARM n'ont pas de FPU (Floating Point Unit)
--disable-sjlj-exceptions Exceptions spécifiques au C++, il
convient de les désactiver vu que notre chaîne ne supporte que le C
--enable-threads=posix Les threads sont au format POSIX
--enable-long-longx En C, support des entiers longs
Table 1.5: Les options de la conception du nouveau GCC

1.7.9  Création de la bibliothèque GMP

Installer le paquet m4 qui est un langage de traitement de macros maintenu par Santiago Vila à l'adresse sanvila@debian.org.
Les bibliothèques GMP et MPFR se compilent avec le GCC précédent. Elles s'installeront dans le répertoire /opt/arm/lib
Depuis le terminal T2, tapons les lignes suivantes:
Nous pouvons créer le répertoire /gmp depuis $BUILDDIR
cd $BUILDDIR/gmp
export CFLAGS=-static
../../sources/gmp-4.3.2/configure
--build=$BUILDMACH
--host=$TARGETMACH
--prefix=$INSTALLDIR
--disable-shared
make
make install

1.7.10  Création de la bibliothèque MPFR

Depuis le terminal T2, tapons les lignes suivantes:
Nous pouvons créer le répertoire /mpfr depuis $BUILDDIR
cd $BUILDDIR/mpfr
../../sources/mpfr-3.0.1/configure
--build=$BUILDMACH
--host=$TARGETMACH
--prefix=$INSTALLDIR
--with-gmp=$INSTALLDIR
make
make install

1.7.11  Construction du GCC final

Nous disposons de tous les éléments pour finaliser la conception du compilateur GCC. La chaîne de compilation croisée s'obtient en la compilant avec le compilateur de l'hôte (d'où la ligne export CC=gcc). C'est une opération assez longue. Les arguments passés sont les mêmes qu'au 4.6.8) à quelques exceptions près : prise en charge des bibliothèques précédentes et compilateur final supportant la compilation dynamique.
Depuis le terminal T1, tapons les lignes suivantes:
Nous pouvons créer le répertoire /gcc-final depuis $BUILDDIR
cd $BUILDDIR/gcc-final
echo "libc_cv_forced_unwind=yes" > config.cache
echo "libc_cv_c_cleanup=yes" >> config.cache
../../sources/gcc-4.3.3/configure
--build=$BUILDMACH
--target=$TARGETMACH
--prefix=$INSTALLDIR
--with-sysroot=$SYSROOTDIR
--enable-languages=c
--with-gnu-ld
--with-gnu-as
--disable-multilib
--with-float=soft
--disable-sjlj-exceptions
--disable-nls
--enable-threads=posix
--disable-libmudflap
--disable-libssp
--enable-long=longx
--with-shared
--with-gmp=$INSTALLDIR
--with-mpfr=$INSTALLDIR
make
make install
La bibliothèque finale de GCC est dans le répertoire : /opt/arm/arm-none-linux-gnueabi/lib La chaîne de compilation croisée est dans le répertoire /opt/arm. Dans le terminal T1, nous pouvons ajouter les exécutables de la chaîne de compilation croisée dans la variable d'environnement PATH en tapant: export PATH=$INSTALLDIR/bin:$PATH En tapant les premières lettres des exécutables arm et sur la touche tabulation, nous avons désormais un accès direct aux exécutables. Le tableau suivant rassemble l'ensemble des exécutables générés ainsi que leur utilisation :
Exécutable Fonction
arm-none-linux-gnueabi-addr2line Convertit les adresses en numéro de ligne dans le fichier originel.
arm-none-linux-gnueabi-ar Crée et manipule le contenu des archives.
arm-none-linux-gnueabi-as GNU assembleur.
arm-none-linux-gnueabi-c++filt Décode les symboles du C++ et du Java.
arm-none-linux-gnueabi-cpp Préprocesseur C++.
arm-none-linux-gnueabi-gcc Compilateur GNU C.
arm-none-linux-gnueabi-gcc-4.3.3 Compilateur GNU C en version 4.3.3 comme le précédent.
arm-none-linux-gnueabi-gccbug Report de bogue GCC.
arm-none-linux-gnueabi-gcov Donne le taux de couverture d'un test dans un programme.
arm-none-linux-gnueabi-gprof Fait du profilage de code source.
arm-none-linux-gnueabi-ld GNU Linker.
arm-none-linux-gnueabi-nm Liste les symboles des fichiers objets.
arm-none-linux-gnueabi-objcopy Copie et traduit les fichiers objets.
arm-none-linux-gnueabi-objdump Affiche les informations du contenu des fichiers objets.
arm-none-linux-gnueabi-ranlib Génère un index du contenu d'une archive.
arm-none-linux-gnueabi-readelf Affiche les informations d'un fichier au format ELF.
arm-none-linux-gnueabi-size Liste les tailles des sections d'un fichier objet.
arm-none-linux-gnueabi-strings Affiche les chaînes de caractères imprimables d'un fichier objet.
arm-none-linux-gnueabi-strip Supprime tous les symboles contenus dans les fichiers objets.
Table 1.6: Les commandes GCC pour ARM

1.7.12  Test de la chaîne de compilation croisée obtenue From Scratch

Faisons un test de compilation avec notre chaîne fraîchement installée. Nous allons compiler le célèbre programme Helloworld qui se contente d'afficher dans un terminal le message "Hello world !". Voici le code source du programme écrit en langage C : helloworld.c
#include <stdio.h>
int main(void)
{
printf("Hello world!n");
return 0;
}
en compilant le programme par
arm-none-linux-gnueabi-gcc -o helloworld helloworld.c
nous pouvons vérifier le type de fichier compilé en utilisant la commande file:
file helloworld
donne:
helloworld: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.16, not stripped

Footnotes:

1http://www.denx.de/wiki/DULG/ELDK
2Téléchargeables à l'adresse: http://gmplib.org
3Téléchargeables à l'adresse: http://www.mpfr.org
4laurent@komite.net


File translated from TEX by TTH, version 4.03.
On 27 Sep 2012, 16:25.