make

Aus Mikiwiki
Version vom 7. Februar 2010, 15:27 Uhr von Michi (Diskussion | Beiträge)
(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)
Zur Navigation springen Zur Suche springen

Der Shell-Befehl make übersetzt beim Kompilieren den Quelltext und installiert das fertige Programm anhand der Variablen und Anweisungen in einer Steuerdatei mit dem Namen "GNU-makefile", "makefile" oder "Makefile". Diese Datei wird genau in dieser Reihenfolge im aktuellen Verzeichnis gesucht.

LATEX-Anwender verwenden make bei grösseren Projekten gern dazu, ein Postscript- oder PDF-Dokument neu zu kompilieren und zu erstellen, wenn eine oder mehrere der Quelldateien verändert wurden.

Bei Bedarf kann make beispielsweise auch ein Sicherungsskript anstossen, wenn auf der Festplatte eine oder mehrere Dateien verändert wurden.

Syntax

# Kommentar
Ziel: [vorausgesetzte Dateien]
      Befehl
      Befehl
      ...

Optionen

Option Beschreibung
-d Ausgabe von Debugging-Informationen. Geeigneter Aufruf:
$ make -d | more

Steuerdatei

Die Steuerdatei heisst üblicherweise "GNU-makefile", "makefile" oder "Makefile".

Variable Beschreibung
CC Compiler
CFLAGS Optionen des Compilers
DEST Zielverzeichnis, wohin das kompiliert Programm schliesslich kopiert wird. Der Wert dieser Variablen muss geändert werden, wenn z. B. "/opt/program" als Zielverzeichnis verwendet werden soll.
MAN Pfad zur Manual-Seite.
MAN1 Pfad zur Manual-Seite

Ausser Variablen stehen in der Steuerdatei auch sogenannte Ziele (engl. target). Dies sind Zeilen, die die Optionen beim Aufruf von "make" festlegen. Ziele stehen am Anfang einer Zeile und schliessen mit einem Doppelpunkt (z. B. "uninstall: "). Hinter dem Doppelpunkt folgen (optional) die Dateien, dir das Ziel zum Erzeugen voraussetzt. Danach folgen durch einen Tabulator (keine Leerzeichen!) eingerückt zeilenweise die Befehle, also diejenigen Aktionen, die das Programm im Fall erfüllter Abhängigkeiten ausführen soll. Lange Zeilen können mit einem Rückstrich ( \ ) am Zeilenende umgebrochen werden. Kommentare stehen hinter einem Doppelkreuz.

Variablen

Variable Beschreibung
$@ Das aktuelle Ziel.
$? Die veränderten Abhängigkeiten, also die Dateien, die immer hinter dem Doppelpunkt des Ziels stehen.

Definition einer Variable.

TEXDATEIEN = kap01.tex kap02.tex kap03.tex \
               kap04.tex kap05.tex kap06.tex\
               kap07.tex buch.tex
buch.dvi: $(TEXDATEIEN)
          latex buch

Verwendung

Übergabe eines Steuerdateinamens, der von make nicht von sich aus als Makefile identifiziert wird.

$ make -f steuerdatei

Angabe des Verzeichnisses, in dem make arbeiten soll.

$ make -C ~/buch

Falls sich an den Quelldateien nichts geändert hat und make dennoch zur Arbeit gezwungen werden soll.

$ make -B buch.pdf

Beispiel: Zusammenarbeit mit LATEX

Gegeben ist ein Makefile, das beim Erstellen eines Buchs mit LATEX hilft. Das Buch selbst liegt in mehreren Dokumenten vor, z. B. gibt es für jedes Kapitel eine eigene Datei. Aus diesen einzelnen Dokumenten bildet LaTeX die Datei "buch.tex".

Zuerst wird eine DVI-Datei erstellt. Make soll den Befehl "latex" nur aufrufen, wenn sich eine der Quelldateien verändert hat.

buch.dvi: kap01.tex kap02.tex kap03.tex \
             kap04.tex kap05.tex kap06.tex\
             kap07.tex buch.tex
          latex buch

Zur automatischen Erzeugung einer Postscript-Datei wird das Programm Dvips verwendet. Auch Dvips wird nur aufgerufen, wenn sich die DVI-Datei des ersten Zieles verändert hat.

buch.ps: buch.dvi
         dvips -q -o buch.ps buch

Bei Bedarf kann aus der Postscript-Datei anschliessend eine PDF-Datei erstellt werden.

buch.pdf: buch.ps
          ps2pdf buch.ps buch.pdf

Je nach Bedarf lohnt sich eine ordentliche Sicherung, bei der die Tex-, PostScript- und PDF-Dateien mit tar zusammengepackt, gezippt und mittels scp auf einen entfernten Rechner kopiert werden.

backup: kap01.tex kap02.tex kap03.tex \
           kap04.tex kap05.tex kap06.tex\
           kap07.tex buch.tex buch.ps buch.pdf
        tar cvfj backup.tar.bz2 *.tex buch.ps buch.pdf
        scp backup.tar.bz2 mik@10.0.1.1:

Das so erstellte Makefile kann auf verschiedene Arten aufgerufen werden.

  • Bei Aufruf von "make" wird lediglich das erste Ziel abgearbeitet, es wird also eine DVI-Datei erstellt, falls mindestens eine der Tex-Dateien verändert wurde.
  • Alternativ kann dem Befehl beim Aufruf ein anderes Ziel übergeben werden, z. B. "make backup", um eine Sicherungskopie zu erstellen.

Fehlerbehebung

