Installation d'une chaîne de compilation croisée (GCC) sous Eclipse
Avant-propos
Ce tutoriel naît du constat qu'il n'existe pas de vraie documentation support accompagnant le développeur désireux d'élaborer un projet quelconque à partir du RaspberryPi. J'entends par là que celui ayant quelques compétences dans le langage C, ayant l'habitude d'écrire des programmes sur PIC ou Atmel se retrouve quelque peu perdu face à la multitude d'outils libres disponibles. Dans toute conception de projet, il est indispensable d'avoir un environnement de développement adapté dans lequel on se sente à l'aise afin de réduire le temps consacré, uniquement à la réflexion et à l'élaboration du projet (écriture de code et débuggage logiciel/matériel). La méthode que je vous propose ici est d'utiliser le principe de compilation croisée à travers l'utilisation d'un logiciel de développement intégré nommé Eclipse. Ce logiciel est multiplateforme, c'est à dire qu'il fonctionne à la fois sous Mac, Windows et Linux, donc que la méthode expliquée ici peut s'appliquer quelque soit votre système d'exploitation.
Intérêts et principes
L'IDE (Environnement de Développement Intégré) et la compilation croisée sont deux choses distinctes :
- Eclipse est un logiciel vous offrant une gestion complète de projet. Pour résumer, à l'instar de MPLAB, il vous offre un espace de travail pour saisir les sources de votre programme, en-têtes, etc. et permet en un clic d'automatiser la compilation de l'ensemble des fichiers (pré-traitement, compilation, assemblage, édition des liens, exécution) via les outils que vous aurez préalablement configurés. Vous n'avez pas à exécuter des tonnes de commandes Linux avant de voir votre programme compilé et executé.
- La compilation croisée est le fait de générer un binaire exécutable sur une architecture (celle du RaspberryPi étant ARM) différente de celle utilisée lors de la compilation. De sorte, il est possible d'utiliser sa propre machine de travail pour compiler le programme dont la cible sera, pour l'occasion, le RasperryPi. Les avantages d'avoir recours à cette méthode sont multiples ; les principaux étant la rapidité de compilation, l'utilisation d'un seul écran (pas besoin d'écran connecté au Rpi, il suffit simplement qu'il soit relié au réseau local et qu'il possède sa propre adresse IP). Enfin et surtout, il est possible de lancer l'exécution du binaire depuis Eclipse et de faire du débuggage temps réel ; les informations de debug étant renvoyées directement du Rpi à Eclipse, installé sur votre propre machine (lecture des registres, valeurs des variables, exécution pas-à-pas, etc).
Installation et configuration
La présente démarche est expliquée pour un système de type Unix (ici GNU/Linux Debian testing) sur machine 64 bits. Cependant, elle peut très bien être portée sous Windows ou Mac. Simplement, l'installation d'Eclipse et le chemin des outils/bibliothèques à configurer diffèreront.
À faire depuis le PC Hôte (votre propre machine)
Installation d'Eclipse
Note : Dans la suite de l'article, les commandes Linux précédées d'un "#" imposent la possession des droits super-utilisateur ; celles précédées d'un "$" n'en nécessitent pas.
~# aptitude install eclipse-cdt
Préparatifs
On téléchargera et installera celle recommandée par la fondation officielle Raspbian.
Préparatifs : Ajout au gestionnaire de paquets la prise en compte des logiciels 32 bits compilés à partir d'architecture 64 bits (le Rpi étant du 32 bits, il faut donc un compilateur 32 bits exécutable sur notre machine 64 bits)
~# dpkg --add-architecture i386 (commande visiblement indisponible sur Ubuntu amd64 -> y a-t-il un équivalent ?)
Mise à jour du cache des paquets logiciels
~# aptitude update
Installation des bibliothèques partagées 32 bits exécutables sur architecture 64 bits (attention, pas mal de dépendances logicielles)
~# aptitude install ia32-libs
Installation de la lib32ncurses5 sans quoi le debuggueur arm-linux-gnueabihf-gdb ne fonctionnera pas
~# aptitude install lib32ncurses5
Installation de la chaîne d'outils croisés
Création du répertoire d'accueil où seront installés les outils de la chaîne de compilation pour le Raspberry (on choisira par exemple /usr/local/)
~# mkdir /usr/local/outils_raspberry
Téléchargement et compilation de la chaîne d'outils officielle, en se plaçant dans le répertoire précédemment créé
~# cd /usr/local/outils_raspberry
~# git clone git://github.com/raspberrypi/tools.git
Déplacement du contenu du dossier "tools" généré, dans le répertoire "outils_raspberry" pour plus de propreté et suppression du dossier "tools" maintenant vide
~# mv ./tools/* . && rm ./tools -R
Il faut maintenant ajouter le chemin des outils à la variable d'environnement PATH
~$ export PATH=$PATH:/usr/local/outils_raspberry/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin
Pour que la nouvelle variable PATH soit prise en compte au prochain redémarrage, il est nécessaire de modifier le fichier ~/.bashrc en rajoutant la ligne suivante en fin de fichier :
~$ nano ~/.bashrc
ligne à rajouter : export PATH=$PATH:/usr/local/outils_raspberry/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin
Configuration de l'IDE
À ce stade, lancer Eclipse pour la création d'un nouveau projet. À l'ouverture du logiciel, il vous est demandé de choisir un répertoire qui servira de référence d'espace de travail. Ensuite, dans le menu : File > New > Project, choisissez à l'ouverture de la fenêtre le projet C/C++ > Executable > Empty Project > Linux GCC (voir première image ci-dessous). Donner un nom au projet puis cliquer sur Finish. À ce moment, la perspective classique de l'IDE doit s'ouvrir, soit l'arborescence du projet à gauche, la zone d'édition du code source au centre, etc. Vous pouvez modifier à souhait les différents modules de vues via le menu Window, Show View, Other...
Ensuite, faites un clic droit sur le projet nouvellement créé (dans l'arborescence à gauche : "Project Explorer"), puis Properties.
Onglet C/C++ Build > Settings > Tools Settings (voir deuxième image)
Configuration : All Configurations
Renseigner ainsi les champs comme suit des différents outils qui seront utilisés pour la compilation :
- GCC C Compiler : Command : arm-linux-gnueabihf-gcc
- GCC C Linker : Command : arm-linux-gnueabihf-gcc
- GCC Assembler : Command : arm-linux-gnueabihf-as
Puis Apply
Onglet C/C++ General > Paths and Symbols (voir troisième image)
Configuration : All Configurations
- Includes (#1 sur la troisième image)
Choisir Languages > GNU C
Rajouter successivement les lignes suivantes via le bouton Add... :
/usr/local/outils_raspberry/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/arm-linux-gnueabihf/include /usr/local/outils_raspberry/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/arm-linux-gnueabihf/libc/usr/include /usr/local/outils_raspberry/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/lib/gcc/arm-linux-gnueabihf/4.7.2/include-fixed /usr/local/outils_raspberry/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/lib/gcc/arm-linux-gnueabihf/4.7.2/include /usr/local/outils_raspberry/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/lib/gcc/arm-linux-gnueabihf/4.7.2/finclude
- Library Paths (#2 sur la troisième image)
Rajouter successivement les lignes suivantes via le bouton Add... :
/usr/local/outils_raspberry/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/arm-linux-gnueabihf/lib /usr/local/outils_raspberry/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/arm-linux-gnueabihf/libc/lib /usr/local/outils_raspberry/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/arm-linux-gnueabihf/libc/lib/arm-linux-gnueabihf /usr/local/outils_raspberry/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/lib/gcc/arm-linux-gnueabihf/4.7.2 /usr/local/outils_raspberry/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/libexec/gcc/arm-linux-gnueabihf/4.7.2
-
Nouveau projet : Linux GCC
-
Outils de la chaîne de compilation
-
Includes et Librarys Paths
À faire depuis la cible (RaspberryPi)
Installation du serveur de débuggage GDBserver
À réaliser soit depuis une connexion distante SSH, soit depuis un clavier+souris+écran branchés au Rpi
~# aptitude install gdbserver
Tests de compilation et d'exécution
En revenant dans Eclipse, faites un clic droit sur le nom du projet, New > Source File > donnez un nom et écrivez un petit programme de test. Compiler ensuite le projet (CTRL+B). À ce stade, l'exécution du programme ne peut s'effectuer que sur la cible (Rpi) puisque compilé pour une architecture ARM. Il s'agit donc maintenant de déposer le binaire sur le RaspberryPi afin de s'assurer que son exécution s'effectue correctement. (Aussi, il est nécessaire d'envoyer une première fois le binaire sur le Rpi pour le rendre exécutable et pour qu'Eclipse puisse renseigner le chemin distant de là où il se trouve)
Se placer dans le répertoire où se situe le binaire de votre projet (ici nommé developpement_Rpi), puis envoyer le fichier sur le RaspberryPi :
~$ cd chemin_de_votre_projet/Debug/developpement_Rpi
~$ scp developpement_Rpi pi@xxx.xxx.xxx.xxx:/home/pi/ (où xxx.xxx.xxx.xxx est l'ip de votre RaspberryPi)
Ensuite, connecter vous en SSH sur le Rpi (ou accéder y depuis un clavier+écran), puis rendez exécutable le fichier précédemment envoyé :
~# chmod +x developpement_Rpi
Session debuggage croisé
Dans Eclipse, sélectionner le projet en cliquant simplement dessus dans l'arborescence, cliquer sur le petit chevron à droite du petit insecte (voir première image), puis "Debug Configuration...". Une fenêtre s'ouvre, double-cliquer ensuite sur C/C++ Remote Application à gauche pour créer un nouveau profil de Debug. Configurer ensuite le profil de la manière suivante (voir deuxième image) :
Onglet Main
- Cliquer sur "Search Project" et choisir le projet Debug courant
- Tout en bas de la fenêtre, Select Other > choisir Using GDB (DSF) Automatic Remote Debugging Launcher
- Connection : New... : Choisir SSH Only
- Host name : adresse IP du RaspberryPi
- Connection name : RaspberryPi
Puis cliquer sur Finish : choisir la connexion nouvellement créée.
- Remote Absolute File Path for C/C++ Application : /home/pi/nom_du_binaire_à_exécuter (ici ça sera : /home/pi/developpement_Rpi, voir troisième image)
- Commands to execute before application : sudo chmod +x /home/pi/developpement_Rpi
Onglet Debugger, sous-onglet Main
- GDB debugger : arm-linux-gnueabihf-gdb
- GDB command file : vide
Onglet Debugger, sous-onglet GDBServer Settings
- GDBServer Name : gdbserver
- Port number : 2345
Cliquer sur Apply, puis Debug
Normalement, une nouvelle compilation s'effectue, Eclipse envoie le binaire à l'emplacement demandé (+ attribue les bons droits), lance le gdbserver et démarre le cross debugging ! La perspective doit alors passer en mode débug. Vous devriez avoir une vue identique à l'image située au début de l'article. Note : Pour plus d'ergonomie, vous pouvez rajouter la vue Project Explorer et Remote System Details via Window > Show View > Other...
-
Accès au mode Debug
-
Configuration profil Debug
-
Pointage du binaire distant
Erreurs et problèmes rencontrés
Si problème lors de passage de commande de l'IDE au serveur gdb (situé sur le RaspberryPi), vérifier que les versions du client gdb et du gdbserver soit compatibles, voire identiques ! (ex: version 4.0.1 ne fonctionne pas avec la 4.4, mais la 4.2.1 fonctionne ! (dépôt unstable))
Utilisation des entrées/sorties
Le RaspberryPi possède plusieurs entrées/sorties GPIO. Bien évidemment, il est possible de les gérer nativement en utilisant l'interface GPIO disponible depuis le noyau Linux. Néanmoins, la complexité de cette solution est telle qu'elle n'est pas facilement accessible au débutant (ou pas...). Ainsi, je vous propose d'utiliser une bibliothèque intégrée, programmée en C, permettant l'exploitation de la plupart des fonctions implémentées sur le RaspberryPi et dont le développeur a souvent besoin : gestion des I/O, SPI, I2C, interface série, PWM, timing, interruptions, etc. Le site web du projet réalisé par l'auteur : http://wiringpi.com/
Installation et utilisation de la bibliothèque wiringPi
À exécuter sur Raspberry
Télécharger les sources
~$ git clone git://git.drogon.net/wiringPi
Les compiler puis les installer
~$ cd wiringPi && ./build
À exécuter sur machine hôte
Création du répertoire où accueillir la wiringPi sur notre hôte
~# mkdir /usr/local/outils_raspberry/wiringPi
Copier les répertoires précédemment construits (grâce à la compilation de la bibliothèque) du RaspberryPi vers la machine hôte (/usr/local/lib et /usr/local/include)
~# cd /usr/local/outils_raspberry/wiringPi
~# scp -r pi@raspberry:/usr/local/lib ./ && scp -r pi@raspberry:/usr/local/include ./
Maintenant, il s'agit de renseigner dans Eclipse les différents chemins des répertoires pour que la compilation se fasse correctement. Donc, à nouveau dans le logiciel, faites un clic droit sur le projet dans l'arborescence puis Properties
Onglet C/C++ General > Paths and Symbols
Configuration : All Configurations
- Onglet Includes
Dans Languages > GNU C
Rajouter la ligne suivante à celles déjà existantes :
/usr/local/outils_raspberry/wiringPi/include
- Onglet Library Paths
Rajouter également la ligne suivante à celles déjà existantes :
/usr/local/outils_raspberry/wiringPi/lib
Puis, dans Onglet C/C++ Build > Settings > Tools Settings
Configuration : All Configurations
- GCC C Linker > Miscelleaneous : Linker flags : rajouter la ligne suivante -> -l:libwiringPi.so.1.0
Puis Apply
Enfin, pour achever la configuration, il faut que le gbbserver sur le RaspberryPi exécute le binaire avec les droits root (pour que la wiringPi puisse utiliser les fonctions internes du Rpi) ; il est donc nécessaire de paramétrer la commande adéquate avant son lancement. Retourner dans la configuration du profil de Debug (petit chevron à droite de l'insecte), et remplacer la commande déjà existante "sudo +x /home/pi/developpement_Rpi" par :
~$ sudo -i
~$ chmod +x /home/pi/developpement_Rpi
Vous pouvez maintenant debugguer à distance en utilisant toutes les fonctions que permet la bibliothèque WiringPi !
Exemple de programme en C
Ci-dessous, un programme simple inversant le niveau logique de la pin 11 du connecteur HE10 :
/* Programme de test */
/* Clignotement LED sur pin 11 */
#include <stdio.h>
#include <wiringPi.h>
int main (void)
{
printf("Hello Raspberry Pi\n");
if(wiringPiSetup() == -1)
return 1 ;
pinMode(0,OUTPUT); // pin 11 du connecteur HE10 configurée en sortie
while(1){
digitalWrite(0,1); // LED ON
delay(500); // tempo 500ms
digitalWrite(0,0); // LED OFF
delay(500); // tempo 500ms
}
return 0 ;
}
-
Debug croisé en action avec wiringPi
-
Clignotement de la LED sur pin 11