dimanche 17 février 2013

Make, ou de la pilosité faciale.

Je suis passé sur Windows 7 sur mon laptop de travail, entrant ainsi dans l'ère de la modernité. Cette réinstallation m'a poussé à repenser ou rationaliser ma boite à outils. Je suis revenu aux fondamentaux : Cygwin, vim en mode texte, openssh... et make.

Car oui, je commence à utiliser ce bon vieux (GNU) make pour tout et n'importe quoi... Peut-être que certains d'entre vous ne connaissent pas, ou peu, ce monument du monde Unix alors ça me fait une belle occasion de blogguer.

À la base, make est utilisé pour lancer un ensemble de commandes. Toutefois attention : on ne veut pas que ces commandes soient lancées inutilement. Si des commandes sont censées produire un fichier cible à partir de fichiers sources, comme par exemple un exécutable à partir des sources, on ne va pas regénérer la cible si celle-ci est plus récente que les sources : il n'y a pas de raison de dépencer du CPU pour ça. C'est toute la beauté de make : il cherche à en faire le moins possible !

Les présentations sont faites, décrivons à présent le fonctionnement de make. Make utilise un fichier décrivant les actions à réaliser (on appelle ça des règles dans le jargons des barbus). Traditionnellement, on utilise un fichier nommé Makefile, qui a la bonne idée d'être automatiquement analysé lorsque la commande make est lancée. Dans ce fichier Makefile, les règles sont organisées de la façon suivante :

cible: dépendance
<tab>commande1
<tab>commande2
<tab>...

<tab> représente ici un caractère tabulation. Pas 4 espaces les gars, un bon gros tab, alors attention à vos éditeurs...

Bref, un exemple de la vraie vie pour compiler un .c super compliqué et closed source.

hello: hello.c
    gcc -o hello hello.c

Lorsque vous lancez make avec ça dans un Makefile, l'outil va vérifier que hello.c a une date de modification plus récente que hello et va lancer gcc si c'est le cas. Dans le cas contraire, il vous dira qu'il n'a rien à faire. Il ne perd pas son temps. Et vous non plus.

Vous pouvez également faire des actions en cascade comme dans l'inutile exemple ci-dessous :

hello: hello.o
    gcc -o hello hello.o

hello.o: hello.c
    gcc -c hello.c

Ci-dessus, hello dépend de hello.o. Alors il va chercher à construire hello.o. Quelle chance : il y a une règle qui fait ça à partir de hello.c. Il génère donc le .o puis notre bel exécutable.

Dernière chose, quand vous lancez make sans lui spécifier de cible, il va prendre la première règle de fichier. C'est tout.

Il s'agit d'un exemple de base : l'outil possède plein de petites subtilités desquelles vous pourrez vous délecter en lisant le putain de manuel. Genre :

  • Utiliser des variables
  • Réutiliser des variables du shell
  • Donner n'importe quoi comme nom de cible (pas forcément un nom de fichier, comme all ou clean)
  • Utiliser des racourcis crypto cabalistiques de barbus pour définir vos règles, comme *.o:*.c, $@, $^,...

(ça ne sert à rien de faire ce listing car vous êtes déjà devant le man make ;  c'est juste pour montrer que je ne suis pas un n00b de base, que je connais quelques trick. Ha ha, vous rigolez moins les barbus, hein ?)

Cette semaine, je n'ai pas du tout utilisé le bousin pour faire de la compilation mais simplement pour envoyer des fichiers shell (de merde) sur le serveur en utilisant scp. Pour que ça ne prenne pas trop de temps, je me suis démerdé pour que make n'envoie que les fichiers qui ont été modifiés. Trop dur, ça donne ça :

# ici, c'est la première règle : elle dépend de toutes les règles que je veux
# lancer. Belle astuce.
all: .fichier1.tmp .fichier2.tmp

.fichier1.tmp: fichier1
    scp fichier1 user@server:/repertoire/destination
    @touch .fichier1.tmp

.fichier2.tmp: fichier2
    scp fichier2 user@server:/repertoire/destination
    @touch .fichier2.tmp

Plus qu'à lancer la commande :make dans vim qui a le bon gout de lancer make par défaut, et là je me relaxe... Pendant que j'y pense, j'aurai pu bricoler un script de test à lancer derrière...

Il y a besoin d'explication ? On fait un touch sur un fichier temporaire si le scp réussi (si une commande plante -retourne autre chose que 0-, make arrète son exécution). Et oui les enfant, touch ne sert pas qu'à créer les fichiers, il met aussi à jour la date de modification des fichiers existants.

Plus d'infos sur make :