SelfLinux Programmierung Make Abschnitt 1 | SelfLinux-0.13.0

| Make | Autor Formatierung GFDL

#### 1 Einführung

Stellen Sie sich vor, Sie möchten ein kleines Programm übersetzen und müssen dazu zu Ihrem Rechner lediglich ein mach mal sagen und Ihr Rechner würde Sie verstehen. Genau zu diesem Zweck gibt es das make-Kommando. Doch ein

user@linux $ make love

wird vom Rechner leider mit einem

don't know how to make 'love'

quittiert. (das GNU-make gibt leider keine so schöne Fehlermeldung aus). Im Verlauf dieses Kapitels werden wir etwas Aufklärungsarbeit für unser Unix-System betreiben, damit es unseren Wunsch erfüllt.

#### 2 Grundlagen

#### 2.1 Ein einfaches Makefile

Basis für unsere Aufklärungsbemühungen ist ein Makefile, aus dem das make-Kommando die nötigen Informationen bezieht, um love zu machen:

    #
    #   Makefile for making love
    #

    love : love.c
            gcc love.c -o love

Jetzt weiss das make-Kommando, dass es nach einem love.c Ausschau halten muss, um dann mit Hilfe des Kommandos gcc love.c -o love (Aufruf des GNU-C-Compilers) ein love zu generieren.

Wenn Sie das Ganze ausprobieren wollen, achten Sie bitte darauf, dass vor gcc ... ein Tabulator-Zeichen steht. Für love.c können Sie folgende C-Quelle verwenden:

love.c

    main()
    {
        printf("Hallo Schatz!\n");
        return 0;
    }

Jetzt haben wir alle Hilfsmittel beisammen, um den Rechner zu einem make love aufzufordern:

user@linux $ make love gcc love.c -o love

Und tatsächlich: der Rechner erwidert unseren Wunsch mit dem Aufruf des GNU-Compilers gcc.... Sollten Sie eine Fehlermeldung (zum Beispiel Makefile:6: *** missing separator...) erhalten, überprüfen Sie bitte nochmal das Makefile: die Zeile mit gcc... muss mit einem Tabulator-Zeichen beginnen! Wenn Sie das Verzeichnis auflisten (zum Beispiel mit ls -l), werden Sie feststellen, dass das make-Kommando tatsächlich ein love erzeugt hat, das sich aufrufen lässt:

user@linux $ ./love Hallo Schatz!

Die beiden Schritte, Kompilation und Programmaufruf, lassen sich natürlich auch zusammen im Makefile unterbringen:

    love : love.c
            gcc love.c -o love
            ./love

Damit wird nach erfolgreicher Kompilation das love-Programm aufgerufen.

#### 2.2 Regel-Werk

Ein Makefile enthält Regeln, die die Abhängigkeiten der Quellen zum Programm, zu Objekt-Dateien, zu Bibliotheken oder auch anderen Dateien definiert. Eine Regel hat dabei typischerweise folgendes Aussehen:

    target: dependencies
            actions

Bei target handelt es sich um das Ziel, das gebaut werden soll (im obigen Beispiel war es love). Die dependencies geben an, wovon das target abhängt (im Beispiel hängt love von love.c ab). Hinter actions verbirgt sich das (oder die) Kommando(s), das/die zum Bau des Targets notwendig ist/sind. Achten Sie bitte darauf, dass die Zeile mit den actions mit einem Tabulator-Zeichen beginnen muss. actions darf dabei aus mehreren Zeilen (= mehrere Kommandos) bestehen, aber alle diese Zeilen müssen mit dem Tabulator-Zeichen beginnen.

Achtung! Leider unterscheidet sich ein Tabulator-Zeichen optisch nicht von 8 Leerzeichen. Das make-Kommando sieht das leider etwas enger und gibt stattdessen eine wenig hilfreiche Fehlermeldung (wie ...missing separator... oder Ähnliches) aus.

Wenn Sie Kommentare in einem Makefile verwenden wollen, leiten Sie diese mit dem #-Zeichen ein. Ein Kommentar erstreckt sich von # bis Zeilenende.

#### 2.3 Abhängigkeiten

Wie kann make wissen, wann es ein Ziel zu bauen hat? Wenn Sie erneut ein make love versuchen, werden Sie von make einen Korb bekommen:

user@linux $ make love make: 'love' is up to date.

Das Geheimnis liegt in den Abhängigkeiten: immer, wenn das Ziel (love) jünger als seine Abhängigkeiten (love.c) ist, geht make davon aus, dass es nichts zu tun gibt. Wenn Sie jetzt love.c editieren und abspeichern, ändert sich dies: jetzt ist love.c jünger. Ein make love wird daraufhin wieder den C-Compiler aufrufen.

Sie werden sich vielleicht fragen: "Wozu der ganze Aufwand? Ich kann doch den C-Compiler manuell aufrufen, wenn ich "love.c" editiere". Aber bei größeren Programmen hat man nicht nur eine C-Quelle, sondern mehrere. Hier hilft das make-Kommando, den Aufruf des Compilers zu automatisieren.

    #
    #   Makefile mit mehreren Abhängigkeiten
    #

    children : mummy.o daddy.o
            gcc mummy.o daddy.o -o children

    mummy.o : mummy.c
            gcc -c mummy.c

    daddy.o : daddy.c
            gcc -c daddy.c

Wie man an diesem Beispiel sieht, können Abhängigkeiten auch mehrstufig sein. children hängt von mummy.o und daddy.o ab. mummy.o und daddy.o sind Objekt-Dateien, die wiederum von mummy.c und daddy.c abhängen. Wenn Sie das erste Mal ein make children eingeben, werden zuerst mummy.o und daddy.o gebaut, ehe daraus dann children erzeugt wird:

user@linux $ make children gcc -c mummy.c gcc -c daddy.c gcc mummy.o daddy.o -o children

Wenn Sie jetzt eine der beiden C-Quellen verändern und erneut das make-Kommando aufrufen, wird nur die Objekt-Datei neu erzeugt, die veraltet ist.

#### 2.4 Pseudo-Ziele

Dies sind Ziele, die keine Abhängigkeiten besitzen. Damit können Sie aber nie up-to-date werden mit dem gewünschten Nebeneffekt, dass von make immer die Aktionen ausgeführt werden, wenn solch ein Pseudo-Ziel aufgerufen wird:

    clean :
            rm *.o core

Jedes Mal, wenn der Benutzer ein make clean eingibt, wird vom make-Kommando ein rm *.o core aufgerufen, d.h. es werden sämtliche Objekt-Dateien (*.o) und core-Dateien (diese werden bei einem Programm-Absturz angelegt) gelöscht.

Weil das Ziel clean nie erzeugt wird, wird es als Pseudo-Ziel bezeichnet.