FreeBSD Developers' Handbook
Zurück | Kapitel 2. Werkzeuge zur Programmierung | Weiter

# 2.5. Make

## 2.5.1. Was ist `make`?

Wenn Sie an einem einfachen Programm mit nur einer oder zwei Quelltextdateien arbeiten, ist die Eingabe von

    % cc file1.c file2.c

zwar nicht aufwendig, wird aber mit zunehmender Anzahl der Quelltextdateien sehr lästig--und auch das Kompilieren kann eine Weile dauern.

Eine Möglichkeit dies zu umgehen besteht in der Verwendung von Objektdateien, wobei man nur die Quelltextdateien neu kompiliert, die verändert wurden. So könnten wir etwa folgendes erhalten:

    % cc file1.o file2.o ... file37.c ...

falls wir seit dem letzten Kompiliervorgang nur die Datei `file37.c` verändert haben. Dadurch könnte der Kompiliervorgang um einiges beschleunigt werden, es muß jedoch immer noch alles von Hand eingegeben werden.

Oder wir könnten uns ein Shell Skript schreiben. Dieses würde jedoch alles immer wieder neu kompilieren, was bei einem großen Projekt sehr ineffizient wäre.

Was ist, wenn wir hunderte von Quelltextdateien hätten? Was ist, wenn wir in einem Team mit anderen Leuten arbeiten würden, die vergessen uns Bescheid zu sagen, falls sie eine der Quelltextdateien verändert haben, die wir ebenfalls benutzen?

Vielleicht könnten wir beide Lösungen kombinieren und etwas wie ein Shell Skript schreiben, welches eine Art magische Regel enthalten würde, die feststellt, welche Quelltextdateien neu kompiliert werden müssten. Alles was wir bräuchten wäre ein Programm, das diese Regeln verstehen könnte, da diese Aufgabe etwas zu kompliziert für eine Shell ist.

Dieses Programm heißt `make`. Es liest eine Datei namens makefile, welche ihm sagt, wie unterschiedliche Dateien voneinander abhängen, und berechnet, welche Dateien neu kompiliert werden müssen und welche nicht. Zum Beispiel könnte eine Regel etwas sagen wie “wenn `fromboz.o` älter als `fromboz.c` ist, bedeutet dies, daß jemand die Datei `fromboz.c` verändert haben muß, und diese daher neu kompiliert werden muß.” Das makefile enthält außerdem Regeln die make sagen, wie die Quelltextdatei neu kompiliert werden muß, was dieses Tool noch sehr viel mächtiger macht.

Makefiles werden normalerweise im selben Verzeichnis wie die Quelltextdateien abgelegt, zu denen sie gehören, und kann `makefile`, `Makefile` oder `MAKEFILE` heißen. Die meisten Programmierer verwenden den Namen `Makefile`, da diese Schreibweise dafür sorgt, daß die Datei gut lesbar ganz oben in der Verzeichnisliste aufgeführt wird. [1]

## 2.5.2. Beispielhafte Verwendung von `make`

Hier ist eine sehr einfache make Datei:

    foo: foo.c
        cc -o foo foo.c

Sie besteht aus zwei Zeilen, einer Abhängigkeitszeile und einer Erzeugungszeile.

Die Abhängigkeitszeile hier besteht aus dem Namen des Programms (auch Ziel genannt), gefolgt von einem Doppelpunkt und einem Leerzeichen, und anschließend dem Namen der Quelltextdatei. Wenn `make` diese Zeile liest überprüft es die Existenz von `foo`; falls diese Datei existiert vergleicht es das Datum der letzten Änderung von `foo` mit der von `foo.c`. Falls `foo` nicht existiert, oder älter als `foo.c` ist, liest es die Erzeugungszeile um herauszufinden, was zu tun ist. Mit anderen Worten, dies ist die Regel die festlegt, wann `foo.c` neu kompiliert werden muß.

Die Erzeugungszeile beginnt mit einem tab (drücken Sie dazu die tab-Taste) gefolgt von dem Befehl, mit dem Sie `foo` manuell erzeugen würden. Wenn `foo` veraltet ist, oder nicht existiert, führt `make` diesen Befehl aus, um die Datei zu erzeugen. Mit anderen Worten, dies ist die Regel die make sagt, wie `foo.c` kompiliert werden muß.

Wenn Sie also `make` eingeben wird dieses sicherstellen, daß `foo` bzgl. Ihrer letzten Änderungen an `foo.c` auf dem neuesten Stand ist. Dieses Prinzip kann auf `Makefile`s mit hunderten von Zielen--es ist bei FreeBSD praktisch möglich, das gesamte Betriebssystem zu kompilieren, indem man nur `make world` im richtigen Verzeichnis eingibt!

Eine weitere nützliche Eigenschaft der makefiles ist, daß die Ziele keine Programme sein müssen. Wir könnten zum Beispiel eine make Datei haben, die wie folgt aussieht:

    foo: foo.c
        cc -o foo foo.c

    install:
        cp foo /home/me

