next up previous contents
Nächste Seite: Versionsverwaltung Aufwärts: Vortragsreihe der LUG Dresden Vorherige Seite: Inhalt   Inhalt

Unterabschnitte

Automatisierung

Make

Das Programm make wird meistens verwendet, um C-Programme automatisiert zu übersetzen. Man kann es jedoch auch für alle anderen Fälle verwenden, in denen eine Datei automatisiert in eine andere transformiert werden soll. Vorraussetzung ist natürlich, dass das Programm zur Transformation mit einer ganz normalen Shell aufgerufen und gesteuert werden kann. Zum Beispiel wird die Übersetzung dieses Dokuments in die verschiedenen Formate1.1 über make gesteuert. Ich beziehe mich hier auf die Variante GNU make, die den Vorteil hat nicht nur unter Linux, sondern nahezu allen Unix-Derivaten verfügbar zu sein und die sich am stärksten am POSIX-Standard orientiert1.2.

Damit make weiß, was es zu tun hat, bekommt es Regeln zugewiesen. Diese Regeln sind in einem Makefile abgespeichert1.3.

Regeln

In einer make-Regel gibt man an, welche Datei aus welcher anderen Datei1.4 erstellt werden soll und welche Kommandos benutzt werden, um dies zu tun. Die Arbeit von make besteht nun darin, die Kommandos in der richtigen Reihenfolge und nur dann, wenn nötig, auszuführen.

Eine Regel sieht in etwa so aus:

meinprogramm: meinprogramm.c
        gcc meinprogramm.c -o meinprogramm

Damit wird make gesagt, dass es die Datei meinprogramm aus der Datei meinprogramm.c erstellen kann und dazu das Kommando gcc ... verwenden soll. Ganz wichtig ist hier, dass nich irgendeine Anzahl von Leerzeichen vor dem Programmaufruf stehen sondern exakt ein Tabulator-Zeichen1.5. Um meinprogramm nun wirklich zu erstellen wird einfach make meinprogramm aufgerufen, man übergibt make also einfach den Namen der Datei, die es erstellen soll1.6.

Sehr oft kommt es vor, dass ein Programm (oder eine andere Datei) aus mehreren Ursprungsdateien abgeleitet wird:

meinprogramm: meinprogramm.c zusatz.c
        gcc meinprogramm.c zusatz.c -o meinprogramm

Jedesmal, wenn sich meinprogramm.c oder zusatz.c geändert hat, wird make meinprogramm neu erstellen1.7. Das kann bei komplexen Programmen mit sehr vielen Dateien jedoch schnell aufwändig werden. Man könnte make doch anweisen nur die Dateien neu zu kompilieren, die sich wirklich geändet haben, also teilen wir den Prozess in mehrere Schritte auf:

meinprogramm: meinprogramm.o zusatz.o
        gcc meinprogramm.o zusatz.o -o meinprogramm

meinprogramm.o: meinprogramm.c
        gcc -c meinprogramm.c

zusatz.o: zusatz.c
        gcc -c zusatz.c

make wird nun, wenn es mit make meinprogramm aufgerufen wird, überprüfen, ob meinprogramm.o und zusatz.o vorhanden sind. Da es für beide Dateien eigene Regeln hat wird es überprüfen, ob diese Dateien auch aktueller, als die angegebenen Quelltexte, sind und sie bei Bedarf neu erstellen. Sollte danach eine der beiden Dateien neuer sein als meinprogramm wird es auch diese Regel ausführen.

Nehmen wir an, nur die beiden Quelltexte existieren: make wird feststellen, dass keine der Objektdateien (.o) vorhanden ist und nach einer Möglichkeit suchen sie zu generieren. Es wird auf die entsprechenden Regeln treffen und sie ausführen. Danach wird es die eigentliche Regel für meinprogramm ausführen.

Modifizieren wir danach einen der Quelltexte (sagen wir zusatz.c) und rufen make erneut auf. make stellt nun fest, dass beide Objektdateien schon existieren, danach überprüft es ob sie auch aktuell sind. Es wird feststellen, dass zusatz.o neu erstellt werden muss. Danach wird es die Regel für meinprogramm auf, da zusatz.o inzwischen neuer ist als meinprogramm.