Geht für make etwas schief, so gibt das Programm oft eine grosse Anzahl von Fehlermeldungen aus. Entscheidend ist dabei die erste, bei allen weiteren handelt es sich üblicherweise um Folgefehler.

Fehlende Datei

Im folgenden Beispiel wird beim Übersetzen der Datei "decodeRFC2047.cpp" die Datei "mimepp.h" nicht gefunden ("No such file or directory") - in diesem Fall kann das Problem einfach durch Installation des Pakets behoben werden, in dem diese Datei enthalten ist.

$ make
...
decodeRFC2047.cpp:21:28: mimelib/mimepp.h: No such file or directory
decodeRFC2047.cpp: In function `QCString decodeQuotedPrintable(const QCString&)':
decodeRFC2047.cpp:40: error: `DwString' undeclared (first use this function)
...
make[2]: *** [decodeRFC2047.o] Fehler 1
make[2]: Leaving directory `/home/andi/test/kshowmail-3.1.0-pre1/kshowmail'
make[1]: *** [all-recursive] Fehler 1
make[1]: Leaving directory `/home/andi/test/kshowmail-3.1.0-pre1'
make: *** [all] Fehler 2

Fehlende Klasse

Das folgende Beispiel zeigt einen Fehler, der beim Übersetzen der Datei "legacyimport.cpp" auftaucht: "`KInputDialog' undeclared (first use this function)". Im konkreten Fall bedeutet das, dass die hier zum ersten Mal in einer Funktion zum Einsatz kommende Klasse "KInputDialog" zuvor nirgendwo definiert wurde, sodass der Compiler nicht weiss, wo er nachsehen soll und ihm damit ein Teil Code fehlt, den er zum Übersetzen benötigt: Er vermisst die Anweisungen, wie er ein Fenster mit Eingabezeile und "OK"-Schaltfläche erzeugen soll.

$ make
...
legacyimport.cpp: In member function `void KLegacyImport::finished()':
legacyimport.cpp:143: `KInputDialog' undeclared (first use this function)
legacyimport.cpp:143: (Each undeclared identifier is reported only once for each
function it appears in.)
legacyimport.cpp:143: parse error before `::' token
make: *** [legacyimport.o] Error 1

Um die vielen Arbeitsschritte, die ein solch komplexes Objekt erzeugen, nicht jedes Mal neu schreiben zu müssen, legen Entwickler sie in wiederverwertbaren Klassen ab. Benötigen sie ein Objekt dieser Klasse, so rufen sie einfach den jeweiligen "Konstruktor" auf. Klassen gehören zu den Schnittstellen eines Rechnerprogramms und werden daher bei C- und C++-Programmen normalerweise in den auf ".h" endenden Header-Dateien aus den "dev(el)"-Paketen abgelegt. Damit alle an der Übersetzung beteiligten Programme diese Klassen finden, schreibt der Entwickler sogenannte Include-Zeilen in den Quelltext. Die folgende Zeile weist den Compiler an, Code einzubinden, der in der Datei "kmessagebox.h" in einem der Include-Verzeichnisse steht. Das sind die Verzeichnisse, die das "Makefile" dem Compiler als Option nach dem Schalter "-I" mitgibt.

#include <kmessagebox.h>

In der folgenden Zeile fehlen die spitzen Klammern, also verwendet der Compiler die Datei "meininclude.h", die im selben Verzeichnis wie die zu übersetzende Datei liegt.

#include "meininclude.h"

Da in der obenstehenden Fehlermeldung nicht steht, dass eine Datei fehlt, hat der Entwickler vermutlich vergessen, die die Klasse enthaltende Datei einzubinden. Um dieses Problem zu beheben, muss die Datei gefunden werden - am besten mit Hilfe des Befehls grep, der Dateien nach einem Suchbegriff durchsuchen kann. Zuerst wird sinnvollerweise im Quellcode-Verzeichnis bzw. in dessen Unterverzeichnis "src" gesucht. Der folgende Befehl sucht in allen auf ".h" endenden Dateien nach der Zeichenfolge "KInputDialog".

$ grep KInputDialog *.h

Im Beispiel führt das nicht zum Erfolg, denn "KInputDialog" ist eine allgemeine KDE-Klasse, die sich in den Include-Verzeichnissen des Systems befindet. Das sind gewöhnlich "/usr/include" und "/usr/local/include", bei KDE manchmal aber auch "/opt/kde3/include". Der folgende Befehl liefert auf dem Beispielsystem zwei Treffer: die Dateien "kinputdialog.h" und "klineeditdlg.h".

$ grep -r KInputDialog /usr/local/include/*

Der passende Eintrag in der Datei "klineeditdlg.h" ist nur ein Kommentar, doch die Zeilen aus "kinputdialog.h" sehen eindeutig so kompliziert aus, wie man sich eine Klasse (class) vorstellt:

/usr/local/include/kinputdialog.h:class KInputDialog : public KDialogBase
/usr/local/include/kinputdialog.h:    KInputDialog( const QString &caption, const QString &label,

Ein weiterer Hinweis: die Datei heisst wie die Klasse, nur kleingeschrieben. Testweise wird nun in die Datei "legacyimport.cpp" nach allen anderen Include-Zeilen die folgende eingetragen:

#include <kinputdialog.h>

make meldet danach tatsächlich keine Fehler mehr. Die beschriebene Methode führt natürlich nur zum Ziel, wenn die Include-Datei mit der passenden Definition bereits auf dem aktuellen System installiert ist.

Weblinks

Herausgeber Sprache Webseitentitel Anmerkungen
Wikipedia ger makewbm Enzyklopädischer Artikel
Linux User ger So beheben Sie Fehler bei der Ausführung von makewbm