Créer un cross compilateur GCC (C/C++)

Pourquoi faire un cross compilateur ?

Il faut faire un cross compilateur car le compilateur fournis avec votre système est configuré pour une plateforme cible (CPU, système d'exploitation etc).

Par exemple, comparons deux platformes différentes (Ubuntu x64 et Debian GNU/Hurd i386). La commandegcc -dumpmachine nous indique la platforme que cible le compilateur, sur Ubuntu GNU/Linux la commande me retourne x86_64-linux-gnu tandis que sur Debian GNU/Hurd nous avons i686-gnu.

Le resultat obtenu n'est pas surprennant, nous avons deux systèmes d'exploitation différent sur du materiel différent.

Ne pas faire un cross compilateur et utiliser le compilateur fournis avec le système c'est allez au devant de toute une série de problèmes.

Quel plateforme cible ?

Tout cela va dépendre de l'architecture que vous ciblez (x86, risc-v) et du format de vos binaires (ELF, mach-o, PE).

Par exemple pour un système x86-64 en utilisant le format ELF: x86_64-elf Ou encore i686-elf pour x86 (32bit)

Bien sur en attendant d'avoir notre propre toolchain.

Compiler GCC et les binutils

Maintenant que la théorie à été rapidement esquissée nous allons pouvoir passer à la pratique.

créons un dossier toolchain/local à la racine de notre projet. C'est dans ce dossier que sera notre cross compilateur une fois compilé.

créons donc une variable $prefix:

prefix="<chemin vers votre projet>/toolchain/local"

Profitons en pour modifier notre $PATH:

export PATH="$PATH:$prefix/bin"

Puis nous allons définir une variable $target (qui contiendra notre platforme cible). Comme dans notre guide nous nous concentrons sur x86-64 notre variable sera définis comme ceci:

target="x86_64-elf"

Nos variables d'environment étant définis nous pouvons passer à l'installation des dépendances.

Dépendance

Pour pouvoir compiler gcc et binutils sous Debian GNU/Linux il nous faut les paquets suivant:

  • build-essential
  • bison
  • flex
  • texinfo
  • libgmp3-dev
  • libmpc-dev
  • libmpfr-dev

Que l'on peut les installer simplement comme ceci:

sudo apt install build-essential bison flex libgmp3-dev \
                    libmpc-dev libmpfr-dev texinfo

Nous allons pouvoir passer à la compilation.

binutils

Commençons par télécharger et décompresser les sources de binutils.

Ici dans ce tutoriel nous compilerons binutils 2.35.

binutils_version="2.35"
wget "https://ftp.gnu.org/gnu/binutils/binutils-$binutils_version.tar.xz"
tar -xf "binutils-$binutils_version.tar.xz"

Maintenant que l'archive est décompressé nous allons passer à la compilation.

cd "binutils-$binutils_version"
mkdir build && cd build
../configure --prefix="$prefix" --target="$target"  \
                --with-sysroot --disable-nls --disable-werror
make all -j $(nproc)
make install -j $(nproc)

Comme la compilation risque de prendre un moment, vous pouvez en profiter pour vous faire un café.

gcc

Maintenant les binutils sont compilé, nous allons pouvoir passer à gcc.

Ici nous compilerons gcc 10.2.0.

gcc_version="10.2.0"
wget http://ftp.gnu.org/gnu/gcc/gcc-$gcc_version/gcc-$gcc_version.tar.xz
tar -xf gcc-$gcc_version.tar.xz

Puis on passe à la compilation:

cd "gcc-$gcc_version"
mkdir build && cd build
../configure --prefix="$prefix" --target="$target" --with-sysroot \
            --disable-nls --enable-languages=c,c++ --with-newlib
make -j all-gcc 
make -j all-target-libgcc
make -j install-gcc 
make -j install-target-libgcc

La encore ça va prendre un certain temps, on peut donc s'accorder une deuxième pause café.

Une fois la compilation terminée vous pouvez utilisez votre cross compilateur, dans le cas de ce tutoriel x86_64-elf-gcc.

Cependant il faudrait plus tard implémenter une toolchain spécifique pour votre os. C'est une toolchain modifiée pour votre système d'exploitation.