Wenn makenun nocheinmal aufgerufen wird, wird es einfach nur feststellen, dass alle Zieldateien aktuell sind und nicht erneut erstellt werden müssen.

Man sollte an dieser Stelle noch anmerken: die Arbeit mit den Regeln, die die Quelltexte (.c) in Objektdateien (.o) übersetzt haben hätten wir uns sparen können, da make einige Regeln schon im Vorherein kennt. Mehr dazu später.

Wenn make ohne Parameter aufgerufen wird, wählt es die erste Regel im Makefile aus und versucht die angegebene Datei zu erstellen. Es ist üblich entweder einen Hinweis auf den korrekten Aufruf auszugeben oder alle Binärdateien zu erstellen, daher wird diese Regel typischerweise all genannt.

all:
       @echo Bitte rufen Sie make mit dem Parameter
       @echo meinprogramm auf.

oder:

all: meinprogramm

Im ersten Fall wird make einfach nur einen Hinweis ausgeben1.8. Im zweiten Fall ist all von meinprogramm abhängig, was dann auch erstellt wird, dass diese Regel keine Datei ``all'' erstellt ist nicht weiter tragisch, da das Vorhandensein der Datei nur beim Einstieg in die Regel geprüft wird, es führt lediglich dazu, dass die Regel bei jedem Aufruf von make ohne Parameter ausgeführt wird.

Variablen

Es ist natürlich sehr aufwändig lange Parameterlisten für jede Regel erneut zu tippen oder bei einer winzigen Änderung mehrere dutzend Regeln anzupassen. Die Lösung sind Variablen:

X=variable 1
VAR=variable 2

echo:
       echo X=$X
       echo VAR=$(VAR)

Es ist üblich Variablen in Großbuchstaben zu schreiben, es ist aber keine Pflicht. Man sollte jedoch darauf achten, dass man eine Variable immer auf die selbe Art und Weise schreibt, denn make interpretiert Variable und VARIABLE als unterschiedliche Variablennamen. Eine zweite Besonderheit von make ist, dass Variablen mit mehr als einem Buchstaben im Namen immer in runden Klammern ($(VAR) statt $VAR) geschrieben werden müssen.

Angenommen wir müssen mehrere C-Dateien compilieren und dann zusammenlinken, dann könnte das Makefile so aussehen (Auszug):

CC = gcc
CFLAGS = -g -O2
LDFLAGS = -lm

all: ls

ls: lsmain.o filenames.o getuser.o getstat.o
       $(CC) $(LDFLAGS) -o ls lsmain.o filenames.o \
       getuser.o getstat.o

lsmain.o: lsmain.c
       $(CC) $(CFLAGS) -c lsmain.c -o lsmain.o

Der Variablen ``CC'' weisen wir den C-Compiler zu. CFLAGS bekommt alle Optionen für den Compiler1.9. LDFLAGS speichert die Parameter für den Linker1.10.

make erzeugt einige einige zusätzliche Variablen selbst. Man kann sie unter anderem dazu verwenden sich sehr viel Tipparbeit zu sparen. Das Makefile von oben kann dann so abgekürzt werden:

CC = gcc
CFLAGS = -g -O2
LDFLAGS = -lm

all: ls

ls: lsmain.o filenames.o getuser.o getstat.o
       $(CC) $(LDFLAGS) -o $@ $^

lsmain.o: lsmain.c
       $(CC) $(CFLAGS) -c $< -o $@

Ausser den oben verwendeten gibt es noch weitere automatische Variablen:

$@ die Zieldatei
$^ alle Abhängigkeiten dieser Regel
$< die erste Abhängigkeit der Regel
$$ ist keine Variable, sonder wird durch ein einfaches $ ersetzt
$? alle Abhängigkeiten, die neuer als die Zieldatei sind
$(MAKE) der Name mit dem make aufgerufen wurde (da auf einigen Systemen unterschiedliche Varianten von makeexistieren, z.B. make und gmake)

Regeln nach Muster

Es ist natürlich sehr aufwändig einige dutzend Mal die selbe Regel mit unterschiedlichen Dateinamen zu schreiben. Deswegen kann man make allgemeine Muster1.11 geben und mit diesen arbeiten:

CC = gcc
CFLAGS = -g -O2
LDFLAGS = -lm

all: ls

