Projekte mit make erstellen

Das erste Make-Skript

Make ist vereinfacht gesagt eine kleine Skriptsprache, deren vorrangige Aufgabe es ist, ein Ziel zu definieren, seine Abhängigkeiten und die Schritte, die erforderlich sind, um das Ziel zu erreichen. Klingt kompliziert, also das ganze mal in verständlicher Sprache. Das Ziel ist „sauberes Geschirr“, die Abhängigkeiten sind „Spülmaschine kaufen“, „Spülmaschine anschließen“, „Spülmaschine einräumen“ und „Spülmaschine schließen“, die erforderlichen Schritte sind „Spülmaschine einschalten“. Die Abhängigkeiten „Spülmaschine kaufen“ und „Spülmaschine anschließen“ sind bei den meisten Spülvorgängen bereits erfüllt. Wenn die Abhängigkeiten „Spülmaschine einräumen“ und „Schließen schließen“ erfüllt sind, können wir die „Spülmaschine einschalten“ und erreichen so unser Ziel: „sauberes Geschirr“.

Make eignet sich für eine Vielzahl von derartigen Problemen, aber gerade zum Programmieren ist es eben äußerst praktisch.

Man schreibt das Ziel, gefolgt von einem Doppelpunkt und den Abhängigkeiten. In den folgenden Zeilen werden die erforderlichen Schritte beschrieben, die erforderlich sind, um das Ziel zu erreichen. Die Befehle, die die erforderlichen Schritte beschrieben, müssen mit einem „Tab“ beginnen. Viele Editoren, und eben auch diese Website machen daraus 8 Leerzeichen, es muss aber tatsächlich ein Tab sein.

testprogramm: node.o main.o parameter.o
        gcc -o testprogramm node.o main.o parameter.o

Hier haben wir das Ziel Testprogramm, dass von node.o, main.o und parameter.o abhängig ist und als erforderliche Schritte den Aufruf des Compilers (mit dem Tab davor).
Hat man anstatt des geforderten Tabulator-Zeichens doch Leerzeichen verwendet, bekommt man folgende Fehlermeldung:

$ make
Makefile:4: *** missing separator (did you mean TAB instead of 8 spaces?).  Stop.

In diesem Fall müssen natürlich die Leerzeichen durch ein Tabulator-Zeichen ersetzen. Dazu muss eventuell der verwendete Editor konfiguriert werden, Tabs nicht automatisch durch Leerzeichen ersetzen.

Die Objektfiles sind ja nicht zwangsläufig vorhanden. Falls sie nicht vorhanden sind, müssen wir erklären, wie sie entstehen sollen:

main.o: main.c node.h

      gcc -c -o main.o main.c

node.o: node.o node.h parameter.h

      gcc -c -o node.o node.c

parameter.o: parameter.c parameter.h

      gcc -c -o parameter.o parameter.c

testprogramm: node.o main.o parameter.o

      gcc -o testprogramm node.o main.o parameter.o

Die einzelnen Objektfiles sind von entsprechenden Quelltexten abhängig, die es ja gibt. Das ganze speichern wir im gleichen Verzeichnis mit dem Namen „Makefile“ (großes 'M' beachten!).

Make erstellt automatisch das erste Ziel. Daher fügen wir noch ein Ziel „all“. Weiterhin fügen wir ein Ziel „clean“ ein, dass alle erstellten Dateien wieder löscht. Hier das Skript mal vollständig:

all: testprogramm

main.o: main.c
        gcc -c -o main.o main.c

node.o: node.c
        gcc -c -o node.o node.c

parameter.o: parameter.c
        gcc -c -o parameter.o parameter.c

testprogramm: node.o main.o parameter.o
        gcc -o testprogramm node.o main.o parameter.o

clean:
        rm testprogramm *.o

Aufruf

Anschließend rufen wir „make“ auf. Make liest grundsätzlich die Datei „Makefile“, sofern es nicht mit dem Schalter „-f“ umkonfiguriert wird. Aber man möchte den Aufruf ja möglichst kurz halten:

xin@trinity:/home/xin/proggen.org/tutorial/build/make# make
gcc -c -o node.o node.c
gcc -c -o main.o main.c
gcc -c -o parameter.o parameter.c
gcc -o testprogramm node.o main.o parameter.o
xin@trinity:/home/xin/proggen.org/tutorial/build/make# ls -l testprogramm 
-rwxr-xr-x 1 root root 9642 20. Dez 13:04 testprogramm

Nun ändere ich die Datei main.c, in dem ich einen Kommentar anfüge und erstelle anschließend das Projekt neu:

xin@trinity:/home/xin/proggen.org/tutorial/build/make# echo "/* Kommentar */" >> main.c
xin@trinity:/home/xin/proggen.org/tutorial/build/make# make
gcc -c -o main.o main.c
gcc -o testprogramm node.o main.o parameter.o

Make prüft die Abhängigkeiten von 'testprogramm' und stellt dabei fest, dass die Abhängigkeit 'main.o' älter ist als seine Abhängigkeit 'main.c'. Damit erstellt make 'main.o' neu. Die beiden anderen Abhängigkeiten des Ziels 'testprogramm' sind noch aktuell und müssen nicht neu erstellt werden.

Zum Schluss wird das Programm wieder mit der neu kompilierten 'main.o' gelinkt.

Ruft man make ohne eine Änderung auf erhält man folgendes:

xin@trinity:/home/xin/proggen.org/tutorial/build/make# make
make: Für das Ziel »all« ist nichts zu tun.

Mit dem Ziel 'clean' können wir alle Dateien löschen.

xin@trinity:/home/xin/proggen.org/tutorial/build/make# make clean
rm testprogramm *.o
xin@trinity:/home/xin/proggen.org/tutorial/build/make# make
gcc -c -o node.o node.c
gcc -c -o main.o main.c
gcc -c -o parameter.o parameter.c
gcc -o testprogramm node.o main.o parameter.o

Aufgabe

Erstelle ein neues Ziel 'rebuild', dass zunächst alle Objektfiles und die ausführbare Datei löscht und anschließend das Projekt neu erstellt.

Siehe auch

Auf proggen.org existiert bereits ein kleines Make-Tutorial, mit dessen Hilfe diese Makefiles gerade bei mehr Quelltexten deutlich verkürzt werden können. Make kann mit Variablen umgehen und deutlich mehr als auf dieser Seite vorgestellt wurde.

Das Programm 'makedepend' erzeugt automatisch Abhängigkeiten von Quelltexten zu Headerdateien.