|
|
make
Sobald ein Programm aus mehreren Dateien besteht, ist schnell der Punkt
erreicht, wo es sinnvoll ist, sich einen kurzen Batch für das Compilieren
zu schreiben. Statt dessen sollten Sie lieber
ein Makefile schreiben. Das ist nicht viel aufwändiger, hat aber
den Vorteil, dass das Programm
Das Projekt meinprog besteht aus den Sourcedateien haupt.c, test.c und tools.c.
Jede dieser
Dateien hat eine Headerdatei (haupt.h, test.h und tools.h), die es jeweils
selbst einbindet. Dazu bindet haupt.c jede andere Headerdatei ein und jedes
Modul bindet die globalen Definitionen aus haupt.h ein.
Eine Datei Makefile wird angelegt und darin wird der Weg der Compilierung
beschrieben. Das Programm meinprog hängt von den Dateien test.o, haupt.o und
tools.o ab. Das formuliert man in einem Makefile folgendermaßen:
meinprog: test.o haupt.o tools.o
Mit dieser Zeile wird die Abhängigkeit der Datei meinprog von den
Dateien test.o, haupt.o und tools.o definiert.
Man bezeichnet meinprog als Ziel oder englisch target.
Die darauf folgenden Zeilen beschreiben, wie die Zieldatei hergestellt wird.
Die Datei meinprog wird generiert, indem der Compiler
mit den Objektdateien als Parameter aufgerufen wird. Mit Hilfe der Option -o
legen Sie fest, dass das Ergebnis meinprog heißen soll.
Der Compiler merkt von sich aus, dass er hier nur linken
soll, da keine echten Quellcodedateien vorhanden sind. Solche Aktionszeilen
müssen mit einem Tabulator beginnen. Es dürfen keine Leerzeichen verwendet
werden.
meinprog: test.o haupt.o tools.o cc -o meinprog test.o haupt.o tools.o
Wer nun einfach make aufruft, erhält überraschenderweise bereits
ein komplett übersetztes Programm. Auf dem Bildschirm erscheinen folgende
Zeilen:
gaston> make cc -c -o test.o test.c cc -c -o haupt.o haupt.c cc -c -o tools.o tools.c cc -o meinprog test.o haupt.o tools.o gaston>
Tatsächlich »weiß«
make , wie man aus c-Dateien o-Dateien macht
und da er mit den Regeln des Makefiles die o-Dateien nicht erzeugen kann,
sieht make im aktuellen Verzeichnis nach, ob es Dateien gibt, aus
denen er o-Dateien generieren kann.
Ändern Sie die Datei test.c, so wird nur test.c übersetzt
und meinprog neu gebunden.
Ändern Sie allerdings test.h, passiert nichts.
make kennt die
Abhängigkeiten der Header nicht. Damit make auch Änderungen der
Headerdateien überwacht, ist folgende Änderung im Makefile notwendig.
test.o : test.c test.h haupt.h
tools.o : tools.c tools.h haupt.h
haupt.o : haupt.c haupt.h test.h tools.h
Eine vollständige Aktionszeile müsste hier eigentlich etwa so lauten:
test.o : test.c test.h haupt.h cc -c -o test.o test.c
Da aber
make die erforderliche Aktion bereits kennt, braucht man
sie nicht zu erwähnen.
Das Programm Ein Makefile hat Einträge der folgenden Grundstruktur:
Ziel : Abhängigkeiten
Generierungskommando Diese Grundstruktur nennt man Regel. Eine neue Regel muss mit einer Leerzeile von der vorherigen getrennt werden. Der Leerraum vor dem Generierungskommando muss ein Tabulatorzeichen sein. Es können auch mehrere Kommandozeilen nacheinander angegeben werden. Alle müssen mit Tabulator eingerückt sein. Die Kommandozeilen werden jeweils in einer separaten Shell abgearbeitet. In manchen Situationen gibt das Seiteneffekte, die Sie berücksichtigen müssen. Beispiel:
try : cd .. ; pwd pwd
Die Ergebnisse der beiden Aufrufe von
cd .. ; pwd /home/arnold/my/src/unix pwd /home/arnold/my/src/unix/make Hängen also Kommandos so zusammen, dass sie in einer gemeinsamen Shell bearbeitet werden müssen, sollten sie in dieselbe Zeile geschrieben werden und mit Semikola getrennt werden. Bei langen Zeilen kann mit einem Backslash die Zeile in der nächsten Zeile fortgesetzt werden. Als Kommentarzeichen gilt das # in der ersten Spalte.
Makros im MakefileDurch die Verwendung von Makros können die Makefiles besser strukturiert und flexibler gestaltet werden. Makros sind Variablen, denen Zeichenketten zugewiesen werden und dann durch Voranstellen eines $-Zeichens ausgewertet werden. Durch das Zusammenfassen von Dateinamen oder Optionen kann ein Makefile kürzer und vor allem besser lesbar werden.
Im Beispiel werden die Objektdateien zusammen behandelt und zweimal
aufgezählt, einmal in der Abhängigkeitsbeschreibung von meinprog
und dann im Compileaufruf.
meinprog: test.o haupt.o tools.o cc -o meinprog test.o haupt.o tools.o
Hier können Sie eine Variable OBJS definieren, die die Objekte bezeichnet.
Durch Einsetzen von OBJS ergibt sich die folgende Makedatei.
OBJS = test.o haupt.o tools.o
meinprog: $(OBJS) cc -o meinprog
Die Variablen müssen nicht im Makefile selbst definiert werden.
Vordefinierte MakrosEs ist möglich, mehrere Ziele mit einer Regel zu behandeln. So könnte beispielsweise $(OBJS) als Ziel verwendet werden. Die einzelnen Ziele werden nacheinander aufgelöst. Im Generierungskommando kann auf das aktuelle Ziel Bezug genommen werden. Dazu gibt es vordefinierte Makros, die hier am Beispiel haupt.o aufgezeigt werden.
[Vordefinierte make-Makros]L|L
Makro & Bedeutung
SuffixregelnDie Suffixregeln beschreiben den Übergang einer Dateiendung zu einer anderen. Eine solche Regel erkennen Sie daran, dass das Ziel die zwei Dateiendungen mit dem jeweiligen Punkt am Anfang direkt hintereinander stehen hat.
.quell.ziel: Der typischste Übergang ist sicher der von C-Sourcen zu Objekten. Die Sourcen enden auf c und die Objektdateien auf o. Die entsprechende Suffixregel lautet dann:
.c.o: cc -c $< Das interne Makro $< darf nur bei Suffixregeln verwendet werden und bezeichnet das aktuelle Ziel.
Mehrere ZieleEin Makefile kann mehrere Programme generieren. Das wird eingesetzt, wenn gleiche Quelltexte für mehrere Projekte gebraucht werden, die vielleicht sogar noch voneinander abhängig sind. Ein typisches Beispiel sind Client- und Serverprogramme, die in den Headern gleiche Datenstrukturen verwenden.
all: client server
client: (COMMONOBJS)
$(CLTOBJS)
...
\par server:$
(SENDHEADER) (SRVOBJS)
...
Das erste Ziel ist immer das Ziel des gesamten Makefiles. In diesem Fall
würde also beim Aufruf von Oft werden Makefiles auch zur Installation verwendet. Dazu wird ein Pseudoziel install eingeführt, das überprüft, ob alle Dateien des Projektes an den richtigen Stellen vorhanden sind und ansonsten als Aktion einfache Kopierbefehle absetzen. Aufgerufen wird so eine Installation mit make und als Parameter das Ziel install.
make install
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|