ls: lsmain.o filenames.o getuser.o getstat.o
       $(CC) $(LDFLAGS) -o $@ $^

%.o: %.c
       $(CC) $(CFLAGS) -c $< -o $@

Die Regel %.o: %.c ist eine allgemeine Regel zur Umwandlung von C-Quelltexten in Objektdateien. Diese Regel ersetzt in unserem Beispiel alle derartigen Regeln1.12. Diese Syntax funktioniert nur bei neueren Varianten von make, einige ältere verlangen eine weniger flexible und weniger intuitive Syntax:

.c.o:
       $(CC) $(CFLAGS) -c $< -o $@

Hier kommt eine weitere automatische Variable ins Spiel: $* . Sie enthält bei Pattern-Regeln den identischen Teil von Ziel- und Quelldatei. Nehmen wir mal an, wir wollen die Fehlermeldungen des C-Compilers in eine Datei umleiten, die genauso heißt, wie Quelltext und Objektdatei, aber auf .log endet (statt auf .c oder .o):

%.o: %.c
       $(CC) $(CFLAGS) -c $< 2> $*.log

Spezielle Regeln und Variablen

Und nach all' der Mühe die ganz gemeine Nachricht: wir hätten uns auch diese Regel sparen können, da make einige Regeln bereits kennt. Aus gutem Grund habe ich oben die beiden Variablen CC, CFLAGS und LDFLAGS benutzt, da dies die Variablen sind, die von den eingebauten Regeln benutzt werden.

Dies ist eine Liste der wichtigsten eingebauten Regeln (in %-Pattern-Schreibweise):

ziel Regel
Erklärung
%.o: %.c $(CC) $(CFLAGS) -c $<
compiliert C-Quelltext
%.o: %.cc $(CXX) $(CXXFLAGS) -c $<
compilert C++-Code
%: %.o $(CC) $(LDFLAGS) $(LOADLIBES) -o $@ $^
linkt Objektdateien in ein Programm; um mehr als eine Datei zu linken gibt man einfach weitere Abhängigkeiten an: will man aus x.o, y.o und z.o das Programm x erstellen, dann sieht die Regel so aus: x: y.o z.o

Weitere eingebaute Regeln (z.B. für Modula und Fortran) finden sich im Manual von make1.13.

Einige Regeln haben besondere Bedeutungen, die dazu führen, dass sie nicht ausgeführt werden, sondern die Ausführung der Regeln in ihrer Abhängigkeitsliste verändern, einige davon sind diese:

.PHONY
die aufgeführten Regeln werden in jedem Fall ausgeführt (wenn sie direkt oder indirekt aufgerufen werden), auch wenn dies eigentlich nicht nötig wäre.

.PRECIOUS
die aufgelisteten Dateien (die Ziele von Regeln sind) werden niemals gelöscht, auch wenn sie nur als Zwischenschritt einer anderen Regel aufgerufen wurden oder make unterbrochen wurde (mit Strg-C oder kill).

.SECONDARY
die aufgelisteten Dateien werden nur gelöscht, wenn make unterbrochen wurde.

.INTERMEDIATE
die aufgelisteten Dateien werden sofort gelöscht, wenn sie nicht mehr von make benötigt werden.

.SILENT
die Befehle dieser Regel werden nicht ausgegeben 1.14.

Es hat sich, insbesondere im GNU-Umfeld, durchgesetzt bestimmte Regeln zu definieren, die der Nutzer erwartet:

all
als erste Regel eines Makefile's, die dafür sorgt, dass alle Programme, Bibliotheken, usw. erstellt werden1.15

install
installiert das Programm (die Bibliothek, ...) in das Verzeichnis, das in der Variablen PREFIX angegeben ist1.16

clean
(.PHONY-Regel) löscht alle unnötigen Dateien und die eigentlichen Zieldateien.

uninstall
deinstalliert das Programm wieder.

Wie weiter?

Das war natürlich noch nicht die ganze Dokumentation eines so komplexen Werkzeugs, wie make. Weitere Informationen finden sich in der online-Dokumentation von make1.17.


next up previous contents
Nächste Seite: Versionsverwaltung Aufwärts: Vortragsreihe der LUG Dresden Vorherige Seite: Inhalt   Inhalt
Konrad Rosenbaum 2001-03-04