Also trotzdem, warum brauchst du make?



Alles begann, wie es scheint, mit einer einfachen Frage, die mich zuerst zu einem Rätsel führte: "Warum muss ich etwas machen? Warum kann ich mich mit Bash- Skripten nicht vertragen ?". Und ich dachte - Wirklich, warum muss ich machen? (und am wichtigsten) Welche Probleme löst er?


Dann habe ich beschlossen, ein bisschen darüber nachzudenken - wie würden wir unsere Projekte sammeln, wenn wir nicht gemacht hätten. Nehmen wir an, wir haben ein Projekt mit Quellcodes. Von ihnen müssen Sie eine ausführbare Datei (oder Bibliothek) erhalten. Auf den ersten Blick scheint die Aufgabe einfach zu sein, aber wir sind noch weiter gegangen. Angenommen, das Projekt besteht zu Beginn aus einer Datei.



Um es zu kompilieren, führen Sie einfach einen Befehl aus:


$ gcc main.c -o main 

Es war ziemlich einfach. Aber einige Zeit vergeht, das Projekt entwickelt sich, einige Module erscheinen darin und die Quelldateien werden größer.



Zum Kompilieren müssen Sie die folgende Anzahl von Befehlen bedingt ausführen:


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

Stimmen Sie zu, dies ist ein ziemlich langwieriger und sorgfältiger Prozess. Um dies manuell zu tun, würde ich nicht. Ich denke, dass dieser Prozess automatisiert werden kann, indem einfach ein build.sh- Skript erstellt wird, das diese Befehle enthält. Okay, das ist viel einfacher:


 $ ./build.sh 

Wir fuhren weiter! Das Projekt wächst, die Anzahl der Quelldateien nimmt zu und es gibt auch mehr Zeilen darin. Wir stellen fest, dass sich die Kompilierungszeit deutlich erhöht hat. Hier sehen wir einen signifikanten Fehler in unserem Skript - es kompiliert alle unsere 50 Dateien mit den Quellen, obwohl wir nur eine modifiziert haben.



Es wird nicht funktionieren! Entwicklerzeit ist eine zu wertvolle Ressource. Nun, wir können versuchen, das Build-Skript so zu ändern, dass wir vor dem Kompilieren den Zeitpunkt der Änderung der Quell- und Objektdateien überprüfen. Und kompilieren Sie nur die Quellen, die geändert wurden. Und bedingt kann es so aussehen:


 #!/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 

Und jetzt werden nur die Quellen kompiliert, die geändert wurden.



Aber was passiert, wenn das Projekt so aussieht:



Früher oder später wird es schwierig sein, das Projekt zu verstehen, und die Unterstützung solcher Skripte selbst wird zu einem mühsamen Prozess. Und es ist keine Tatsache, dass dieses Skript alle Abhängigkeiten angemessen überprüft. Darüber hinaus können wir mehrere Projekte haben und jedes wird ein eigenes Skript für die Montage haben.


Natürlich sehen wir, dass eine allgemeine Lösung für dieses Problem entsteht. Ein Tool, das einen Mechanismus zum Überprüfen von Abhängigkeiten bereitstellt. Und hier kommen wir langsam zur Erfindung von make . Und jetzt, da ich weiß, mit welchen Problemen wir beim Aufbau des Projekts konfrontiert sein werden, würde ich am Ende die folgenden Anforderungen formulieren:


  • Analyse der Zeitstempel von Abhängigkeiten und Zielen
  • Minimaler Arbeitsaufwand, um die Relevanz abgeleiteter Dateien zu gewährleisten
  • (naja, + parallele Ausführung von Befehlen)

Makefile


Makefiles werden verwendet, um Projektassemblierungsregeln zu beschreiben. Beim Erstellen eines Makefiles beschreiben wir deklarativ einen bestimmten Status der Beziehungen zwischen Dateien. Die deklarative Natur der Zustandsbestimmung liegt darin, dass wir sagen, dass wir eine Liste von Dateien haben und eine neue Datei von ihnen durch Ausführen einer Liste von Befehlen erhalten müssen. Im Fall der Verwendung einer imperativen Sprache (z. B. Shell) müssten wir eine große Anzahl verschiedener Überprüfungen durchführen, um komplexen und verwirrenden Code in der Ausgabe zu erhalten, während make dies für uns erledigt. Die Hauptsache ist, den richtigen Abhängigkeitsbaum zu erstellen.


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

Ich werde nicht darüber reden, wie man Makefiles schreibt. Im Internet gibt es viele Handbücher zu diesem Thema, und wenn Sie möchten, können Sie auf sie verweisen. Außerdem schreiben nur wenige Leute Makefiles manuell. Und sehr komplexe Makefiles können zu Komplikationen führen, anstatt den Erstellungsprozess zu vereinfachen.

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


All Articles