Version en ligne

Tutoriel : Écrire du code C avec Emacs

Table des matières

Écrire du code C avec Emacs
Édition du code avec le c-mode
Plusieurs fichiers sources
Gestion de l’historique des modifications avec VC

Écrire du code C avec Emacs

Édition du code avec le c-mode

Emacs est capable de beaucoup de choses telles que la gestion des fichiers, la messagerie électronique ou encore la lecture de musique, mais l’un des emplois premiers de l’Éditeur demeure la programmation.

Ce tutoriel est le premier d’une série de trois articles, au travers desquels nous allons apprendre à utiliser Emacs en tant qu’environnement de développement pour le langage C.

Cette série s’adresse tout particulièrement aux débutants puisqu’elle s’attache à expliquer au passage les mécanismes derrière chaque aspect du développement tels que la gestion des fichiers sources, la compilation séparée, ou la chasse aux bogues. De ce fait, elle peut être lue plus ou moins de manière autonome, sans nécessiter de grandes connaissances dans l’usage des outils de programmation (vous n’avez rien à faire, tout est dans Emacs ! ou presque…). Il vous faudra tout de même des bases à la fois en C et dans l’usage d’Emacs en tant qu’éditeur. Je recommande aussi de lire l’introduction à la configuration d'Emacs que j’ai écrite, si vous n’avez encore jamais édité votre .emacs.

Mais avant de nous attaquer à Emacs, nous devons identifier nos besoins. Les trois tâches attribuées aux environnements intégrés tels que KDevelop ou Code::Blocks sont les suivantes :

Ce premier volet s’intéresse à l’écriture du code en elle-même, et bien sûr, aux fonctionnalités d’Emacs qui vous y aideront !

Édition du code avec le c-mode

Plusieurs fichiers sources

Le mode d’édition du code C dans Emacs se nomme très simplement le c-mode et est inclus par défaut avec l’éditeur ; vous pouvez aussi obtenir la dernière version du mode (qui est développé en dehors d’Emacs lui-même) sur le site du cc-mode. Le c-mode offre plusieurs fonctionnalités et commandes intéressantes.

Indentation automatique

Tout d’abord, comme tous les modes de programmation dans Emacs, le c-mode possède l’indentation automatique. Cela signifie que la touche TAB (ou, de manière équivalente, C-i) n’est pas utilisée pour insérer un caractère « tabulation » mais pour indenter la ligne actuelle, c’est-à-dire aligner le début de celle-ci sur la colonne adéquate, comme vous le feriez vous-même si Emacs n’était pas là. Il est important de remarquer que cette opération ne tient absolument pas compte de l’indentation actuelle de la ligne : qu’elle soit trop décalée à gauche ou à droite, Emacs la replacera au bon endroit.

