Verwendung von make

Die im letzten Abschnitt gezeigte grafische Darstellung von Abhängigkeiten und Kommandos kann hilfreich sein, um im Einzelfall zu entscheiden, welche Kommandos zum Aktualisieren einer Zieldatei nötig sind.

Da diese Arbeit aber -falls man erst einmal die Abhängigkeiten wie beschrieben aufgestellt hat- vollkommen mechanisch erfolgt (anhand des letzten Änderungsdatums aller Dateien die nötigen Wege der Grafik entlanggehen, und die an den Pfeilen stehenden Kommandos ausführen), kann man sie auch einem Programm überlassen.

Dieses Programm existiert wohl auf jedem Unix- und GNU/Linux-System, und heißt make2.1.

Leider kann make mit einem gezeichneten Diagramm nicht viel anfangen; vielmehr liest es eine Datei, in der man in Textform exakt die Informationen der Grafik eintragen muß. Diese Datei heißt in aller Regel makefile. Beim Start von make wird die Datei mit dem Namen makefile gelesen, daraus die Abhängigkeiten und die zugehörigen Kommandos gelesen, und -je nach dem letzten Änderungsdatum aller beteiligten Dateien- werden Kommandos ganz, teilweise oder gar nicht ausgeführt. Dabei zählen nicht existierende Dateien als ,,sehr alt``, so daß sie bei Bedarf neu erzeugt werden.

Um jetzt diese Abhängigkeiten und die Kommandos eintragen zu können, muß man eine besondere Syntax beachten, die im Folgenden (etwas vereinfacht) vorgestellt wird.

Die meisten Bestandteile des makefile sind in je einer logischen Zeile untergebracht. Eine solche logische Zeile entspricht meistens einer tatsächlichen Zeile der Datei. Allerdings kann man eine lange logische Zeile auf mehrere tatsächliche Zeilen verteilen, wenn sie sonst zu lang wird (identisch zu C/C++). Dazu trennt man die Zeile einfach auf, und beendet jede tatsächliche Zeile außer der letzten mit einem back slash(\). Nach dem \ darf außer dem Zeilenendezeichen (LF, line feed) nichts mehr kommen, auch kein Leerzeichen oder Tabulator!

Die Datei besteht hauptsächlich aus:

Wenn man dann noch beachtet, daß man zwar nicht innerhalb von Regeln, aber zwischen selbige Leerzeilen einstreuen kann, um die Datei etwas übersichtlicher zu machen, dann kann man für das obige Beispiel aus drei Quelltexten folgendes makefile schreiben:

# Time-stamp: "(25.11.01 09:00) makefile [Klaus Wachtler (aw38)]"
# makefile für ein kleines Projekt aus haupt.cpp, up.cpp/.h,
# sowie db.cpp/.h.

haupt: haupt.o up.o db.o
        g++ haupt.o up.o db.o -o haupt

haupt.o: haupt.cpp up.h db.h
        g++ -c haupt.cpp

up.o: up.cpp up.h db.h
        g++ -c up.cpp

db.o: db.cpp db.h
        g++ -c db.cpp

Durch die Verwendung einer impliziten Regel kann man die Datei etwas vereinfachen:

haupt: haupt.o up.o db.o
        g++ haupt.o up.o db.o -o haupt

haupt.o: haupt.cpp up.h db.h

up.o: up.cpp up.h db.h

db.o: db.cpp db.h

-cpp.o:
        g++ -c $<

(Bitte beachten: Vor den Kommandos g++... stehen keine Leerzeichen, sondern jeweils ein Tabulator!)

Mit dem Aufruf:
make
wird dann das Programm make gestartet. Dieses liest die Datei makefile und findet als erstes target die Datei haupt.

Da diese Datei laut makefile von haupt.o, up.o sowie von db.o abhängt, prüft make als nächstes, ob diese drei Dateien existieren und auf dem neuesten Stand sind, also neuer als ihre eigenen prerequisites. Gegebenenfalls werden sie aktualisiert mit den angegebenen Kommandos, und dann wird -falls nötig- haupt neu gelinkt.

Davon abgesehen, daß make das erste gefundene Target zu aktualisieren versucht, ist die Reihenfolge der Regeln im makefile gleichgültig.

Wenn man nicht das erste im makefile aufgeführte target aktualisiert haben möchte, gibt man einfach das gewünschte Target (oder mehrere) als Argumente an:
make up.o db.o
würde die Dateien up.o und db.o aktualisieren, ohne sich um haupt zu kümmern.

Falls man den Namen makefile nicht verwenden möchte, kann man beim Aufruf von make mit der Option -f einen anderen Namen vorgeben.



Unterabschnitte
AnyWare@Wachtler.de