La plupart des développeurs ont l’habitude d’utiliser les chaînes de compilation fournies par leur distribution. Elles sont généralement faciles à installer et fiables car fréquemment utilisées.
Elles sont en revanche peu configurables. Créer sa propre chaîne de compilation permet de l’adapter à une cible et à des besoins spécifiques. Il pourra être possible de choisir la libc, la version de linux, le compilateur, configurer les accélérations matérielles, etc.
Crosstool-ng, en plus de permettre cela, amène un avantage majeur : la chaîne de compilation créée est indépendante de l’endroit où elle est fabriquée. Elle peut être déplacée et même transmise à un tiers, et ainsi, il est possible de créer une toolchain pour une machine différente, dédiée à son architecture.
Cet article s'appuie sur la documentation de crosstool-ng.
Installation de crosstool-ng
Crosstool-ng peut être installé sur n’importe quelle distribution Linux ou BSD, sur MacOS X ou Windows. Pour chaque OS supporté, une liste des prérequis nécessaires est disponible sur le site.
Certaines distributions proposent un paquet mais il est préférable de compiler crosstool-ng soi-même. Les dernières versions des sources peuvent être téléchargées sur le site ou alors directement depuis le dépôt Git. Sur un PC équipé d'une version récente de gcc, il est possible qu’il faille partir de la branche master du dépôt. Les deux méthodes sont détaillées sur la page d’installation.
$ git clone https://github.com/crosstool-ng/crosstool-ng
$ cd crosstool-ng
$ ./bootstrap
Le répertoire de destination peut être spécifié avec l’option --prefix lors de l'appel à configure. Par défaut, l'outil sera installé dans /usr/local, ce qui nous convient très bien :
$ ./configure
$ make
$ sudo make install
Ajout au PATH
Si un répertoire de destination a été choisi, il faudra penser à le rajouter dans le PATH. Attention également aux distributions qui n'ont pas /usr/local par défaut dans le PATH.
Auto-complétion bash
- Les commandes de crosstool-ng pouvant être très longues, l'auto-complétion s'avère très pratique et par chance un script est disponible. Pour les versions antérieures à 1.24, il faut sourcer le script ct-ng.comp à la racine des sources.
- À partir de la version 1.24 de crosstool-ng (pas encore disponible à ce jour), le script est directement installé dans le répertoire de destination. S'il est sur /usr/local, il devrait être chargé automatiquement. Sinon, il faut sourcer le fichier /your/installation/path/share/bash-completion/ct-ng.
Utiliser crosstool-ng pour créer une toolchain
Plaçons-nous maintenant dans un répertoire spécifique de compilation, par exemple ~/mytarget.
$ mkdir ~/mytarget
$ cd ~/mytarget
L'utilitaire peut être utilisé par la commande ct-ng. Reportez-vous à l’aide pour un résumé des commandes ou au manuel pour plus de détails.
$ ct-ng help [COMMAND]
$ man 1 ct-ng
Configuration de la toolchain
Pour commencer, il faut configurer la toolchain pour la cible désirée. Pour faciliter la tâche, une liste de configurations de base est disponible. Elle est observable avec les commandes ct-ng list-samples et ct-ng list-samples-short :
Beaucoup d'architectures sont déjà configurées, et sont un excellent point de départ sur la quasi-totalité des projets.
Il est possible d'obtenir des informations sur une cible en la préfixant par show-. Par exemple, pour un ARM avec GNU/Linux :
$ ct-ng show-arm-unknown-linux-gnueabi [G..] arm-unknown-linux-gnueabi OS : linux-4.16.1 Companion libs : gmp-6.1.2 mpfr-4.0.1 mpc-1.1.0 isl-0.19 libelf-0.8.13 expat-2.2.5 ncurses-6.1 libiconv-1.15 gettext-0.19.8.1 Binutils : binutils-2.30 Compiler : gcc-8.1.0 Languages : C,C++ C library : glibc-2.27 Debug tools : duma-2_5_15 gdb-8.1 ltrace-0.7.3 strace-4.22 Companion tools : autoconf-2.69 automake-1.16.1
Une fois la cible choisie, elle doit être sélectionnée :
$ ct-ng arm-unknown-linux-gnueabi
Cela a pour effet de créer un fichier .config dans le répertoire actuel. Ce fichier répertorie la configuration de la cible. Il peut être transmis à un tiers qui pourra ainsi construire une toolchain identique.
Personnalisation
Cette configuration est personnalisable avec menuconfig :
$ ct-ng menuconfig
Les options sont nombreuses, voici une liste non exhaustive de ce qu'il est possible de faire :
- changer le nom de la toolchain (utile pour avoir arm-none-eabi au lieu de arm-unknown-eabi)
- activer les logs et le debug de compilation
- activer des optimisations (calcul flottant, etc.)
- choisir le répertoire de destination
- configurer des miroirs
- modifier l’architecture, l’"endianisme"
- choisir la libc
- ajouter la compilation des compilateurs pour les langages C++, Fortran etc.
- compiler les outils de debug :
- gdb/gdbserver
- strace
- ltrace
- duma
Build
La compilation est lancée avec la commande build. Pour l'accélérer, le nombre de threads peut être réglé en suffixe. Il n'y aura pas de parallélisation des tâches, mais plutôt un multithreading de chaque tâche.
$ ct-ng build $ ct-ng build.4
La chaîne est construite par défaut dans ~/x-tools. Ce répertoire peut être déplacé (dans la distribution hôte).
Utilisation de la toolchain générée
Les utilitaires générés sont répartis sur deux répertoires :
- Les utilitaires pour la machine hôte dans /your/toolchain/path/bin
- Les utilitaires pour la cible dans /your/toolchain/path/<tuple>/debug-root/usr/bin
Cross-compilation avec GCC ou G++
Il est maintenant possible de compiler un programme avec gcc :
$ /your/toolchain/path/bin/arm-unknown-linux-gnueabi-gcc helloworld.c -o hello $ file hello hello: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.3, for GNU/Linux 4.16.1, with debug_info, not stripped
Cross-compilation avec autoconf
Un projet utilisant autoconf peut être compilé facilement en spécifiant la cible lors de la configuration :
$ autoreconf -i $ ./configure --host arm-unknown-linux-gnueabi $ make
Outils de debug
S’ils ont été compilés, les outils de debug (gdb, strace…) pour la machine hôte sont installés dans le sous-dossier /your/toolchain/path/<tuple>/debug-root/usr/bin :
$ ls ~/x-tools/arm-unknown-linux-gnueabi/arm-unknown-linux-gnueabi/debug-root/usr/bin/ duma gcore gdb gdbserver ltrace strace strace-graph strace-log-mergeConclusion
On pourra par exemple installer gdbserver et utiliser le gdb correspondant :
$ ~/x-tools/arm-unknown-linux-gnueabi/bin/arm-unknown-linux-gnueabi-gdb
Quel que soit l'environnement, la version de distribution, ou même le système d'exploitation utilisé (Linux, MacOS X ou Windows), Crosstool-ng permet de construire une même toolchain, simplement en partageant un fichier de configuration.
Mis à part quelques éventuelles difficultés dans la compilation de ct-ng, son utilisation épargnera au final bien des soucis.
Bibliographie
http://crosstool-ng.github.io/docs
https://www.blaess.fr/christophe/2012/10/19/toolchain-crosstool-ng-pour-raspberry-pi/
Louis,
Est ce que crosstool-ng propose des outils (testsuite) pour tester la toolchain générée ?
Je constate que les PR sur github sont (build) testé avec Travis en utilisant les cible suivante:
arm-unknown-eabi, arm-unknown-linux-musleabi, aarch64-unknown-linux-gnu, mips64el-multilib-linux-uclibc,
powerpc-e500v2-linux-gnuspe, x86_64-unknown-linux-uclibc et xtensa-fsf-linux-uclibc
Ce qui est déjà pas mal mais cela ne permet pas de détecter un problème au runtime...
Connais-tu le projet toolchain-builder ? [1]
Toolchain-builder permet de compiler la toolchain, générer un système minimal et de l'exécuter dans Qemu (lorsque le support Qemu est disponible).
Cependant, le test reste limité car le système ne fait que démarrer jusqu'au shell.
Aussi, Toolchain-builder se base sur l'infrastructure de Buildroot pour générer une toolchain interne, le choix de la cible est limité par ce qui est supporté par Buildroot.
Crosstool-ng est capable de générer des toolchain baremetal et supporte des cibles qui ne sont pas disponible dans Buildroot (alpha, s390, mingw).
[1] https://gitlab.com/free-electrons/toolchains-builder
Romain