Emacs indentera la ligne selon deux informations : le contexte syntaxique (si vous êtes au début d’une instruction, au milieu d’un appel de fonction, etc.) et le style sélectionné (par exemple, K&R ou BSD ; voyez mon introduction à la configuration d'Emacs pour plus d’informations).

Comme il peut devenir lassant de devoir appuyer (quoique ce ne soit qu’une seule fois) sur la touche TAB à chaque début de ligne, sachez que vous pouvez aller à la ligne et indenter en une seule commande : C-j (newline-and-indent).

Mais l’indentation d’Emacs ne se limite pas à la ligne actuelle ! Vous pouvez également lui demander d’indenter tout un bloc ou une fonction pour vous. Il s’agit respectivement des commandes C-M-\ (indent-region) et C-c C-q (c-indent-defun), qui indentent la région actuelle (la zone de texte située entre la marque, usuellement apposée par C-SPC, et le curseur) et la fonction dans laquelle se trouve le curseur. En théorie, vous pourriez indenter tout le fichier ainsi, mais je vous le déconseille ; l’algorithme est lent et perd en précision si les constructions sont trop vilaines ou complexes. En revanche, si vous effectuez une modification au milieu d’un bloc, et que, par exemple, vous supprimez un niveau d’indentation, ces commandes peuvent s’avérer très utiles.

Parfois, en revanche, vous voulez aligner des éléments (comme le ferait la touche TAB en temps normal) sans qu’Emacs n’essaie d’indenter la ligne. Pour cela, vous pouvez utiliser la commande M-i (tab-to-tab-stop). C’est le cas, par exemple, si vous alignez vos déclarations ou vos instructions dans un switch.

Pour résumer, voici un tableau des commandes d’indentation et d’alignement :

TAB

indente la ligne actuelle

C-j

retour à la ligne et indentation simultanés

C-M-\

indente la région actuelle

C-c C-q

indente la fonction actuelle

M-i

aligne le curseur sur la prochaine colonne de tabulation

Gestion des commentaires

De même qu’Emacs sait indenter le code automatiquement, il sait insérer des commentaires au bon endroit ; pour se faire, il vous suffit d’actionner la commande M-; (comment-dwim). Que vous soyez sur une ligne vide ou non, Emacs déterminera la syntaxe à adopter. C’est la commande idéale pour ceux qui trouvent les commentaires de type C (/* ... */) trop longs à taper.

De plus, Emacs dispose des commandes de traitement de régions suivantes : comment-region et uncomment-region. Elles sont accessibles par M-x et qui peuvent être associées à une combinaison de votre choix si vous en sentez le besoin. Je vous laisse deviner ce qu’elles font. Elles peuvent être utiles à ceux qui aiment isoler des morceaux de code avec des commentaires (personnellement, je préfère utiliser #if 0).

M-;

insère un commentaire

Déplacements contextuels

Enfin, le c-mode dispose de mécanismes de navigation contextuelle. La plupart des commandes utilisées sont communes à tous les modes d’édition mais leur fonctionnement a été adapté à la structure du code C.

Vous pouvez, comme toujours, vous déplacer de mot en mot avec les habituels M-b (backward-word) et M-f (forward-word).

Juste au niveau supérieur, les commandes C-M-b (backward-sexp) et C-M-f (forward-sexp) vous permettent de sauter d’un bout à l’autre d’expressions équilibrées (un groupe entre parenthèses, crochets ou accolades). En complément, C-M-u (backward-up-list) et C-M-d (down-list) naviguent à travers les niveaux de parenthésage : C-M-u vous amène au début du groupe dans lequel se situe le curseur et C-M-d vous transporte au début du prochain groupe à l’intérieur de l’expression actuelle. Le plus simple est encore de les essayer pour en voir les effets !

Vous pouvez également vous déplacer au début et à la fin des instructions avec M-a (c-beginning-of-statement) et M-e (c-end-of-statement), respectivement.

Enfin, les commandes beginning-of-defun et end-of-defun font, sans surprise, le voyage au début et à la fin d’une définition de fonction.

Récapitulons les commandes directement accessibles :

C-b, C-f

déplacement au mot

C-M-b, C-M-f, C-M-u, C-M-f

déplacement à l’expression (équilibrée)

M-a, M-e

déplacement à l’instruction


Plusieurs fichiers sources

Plusieurs fichiers sources

Édition du code avec le c-mode Gestion de l’historique des modifications avec VC

Avec ce que nous venons juste de voir, nous sommes maintenant capables d’éditer un fichier source C. Toutefois, la plupart des projets ne sont pas constitués d’un seul fichier, aussi, nous allons nous pencher sur la gestion de plusieurs fichiers dans Emacs. Cette section n’est pas directement liée à la programmation en C, mais la question revient fréquemment chez les novices, et c’est pourquoi j’ai décidé de la traiter ici.

Hiérarchies de fichiers

Typiquement, le scénario est le suivant : vous possédez plusieurs fichiers sources regroupés dans un dossier. Quelque chose que beaucoup de gens aiment faire est pouvoir regarder la hiérarchie des fichiers et naviguer de fichier en fichier. Pour cela, Emacs offre deux mécanismes : dired, un explorateur de fichiers, et la speedbar, une barre latérale.

Selon vos goûts, vous préférerez sans doute l’un ou l’autre. Les différences sont multiples : dired possède plus de facilités pour la gestion des hiérarchies de fichiers et de dossiers, avec toutes les fonctions classiques que l’on pourrait attendre d’un explorateur de fichiers, et se présente comme une application Emacs à part entière, utilisant ses propres buffers. À l’opposé, la speedbar s’affiche dans un cadre (frame) à part, et son contenu est constamment recalculé de sorte que le dossier affiché dans la barre soit toujours celui du fichier actuel.

À l’usage, l’un ou l’autre est assez naturel. Pour lancer dired, utilisez la commande C-x d (dired) ou C-x C-f (find-file) avec le chemin d’un dossier. Pour lancer la speedbar, tapez M-x speedbar ; un cadre devrait apparaître à côté de votre cadre principal.

Une fois à l’intérieur de l’un ou l’autre, placez-vous sur un fichier et tapez RET (dired-advertised-find-file ou speedbar-edit-line) pour le visiter. Sous dired, vous avez l’option de visiter le fichier dans une autre fenêtre avec o (dired-find-file-other-window).

Si vous voulez parcourir des sous-dossiers, sachez que dired prône une disposition plane tandis que la speedbar affiche les dossiers et les fichiers sous forme arborescente. Lorsque votre curseur est sur une ligne correspondant à un sous-dossier, tapez i sous dired ou + dans la speedbar (respectivement, dired-maybe-insert-subdir et speedbar-expand-line) pour insérer son listage dans le buffer actuel. Pour supprimer l’affichage d’un sous-dossier, placez-vous sur son en-tête (son chemin, juste au-dessus du listage, pour dired, ou son nom dans l’arborescence, pour la speedbar) et exécutez la commande M-x dired-kill-subdir ou - (speedbar-contract-line), pour dired et la speedbar respectivement. Au lieu de l’effacer complètement, dired vous propose aussi d’utiliser la commande $ (dired-hide-subdir), qui, malgré son nom, permet de cacher et de découvrir le contenu du dossier.

Et comme précédemment, un petit récapitulatif :

dired

speedbar

parcourir un dossier

C-x d

automatique

visiter un fichier

RET

RET

insérer un sous-dossier

i

+

cacher un sous-dossier

$ ou M-x dired-kill-subdir

-

Plusieurs fichiers dans Emacs

Maintenant que vous savez accéder facilement à plusieurs fichiers de votre projet, vous risquez fort d’être vite submergé par le grand nombre de buffers ouverts. Emacs ne dispose pas de tabs (ce n’est pas comme si vous alliez vous servir de votre souris pour y accéder, de toute manière). En revanche, plusieurs modes sont disponibles pour gérer vos buffers. Je ne vais pas tous les passer en revue ici, je ne donnerai qu’une seule solution.

La première commande à connaître pour bien gérer vos multiples buffers est sans doute C-x C-b (list-buffers). Elle démarre le gestionnaire de buffers. Ce dernier se présente comme une simple liste des buffers ouverts. Vous pouvez y effectuer les opérations de navigation habituelles, dont la recherche (avec C-s (isearch-forward) pour les étourdis). RET (Buffer-menu-this-window) vous permet de visiter le buffer à la ligne actuelle. Une autre utilisation très pratique est de supprimer plusieurs buffers à la fois. Pour cela, marquez chaque buffer à détruire avec la commande d (Buffer-menu-delete). La lettre 'D' apparaît alors à gauche du nom. La commande x (Buffer-menu-execute) effectue l’opération de nettoyage en elle-même. Ainsi, si vous vous êtes trompé dans votre marquage, vous pouvez revenir en arrière en utilisant la commande u (Buffer-menu-unmark) sur la même ligne.

Tout cela est bien utile pour faire le ménage mais ne vous aide guère pour votre besoin le plus simple : naviguer de buffer en buffer. Pour cela, il y a bien sûr la commande C-x b (switch-to-buffer) par défaut d’Emacs pour changer de buffer. Mais elle n’est pas très pratique ; en effet, elle demande d’entrer le début du nom pour accéder au buffer. Fort heureusement, il existe (au moins) un mode qui vous permet de changer de buffer en tapant quelques lettres n’importe où dans le nom. Je vous présente là l’iswitchb-mode. Pour l’essayer, il vous suffit d’effectuer la commande M-x iswitchb-mode ; de même pour le désactiver. Pour l’adopter définitivement, ajoutez à votre .emacs la ligne :

(iswitchb-mode t)

La combinaison C-x b invoquera à présent iswitchb-buffer. Si vous l’essayez, vous remarquerez que la liste des buffers qui sont encore candidats à la sélection est maintenant affichée à côté de votre saisie. Dans ce mode, les commandes C-r (iswitchb-prev-match) et C-s (iswitchb-next-match) vous permettent de faire défiler les éléments de la liste de manière cyclique, et RET sélectionne le premier buffer de la liste. Ainsi, vous n’aurez plus à taper le début exact du nom que vous voulez, il vous suffira simplement d’entrer quelques lettres remarquables et, moyennant quelques rotations de la liste, vous arriverez rapidement à destination.

Vous pouvez aussi demander à utiliser des expressions régulières. La commande C-t (iswitchb-toggle-regexp), dans l’iswitchb-mode, vous permet cela. Par exemple, pour obtenir une liste des fichiers C ouverts, vous pourriez utiliser le motif \.c$. Veuillez cependant prendre note du fait que les expressions régulières d’Emacs diffèrent d’autres syntaxes, soyez donc averti et pensez à lire le manuel (avec C-h i (info), par exemple) si vous désirez en faire bon usage.

Avec l’habitude, ce système très flexible remplace avantageusement les tabs. Vous n’êtes plus lié à une liste prédéfinie ; vous avez la possibilité de fabriquer rapidement la vôtre, adaptée à votre requête. Du reste, il vous permettra de même d’aller de buffer en buffer. Et tout cela pour un encombrement nul dans vos autres actions !

Et pour les petits étourdis :

C-x C-b

gestionnaire de buffers

C-x b

change de buffer

C-r et C-s

défilement de la liste (dans iswitchb)

C-t

activation des regexps (dans iswitchb)

Édition simultanée de plusieurs fichiers

Bien sûr, vous n’êtes pas encore capable de vous dédoubler pour éditer plusieurs fichiers à la fois, mais parfois, vous pourriez vouloir afficher deux fichiers (voire plus) côte à côte.

Pour se faire, rien de plus simple. Il vous suffit de partager votre affichage en deux : verticalement avec C-x 2 (split-window-vertically) ou horizontalement avec C-x 3 (split-window-horizontally). Pour passer d’une fenêtre à l’autre, utilisez C-x o (other-window). Enfin, C-x 0 (delete-window) et C-x 1 (delete-other-windows) vous permettent respectivement de supprimer la fenêtre sur laquelle se trouve le focus et de ne laisser qu’elle.

Ainsi, vous pourrez plus facilement comparer ou transférer du code d’un fichier à un autre.

Sachez également qu’il existe des commandes qui marient une action donnée à un changement de fenêtre, telles queC-x 4 f (find-file-other-window) et C-x 4 b (switch-to-buffer-other-window). La première ouvre un fichier, à l’instar de C-x C-f (find-file) mais l’affiche dans une fenêtre séparée. La seconde agit comme C-x b (switch-to-buffer) mais, de même, place le contenu dans une autre fenêtre. Si le cadre n’est constitué que d’une fenêtre, celui-ci est automatiquement scindé en deux.

C-x 2, C-x 3

création de fenêtres

C-x o

déplacement de fenêtre à fenêtre

C-x 0, C-x 1

suppression de fenêtres

C-x 4 f

visite un fichier dans une autre fenêtre

C-x 4 b

affiche un buffer dans une autre fenêtre


Édition du code avec le c-mode Gestion de l’historique des modifications avec VC

Gestion de l’historique des modifications avec VC

Plusieurs fichiers sources

Le dernier outil essentiel à tout projet sérieux est un gestionnaire de versions. Si vous n’êtes pas familier avec ce concept, voici une brève introduction. Vos fichiers seront amenés à grandement évoluer avec les phases d’essai, de correction, d’essais publics, d’amélioration, etc. Il est donc primordial de contrôler ces changements sous forme de versions. Des logiciels spécialisés appelés « systèmes de contrôle de versions » (VCS en anglais) permettent de faire cela. Nous n’entrerons pas ici dans le détail du fonctionnement de ceux-ci, mais le principe général est le suivant : chaque fichier est associé à une copie persistante, qui représente tous ses états depuis le début, toutes ses versions, sous forme de différences. Cela signifie qu’une version n’est pas stockée en entier mais uniquement sous une forme relative à une version voisine. Dans sa réalisation la plus classique, par exemple, si vous ajoutez une ligne à un fichier, le fichier de contrôle, contenant la copie persistante, enregistrera une différence d’une ligne par rapport à la version précédente.

Emacs intègre un support de certains de ces systèmes, dont RCS, CVS, SVN et GNU Arch. Pour illustrer cette intégration, qui porte le petit nom de VC pour, vous l’aurez deviné, Version Control, nous allons nous intéresser au plus simple d’entre eux : RCS. Mais les commandes demeurent approximativement les mêmes quel que soit le programme de gestion de versions.

Traditionnellement, les fichiers de contrôle de RCS sont stockés localement dans un sous-dossier de celui où se situent vos fichiers sources, ce sous-dossier portant le nom RCS. Si vous ne le créez pas par vous-même, Emacs vous le proposera en temps voulu.

L’utilisation de VC repose sur la commande C-x v v (vc-next-action). Comme son nom l’indique, elle fait… des choses, selon l’état actuel du fichier. Avec RCS, un fichier peut avoir plusieurs états. Dans son utilisation classique, ce sont les suivants.

  1. Au départ, le fichier est inconnu de RCS. Lorsque vous l’enregistrez auprès de ce dernier (avec C-x v v), celui-ci s’approprie le contenu. Le fichier et la version la plus récente connue de RCS sont alors les mêmes.

  2. À ce stade, vous ne pouvez pas modifier le fichier à nouveau. Il vous faut prévenir RCS de votre intention, ceci afin d’empêcher que plusieurs personnes ne modifient le même fichier en même temps. Cette action s’appelle le verrouillage et s’effectue aussi par C-x v v. Une fois le fichier verrouillé, vous êtes sûr qu’il est la seule copie de travail existante.

  3. Une fois vos modifications effectuées, C-x v v synchronise votre brouillon avec la copie de contrôle. VC vous demande alors de fournir un commentaire décrivant les changements, commentaire qui sera inscrit dans une espèce de journal de bord du fichier. La fenêtre d’édition du message est tout à fait banale et la validation est obtenue par le traditionnel C-c C-c, valable pour la plupart des formulaires sous Emacs. Après cette étape, le fichier et la version la plus récente connue de RCS sont à nouveau les mêmes.

Tout ceci est bien joli, mais à quoi serviraient un historique et un journal que l’on ne peut consulter ?

La commande C-x v ~ (vc-version-other-window) vous permet d’accéder au contenu d’une version antérieure de votre fichier. Le numéro de la version vous sera demandé. Mais que faire si vous ne vous rappelez plus de la bonne version ? C’est à cela que servent les commentaires que vous avez pris soin d’entrer tout au long de votre travail ! Pour voir la liste des versions ainsi que les messages associés, tapez C-x v l (vc-print-log).

Une fois la version voulue récupérée dans un buffer secondaire, vous pouvez afficher les deux buffers en parallèle comme nous avons vu précédemment. Mais VC propose une commande intéressante pour vous aider à voir les différences entre vos versions : C-x v = (vc-diff). Elle vous propose une comparaison rapide de deux versions, avec la différence placée dans un buffer à part.

Cela peut sembler beaucoup de choses à enregistrer si vous n’avez jamais utilisé de VCS auparavant, mais j’ai moi-même débuté dans ce domaine avec VC qui est, à mon avis, un moyen simple de se familiariser avec le concept tout en restant bien au chaud dans son éditeur préféré. Et pour vous y aider, voici un… récapitulatif ! Avouez que vous ne vous y attendiez pas.

C-x v v

change d’état

C-x v ~

ressuscite une version

C-x v l

invoque la liste des versions

C-x v =

compare deux versions

Cette présentation de VC et de RCS achève ce premier article. Dans le prochain chapitre, nous parlerons de la compilation de fichiers et de projets écrits en C, à l’aide de makefiles, le tout depuis Emacs. Contrairement à ce premier tutoriel, il sera bien moins porté sur Emacs lui-même que sur les outils à mettre en œuvre pour compiler depuis Emacs, c’est-à-dire GCC et make.


Plusieurs fichiers sources