close
  • chevron_right

    `smk`, un make sans Makefile

    Adrien Dorsaz – Tuesday, 11 December - 06:10

ou "comment créer un outil de compilation à partir d'un outil de debug": une boucle est bouclée :D


  • chevron-right

    `smk`, un make sans Makefile

    Sommaire Au début était la flemme… D'accord, mais on fait comment? Et à l'usage, ça ressemblerait à quoi smk? Première invocation Deuxième invocation C'est maintenant le tour de passe-passe? Il ne te reste plus qu'a l'essayer Quelques caractéristiques fun Y-a-quoi dans la boite? Et pour faire le ménage? Après la frappe chirurgicale, le build chirurgical Prends toutes les options, c'est le même prix Un peu d'histoire Le plan de développement à court terme Et toi dans tout ça? En savoir plus Au début était la flemme… Ça fait bien longtemps que je me dit que quand j'écris un Makefile, je travaille trop. Si on considère cet exemple : main.o : main.c hello.h gcc -o main.o -c main.c Le kernel sait parfaitement que ma commande gcc -o main.o -c main.c lit main.c, et écrit main.o. Et donc que si main.c change, je dois recompiler, et si main.o n'est pas là, idem. Et pareil pour les dépendances entre commandes. Mieux encore, le kernel sait que gcc a également lu tout un tas d'autre .h ou .c, il connait donc mieux les 'prerequisite' de main.o que moi. Alors, pourquoi devrais-je écrire tout ça dans le Makefile? Évidemment, il existe des solutions qui insèrent automatiquement dans le Makefile les dépendances aux "includes", ou des systèmes qui surveillent les mise à jour du file system pour déclencher ou préparer des lancements de build. Mais je n'ai pas vu de système simple et universel, qui ne demande rien à l'utilisateur si ce n'est les commandes à exécuter (ce qui est un peu le minimum, sauf à ce que l'outil fasse dans la médiumnité pour deviner ce que veut l'utilisateur). Note au passage : si j'ai raté un projet existant de ce type, merci d'avance pour vos références! C'est là que né l'idée séminale du projet smk : et si on essayait de faire un make un peu intelligent (sans mépris pour son fantastique ancêtre), à qui on ne donnerait que des commandes type gcc -o main.o -c main.c, et qui se débrouillerait pour comprendre par lui même les entrées, les sorties et les dépendances? Smk, c'est "Simple Make", j'ai pas été cherché loin. Mais c'est tellement ça. D'accord, mais on fait comment? Sur Linux, le kernel offre depuis belle lurette une interface pour tracer tout un tas de chose: ptrace. (Je développe sous Linux, alors je ne parle que pour Linux, mais il y aurait des équivalents laissant espérer un portage pas trop galère sur pas mal d'autres OS). Et même plus simple que ptrace, et suffisant pour ce qu'il est convenu d'appeler un POC, il y a l'outil strace. strace est surtout utilisé à des fins d'analyse ou de debug, mais après tout, pourquoi ne pas le sortir un peu de ses rails? Alors l'idée, c'est juste de demander à strace de lancer les commandes du smkfile en espionnant les opérations sur les fichiers, et d'analyser ensuite le log pour déduire des opérations de "read" les fichiers sources, et des opérations de "write" les fichiers cibles. Sur le papier, ça à l'air simple, hein? Mais l'expérience t'apprend que quand ça à l'air simple, ça veut juste dire que c'est le début. (Houla, je suis en forme! Note la bien celle là, on dirait du Sénèque à sa sortie de l'Epitech) Et à l'usage, ça ressemblerait à quoi smk? Je vais me servir d'un petit exemple tiré du tuto, un classique Makefile avec trois compilation : all : hello hello.o : hello.c gcc -o hello.o -c hello.c main.o : main.c hello.h gcc -o main.o -c main.c hello : hello.o main.o gcc -o hello hello.o main.o Note que smk ingère ce fichier tel quel (smk sait lire des Makefile simple). Mais, me diras-tu, si il faut écrire ça pour l'utiliser, je ne vois pas bien l'intérêt, autant utiliser make. En effet! La promesse de smk, c'est de réduire le Makefile au strict minimum, et voici donc le smkfile correspondant: gcc -o hello.o -c hello.c gcc -o main.o -c main.c gcc -o hello hello.o main.o Au niveau ménage, je dirai qu'on est pas mal : on ne peut pas retirer grand chose de plus sans taper dans l'indispensable! Appelons ce smkfile mybuild.txt et allons-y. Première invocation > smk mybuild.txt gcc -o hello.o -c hello.c gcc -o main.o -c main.c gcc -o hello hello.o main.o Jusque là tout va bien. Deuxième invocation > smk Nothing to run OK, c'est bien ce que ferait make. Note que je ne précise plus le nom du smkfile. smk garde la trace de ce qui a été exécuté dans ses runfiles (fichiers .smk.* dans le répertoire courant). Si il n'y a eu qu'un seul run dans ce répertoire, pas d'ambiguïté, donc pas besoin de préciser. C'est maintenant le tour de passe-passe? > touch hello.c > smk gcc -o hello.o -c hello.c gcc -o hello hello.o main.o Ah ouais, c'est bien comme make, alors qu'on a pas décrit la moindre "target" ou la moindre "recipe". Mais attends, je ne comprends pas : un tuto? des exemples? Tu veux dire que ça tourne déjà?? Je te l'avais dit que tu ne regretterais pas d'être resté! Il ne te reste plus qu'a l'essayer Inutile de te dire que je n'en suis pas à packager ou à dockeriser smk, va falloir faire à ça l'ancienne. Heureusement, ça reste simple. Il faut juste un gcc Ada:apt install gnat (ou ce qui va bien sur ta distro), ou bien télécharge GNAT ici (il s'installera alors sous /opt). Puis : git clone https://github.com/LionelDraghi/smk.git cd smk gprbuild -P smk.gpr Et ensuite, direction le tuto! Quelques caractéristiques fun Y-a-quoi dans la boite? Maintenant que ça a tourné, tu aimerais peut-être savoir ce que smk a compris et stocké de la situation, en terme de commandes, sources et cibles. Note au passage que ce sont les seuls concepts: il n'y a pas besoin de 'recipes' pour faire le lien entre les sources et les cibles, la commande est le lien. Il y a une option pour ça: > smk -rl (read previous runs) 2018-12-10 22:15:39.30 [hello] gcc -o hello hello.o main.o Sources (2) : - 2018-12-10 22:15:39.00:/home/lionel/Proj/smk/tests/hello.c/hello.o - 2018-12-10 22:15:39.00:/home/lionel/Proj/smk/tests/hello.c/main.o Targets (1) : - 2018-12-10 22:15:39.00:/home/lionel/Proj/smk/tests/hello.c/hello 2018-12-10 22:15:39.08 [hello.o] gcc -o hello.o -c hello.c Sources (1) : - 2018-12-10 22:15:38.00:/home/lionel/Proj/smk/tests/hello.c/hello.c Targets (1) : - 2018-12-10 22:15:39.00:/home/lionel/Proj/smk/tests/hello.c/hello.o 2018-12-10 22:15:39.19 [main.o] gcc -o main.o -c main.c Sources (2) : - 2018-11-14 23:14:17.00:/home/lionel/Proj/smk/tests/hello.c/hello.h - 2018-12-07 00:41:31.00:/home/lionel/Proj/smk/tests/hello.c/main.c Targets (1) : - 2018-12-10 22:15:39.00:/home/lionel/Proj/smk/tests/hello.c/main.o Elle donne pour chaque commande, l'heure d’exécution, et la liste des sources et des cibles avec la date de modification de chaque fichier. Et pour faire le ménage? Comme smk connait toutes les cibles, fini les multiples rm -rf dans les sections clean des Makefile, smk s'en charge: > smk --clean Deleting /home/lionel/Proj/smk/tests/hello.c/hello Deleting /home/lionel/Proj/smk/tests/hello.c/hello.o Deleting /home/lionel/Proj/smk/tests/hello.c/main.o Après la frappe chirurgicale, le build chirurgical Toujours parce que smk connait toutes les cibles, un build particulier sera aussi simple que > smk hello.o ("sera", parce que ça, je ne l'ai pas encore implémenté. Mais tu l'auras pour Noël, promis!) Et ça pourra être n'importe lequel des fichiers cibles (liste que l'on obtient par > smk -lt (--list-targets)). Pratique, non? Prends toutes les options, c'est le même prix Bien sûr, smk s'efforce de rendre les fonctions essentielles de make, avec si possible le même nom d'option (inspirés soit de make, soit de mk):-k (keep-going), -n (dry-run), -e (explain), etc. Un peu d'histoire L'idée est resté en sommeil pendant pendant longtemps, parce que l'aspect trifouillage des appels au kernel ne me tentait pas trop, j'imaginais ça très compliqué. Mais en fait, dès les premières recherches, je suis tombé sur l'outil idéal même si fait pour des fonctions plus classiques de debug et de d'espionnage, strace. C'est ainsi qu'est né en moins de deux semaines la première version utilisable de ce POC (la v0.0.2). Finalement, j'ai galéré là ou je ne pensais pas (problème de précision de la date de modification de fichier dans mon environnement de dev. GNAT), et au contraire, j'ai été assez vite là ou j'anticipais une galère (interprétation de la sortie de strace pour classifier un accès fichier en 'read' ou en 'write'). L'aventure à commencé il y a tout juste un mois, mais j'ai déjà eu quelques retours qui me font penser que l'idée ira au-delà de ce "POC". Et toi, t'en dit quoi? Le plan de développement à court terme Mon intention est d'aller vers la prise en compte de besoins un peu plus complexes. Ce que j'ai aujourd'hui dans le radar: la prise en compte d'objectifs différents, voir même antagonistes dans le même fichier: actuellement, si tu veux un build prod et un build debug, il faut faire deux smkfile. Et on a pas toujours envie de multiplier les fichiers, alors je suis parti pour implémenter un mécanisme de "sections", avec une syntaxe à la make: section1 : commande 1 commande 2 section2 : commande 1 commande 2 etc. Que l'on pourra invoquer avec un: > smk section2: la "récursion": si on veut que le build de prod et le build de debug exécutent la même suite de tests, alors il serait bon que l'on puisse dans un smkfile en invoquer un autre. Ce sera alors fait en appelant smk autrefichier.txt, et non par une syntaxe d'include particulière, car je veux que le format du smkfile reste simple. Et quoi de plus simple que juste ce que l'on aurait tapé sur la ligne de commande? les cibles sans cibles, comme rm main.o. Clairement pour moi, la cible n'est pas le fichier, c'est l'effacement. A discuter. Mais bien sûr si je publie ceci, c'est pour avoir des réactions, des idées, des envies, et surtout des utilisateurs (voire même des contributeurs!). Et vos retours peuvent grandement changer mes plans. Alors, en ce qui concerne le plan de dev, demain est un autre jour. Et toi dans tout ça? Cette v0.1.0 me semble d'ores et déjà utilisable, et je suis curieux d'avoir des retours sur le concept. Et de savoir ce que serait ton "dream-product". Juste une précision, afin de cadrer le débat : smk n'a pas vocation à faire tout ce que fait make ou un système de build sophistiqué. Mais en revanche je pense qu'il y a un créneau d'application assez large, tout en respectant son ADN : universel et très simple. Merci d'y penser avant de me sortir tous les truc magiques que tu fait avec des Makefiles imbitables! :-) En savoir plus Sur le site de smk, tu trouveras diverses choses utiles, comme (en vrac) les tests, des indications sur le format du fichier texte en entrée (baptisé logiquement smkfile), la compatibilité de ce format avec celui des Makefile, une petite comparaison smk/make, des discussions sur le design, etc. C'est un POC, mais ce n'est pas une raison pour ne pas faire les choses biens! Les sources sont disponibles sur https://github.com/LionelDraghi/smk/, que tu peux utiliser pour remonter tes idées, bugs, remarques… Last but not least, smk est sous Apache 2.0. Télécharger ce contenu au format Epub Commentaires : voir le flux atom ouvrir dans le navigateur

    group_work LinuxFRJournaux 10 December