Wir können make sagen welches Ziel wir erzeugt haben wollen, indem wir etwas wie folgt eingeben:

    % make target

`make` wird dann nur dieses Ziel beachten und alle anderen ignorieren. Wenn wir zum Beispiel `make foo` mit dem obigen makefile eingeben, dann wird make das Ziel `install` ignorieren.

Wenn wir nur `make` eingeben wird make immer nur nach dem ersten Ziel suchen und danach mit dem Suchen aufhören. Wenn wir hier also nur `make` eingegeben hätten, würde es nur zu dem Ziel `foo` gehen, gegebenenfalls `foo` neu kompilieren, und danach einfach aufhören, ohne das Ziel `install` zu beachten.

Beachten Sie das das `install`-Ziel von nichts anderem abhängt! Dies bedeutet, daß der Befehl in der nachfolgenden Zeile immer ausgeführt wird, wenn wir dieses Ziel mittels `make install` aufrufen. In diesem Fall wird die Datei `foo` in das Heimatverzeichnis des Benutzers kopiert. Diese Vorgehensweise wird häufig bei makefiles von Anwendungen benutzt, damit die Anwendung nach erfolgreicher Kompilierung in das richtige Verzeichnis installiert werden kann.

Dieser Teil ist etwas schwierig zu erklären. Wenn Sie immer noch nicht so richtig verstanden haben, wie `make` funktioniert, wäre es das Beste, sie erstellen sich selber ein einfaches Programm wie “hello world” und eine make Datei wie die weiter oben angegebene, und experimentieren damit selber ein bischen herum. Als nächstes könnten Sie mehrere Quelltextdateien verwenden, oder in Ihrer Quelltextdatei eine Header-Datei includen. Der Befehl `touch` ist an dieser Stelle ganz hilfreich--er verändert das Datum einer Datei, ohne das Sie diese extra editieren müssen.

## 2.5.3. Make und include-Dateien

