Créer sa chaîne de cross-compilation

Le projet crosstool-ng permet de compiler sa propre chaîne de compilation, pour les architectures alpha, arm, armeb, i586, i686, m68k, mips et mips64, powerpc et powerpc64, s390, x86_64.
Une chaîne de compilation, dite « cross », peut ainsi être générée pour compiler un projet vers une autre architecture que celle de la machine qui effectue la compilation. Il est également possible d’effectuer une compilation dite « canadian », c’est-à-dire que la machine qui compile la chaîne de compilation, la machine qui compile le code à l’aide de cette chaîne et la machine qui exécute le code ont trois architectures différentes.
Le projet crosstool-ng offre donc la possibilité, par exemple, de compiler un code pour une architecture arm depuis une architecture Intel x86_64.

Les pré-requis suivants doivent être installés. Depuis une Debian Wheezy lite, exécuter la commande qui suit :

# aptitude install build-essential bison flex gperf makeinfo texinfo gawk \
libtool automake libncurses5-dev subversion zip unzip gcj-4.6-jdk gcj-4.6-base \
expat libexpat1-dev

La commande gcj doit être accessible directement :

# ln -s /usr/bin/gcj-4.6 /usr/bin/gcj

Préparation

Téléchargeons les dernières sources du projet crosstool-ng.

$ cd $HOME
$ wget http://crosstool-ng.org/download/crosstool-ng/crosstool-ng-1.19.0.tar.bz2
$ tar -xvf crosstool-ng-1.19.0.tar.bz2
$ cd crosstool-ng-1.19.0

Compilons le projet, puis installons le (avec l’utilisateur root).

$ ./configure --prefix=/autre/endroit/où/installer
$ make
$ su
# make install
# exit
$ export PATH="${PATH}:/autre/endroit/où/installer/bin

Créons le répertoire des sources dans notre répertoire personnelle. Ce répertoire contiendra les sources du noyau, ainsi que les sources de binutils, gcc et la libc qu’on utilisera pour notre chaîne.

$ mkdir $HOME/src

Utilisation

On peut lister les patrons de conceptions (template) disponibles pour générer la chaîne de compilation par la commande :

$ ct-ng list-samples
Status  Sample name
  LN    config
  MKDIR config.gen
  IN    config.gen/arch.in
  IN    config.gen/kernel.in
  IN    config.gen/cc.in
  IN    config.gen/binutils.in
  IN    config.gen/libc.in
  IN    config.gen/debug.in
[G.X]   alphaev56-unknown-linux-gnu
[G.X]   alphaev67-unknown-linux-gnu
[G.X]   arm-bare_newlib_cortex_m3_nommu-eabi
[G.X]   arm-cortex_a15-linux-gnueabi
[G..]   arm-cortex_a8-linux-gnueabi
[G..]   arm-davinci-linux-gnueabi
[G..]   armeb-unknown-eabi
[G.X]   armeb-unknown-linux-gnueabi
[G.X]   armeb-unknown-linux-uclibcgnueabi
[G..]   arm-unknown-eabi
[G..]   arm-unknown-linux-gnueabi
[G.X]   arm-unknown-linux-uclibcgnueabi
[G.X]   armv6-rpi-linux-gnueabi
[G.X]   avr32-unknown-none
[G..]   bfin-unknown-linux-uclibc
[G..]   i586-geode-linux-uclibc
[G.X]   i586-mingw32msvc,i686-none-linux-gnu
[G.X]   i686-nptl-linux-gnu
[G.X]   i686-unknown-mingw32
[G.X]   m68k-unknown-elf
[G.X]   m68k-unknown-uclinux-uclibc
[G.X]   mips64el-n32-linux-uclibc
[G.X]   mips64el-n64-linux-uclibc
[G.X]   mips-ar2315-linux-gnu
[G..]   mipsel-sde-elf
[G..]   mipsel-unknown-linux-gnu
[G.X]   mips-malta-linux-gnu
[G..]   mips-unknown-elf
[G.X]   mips-unknown-linux-uclibc
[G..]   powerpc-405-linux-gnu
[G.X]   powerpc64-unknown-linux-gnu
[G..]   powerpc-860-linux-gnu
[G.X]   powerpc-e300c3-linux-gnu
[G.X]   powerpc-e500v2-linux-gnuspe
[G..]   powerpc-unknown-linux-gnu
[G..]   powerpc-unknown-linux-uclibc
[G..]   powerpc-unknown_nofpu-linux-gnu
[G.X]   s390-ibm-linux-gnu
[G.X]   s390x-ibm-linux-gnu
[G..]   sh4-unknown-linux-gnu
[G..]   x86_64-unknown-linux-gnu
[G..]   x86_64-unknown-linux-uclibc
[G.X]   x86_64-unknown-mingw32
 L (Local)       : sample was found in current directory
 G (Global)      : sample was installed with crosstool-NG
 X (EXPERIMENTAL): sample may use EXPERIMENTAL features
 B (BROKEN)      : sample is currently broken

