Certains projets posent des problèmes difficiles à surmonter lorsqu’il s’agit de les cross-compiler pour une plate-forme différente du poste de compilation. Citons par exemple Apache ou PHP que nous avons laborieusement réussi à cross-compiler dans les quatrième et cinquième articles de notre série « Construire son système personnel sur Pandaboard« . Il peut être utile de disposer sur la cible embarquée d’une chaîne de compilation native c’est-à-dire capable de produire du code exécutable pour le processeur sur lequel la compilation a eu lieu.
Nous allons mettre ceci en oeuvre sur une carte à processeur Arm à l’aide de Buildroot.
Je vous propose de procéder en deux étapes : génération de la chaîne de compilation croisée classique, puis une fois celle-ci prête, construction de la chaîne de compilation native. Comme toujours, il faudra intervenir un peu manuellement pour réussir toute la compilation…
Tout d’abord téléchargeons et décompressons les sources de Buildroot :
[~]$ mkdir Projets/Arm/ [~]$ cd Projets/Arm/ [Arm]$ wget http://buildroot.uclibc.org/downloads/buildroot-2011.05.tar.bz2 --2011-06-30 23:22:45-- http://buildroot.uclibc.org/downloads/buildroot-2011.05.tar.bz2 [...] 2011-06-30 23:22:50 (522 KB/s) - «buildroot-2011.05.tar.bz2» sauvegardé [1834679/1834679] [Arm]$ tar -xjf buildroot-2011.05.tar.bz2 [Arm]$ cd buildroot-2011.05 [buildroot-2011.05]$
Je vous propose de télécharger ce fichier de configuration qui va générer la chaîne de compilation croisée et installer dans les répertoires destinés à la cible les fichiers d’entête de la bibliothèque C (option Development files in target filesystem du menu Build Options ci-dessous).
[buildroot-2011.05]$ cp ~/config-buildroot-2011-05-pass-1 ./.config [buildroot-2011.05]$ make menuconfig [...]
Vérifiez en particulier les chemins mentionnés dans le menu « Build Options », pour qu’il soient en accord avec votre système. Le répertoire « Host Dir » doit être un chemin absolu (il contiendra donc probablement votre nom d’utilisateur plutôt que le mien !). Quittez le menu et lancez la compilation :
[buildroot-2011.05]$ make [...]
Pendant la compilation, make
nous pose une dizaines de questions (probablement de nouvelles options qui ne sont pas enregistrées dans le fichier .config
), auxquelles nous pouvons répondre en utilisant le choix par défaut, c’est-à-dire en pressant simplement Entrée.
[...] grep -qx $lang /home/cpb/Projets/Arm/buildroot-2011.05/output/build/locales.nopurge || rm -rf $dir/$lang; done; done rm -f /home/cpb/Projets/Arm/buildroot-2011.05/output/build/.fakeroot* [buildroot-2011.05]$
La première étape est terminée nous avons une chaîne de compilation croisée, contenant GCC, accessible ainsi :
[buildroot-2011.05]$ ~/Projets/Arm/Target/usr/bin/arm-linux-gcc -v Utilisation des specs internes. Target: arm-unknown-linux-uclibcgnueabi Configuré avec: /home/cpb/Projets/Arm/buildroot-2011.05/output/toolchain/gcc-4.3.5/configure --prefix=/home/cpb/Projets/Arm/Target/usr --build=i686-pc-linux-gnu --host=i686-pc-linux-gnu --target=arm-unknown-linux-uclibcgnueabi --enable-languages=c,c++ --with-sysroot=/home/cpb/Projets/Arm/Target/usr/arm-unknown-linux-uclibcgnueabi/sysroot --with-build-time-tools=/home/cpb/Projets/Arm/Target/usr/arm-unknown-linux-uclibcgnueabi/bin --disable-__cxa_atexit --enable-target-optspace --disable-libgomp --with-gnu-ld --disable-libssp --disable-multilib --disable-tls --enable-shared --with-gmp=/home/cpb/Projets/Arm/Target/usr --with-mpfr=/home/cpb/Projets/Arm/Target/usr --enable-threads --disable-decimal-float --with-abi=aapcs-linux --with-pkgversion='Buildroot 2011.05' --with-bugurl=http://bugs.buildroot.net/ Modèle de thread: posix gcc version 4.3.5 (Buildroot 2011.05) [buildroot-2011.05]$
Passons à la seconde phase, la compilation d’un environnement de développement natif pour notre système embarqué en utilisant ce fichier de configuration.
[buildroot-2011.05]$ cp ../config-buildroot-2011-05-pass-2 ./.config [buildroot-2011.05]$ make menuconfig
Vous pourrez remarquer que nous avons inséré plusieurs outils de développement comme Bison, Flex, Make, Gcc, et même l’interpréteur Microperl, qui comme son nom l’indique implémente un sous-ensemble (assez conséquent) du langage Perl.
[buildroot-2011.05]$ make [...] -DDEPENDS_ON_LIBINTL=1 -DEXEEXT="" -Os -pipe -Os -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -c csharpcomp.c -o csharpcomp.o >/dev/null 2>&1 make[5] : on quitte le répertoire « /home/cpb/Projets/Arm/buildroot-2011.05/output/build/gettext-0.16.1/gettext-tools/gnulib-lib » make[4]: *** [all] Erreur 2 make[4] : on quitte le répertoire « /home/cpb/Projets/Arm/buildroot-2011.05/output/build/gettext-0.16.1/gettext-tools/gnulib-lib » make[3]: *** [all-recursive] Erreur 1 make[3] : on quitte le répertoire « /home/cpb/Projets/Arm/buildroot-2011.05/output/build/gettext-0.16.1/gettext-tools » make[2]: *** [all] Erreur 2 make[2] : on quitte le répertoire « /home/cpb/Projets/Arm/buildroot-2011.05/output/build/gettext-0.16.1/gettext-tools » make[1]: *** [all-recursive] Erreur 1 make[1] : on quitte le répertoire « /home/cpb/Projets/Arm/buildroot-2011.05/output/build/gettext-0.16.1 » make: *** [/home/cpb/Projets/Arm/buildroot-2011.05/output/build/gettext-0.16.1/gettext-runtime/src/gettext] Erreur 2 [buildroot-2011.05]$
Comment ? Une erreur de compilation ? Quelle surprise !
La cause apparait un peu plus haut dans les traces :
/home/cpb/Projets/Arm/Target/usr/bin/arm-unknown-linux-uclibcgnueabi-gcc -DHAVE_CONFIG_H -DEXEEXT="" -DEXEEXT="" -I. -I.. -I../intl -I../intl -I../intl -I.. -I.. -DDEPENDS_ON_LIBICONV=1 -DDEPENDS_ON_LIBINTL=1 -DEXEEXT="" -Os -pipe -Os -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -c copy-file.c -fPIC -DPIC -o .libs/copy-file.o copy-file.c:35:25: error: sys/utime.h: No such file or directory make[5]: *** [copy-file.lo] Erreur 1
Un fichier utime.h
ne se trouve pas dans le bon répertoire. Classique. Cherchons-le.
[buildroot-2011.05]$ find . -name 'utime.h' ./output/toolchain/uClibc-0.9.31/include/utime.h ./output/toolchain/uClibc_dev/usr/include/linux/utime.h ./output/toolchain/linux/include/linux/utime.h ./output/toolchain/linux-2.6.38.7/include/linux/utime.h [buildroot-2011.05]$
Nous ne prendrons pas les deux dernières instances, elles sont réservées à la compilation de modules du noyau, mais plutôt la première. A présent nous voyons que le compilateur cherche ce fichier dans un sous-répertoire sys/
or il n’y en a pas dans les répertoires de recherches des fichiers d’entête lors de la compilation de copy-file.c
.
Nous allons devoir faire une petite opération manuelle avant de relancer la compilation.
[buildroot-2011.05]$ mkdir -p output/build/gettext-0.16.1/gettext-tools/gnulib-lib/sys [buildroot-2011.05]$ cp output/toolchain/uClibc-0.9.31/include/utime.h output/build/gettext-0.16.1/gettext-tools/gnulib-lib/sys/ [buildroot-2011.05]$ make
A vrai dire, la commande make
s’est à nouveau interrompue en erreur sur mon système. Toutefois, soupçonnant une erreur due à la compilation en parallèle (8 jobs), j’ai relancé simplement make
qui a fonctionné.
[...] do grep -qx $lang /home/cpb/Projets/Arm/buildroot-2011.05/output/build/locales.nopurge || rm -rf $dir/$lang; done; done rm -f /home/cpb/Projets/Arm/buildroot-2011.05/output/build/.fakeroot* [buildroot-2011.05]$ ls output/target/usr/bin/ addr2line as c++ c++filt elfedit g++ gccbug gprof ld ldd microperl objcopy perl readelf strings yacc ar bison cc cpp flex gcc gcov iconv ld.bfd make nm objdump ranlib size strip [buildroot-2011.05]$ file output/target/usr/bin/gcc output/target/usr/bin/gcc: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), stripped [buildroot-2011.05]$
Pour tester notre toolchain native, nous allons l’installer sur un système Pandaboard, contenant simplement un noyau Linux et une Busybox intrégrant une connexion à distante par telnet
. Après avoir inséré la carte micro-SD sur mon PC, je vais copier le contenu du répertoire ~/Projets/Arm/buildroot-2011.05/output/target/usr/
sur la cible :
[buildroot-2011.05]$ cp -R output/target/usr/* /media/root/usr/ [buildroot-2011.05]$ umount /media/root/ [buildroot-2011.05]$
Après avoir inséré la micro-SD dans la carte Pandaboard, laissons-la booter, puis connectons-nous dessus via le réseau.
[buildroot-2011.05]$ telnet 192.168.3.152 Trying 192.168.3.152... Connected to 192.168.3.152. (none) login: root Password: BusyBox v1.18.4 (2011-06-22 12:27:46 CEST) built-in shell (ash) Enter 'help' for a list of built-in commands. [PANDABOARD]$ vi /root/hello.c
A l’aide du petit éditeur vi
intégré dans Busybox, nous saissons un petit programme de test
#include <stdio.h> int main(void) { fprintf(stdout, "Hello from the native Panda Compiler !n"); return 0; }
Que nous compilons ainsi :
[PANDABOARD]$ gcc /root/hello.c -o /root/hello [PANDABOARD]$ /root/hello Hello from the native Panda Compiler ! [PANDABOARD]$
Voilà ! notre compilateur natif est prêt. Il manque encore quelques utilitaires pour se lancer dans une compilation de plus grande envergure (le noyau Linux par exemple), nous les verrons la semaine prochaine.
PS : Cet article est plus court que d’habitude, mais cette période est très chargée pour moi : plusieurs développements importants arrivant à leurs termes, un déménagement, et quelques nouveaux projets traitant de robotique et de micro-contrôleurs (que je développerai prochainement)…
Hello,
Merci pour ces supers tutos, pourriez-vous corriger car les liens de fichiers de configs ne pointent nul part !
Merci encore et au plaisir de vous lire !
Salutations.
David
Voila qui est fait.
J’avais nommé par inadvertance les fichiers config-buildroot-2010-XXX au lieu de config-buildroot-2011-XXX.
Merci de m’avoir signalé cette erreur.
Bonjour,
je viens juste d’acquerir une pandaboard et je tente de construire dans un premier temps une toolchain adaptée.
Je suit votre démarche mais je me trouve confronté à l’erreur suivante:
« make: *** No rule to make target `host-gettext’, needed by `host-binutils-depends’. Stop. »
La description n’est pas documenté et lorsque je trouve quelque chose cela ne résout pas le problème.
J’utilise un disque dur externe pour le developpement, j’ai écrit une régle ‘udev’ qui me permet de monter le hdd avec un nom prédéfinit en utilisant son ‘UUID’. J’ai donc adpaté les chemins vers l’endroit où se trouve ma version de BR (2011.11).
Que faudrait-il modifier ou adapter pour résoudre se problème. En cherchant sur le site de BR j’ai trouvé dans le très mince FAQ un rapport à la gestion de ‘LOCALE’ et j’ai donc activé 2 autres règles en conséquence mais le résultat reste similaire!
Des idées.
Merci d’avance.
A priori il manque sur votre système de développement le package « gettext ».
Essayez de l’installer avec apt-get (pour Debian/Ubuntu/…) ou yum (pour Fedora/RedHat/CentOs/…)
Après quelques soucis avec mon disque dur! (fct économie d’énergie réduit grandement la durée de vie). J’ai tenté de reproduire les memes conditions tout en re-installant « gettext » mais j’ai obtenu des erreurs jusqu’a obtenir une combinaison entre les différentes versions:
2.6.3 Kernel Headers
0.9.32 uClibc
2.20 Binutils
4.5 gcc
Dans le cas contraire les « locales » sont intégrés et générent une erreur de compil.
Une fois cette TC basique obtenue je ré-active le support de l’i18n et lance un
> make V=1
qui me permet d’obtenir une TC avec les « locales » intégrés cette fois-ci.
Il semble que le problème vienne de la combinaisons des versions.
Bonjour,
J’ai un petit souci avec ma Pandaboard : tout se passe bien jusqu’au moment où je copie output/target/usr/* sur la carte SD. Je n’ai pas d’erreur, mais lorsque je démarre la Pandaboard, elle ne connait pas gcc…
Si je fais ls -l /usr/bin/ , il y a bien gcc (et les autres), avec les mêmes droits que les scripts shell que j’ai fait à la main et qui marchent, et pourtant si je fais /usr/bin/gcc, j’obtiens « -sh: /usr/bin/gcc: not found ». Je ne vois vraiment pas d’où ça peut venir… Une idée ?
Merci d’avance !
Je pense qu’il faut juste configurer le
PATH
dans/etc/profile
pour qu’il contienne le répertoire/usr/bin
.Merci pour cette réponse rapide, mais ça ne vient pas de là, /etc/profile contient déjà ce qu’il faut.
Par contre, bien que j’obtienne ce qu’il faut quand je fais « file output/target/usr/bin/gcc » (à savoir ELF 32bits executable), il me dit « not an ELF file » quand je lance la commande host/usr/bin/ldd dessus. J’avoue que je suis un peu perdu du coup.
Peut-être est-ce dû à un problème de bibliothèques.
J’ai déjà remarqué que arm-linux-ldd ne marche pas bien si la cible est 32 bits et l’hôte 64 bits (est-ce le cas ?). (arm-linux-readelf est dans la cross-toolchain). Elles sont indiquées en haut du contenu de la section dynamique.
On peut obtenir la liste des bibliothèques dynamiques en utilisant arm-linux-readelf -d
Les bibliothèques nécéssaires sont-elles bien présentes ?
Oui, j’ai pensé aussi à un problème de bibliothèques, c’est pour ça que j’ai tenté de lancer ldd et que j’ai découvert qu’il ne fonctionnait pas. Et effectivement je suis en 64 bits.
J’ai donc continué à chercher, j’ai lancé arm-linux-readelf -d et j’ai découvert qu’effectivement il manquait une bibliothèque nécessaire : libc.so.0 . Le problème, c’est que du coup je l’ai copié, j’ai rebooté la Panda, et le problème persiste… Rien n’a changé au niveau du comportement de la bête. Donc c’est sans doute quand même mieux avec la bibliothèque libc.so mais ça ne se voit pas :S .
Je suis en train de me re-créer la même configuration pour vérifier.
Libc.so.0 est normalement un lien symbolique vers libuClibc-xxx.so. Pas de souci de ce côté là ?
Merci de prendre autant de temps pour moi, au final je viens de trouver une solution qui résout le problème :
il suffisait de copier output/target/lib/* en plus de output/target/usr/*
Par contre, maintenant que gcc se lance, il ne trouve pas . Je l’ai cherché avec find et il est présent dans le dossier /usr/include/c++/tr1/. Je suppose que c’est le bon, mais comment lui dire d’aller le chercher là-bas ?
J’ai fait un essai qui fonctionne (avec Buildroot-2012-05 au lieu de 2011-05) sur une carte RaspberryPi au lieu de la Pandaboard.
A la fin de la compilation j’ai copié tout le contenu de
output/target/usr
sur la cible. J’y trouve donc les fichiers suivantsWaouh, merci pour ce travail ^^.
Globalement, j’ai la même chose. Et je ne vois pas non plus de libc.so dans /usr/. Pourquoi j’ai eu besoin de copier de /output/target/lib/* ?
Enfin, comme je le disais dans mon dernier commentaire (mais je viens de remarquer qu’apparemment les chevrons ne sont pas passés), gcc arrive maintenant à se lancer, mais il ne trouve pas stdio.h.
Ce fichier existe bien, mais sans doute pas dans le bon dossier (il est uniquement dans /usr/include/c++/tr1/). Je pourrais le copier dans /usr/include directement, mais est-ce la bonne solution ? Comment faire en sorte qu’il aille le chercher où il faut ? Et pourquoi moi ça ne marche pas par défaut ?
J’ai dû rater une étape quelque part… Mais laquelle ?
Je confirme que
stdio.h
(et quelques dizaines d’autres fichiers d’en-tête) doivent se trouver dans/usr/include/
(je les vois dansoutput/target/usr/include/
de Buildroot).Tous les fichiers de
/lib
auraient dû être installés précédemment (voir cet article).N’ayant pas toujours utilisé les mêmes versions des différentes composantes du système, je n’avais pas exactement les mêmes lib, mais c’est réglé. Quant aux headers, je ne les ai pas dans target/output/usr/include/ mais je vais voir ce que je peux faire pour résoudre le problème.
En tout cas encore merci pour tout !
Pour les headers, il ne faut pas oublier d’activer la case « development files in target filesystem » dans le menu « Build options » de Buildroot.
Bon courage