C-Code beginnt häufig mit einer Liste von Dateien, die included werden sollen, zum Beispiel stdio.h. Manche dieser Dateien sind include-Dateien des Systems, andere gehören zum aktuellen Projekt, an dem Sie gerade arbeiten:

    #include <stdio.h>
    #include "foo.h"

    int main(....

Um sicherzustellen, daß diese Datei neu kompiliert wird, wenn `foo.h` verändert wurde, müssen Sie diese Datei Ihrem `Makefile` hinzufügen:

    foo: foo.c foo.h

Sobald Ihr Projekt größer wird und Sie mehr und mehr eigene include-Dateien verwalten müssen wird es nur noch sehr schwer möglich sein, die Übersicht über alle include-Dateien und Dateien, die von diesen abhängen, beizubehalten. Falls Sie eine include-Datei verändern, jedoch das erneute Kompilieren aller Dateien, die von dieser Datei abhängen, vergessen, werden die Folgen verheerend sein. Der `gcc` besitzt eine Option, bei der er Ihre Dateien analysiert und eine Liste aller include-Dateien und deren Abhängigkeiten erstellt: `-MM`.

Wenn Sie das Folgende zu Ihrem Makefile hinzufügen:

    depend:
        gcc -E -MM *.c > .depend

und `make depend` ausführen, wird die Datei `.depend` mit einer Liste von Objekt-Dateien, C-Dateien und den include-Dateien auftauchen:

    foo.o: foo.c foo.h

Falls Sie `foo.h` verändern werden beim nächsten Aufruf von `make` alle Dateien, die von `foo.h` abhängen, neu kompiliert.

Vergessen Sie nicht jedes mal `make depend` aufzurufen, wenn Sie eine include-Datei zu einer Ihrer Dateien hinzugefügt haben.

## 2.5.4. FreeBSD Makefiles

Makefiles können eher schwierig zu schreiben sein. Glücklicherweise kommen BSD-basierende Systeme wie FreeBSD mit einigen sehr mächtigen solcher Dateien als Teil des Systems daher. Ein sehr gutes Beispiel dafür ist das FreeBSD Portssystem. Hier ist der grundlegende Teil eines typischen `Makefile`s des Portssystems:

    MASTER_SITES=   ftp://freefall.cdrom.com/pub/FreeBSD/LOCAL_PORTS/
    DISTFILES=      scheme-microcode+dist-7.3-freebsd.tgz

    .include <bsd.port.mk>

Wenn wir jetzt in das Verzeichnis dieses Ports wechseln und `make` aufrufen, passiert das Folgende:

1. Es wird überprüft, ob sich der Quelltext für diesen Port bereits auf Ihrem System befindet.

2. Falls dies nicht der Fall ist wird eine FTP-Verbindung zu der URL in `MASTER_SITES` aufgebaut und der Quelltext heruntergeladen.

3. Die Checksumme für den Quelltext wird berechnet und mit der schon bekannten und für sicher und gut empfundenen verglichen. Damit wird sichergestellt, daß der Quelltext bei der Übertragung nicht beschädigt wurde.

4. Sämtliche Anpassungen, die nötig sind, damit der Quelltext unter FreeBSD funktioniert, werden vorgenommen--dieser Vorgang wird auch patchen genannt.

5. Alle speziellen Konfigurationen, die am Quelltext nötig sind, werden vorgenommen. (Viele UNIX® Programmdistributionen versuchen herauszufinden, auf welcher UNIX-Version sie kompiliert werden sollen und welche optionalen UNIX-Features vorhanden sind--an dieser Stelle erhalten sie die Informationen im FreeBSD Ports Szenario).

6. Der Quelltext für das Programm wird kompiliert. Im Endeffekt wechseln wir in das Verzeichnis, in das der Quelltext entpackt wurde, und rufen `make` auf--die eigene make-Datei des Programms besitzt die nötigen Informationen um dieses zu bauen.

7. Wir haben jetzt eine kompilierte Version des Programmes. Wenn wir wollen können wir dieses jetzt testen; wenn wir überzeugt vom Programm sind, können wir `make install` eingeben. Dadurch werden das Programm sowie alle zugehörigen Dateien an die richtige Stelle kopiert; es wird auch ein Eintrag in der Paketdatenbank erzeugt, sodaß der Port sehr einfach wieder deinstalliert werden kann, falls wir unsere Meinung über dieses geändert haben.

Ich glaube jetzt werden Sie mit mir übereinstimmen, daß dies ziemlich eindrucksvoll für ein Skript mit vier Zeilen ist!

Das Geheimnis liegt in der letzten Zeile, die `make` anweist, in das makefile des Systems mit dem Namen `bsd.port.mk` zu sehen. Man kann diese Zeile zwar leicht übersehen, aber hierher kommt all das klevere Zeugs--jemand hat ein makefile geschrieben, welches `make` anweist, alle weiter oben beschriebenen Schritte durchzuführen (neben vielen weiteren Dingen, die ich nicht angesprochen habe, einschließlich der Behandlung sämtlicher Fehler, die auftreten könnten) und jeder kann darauf zurückgreifen, indem er eine einzige Zeile in seine eigene make-Datei einfügt!

Falls Sie einen Blick in die makefiles des Systems werfen möchten, finden Sie diese in `/usr/share/mk`. Es ist aber wahrscheinlich besser, wenn Sie damit noch warten, bis Sie ein bischen mehr Praxiserfahrung mit makefiles gesammelt haben, da die dortigen makefiles sehr kompliziert sind (und wenn Sie sich diese ansehen sollten Sie besser eine Kanne starken Kaffee griffbereit haben!)

## 2.5.5. Fortgeschrittene Verwendung von `make`

`Make` ist ein sehr mächtiges Werkzeug und kann noch sehr viel mehr als die gezeigten einfachen Beispiele weiter oben. Bedauerlicherweise gibt es mehrere verschiedene Versionen von `make`, und sie alle unterscheiden sich beträchtlich voneinander. Der beste Weg herauszufinden was sie können ist wahrscheinlich deren Dokumentation zu lesen--hoffentlich hat diese Einführung Ihnen genügend Grundkenntisse vermitteln können, damit Sie dies tun können.

Die Version von make, die in FreeBSD enthalten ist, ist Berkeley make; es gibt eine Anleitung dazu in `/usr/share/doc/psd/12.make`. Um sich diese anzusehen, müssen Sie

    % zmore paper.ascii.gz

in diesem Verzeichnis ausführen.

Viele Anwendungen in den Ports verwenden GNU make, welches einen sehr guten Satz an “info”-Seiten mitbringt. Falls Sie irgendeinen dieser Ports installiert haben wurde GNU make automatisch als `gmake` mit installiert. Es ist auch als eigenständiger Port und Paket verfügbar.

Um sich die Info-Seiten für GNU make anzusehen müssen Sie die Datei `dir` in `/usr/local/info` um einen entsprechenden Eintrag erweitern. Dies beinhaltet das Einfügen einer Zeile wie

     * Make: (make).                 The GNU Make utility.

in die Datei. Nachdem Sie dies getan haben können Sie `info` eingeben und dann den Menüeintrag make auswählen (oder Sie können in Emacs die Tastenkombination `C-h i` verwenden).

### Fußnoten

[1] | Sie verwenden nicht `MAKEFILE` mit lauter Großbuchstaben, da diese Schreibweise häufig für Dokumentationsdateien wie `README` benutzt wird.

Zurück | Zum Anfang | Weiter
Kompilieren mit dem `cc` | Nach oben | Debuggen

Wenn Sie Fragen zu FreeBSD haben, schicken Sie eine E-Mail an <de-bsd-questions@de.FreeBSD.org>.
Wenn Sie Fragen zu dieser Dokumentation haben, schicken Sie eine E-Mail an <de-bsd-translators@de.FreeBSD.org>.