On peut éventuellement utiliser un des patrons disponible directement, tel que armv6-rpi-linux-gnueabi par exemple, ou le modifier par la suite. On peut aussi personnaliser complètement la génération de la chaîne de compilation en utilisant son propre noyau téléchargé depuis kernel.org, sa propre libc, ulibc et une version spécifique de binutils.

Utiliser un template

Pour utiliser un des patrons de conception disponible, exécuter la commande suivante :

$ ct-ng armv6-rpi-linux-gnueabi

Personnaliser la chaîne de compilation

Pour personnaliser la chaîne de compilation, exécuter la commande :

$ ct-ng menuconfig

On peut utiliser l’un des noyaux proposés ou un noyau personnalisé depuis le menu :

Operating System  --->Linux kernel version --->

La dernière option « custom tarball or directory » permet de choisir ses propres sources de noyau. Il faut alors indiquer le chemin depuis la racine de l’archive ou du répertoire qui contient le noyau dans le menu :

Operating System  --->Path to custom source, tarball or directory

Le menu « Binary utilities » permet de définir le format (ELF), ainsi que la version de librairie binutils à utiliser.

Le menu « C compiler » permet de choisir la version de gcc que la chaîne de compilation utilisera, ainsi que les languages additionels que le compilateur doit gérer parmis :

  • C++ ;
  • Fortran ;
  • Java.

Le menu « C-library » permet de choisir entre les librairies :

  • eglibc, optimisé pour les systèmes embarqués ;
  • glibc ;
  • uClibc, optimisé pour les systèmes embarqués.

Leur version peut également être sélectionnée, ainsi que des options spécifiques tel que le support des locales et de WCHAR.

Le menu « Companion librairies » permet de définir la version de GMP, MPFR, PPL, CLooG/ppl et MPC.

Le menu « Toolchain options » permet de définir la variable Tuple’s vendor string, qui contient un nom personnalisé pour reconnaître sa chaîne de compilation parmi d’autres. Par exemple, pour une chaîne de compilation pour architecture armv5, noyaux linux, si on définit la variable à my, le nom du compileur gcc sera « armv5-my-linux-gnueabi-gcc ».

Le menu « Target options » permet de définir :

  • l’architecture cible (alpha, arm, avr32, blackfin, m68k, mips, powerpc, s390, sh, sparc, x86) ;
  • l’utilisation ou non de la MMU ;
  • l’endianisme (little endian, big endian) ;
  • le nombre de bits (32,64) ;

Il est également possible de définir le CPU, le FPU et le type de virgule flottante (hardware, softfp, software). Les instructions spécifique au processus cible peuvent-être précisés, par exemple, pour arm, le mode (arm ou thumb) et si on doit utiliser le « thumb-interworking ». Bien entendu, si ces options ne sont pas précisés, elles peuvent-êtres définies via les options de la ligne de commande à l’utilisation du cross compilateur après génération.

Générer la chaîne

La génération est assez simple :

$ ct-ng build

Utilisation

Par défaut, la chaîne de compilation est générée dans le répertoire :

$HOME/x-tools/ARCH-XXX-linux-gnueabi/

Pour l’utiliser, il suffit de rajouter le chemin dans le PATH :

$ PATH="$PATH:$HOME/x-tools/ARCH-XXX-linux-gnueabi/"

Voilà, il n’y à plus qu’à compiler le code pour l’architecture cible…