Das make-Programm

Im folgenden werden wir immer wieder leichte Änderungen an unserem Programm vornehmen. Dabei müssen natürlich entsprechende Teile des Source-Codes neu übersetzt werden. Um uns alle damit verbundene Arbeit abzunehmen, gibt es das Programm make: make liest ein Beschreibungsfile Makefile oder makefile (andere Namen können mit der Option -f angegeben werden), in dem beschrieben wird, welche Programme man erzeugen möchte, wie die zugehörigen Files voneinander abhängen und wie man aus ihnen das Programm erhält.
Ein Makefile beginnt meistens mit Definitionen von Variablen, z.B.:
        FC = /usr/convex/fc
        FFLAGS = -O2 -pa
        INCLUDE =
Diese Variablen können dann an beliebiger Stelle im Makefile in der Form $(FC) benutzt werden. Man kann sie auch erst beim Aufruf von make definieren, z.B.:
        make FC=/usr/local/gnu/fc linalg
Diese Definition überschreibt eine im Makefile vorhandene. Außerdem können Kommentarzeilen eingefügt werden, die mit # beginnen.
Die Beschreibung der Aktionen geschieht in Zeilen der Form
        Zielname: Abhaengigkeiten
        <TAB>Aktion1
        .
        .
        <TAB>AktionN
wobei weitere Aktionszeilen folgen können. Zu beachten ist, daß Aktionszeilen mit einem $<$TAB$>$ (Tabulator-Zeichen) beginnen müssen; es dürfen dort keine Blanks stehen. Z.B. geben die Zeilen
        main.o: $(INCLUDE) main.f
                $(FC) $(FFLAGS) -c main.f
an, daß das ''Ziel'' (File) main.o neu erstellt werden muß, wenn sich das File main.f oder ein mögliches Include-File geändert haben. Die zweite Zeile gibt an, was in einem solchen Fall zu tun ist, nämlich neu kompilieren. Es ist auch möglich, daß das Ziel von Files abhängt, die quasi als Zwischenziele ebenfalls im Makefile angegeben sind. Diese werden dann zunächst überprüft und ggf. neu erstellt. Etwa im Beispiel
        linalg: $(OBJECTS)
                $(FC) $(OBJECTS) $(LIBS) -o $@ $(LFLAGS)
enthalte die Variable OBJECTS die Liste aller Objekt-Dateien, aus denen das Programm linalg bestehen soll. Um linalg auf den neuesten Stand zu bringen, müssen also zuerst alle Object-Files, deren Source-Files sich geändert haben oder die überhaupt noch nicht vorhanden sind, neu erzeugt werden, wobei entsprechende Makefile-Einträge wie oben für main.o verwendet werden. Erst dann wird der angegebene Link-Schritt ausgeführt. LFLAGS und LIBS stehen dabei für vorher definierte Variable, die spezielle Link-Optionen oder Libraries enthalten, die Variable $@ ist eine Abkürzung für den Namen des Ziels, hier also für linalg.
Möchte man nach einigen Änderungen linalg neu übersetzen, werden nach dem Aufruf ''make linalg'' oder einfach ''make'' (dann wird das erste Ziel im Makefile benutzt) alle nötigen Schritte unternommen. Hat sich nichts geändert, meldet sich make mit ''`linalg' is up to date.''
Manchmal möchte man einen Schritt ausführen, obwohl das zugehörige File sich nicht geändert hat, z.B. weil man in FFLAGS neue Optionen eingetragen hat. Eine Möglichkeit ist, das Makefile selbst in die Liste der Abhängigkeiten mit aufzunehmen. Allerdings wird dann bei jeder Änderung des Makefiles immer alles ganz neu übersetzt. Alternativ kann man auch einfach den Datumsstempel des aufzufrischenden Files mit ''touch main.f'' ändern.
Gewisse Aktionen kommen immer wieder in gleicher Weise vor, z.B. das Übersetzen von Source-Files in Object-Files. Um das Erstellen eines Makefiles weiter zu vereinfachen, kann man für solche Aktionen im Makefile Regeln definieren, die von File-Endungen abhängen. Zunächst muß man in einer ''SUFFIXES''-Zeile angeben, welche Endungen besonders behandelt werden sollen, z.B.
        .SUFFIXES: .o .f
Dann kann man die eigentlichen Regeln definieren, etwa:
        .f.o:
                /usr/convex/fc $(FFLAGS) -c $*.f
Die 1. Zeile gibt an, daß die folgenden Aktionszeilen (bis zur nächsten Leerzeile) benutzt werden sollen, um aus .f-Files .o-Files zu erzeugen. Die Aktionszeilen haben die gleiche Form wie sonst, allerdings gibt es in Regeln zusätzliche Variable. $$*$ etwa bezeichnet den Namen des Ziels ohne die Endung, d.h. $$*$ = main, falls main.o erzeugt werden soll. Nach einer solchen Definition braucht man keine Abhängigkeiten von Object-Files mehr anzugeben, sondern make benutzt diese Regel, wenn es ein .o-File braucht und ein zugehöriges .f-File findet. Da einige Regeln eigentlich immer gebraucht werden (z.B. die oben angegebene), sind sie schon systemweit vordefiniert. Eine Liste dieser Regeln erhält man mit ''make -p -q''.

Eine nützliche Option von make ist ''-n''. Damit gibt make alle Kommandos aus, die es jetzt absetzen würde, ohne sie aber auszuführen. Das ist vor allem dann nützlich, wenn man Besonderheiten in seinem Makefile ausprobiert (wie eigene Regeln). Weitere Optionen und Möglichkeiten von make kann man dem Handbuch entnehmen.

Zum Schluß noch ein Beispiel, das zeigt, daß man mit make nicht nur kompilieren kann:

        clean:
                -/bin/rm *.o
                -/bin/rm *~
Nach ``make clean'' werden immer die angegebenen Aufräum-Kommandos ausgeführt. ''-'' am Anfang einer Aktionszeile bewirkt, daß make mit der nächsten Zeile weiter macht, wenn eine Zeile einen Fehler meldet. (rm gibt z.B. einen Fehler zurück, wenn kein File gelöscht wird.)

previous    contents     next

Peter Junglas 18.10.1993