Journal `smk`, un make sans Makefile

Posté par  (site web personnel) . Licence CC By‑SA.
Étiquettes :
68
11
déc.
2018

Sommaire

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.

  • # Bravo pour le concept et le "hack" de strace !

    Posté par  (site web personnel, Mastodon) . Évalué à 9. Dernière modification le 11 décembre 2018 à 07:08.

    Hello,

    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.

    Le concept me semble hyper sain, ça à l'aire chouette à utiliser :)

    Il reste que les commandes devront inclure de longs arguments comme dans Make pour ajouter toutes les dépendances externes dans les premières commandes.

    Est-ce que tu prévois d'ajouter la définition de variables pour pouvoir raccourcir l'écriture des premières commandes qui devront inclure les bibliothèques externes ?

    Dans tous les cas, je trouve géniale l'idée de "hacker" (dans le sens propre du terme) un outil de débug pour aider à la compilation: j'ai l'impression qu'une boucle est bouclée et que l'on ne saura plus à terme qui est de l'oeuf ou de la poule la première étape d'une compilation de projet :D

    • [^] # Re: Bravo pour le concept et le "hack" de strace !

      Posté par  (site web personnel) . Évalué à 5. Dernière modification le 11 décembre 2018 à 10:19.

      Merci Adrien pour ta super appréciation sur l'idée!

      Mon intention est de limiter au maximum le travail fait pour être compatible avec un shell file ou un Makefile.
      Mais j'ai posté ce journal exactement pour avoir ce genre de retour.

      Je suppose que tu fait allusion aux lignes du genre:

      CFLAGS=-W -Wall -ansi -pedantic
      

      Oui, je ne suis pas sûr de pouvoir passer au travers.
      J'y ai réfléchi, et la partie substitution de variable n'est pas si compliquée, je créé une entrée dans github pour m'y atteler pendant les vacances de Noël!

      • [^] # Re: Bravo pour le concept et le "hack" de strace !

        Posté par  (site web personnel) . Évalué à 5.

      • [^] # Re: Bravo pour le concept et le "hack" de strace !

        Posté par  (site web personnel, Mastodon) . Évalué à 2.

        En fait, je pensais aux arguments -I pour inclure les headers et -l pour faire les liens avec gcc, car selon le nombre de dépendance externe ça peut vraiment faire de grandes lignes de commandes.

        Par exemple, pour un tout petit projet que je viens de commencer, je vois que ninja exécute déjà ce genre de commande:

        [1/2] c++ -Isrc/src@@ibex@exe -Isrc -I../../code/Ibex/src -I/usr/include/gtkmm-3.0 -I/usr/lib/x86_64-linux-gnu/gtkmm-3.0/include -I/usr/include/atkmm-1.6 -I/usr/include/gtk-3.0/unix-print -I/usr/include/gdkmm-3.0 -I/usr/lib/x86_64-linux-gnu/gdkmm-3.0/include -I/usr/include/giomm-2.4 -I/usr/lib/x86_64-linux-gnu/giomm-2.4/include -I/usr/include/pangomm-1.4 -I/usr/lib/x86_64-linux-gnu/pangomm-1.4/include -I/usr/include/glibmm-2.4 -I/usr/lib/x86_64-linux-gnu/glibmm-2.4/include -I/usr/include/at-spi2-atk/2.0 -I/usr/include/at-spi-2.0 -I/usr/include/dbus-1.0 -I/usr/lib/x86_64-linux-gnu/dbus-1.0/include -I/usr/include/gtk-3.0 -I/usr/include/gio-unix-2.0/ -I/usr/include/libdrm -I/usr/include/harfbuzz -I/usr/include/pango-1.0 -I/usr/include/fribidi -I/usr/include/atk-1.0 -I/usr/include/cairomm-1.0 -I/usr/lib/x86_64-linux-gnu/cairomm-1.0/include -I/usr/include/cairo -I/usr/include/pixman-1 -I/usr/include/uuid -I/usr/include/freetype2 -I/usr/include/libpng16 -I/usr/include/sigc++-2.0 -I/usr/lib/x86_64-linux-gnu/sigc++-2.0/include -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/libsecret-1 -I/usr/include/libsoup-2.4 -I/usr/include/libxml2 -I/usr/include/libxml++-2.6 -I/usr/lib/x86_64-linux-gnu/libxml++-2.6/include -fdiagnostics-color=always -pipe -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -Wnon-virtual-dtor -std=c++17 -g -pthread  -MD -MQ 'src/src@@ibex@exe/main.cpp.o' -MF 'src/src@@ibex@exe/main.cpp.o.d' -o 'src/src@@ibex@exe/main.cpp.o' -c ../../code/Ibex/src/main.cpp
        

        Je vais essayer de configurer smk sur ce projet pour voir ce que ça donne en vrai: peut être que finalement ce ne sera que les quelques premières commandes qui vont vraiment nécessiter de configurer tous ces paramètres, puisque, pour les commandes suivantes, les arguments sont "devinés".

    • [^] # Re: Bravo pour le concept et le "hack" de strace !

      Posté par  (site web personnel) . Évalué à 5.

      J’applaudis aussi des deux mains et des deux pieds ! Justement, ça faisait un moment que je saturais des outils de “build” modernes qui soit se limitent à un langage, soit ont une détection des dépendances catastrophique malgré leurs promesses. En comparaison, je trouve l’idée de smk vraiment bonne.

      La seule limitation que j’y vois pour que je me mette à l’utiliser, c’est la gestion des profils. J’imagine qu’entre ce que l’auteur présente dans le texte avec ses « sections » et des substitutions de variables, il sera à terme possible de très bien s’en sortir. En attendant, je n’écris quasiment jamais les Makefile à la main, mais c’est un script « ./configure » qui l’écrit, en le paramétrant en fonction du système et d’options (compilateur trouvé, bibliothèques disponibles). Un tel paramétrage peut être envisagé avec des variables dans le « smkfile » et éventuellement des sections (qui pour les cas simples remplaceraient même complètement le « ./configure »).

      En tout cas, super idée, super outils ! Je suis impatient de voir la suite.

  • # seulement pour du C ?

    Posté par  . Évalué à 3.

    Est-ce que ça marche avec un langage autre que le C ? Fortran par exemple.

    • [^] # Re: seulement pour du C ?

      Posté par  (site web personnel) . Évalué à 8.

      Hello Jean-Baptiste,

      la force de l'outils, c'est qu'il est complètement indépendant des commandes exécutées.

      Il n'a pas la moindre idée de ce qui est compilé, il ne sait même pas si c'est de la compilation, et c'est tout à fait ce que je veux.
      Il fonctionne donc aussi bien avec Fortran qu'avec n'importe quel langage y compris pas encore inventé (sauf à ce que les sources ne soient pas dans des fichiers).
      J'ai utilisé un build typique C, mais c'est par facilité parce que c'est ce que l'on trouve dans tout les tutos de make.

      En fait, je suis aussi preneur d'autres scripts que vous auriez, pour varier mes exemples et mes tests, comme par exemple la production de sites web, ou de documents, type:

      latex <file>.tex
      dvips <file>.dvi
      ps2pdf <file>.ps
      pdf2eps <pagenumber> <file>

      • [^] # Re: seulement pour du C ?

        Posté par  . Évalué à 1. Dernière modification le 11 décembre 2018 à 10:05.

        Ok, merci de la réponse. Donc je vais relire plus attentivement car je n'ai manifestement pas tout compris. Ensuite j'essaierai de tester. :-)

      • [^] # Re: seulement pour du C ?

        Posté par  (site web personnel) . Évalué à 7.

        Puisque tu parles de latex, voilà ce que j'ai systématiquement dans mes Makefile, pour recalculer les indexes de page :

        # Generate each pdf with latex
        tmp/%.pdf: tmp/%.tex | tmp
            $(TEX) -output-directory tmp $<
            while grep 'Rerun to get ' tmp/$*.log ; do $(TEX) -output-directory tmp $< ; done

        Dans ta syntaxe, cela veut dire qu'il me suffit de mettre directement la boucle while dans le script ?

        • [^] # Re: seulement pour du C ?

          Posté par  (site web personnel) . Évalué à 1.

          Malheureusement, ça ne marchera pas, car smk ne sait pour l'instant lancer que des commandes. Or, là, c'est du shell…

          Lancer un shell réglerait ce problème et pas mal d'autres, mais j'hésite à cause des perfs.

          • [^] # Re: seulement pour du C ?

            Posté par  (site web personnel) . Évalué à 2.

            Tu risques de ne pas pouvoir y couper, c'est généralement le truc qui permet de résoudre un problème qui déborde des capacités de l'outil. Si pour tout le reste l'outil apporte un plus lisible et efficace… au pire, si le «truc» revient souvent, c'est un élément pour indiquer qu'il faudrait ajouter quelque chose nativement dans l'outil.

            Python 3 - Apprendre à programmer dans l'écosystème Python → https://www.dunod.com/EAN/9782100809141

            • [^] # Re: seulement pour du C ?

              Posté par  (site web personnel) . Évalué à 1.

              Oui, je suis d'accord sur la politique générale: offrir un voie pour permettre de faire tout ce que tu n'as pas envie de prendre en compte directement permet de ne pas bloquer l'usage de l'outils à cause d'une impossibilité fonctionnelle.

              Je vais garder le cas d'usage du re-run de Latex de chimrod dans la whish list, auquel j'essaierai surement d'arriver par des étapes plus simples.

        • [^] # Re: seulement pour du C ?

          Posté par  . Évalué à 1.

          J'allais poser la même question à propos de LaTeX.

          Perso, j'ai cela dans mes Makefile avec LaTeX :

          include LaTeX.mk

          L'outil en question est un gros truc compliqué en Makefile et LaTeX (.sty) qui (tente de) détecte(r) les dépendances automatiquement en détournant les commandes "include/input/…" de LaTeX. Il y a longtemps que j'envisage ta solution (strace) sans avoir le courage de le faire (le code actuel fonctionne suffisamment bien pour mes besoins).

          Mais, pour LaTeX, on doit gérer en plus les recompilations et les lancements d'outils externes (bibtex, makeindex, …) après une (ou plusieurs) compilation(s) initiale(s). LaTeX-Make tente de le faire avec différents hacks, mais ce n'est pas très propre (et je n'ai pas d'idée de comment rendre cela propre).

  • # Au début était la flemme…

    Posté par  . Évalué à 10.

    Au début était la flemme…

    Pour moi, c’est la compétence ultime du bon développeur. Il doit être flemmard. Maximiser le ratio travail machine / travail humain. Avoir du temps à investir pour avoir plein de temps à faire autre chose après.

    On construit des machines ultra-puissantes qui ne font rien. Soyons flemmard, laissons-les en faire plus.

    • [^] # Re: Au début était la flemme…

      Posté par  . Évalué à 10.

      Larry Wall (papa de Perl) le dit très bien (et je le cite régulièrement) : un bon programmeur a trois qualités :

      1. La paresse : s'il faut faire plus d'une fois un traitement similaire, autant l'automatiser.
      2. L'impatience : le soft ne va pas assez vite, ou ne devine pas suffisamment à l'avance ce que je veux faire. Il va falloir améliorer ça.
      3. L'orgueil : lorsqu'on lui signale un bug, le bon programmeur prendra ce bug comme une offense, et ira le corriger aussi vite et bien que possible.
      • [^] # Re: Au début était la flemme…

        Posté par  . Évalué à 6.

        Comme le journal évoque Sénèque, voir aussi son L’Oisiveté. J'ajoute un journal dédié au thème, The Idler ! Ici par exemple, on attribue ceci à Bill Gate : “[…]an unwritten rule attributed to Bill Gates from the software industry: hire lazy programmers. Why? Lazy programmers will figure out the smartest way to get something done to avoid having to do it.”

    • [^] # Re: Au début était la flemme…

      Posté par  . Évalué à 3. Dernière modification le 11 décembre 2018 à 15:14.

      nimage

      Saloperie de xkcd, il a insinué le doute en moi :)

      • [^] # Re: Au début était la flemme…

        Posté par  . Évalué à 6.

        il y a aussi cet autre xkcd et ce commitstrip sur le même sujet.

      • [^] # Re: Au début était la flemme…

        Posté par  . Évalué à 6.

        C'est vrai, MAIS : le problème est qu'on ne parle pas que d'une tâche qu'on automatise, mais d'un ensemble de tâches au fil de l'eau. Il faudra ainsi additionner le nombre de tâches qu'on répète plusieurs fois dans la journée/le mois/l'année et leur durée pour réellement identifier ce que la somme agrégée nous coûte en temps.

        Il faut aussi considérer l'aspect énervement/agacement/fatigue (mentale ou physique) à devoir répéter les mêmes tâches, parfois fastidieuse (même si possiblement rapide) plusieurs fois dans la journée, même s'il s'agit de « micro-tâches », car elles coûtent aussi en « context switch ».

        (bon sinon j'aime bien ce xkcd :-))

        • [^] # Re: Au début était la flemme…

          Posté par  . Évalué à 1.

          Pour le premier point ça reste linéaire

        • [^] # Re: Au début était la flemme…

          Posté par  . Évalué à 0.

          Je remarque que ce genre de phénomène relativiste touche aussi les bidouilleurs/constructeurs, il est souvent mis en parallèle le coût/gain d'un dispositif clé en main +- positif à celui produit en partant de zero ou issu de plusieurs récupèrations de matériaux (recyclage, conversion) + le temps de conception dont le tout serait à priori négatif.

          Or je trouve que les 2 activités, automatisation ou reconditionnement pour nouvelle application, apportent autant un enrichissement intellectuel que "matériel" et ce bénéfique sur le long terme.

          Bref, faites vous plaisir!

  • # Yet another build system

    Posté par  (site web personnel) . Évalué à 7. Dernière modification le 11 décembre 2018 à 10:27.

    Tu peux récupérer les dépendances aux headers via le compilateur, par exemple avec gcc -M et gcc -MM
    Cf. https://stackoverflow.com/a/2394651/518853

    J'avoue que j'ai du mal à voir l'intérêt du projet (si ce n'est pédagogique, et ça c'est toujours bien). Les cas où on se farcit toutes les commandes pour compiler un binaire en spécifiant indépendamment les .o sont rares. En général tu utilises plutôt les fonctions de remplacement de make pour créer des règles génériques (voilà comment transformer des .c en .o, et tel binaire a besoin de tels fichiers .c, et voilà comment déduire les headers nécessaires).

    Je te conseille de regarder un peu du côté de Ninja, même si les fichiers de règles de ce dernier n'ont pas vocation à être écrites à la main, mais plutôt via un build system comme CMake ou Meson.

    • [^] # Re: Yet another build system

      Posté par  . Évalué à 8.

      Tu peux récupérer les dépendances aux headers via le compilateur, par exemple avec gcc -M et gcc -MM

      Yep il peux et si demain il veux utiliser le même système de build pour utiliser lex/yacc, javac, ou autre, il n'a pas à se farcir 50 pages de man pour savoir comment gérer les dépendances ;)

      le système est simple : pour générer truc, le système à touché à machin, bidule, pika, plop, gong. Les dépendances sont donc ( machin, bidule, pika, plop, gong).

      Moi j'aurai plus des questions d'ordre :

      • en cas de recompilation le système refait il aussi un calcul de dépendance
      • quel est l'overhead de l'analyse des dépendance

      Il ne faut pas décorner les boeufs avant d'avoir semé le vent

      • [^] # Re: Yet another build system

        Posté par  (site web personnel) . Évalué à 3.

        Hello, pas sur de comprendre ta question le calcul de dépendance, tu parles bien du cas ou l'output d'une commande invalide l'input d'une autre?

        Dans ce cas, oui, c'est fait.

        L'implémentation est naïve aujourd'hui, car je n'ai pas implémenté de graphe de dépendance.
        C'est fait ainsi : je parcours la liste des commandes, si l'une d'entre elle est exécutée, alors je re-parcours toute la liste. Quand plus aucune commande n'est exécutée, je sors.

        Pour éviter des cas pathologiques de dépendances récursives, le nombre de boucles est limité au nombre de commande, qui est le max du worst-case.

        Pas forcément optimal en terme de perf, mais tellement plus simple à coder dans un premier temps.

        Sur le second point, justement l'overhead, pas encore de mesure à ce point. Mais vu que vous êtes plusieurs à poser la question, je ferai un "time" comparatif d'un Makefile et d'un smkfile équivalent
        (j'ai créé une issue sur GitHub).

    • [^] # Re: Yet another build system

      Posté par  (site web personnel) . Évalué à 3.

      oui, on m'a déjà fait des retours de ce type (je crois même que c'est l'issue #1 sur GitHub!).

      Je ferai une section "hints", donnant quelques commandes habituelles pour générer les dépendances, c'est toujours intéressant, mais ce sera pour mieux préciser que ce n'est pas la cible de smk.

      Je ne prétends pas faire mieux qu'un outil dédié qui recompile ce qui doit l'être (comme gprbuild que j'utilise pour le code de smk), et qui peut même faire une analyse sémantique des sources et ne pas recompiler si par exemple seul les commentaires ont étés modifiés.

      L'idée est plutôt d'optimiser des enchaînements de commandes plus simple (le make complexe de compilation pouvant d'ailleurs être une de ces commandes), avec un outil universel (non dépendant de la sémantique de ce qui est construit).

      Cela montre l'urgence d'avoir dans ma doc d'autres exemples que du build gcc!

      Est-ce que tu vois un intérêt à l'outil pour des choses autres, que tu traiterais par exemple par shell script?
      (et merci en tout cas pour le retour)

    • [^] # Re: Yet another build system

      Posté par  (site web personnel) . Évalué à 5.

      Tu peux récupérer les dépendances aux headers via le compilateur, par exemple avec gcc -M et gcc -MM
      Cf. https://stackoverflow.com/a/2394651/518853

      La meilleure façon de capturer les dépendances – meilleure parcequ'elle est exhaustive et indépendante du compilateur – est de tracer les appels système.

      C'est ce que fait le make de NetBSD et de FreeBSD qui est bmake. avec son meta-mode. L'intérêt de cette méthode est qu'elle permet d'avoir les vraies dépendances et donc paralléliser au mieux.

      • [^] # Re: Yet another build system

        Posté par  . Évalué à 7.

        La meilleure façon de capturer les dépendances – meilleure parcequ'elle est exhaustive et indépendante du compilateur – est de tracer les appels système.

        On peut tout de même garder son calme. D'une part tous les langages sorti depuis 10 ou 15 ans ont résolu par conception l'ensemble de ses problèmes (et un tas de langages plus anciens l'avait déjà résolu avant). C'est quelque chose qui est surtout utile pour les langages comme le C, le C++, le fortran, (La)TeX,… qui sont tous de très vieux langages. Ils n'ont pas de notion de module mais font d'include. Je ne connais pas de langages plus récent que l'Objective-C qui ai gardé des includes plutôt que des import.

        • [^] # Re: Yet another build system

          Posté par  (site web personnel) . Évalué à 4. Dernière modification le 13 décembre 2018 à 14:27.

          On peut tout de même garder son calme. D'une part tous les langages sorti depuis 10 ou 15 ans ont résolu par conception l'ensemble de ses problèmes

          Les langages oui, les chaines de compilation non.

          Pour le moment, les seules fois que je connais où le problème est réglé, c’est quand on code avec un seul langage, et qu’il a son propre outils de construction. Mais tous ces outils spécifiques ne connaissent qu’un langage à la fois.

          À l’inverse, le Fortran (post 90) fonctionne avec des modules, ce qui résout le problème des dépendances proprement, mais aucun outil de construction ne les interprète correctement. Ma solution actuelle, c’est un script shell qui construit un Makefile.in en lisant les fichiers sources, mais ce n’est pas très robuste (à moins de réimplémenter tout un interpréteur Fortran dans mon script).

          Du coup, je trouve smk très bien pensé et non seulement j’approuve la remarque de Michaël, « La meilleure façon de capturer les dépendances […] est de tracer les appels système » mais je ne connais aucun exemple d’outil générique qui fasse du bon travail autrement.

          • [^] # Re: Yet another build system

            Posté par  (site web personnel) . Évalué à 4.

            aucun outil de construction ne les interprète correctement.

            En formation récemment il a été conseillé makedepf90, il y a des cas où il foire ?

            Python 3 - Apprendre à programmer dans l'écosystème Python → https://www.dunod.com/EAN/9782100809141

            • [^] # Re: Yet another build system

              Posté par  (site web personnel) . Évalué à 3. Dernière modification le 16 décembre 2018 à 16:40.

              makedepf90 fonctionne bien mais il tombe dans la catégorie des outils spécifiques à un langage. Je l’avais essayé il y a quelques temps et en avais gardé un souvenir mitigé, mais je l’ai réessayé suite à ta suggestion et il semble effectivement faire du très bon boulot. Merci de l’avoir rappelé à mon souvenir.

  • # Quid des perfs ?

    Posté par  (site web personnel) . Évalué à 5.

    Merci pour le journal et le projet, ça fait très plaisir de voir une approche audacieuse à un problème ancien ;-)

    Dans mes souvenir un pauvre hello world en C++ se retrouve tout de suite avec des tonnes d'includes en cascade, dont beaucoup ne sont des bibliothèques standards fournies par le compilo (donc ne devant jamais changer en théorie…).
    De plus ce travail est réalisé pour chaque fichier.

    (Le comité C++ est d'ailleurs en train de travailler sur une feature de module pour justement résoudre ces soucis, il avait été annoncé un gain de 20% sur le temps de compile grâce à ça)

    Du coup en te basant sur les appels systèmes pour déterminer les dépendances (et sans faire d'optimisations propre au langage pour rester agnostique) j'aurai tendance à croire à un gros overhead (aussi bien en temps qu'en taille de logs dans tes fichiers .smk.*).

    Tu as des chiffres là dessus ? J'imagine que tu n'as pas pu résister à l'envie de compiler smk avec smk ;-)

    • [^] # Re: Quid des perfs ?

      Posté par  (site web personnel) . Évalué à 6.

      Merci pour le journal et le projet, ça fait très plaisir de voir une approche audacieuse à un problème ancien ;-)

      Merci!

      Dans mes souvenir un pauvre hello world en C++ se retrouve tout de suite avec des tonnes d'includes en cascade, dont beaucoup ne sont des bibliothèques standards fournies par le compilo (donc ne devant jamais changer en théorie…).

      Oui, c'est amusant dans mon exemple de voir que pour gcc -o hello.o -c hello.c, il y a 55 fichiers accédés en read, alors qu'un seul nous intéresse, hello.c!

      D’ou mon choix d'ignorer par défaut les fichiers systèmes dans les affichages, sinon c'était illisible.
      (pour voir les fichiers systèmes, il y a une option --shows-all-files)
      Par contre, tous les fichiers sont bien pris en compte: si /usr/include/stdio.h est mis à jour, la recompilation sera bien faite.

    • [^] # Re: Quid des perfs ?

      Posté par  (site web personnel) . Évalué à 5.

      Du coup en te basant sur les appels systèmes pour déterminer les dépendances (et sans faire d'optimisations propre au langage pour rester agnostique) j'aurai tendance à croire à un gros overhead (aussi bien en temps qu'en taille de logs dans tes fichiers .smk.*).

      Tu as des chiffres là dessus ?

      Non, et je n'ai pas envie de me lancer dans ces mesures tant que je n'aurai pas les idées claires sur l'intérêt de l'outil, et sur son domaine d'emploi.
      Dans mon intention, l'idée principale est de gagner du temps lors de l'écriture / l'automatisation du process.
      A première vue, l'exécution est rapide.
      Mais peut-être que sur mes cas de tests simple, l'overhead est supérieur au temps d'exécution d'une commande gcc que l'on cherche à éviter, c'est tout à fait possible!!

      (en taille de fichier, ça reste négligeable, mais je n'ai pas encore mis dans ma suite de test un gros build avec plein de fichier lu et écrits, type prod de site web).

      J'imagine que tu n'as pas pu résister à l'envie de compiler smk avec smk ;-)

      Bien sûr :-)
      Mais mon Makefile est déjà trop complexe. Par exemple, je pipe des commandes les unes dans les autres sur certaines lignes. Et smk ne sait pas lancer de shell, juste des commandes.
      Et bien sûr j'utilise des variables, pas encore supportées non plus.

      Mais je garde en tête cet objectif, qui est de faire la même chose que mon Makefile, et de voir si j'y arrive vraiment de façon plus simple.

    • [^] # Re: Quid des perfs ?

      Posté par  (site web personnel) . Évalué à 6.

      Dans mes souvenir un pauvre hello world en C++ se retrouve tout de suite avec des tonnes d'includes en cascade, dont beaucoup ne sont des bibliothèques standards fournies par le compilo (donc ne devant jamais changer en théorie…).

      Ce qui est bien avec "en théorie" c'est que cela ne marche jamais ;)

      Pour faire un vrai build reproductible à 100%, tu ne peux pas supposer que tes dépendances système ne changent pas. Et aussi, tu ne veux pas utiliser les dépendances système, car tu n'as pas de contrôle dessus, mais ceci est une autre histoire. En bref, tu veux absolument faire ce traitement de vérification.

      Je serais intéressé par des benchmarks, mais le coût de l'appel système pour construire la liste de dépendance est très faible comparé au coût du build. Et une fois que le build est fait, tu as un cache du graph de dépendance, la seule chose qui devient nécessaire c'est de vérifier que tes dépendances sont à jour.

      L'approche est intéressante et déja utilisée dans de nombreux autre outils:

      Le problème de cette approche c'est que tu ne connais le graph de dépendance qu'une fois que tu a réalisé un build complet, ce qui est acceptable sur un petit projet, mais pas sur un gros, car en pratique on build rarement un projet en entier. Par example, ici, je travaille sur une sous partie d'un projet logiciel dont le build ne prend que 2h sur mon gros i7. Mais l'ensemble du projet prend plusieurs jours.

      Note que ce n'est pas une critique fondamentale de l'outil, c'est un problème seulement si tu as un gros projet pour lequel tu veux faire un build partiel.

      • [^] # Re: Quid des perfs ?

        Posté par  (site web personnel) . Évalué à 3.

        Merci Guillaum, très intéressant, je vais aller voir les références.

        Pour ce qui est du problème du build initial, effectivement, convertir un énorme projet à cette approche peut poser problème si le temps total de build est en jours (même si on peut toujours réfléchir à une conversion progressive, en insérant progressivement smk dans les makefiles existants).

        Par contre, le stockage de smk est fait ainsi :
        pour chaque smkfile, chaque couple sources/cibles est indexé par la ligne de commande. Donc si tu rajoutes une commande, ça rajoute une entrée, et si tu modifies une commande, idem. Il n'y a donc pas a ré-exécuter tout à chaque mise à jour du smkfile, et donc pas de problème pour croître avec le projet.

        Il faut juste que j'ajoute dans ma suite un test pour vérifier que le runfile n'enfle pas quand on le fait de façon répétitive avec des lignes de commandes "mortes" qui ne figurent plus dans le smkfile. Je vais m'enregistrer une issue pour penser à traiter ce problème.

      • [^] # Re: Quid des perfs ?

        Posté par  (site web personnel) . Évalué à 2. Dernière modification le 12 décembre 2018 à 07:53.

        fabricate a un argumentaire de vente que je pourrais reprendre tel quel :-)
        J'ai bien noté l'utilisation de strace, ou des time tags, ainsi que celle de MD5 pour vérifier si un fichier a changé, intéressant.
        De même que l'autoclean, évidemment.

        C'est l'outil le plus proche de smk que j'ai vu a date, et il est bien plus puissant. Mais il s'agit plus d'une lib que d'un exe (même si on peut l'invoquer en ligne en lui passant tout en paramètre) : pour l'utiliser dans toute ses possibilités, il faut écrire son script de build en Python.
        (Même remarque pour Shake-Forward, sauf que la il faut scripter en haskell).

        Donc ça confirme que l'on peut faire smk depuis au moins dix ans. Reste la forme, je pense qu'ils ne sont pas sur le même créneau simplicité - universalité.

        • [^] # Re: Quid des perfs ?

          Posté par  (site web personnel) . Évalué à 2.

          404… l'a du bouger

          Python 3 - Apprendre à programmer dans l'écosystème Python → https://www.dunod.com/EAN/9782100809141

        • [^] # Re: Quid des perfs ?

          Posté par  . Évalué à 1.

          Fabricate est maintenant sur : https://github.com/SimonAlfie/fabricate

          J'y ai un peu contribué. Un des problèmes de la solution avec strace, c'est que tu n'as aucune garantie sur le format de la sortie. Il y a eu des problèmes avec fabricate car il ne marchait pas bien dans certains contextes avec certaines versions de strace.

          D'où l'idée d'utiliser Fuse comme ce qui a été fait dans tup, qui s'avère bien plus robuste.

    • [^] # Re: Quid des perfs ?

      Posté par  . Évalué à 6.

      Dans mes souvenir un pauvre hello world en C++ se retrouve tout de suite avec des tonnes d'includes en cascade, dont beaucoup ne sont des bibliothèques standards fournies par le compilo (donc ne devant jamais changer en théorie…).

      Pour info, il y a nettement moins de cascade d'inclusions quand on évite les lib fournies par gcc.
      Pour C++:

      % find /usr/include/c++/6 -type f | wc -l
      722
      % find /usr/include/c++/v1 -type f | wc -l   
      119

      Nombre de fichiers divisé par 7. Et lire le code est tout aussi intéressant, celui de clang est nettement plus lisible, notamment parce qu'il fait moins d'appels.

      Pour le C (bon, ça, c'est bancal, tous les include ne sont pas dans le même dossier je pense):

      % find /usr/include/x86_64-linux-gnu -type f | wc -l
      310
      % find /usr/include/x86_64-linux-musl -type f | wc -l 
      211

      À peu près 30% de fichiers en moins pour musl.

      Par contre, la compilation d'un

      #include <iostream>
      int main(){
        std::cout << "hello world";
      }

      génère un binaire de 2M avec clang++ -static -stdlib=libstdc++ -pthread contre 2.4M avec clang++ -static -stdlib=libc++ -pthread (pour une raison qui m'échappe, lier avec pthread est obligatoire avec libc++…).

      Pour info, l'inclusion d'un std::string pour affichage à coup de printf fait passer le binaire libstdc++ à 1.9M et celui de libc++ à 1.3M (très honnêtement, je déteste les stream du C++, je trouve ça illisible, mais je ne m'attendais pas à ça pour autant).

      Pour ce qui est C, le code

      #include <stdio.h>
      int main(){
        printf( "hello world" );
      }

      génère avec gcc -static hello.c un binaire de 792K contre 29K pour musl-gcc -static hello.c.

      Du coup, si vraiment les performances de compilation sont importantes, peut-être qu'avant de vouloir sortir des outils qui font le café, utiliser des libs performantes peut aider? Bon, pour être honnête, musl n'implémente pas encore, à ma connaissance, la gestion des "locales", et se limite aux standards, cette lib n'essaie pas de fournir de fonctionnalités non standard, contrairement à GCC.
      J'ai utilisé pour ces «tests» les paquets fournis par debian stable.
      Je n'ai pas mesuré le temps de compilation, pour un hello world ce serait difficile à mesurer de toute façon, mais je serai surpris que les libs de gcc soient les plus rapides.

      Bon, faire un strip permets de grappiller quelques octets en C. Pour le C++, le résultat est nettement plus impressionnant et place le binaire de libc++ en 1ère position (1615768 octets pour libc++ contre 1619880 octets pour libstdc++, soit à peu près 1.6M pour les deux).

  • # Une amélioration possible

    Posté par  (site web personnel) . Évalué à 8.

    Projet intéressant, et qui peut être très utile pour des petits projets!
    À mon avis, un ajout de taille serait la gestion des commandes "génériques", un équivalent à ce genre de Makefile :

    all: hello
    
    %.o: %.c
        gcc -c -o $@ $<
    
    hello:
        gcc -o $@ main.o hello.o

    Dans un cas comme celui-ci, make comprend qu'il doit d'abord transformer le .c en .o avec la règle générique, puis ensuite utiliser le .o généré dans la règle hello.
    Typiquement, pour un fichier avec un certain nombre de fichiers C, ça pourrait donner un smkfile qui ressemblerait à ça :

    [%.c%.o] gcc -c -o $@ $<
    gcc -o hello <liste des .o>
    

    Ça économise autant de lignes qu'il y a de fichiers C en entrée (-1).

    • [^] # Re: Une amélioration possible

      Posté par  (site web personnel) . Évalué à 1.

      Tout à fait, parce que moi j'utilise mon modèle de makefile (https://github.com/ColinPitrat/CppMisc/tree/master/Model) et je n'ai jamais à l'éditer. Il fait un find pour trouver les sources et sait automatiquement quoi compiler.

      Si pour chaque nouveau fichier je dois ajouter une ligne dans le smkfile alors c'est plus compliqué à l'usage, même si le fichier est plus lisible.

      • [^] # Re: Une amélioration possible

        Posté par  (site web personnel) . Évalué à 1.

        Ca rejoint également ce que disait liberf0rce plus haut : utiliser gcc -MM
        Je vais potasser ça!

      • [^] # Re: Une amélioration possible

        Posté par  . Évalué à 2.

        Pour un argumentaire sur le fait que lister les fichiers, c'est bien, voir la doc d'automake :
        https://www.gnu.org/software/automake/manual/html_node/Wildcards.html#Wildcards

        En tous cas, ton Makefile « tout prêt », il ressemble vraiment beaucoup à ce que génère autoconf/automake.

        Et bien sûr le système présenté ici, smk, oubli tous les autres aspects importants qui arriveront avec tout projet qui mature : gérer la distribution, l'installation (et la désinstallation), les licences des sources, la reproductibilité, etc.

        Bref, intéressant comme essai pédagogique, mais assez inutile pour de la vraie production.

        • [^] # Re: Une amélioration possible

          Posté par  . Évalué à 3.

          Bref, intéressant comme essai pédagogique, mais assez inutile pour de la vraie production.

          Je ne suis pas d'accord, avoir un outils de build qui ne fait que le build c'est bien.

          le packaging c'est une autre problématique qui doit être géré par un autre outil. Avoir un outils qui fait tout crée une usine à gaz.

          Tu peux aussi avoir une commande qui génère le rpm/msi/deb/autre

          Il ne faut pas décorner les boeufs avant d'avoir semé le vent

          • [^] # Re: Une amélioration possible

            Posté par  . Évalué à 2.

            le packaging c'est une autre problématique qui doit être géré par un autre outil.

            Non. Le build est lié à la licence, car un bon système de build permet de respecter qu'on distribue bien les sources associées à tel binaire, et qu'on est capable de le reproduire dans un environnement donné. Pour l'installation, le linkage peut être dépendant de la manière dont sont installées les bibliothèques, et tu devras forcément introduire dans ton système à un moment où aller chercher tel fichier. Ces problématiques sont très liées, et limiter un outil de build à faire uniquement ça c'est dupliquer les efforts pour plus tard gérer les autres aspects.

            Avoir un outils qui fait tout crée une usine à gaz.

            C'est parce que builder, installer, reproduire et installer sont un ensemble de problèmes complexe. Les autotools sont éventuellement une usine à gaz pour la flexibilité dans certains choix, mais ils simplifient tout de même beaucoup l'ensemble de ces tâches, avec des paramètres par défaut plutôt bon qui font qu'on n'a pas forcément à toucher tout son paramétrage.

            Tu peux aussi avoir une commande qui génère le rpm/msi/deb/autre

            Si on avait un système de package (au sens « distribution Linux » du terme) universel, oui on pourrait, mais c'est un problème politique trop grand. Alors c'est l'inverse qui est arrivé : le packaging Debian (par exemple) d'un paquet déjà géré par autotools est fait en une ligne de procédure (et quelques lignes de description de données spécifiques au système de Debian).

        • [^] # Re: Une amélioration possible

          Posté par  (site web personnel) . Évalué à 2.

          Bonjour Benoar,

          On ne peut pas dire que smk "oublie", puisque ce que tu décrit n'est pas du tout la cible visée par l'outil, et que c'est indiqué clairement à plein d'endroit sur le site, dans l'article et dans mes réponses. Je rappelle le créneau : simplicité, universalité.
          Je n'ai aucune intention de refaire un bmake.

          (D'ailleurs, si le créneau n'était pas celui là, j'aurai juste arrêté le projet et conseiller l'usage de fabricate, que j'ai découvert par les réponses dans ce journal).

          La ou je suis moins pessimiste que toi sur l'utilité même pour un grand programme, c'est que je vois très bien en revanche un smkfile lister les commandes à exécuter pour le packaging, l'installation et la désinstallation, etc.

          Je te dirais même que pour la désinstallation par exemple, comme smk connait tous les fichiers qui ont été créé par l'installation, y a moyen que ce soit redoutablement simple.
          Merci pour l'idée, je vais voir si je peux en faire un cas de test (qui ne sera pas simple, car comment gérer les updates de fichiers existant?, mais bon, bonne idée en tout cas).

    • [^] # Re: Une amélioration possible

      Posté par  (site web personnel) . Évalué à 1.

      OK, à discuter.

      A priori, ce n'est pas dans mon idée de développer un tel mécanisme, je préférerais garder une syntaxe simple, et compatible shell script.

      • [^] # Re: Une amélioration possible

        Posté par  . Évalué à 1.

        Peut-être une boucle for ?

        for f in *.c do
            gcc -o $(basename $f .c).o -c $f
        done

        Bon du coup c'est pas aussi simple car ça suppose d'avoir une fonction qui permet de changer l'extension d'un fichier, et aussi d'avoir des variables.

  • # pourquoi -o machin.o

    Posté par  (site web personnel) . Évalué à 2. Dernière modification le 11 décembre 2018 à 12:50.

    Ça fait longtemps que je n'ai plus fait de C … et j'ai un peu oublié les MakeFile, mais, pour produire polo.o on peut écrire, seulement :
    gcc -c polo.c
    Du coup, pourquoi ajouter systématiquement l'option -o ?
    gcc -o polo.o -c polo.c

    Sinon, effectivement, c'est sympa l'idée de vouloir améliorer quelque chose d'aussi vieux que make.

    • [^] # Re: pourquoi -o machin.o

      Posté par  (site web personnel) . Évalué à 1.

      Il n'y a pas vraiment de raison, j'ai juste repris les exemples de ce tuto

      Après je pense que c'est plus clair pour comprendre ces histoires de sources et de cibles d'avoir les cibles de façon explicite dans la ligne de commande.

      Mais on est bien d'accord que ça ne change rien pour smk, puisque l'outils regarde les fichiers réellement accédés, pas la ligne de commande ni le smkfile.

    • [^] # Re: pourquoi -o machin.o

      Posté par  . Évalué à 3.

      Dans le cas des Makefile ça permet de faire une compilation en 2 passes. Le seul intérêt que j'y vois c'est de pouvoir spécifier le dossier où sont rangés les .o afin de ne pas polluer le dossier avec les fichiers source.

  • # Meta mode de FreeBSD

    Posté par  . Évalué à 6.

    Pour info une idée similaire est implémentée dans le make de FreeBSD, sous le doux nom de meta mode. Note qu'il utilise une interface spécifique à FreeBSD à la place de ptrace, probablement pour des questions de performance (?). Peut-être pourrais-tu t'en inspirer pour porter ton smk sur FreeBSD ou inversement utiliser tes compétences pour porter bmake+meta mode sur Linux/ptrace ?

    https://www.freebsd.org/cgi/man.cgi?query=make

    • [^] # Re: Meta mode de FreeBSD

      Posté par  (site web personnel) . Évalué à 3. Dernière modification le 11 décembre 2018 à 23:03.

      Merci à toi pour l'info (et à Michaël).
      L'exploration de bmake et du méta mode a été très intéressante!

      Voici mon retour:

      • l'outil repose sur filemon. filemon est un device spécial qui permet de collecter toutes les opérations fichier d'un process et de ses fils.
        Il a été pensé exprès pour l'usage d'outils de build, et il est expliqué que ktrace permet de le faire, mais que ktrace capture tout, et qu'il faudrait ensuite filtrer dans un énorme log (info peut-être pas à jour). (sur Linux, strace traite le problème, puisqu'on lui dit sur la ligne de commande "-e trace=file"). Il est dit également que le proto de bmake utilisait un autre équivalent de strace, DTrace. Mais celui-ci exigeait des privilèges root.
        Pour info, existe sur GitHub un port de filemon sur Linux.

      • bmake est pensé pour reconstruire FreeBSD sur toutes les plateformes. Autant dire que c'est au antipode de smk en terme de complexité de cible:

        While meta mode may be the coolest thing since sliced bread, it may not be for everyone. It does provide a simple solution to some rather complex problems

      Mais surtout bmake reste un make : sa syntaxe relève du grand art, (tu l'écrit le lundi, le mardi tu ne comprends plus ce que tu as écrit, le mercredi tu te demande qui est le con qui a été piqué ce code dans un obfuscation contest!). Personne n'a envie de ça pour un outils simple.
      Et vice versa, smk ne fera jamais la moitié de ce que fait bmake.

      • j'ai trouvé également intéressant de voir ce que stockait bmake dans ses fichiers .meta (l'équivalent des runfiles smk). Comme pour smk, y sont stockés la commande et ses options, et les fichiers classés en read et write, mais aussi quelques autres infos, comme le répertoire d'exécution. Je retiens l'idée d'un format de fichier en clair (texte), pour faciliter le debug. Pour l'instant, smk c'est du binaire. Je vérifierai l'impact en performance de ce changement, mais si c'est faible, je ferais le switch.
  • # Et par rapport à redo ?

    Posté par  (site web personnel) . Évalué à 9.

    Redo est une autre alternative à Make. Je serais curieux d'avoir l'avis de l'auteur de smk pour comparer les deux. Par exemple, est-ce que smk s'appuie uniquement sur le mtime pour savoir si un fichier a été modifié depuis la dernière exécution d'une commande ? L'auteur de redo considère cela comme étant fragile : https://apenwarr.ca/log/20181113.

    Sinon, j'ai vu passer https://github.com/jacereda/fsatrace qui pourrait aider l'auteur :

    This tool injects code into other applications in order to trace file accesses. This can be useful for things like build systems, since it allows to automatically generate dependencies in a toolchain-agnostic way or to ensure declared dependencies match the real ones.

    • [^] # Re: Et par rapport à redo ?

      Posté par  (site web personnel) . Évalué à 3.

      Merci pour le papier mtime comparison considered harmful, j'ai appris plein de chose, et découvert qu'un des défauts que je mettais dans limitations est aussi un défaut de make.

      Je ne suis pas rentré dans le mécanisme de redo, je n'ai pas trouvé d'explication claire et concise.

      redo's design fundamentally depends on keeping a database of targets, if only to remember which files were produced by redo and which were not. From there, it's easy enough to extend that database to include mtime information about sources.

      Ca à l'air de ressembler à ce que stocke smk, mais je ne peut pas en dire plus.

      Le mécanisme à l'air très safe, mais la syntaxe est trop compliqué pour moi. Quand je vois dans l'intro ce qu'il faut écrire pour lancer un pauvre gcc, ça ne me donne pas envie d'aller plus avant.

      Je comprends que le mécanisme permet d'éviter qu'une source soit considérée comme valide alors qu'il s'agit d'un fichier intermédiaire (parce que la compilation a été interrompue au milieu, par exemple).
      Pour les cas simples que je vise, cela ne justifie pas la complexité ajoutée autour de la commande gcc.

      Après, sur le fait d'avoir les cibles all clean etc. éclatés en plusieurs fichier script dans le répertoire courant, je ne suis pas hostile, et je propose de faire la même chose avec smk, mais le contenu des fichiers doit rester très simple.

      Pour répondre à ta question : en effet, je m'appuie sur mtime pour savoir si un fichier a été modifié depuis la dernière exécution de la commande, mais pas pour distinguer les inputs des outputs. C'est ce que faisait ma première version, date fichier < heure d'exécution => source, date fichier > heure exécution => target. Mais la ça dysfonctionnait carrément pour les problèmes évoqué dans l'article, au moins celui de granularité faible du mtime).

      Il n'en reste pas moins que la version actuelle souffre encore (marginalement) de ce défaut dans un cas bien précis également décrit dans l'article:

      Computers are now so fast that you can save foo.c in your editor, and then produce foo.o, and then compile foo, all in the same one-second time period. If you do this and, say, save foo.c twice in the same second (and you have one-second granularity mtimes), then make can't tell if foo.o and foo are up to date or not.

      Comme c'est ce que je fait dans les tests de smk, j'ai du mettre à deux endroits "sleep 1" dans le Makefile pour ne pas tomber dans ce bug. Mais grâce à ton lien, je vois ce que fait redo pour éviter ça (par exemple stocker et comparer également la taille), c'est une très bonne source, merci.

      • [^] # Re: Et par rapport à redo ?

        Posté par  (site web personnel) . Évalué à 7.

        Je n'ai pas compris si tu utilisais un hash du fichier ou un diff, ou la date comme make, ce qui pose tout un tas de problème chiant. L'avantage d'utiliser un hash est de permettre aussi de sauver des fichiers intermédiaires, et si ils sont identiques, ne pas tout refaire (cas typique d'ajouts d'un commentaire dans un include C++, qui recompile tout, au lieu de se rendre compte que le fichier.o est toujours le même).

        "La première sécurité est la liberté"

  • # tup

    Posté par  . Évalué à 4.

    Un autre système de build au concept un peu similaire est tup. Cette page du site explique un système de dépendances qui ressemble à ce qui est expliqué ici pour smk.

    • [^] # Re: tup

      Posté par  (site web personnel) . Évalué à 3. Dernière modification le 12 décembre 2018 à 00:51.

      Oui, on m'en a parlé quand je suis sorti du bois il y a un mois avec mon idée.

      Mais même si le système est très intéressant, il oblige à créer un tupfile.
      Par exemple pour
      "gcc hello.c -o hello", le tupfile contiendra
      ": hello.c |> gcc hello.c -o hello |> hello"

      C'est donc l'utilisateur qui donne la règle de production avec ce format source|commande|target.
      C'est une syntaxe différente Make, mais c'est la même idée.

      smk vise à se passer complètement de cette description.

  • # Une alternative à l'alternative

    Posté par  (site web personnel) . Évalué à 3.

    Je vois bien l'intérêt pour faire des fichiers de build pour des petits projets, et en lisant la description, je me demande si ca ne pourrait pas servir à autre chose qu'à compiler des programmes/librairies.

    • Alimenter une BD avec des fichiers mais en ne poussant que les fichiers récents
    • Redémarrer des services si des fichiers de config ont changé
    • Faire des sauvegardes incrémentales assez simples

    Je sais que tout ce que je décris existe déjà dans plein de solutions, mais ce que j'aime bien dans smk c'est sa simplicité de mise en place.
    Je le garde dans un coin de l'oreille pour plus tard, merci!

    • [^] # Re: Une alternative à l'alternative

      Posté par  (site web personnel) . Évalué à 3.

      Ah oui, très bonnes idées!
      Et pour moi pour illustrer l'utilisation de smk sans faire dans le gcc!

      Ça me fait penser que j'ai un cas aussi : j'utilise rapid photo downloader pour renommer et classer toutes les photos que j'archives.
      Quelque soit l'origine, je déverse tout dans le même répertoire tmp "à classer", et rapid s'occupe du reste.

      Je vais tester smk:
      - répertoire tmp vide, ne doit rien faire
      - répertoire tmp plein de photos déjà traitées, ne doit rien faire
      - répertoire tmp avec des photos inconnues -> run

      Et pour le besoin d'outils type backintime, qui sauvegardent leur propre configuration et que l'on peut lancer quasiment sans options sur la ligne de commande, pas la peine de faire un fichier smkfile, je vais prévoir le lancement directement en ligne de commande, type smk backintime --backup-job.

      Merci pour les idées!

  • # avec les règles automatiques de make

    Posté par  (site web personnel) . Évalué à 4.

    Salut,
    Sur ton exemple, il me semble que le Makefile peut être raccourci en :

    all: main
    main: main.o hello.o
    

    Make trouvera les dépendances automatiquement.
    Et tu peux aussi profiter des variables d'environnement, par exemple pour compiler en debug et avec un autre compilateur :

    CC=clang CFLAGS=-g make
    
    • [^] # Re: avec les règles automatiques de make

      Posté par  (site web personnel) . Évalué à 1.

      Hello Nokomprendo, oui, il pourrait.
      Mais le but est ici pédagogique, faire clair avant de faire court. Si dans mon tuto une commande est lancée, j'aime autant qu'elle apparaisse en clair dans le Makefile ainsi que les fichiers concernés.

      Et pour les variables, j'en utiliserai dans le Makefile d'exemple dès que smk saura les traiter (ce que j'ai annoncé vaillamment pour Noël un peu plus haut!).

  • # inotify vs ptrace

    Posté par  . Évalué à 4.

    Hello, tu serais peut-être intéressé par lk-reducer, un programme qui utilise inotify(7) pour surveiller les accès/modifications/créations de fichiers: https://github.com/jduck/lk-reducer

    Ça peut donner des idées plutôt que d’utiliser strace(1) qui serait plus lourd.

    • [^] # Re: inotify vs ptrace

      Posté par  (site web personnel) . Évalué à 2.

      Merci pour le pointeur, je vais regarder ce que sait faire inotify.

      Incidemment, le cas d'usage de lk-reducer est très intéressant: Il s'agit, si j'ai bien compris, de nettoyer une arborescence kernel de tous les fichiers qui trainent mais ne servent plus.
      On lance sous monitoring un make et un make mrproper, et ensuite on repère les fichiers qui n'ont pas été accédé pendant le make, et qui ne sont pas nettoyé par le make mrproper.

      Je ne me suis intéressé qu'aux fichiers lus ou écrits, mais en effet, dans ce cas les fichiers non accédés sont une info intéressante! Je le note comme un ajout fonctionnel possible à smk: après un build, on pourrait demander à smk quels fichiers d'une arborescence n'ont pas été concerné par ce qui a été exécuté.

      L'autre point pas inintéressant, c'est le mode interactif: je lance un shell, et c'est tout ce qui est exécuté pendant que je suis dans ce shell qui est observé. Le fichier de log qui classe les fichiers en "Accessed, Untouched, or Generated" est écrit à la sortie du shell. Les commandes sont donc analysées comme une opération unique, puisque c'est ce qui nous intéresse ici.

      Pas encore sûr d'en faire quelque chose, mais je le note!

      • [^] # Re: inotify vs ptrace

        Posté par  . Évalué à 2.

        Oui c’est exactement ça. Je l’ai déjà utilisé dans des builds qui n’ont rien à voir avec le kernel pour nettoyer des bases de code legacy.

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.