Alors, pourquoi avez-vous besoin de faire?



Tout a commencé, semble-t-il, par une question simple qui m'a d'abord conduit dans une stupeur - "Pourquoi dois-je faire? Pourquoi ne puis-je pas m'entendre avec les scripts bash ?". Et j'ai pensé - Vraiment, pourquoi ai-je besoin de faire? (et le plus important) Quels problèmes résout-il?


Ensuite, j'ai décidé de réfléchir un peu - comment collecterions-nous nos projets si nous n'avions pas de marque. Disons que nous avons un projet avec des codes sources. Vous devez obtenir d'eux un fichier exécutable (ou une bibliothèque). À première vue, la tâche semble simple, mais nous sommes allés plus loin. Supposons qu'au stade initial, le projet se compose d'un seul fichier.



Pour le compiler, exécutez simplement une commande:


$ gcc main.c -o main 

C'était assez simple. Mais le temps passe, le projet se développe, certains modules y apparaissent et les fichiers source deviennent plus volumineux.



Pour compiler, vous devez exécuter conditionnellement le nombre de commandes suivant:


 $ gcc -c src0.c $ gcc -c src1.c $ gcc -c main.c $ gcc -o main main.o src0.o src1.o 

D'accord, c'est un processus assez long et laborieux. Pour ce faire manuellement, je ne le ferais pas. Je pense que ce processus peut être automatisé en créant simplement un script build.sh qui contient ces commandes. D'accord, c'est beaucoup plus simple:


 $ ./build.sh 

Nous avons roulé! Le projet se développe, le nombre de fichiers sources augmente et il y a aussi plus de lignes dedans. Nous commençons à remarquer que le temps de compilation a considérablement augmenté. Ici, nous voyons une faille importante dans notre script - il compile l'ensemble de nos 50 fichiers avec les sources, bien que nous n'en ayons modifié qu'un.



Ça ne marchera pas! Le temps des développeurs est une ressource trop précieuse. Eh bien, nous pouvons essayer de modifier le script de construction afin qu'avant la compilation, nous vérifions l'heure de modification des fichiers source et objet. Et compilez uniquement les sources qui ont été modifiées. Et conditionnellement, cela peut ressembler à ceci:


 #!/bin/bash function modification_time { date -r "$1" '+%s' } function check_time { local name=$1 [ ! -e "$name.o" ] && return $? [ "$(modification_time "$name.c")" -gt "$(modification_time "$name.o")" ] && return $? } check_time src0 && gcc -c src0.c check_time src1 && gcc -c src1.c check_time main && gcc -c main.c gcc -o main main.o src0.o src1.o 

Et maintenant, seules les sources qui ont été modifiées seront compilées.



Mais que se passe-t-il lorsque le projet se transforme en quelque chose comme ceci:



Tôt ou tard, un moment viendra où il sera très difficile de comprendre le projet et le support de tels scripts deviendra en soi un processus laborieux. Et ce n'est pas un fait que ce script vérifiera correctement toutes les dépendances. De plus, nous pouvons avoir plusieurs projets et chacun aura son propre script pour l'assemblage.


Bien sûr, nous voyons qu'une solution générale à ce problème se pose. Un outil qui fournirait un mécanisme de vérification des dépendances. Et ici, nous arrivons lentement à l'invention de la marque . Et maintenant, sachant à quels problèmes nous serons confrontés dans le processus de construction du projet, à la fin je formulerais les exigences suivantes pour faire:


  • analyse des horodatages des dépendances et des objectifs
  • quantité minimale de travail requise pour garantir la pertinence des fichiers dérivés
  • (enfin, + exécution parallèle de commandes)

Makefile


Les Makefiles sont utilisés pour décrire les règles d'assemblage du projet. En créant un Makefile, nous décrivons de manière déclarative un certain état des relations entre les fichiers. La nature déclarative de la détermination de l'état est pratique dans la mesure où nous disons que nous avons une liste de fichiers et que nous devons en obtenir un nouveau en exécutant une liste de commandes. Dans le cas de l'utilisation d'un langage impératif (par exemple, shell), nous aurions à effectuer un grand nombre de vérifications différentes, obtenant du code complexe et déroutant dans la sortie, tandis que make le fait pour nous. L'essentiel est de construire le bon arbre de dépendances.


 <  > : <  ... > <  > ... ... 

Je ne parlerai pas de la façon d'écrire des Makefiles. Sur Internet, il existe de nombreux manuels sur ce sujet et si vous le souhaitez, vous pouvez vous y référer. Et d'ailleurs, peu de gens écrivent des Makefiles manuellement. Et les Makefiles très complexes peuvent être une source de complications au lieu de simplifier le processus de construction.

Source: https://habr.com/ru/post/fr477656/


All Articles