Makefiles¶
Mit dem Programm make
lassen sich Übersetzungs-Routinen einfach
organisieren. Hierzu wird im Ordner des zu übersetzenden Quellcodes eine Datei
namens Makefile
angelegt. Darin werden Anweisungen nach folgender Regel
festgelegt:
Ziel : Abhängigkeiten
Anweisung(en) zur Generierung
- Die erste Zeile gibt jeweils an, welche (Ziel-)Dateien von welchen (Quell-)Dateien abhängen.
- Nach jeder so festgelegten Abhängigkeitsregel wird in einer oder mehreren Zeilen festgelegt, auf welche Weise die Quelldateien zu übersetzen sind. In jeder Zeile wird üblicherweise eine Anweisung angegeben, mehrere Anweisungen in einer Zeile müssen gegebenenfalls mit einem Strichpunkt getrennt werden.[1] Die Anweisungsliste wird durch eine Leerzeile beendet.
Eine Makedatei enthält üblicherweise mehrere Ziele und zugehörige Übersetzungsregeln.
Der Einsatzbereich von make
ist wegen dem allgemein gehaltenen Aufbau sehr
weitreichend; so findet make
beispielsweise Einsatz beim Compilieren von
eigenem Quellcode, bei Installationsroutinen oder sogar beim Übersetzen von
RestructuredText-Dateien in PDF- oder Html-Dateien mittels Sphinx.
Beispiel:
Eine Makefile zum Übersetzen eines C-Programms namens
hallo-welt.c
in ein ausführbares Programmhallo-welt
sieht im einfachsten Fall folgendermaßen aus:# Makefile-Beispiel 1: hallo: hallo-welt.c gcc -o hallo hallo-welt.c
Speichert man das obige Beispiel als
Makefile
im gleichen Ordner, in dem sich auchhallo-welt.c
befindet, so kann diese aus dem gleichen Ordner heraus in einer Shell mittelsmake hallo
compiliert werden.[2]
Mittels des Hash-Zeichens #
können Makefiles an beliebigen Stellen mit
Kommentaren versehen werden, die jeweils bis zum Zeilenende reichen.
Makefiles werden vor allem dann eingesetzt, wenn mehrere Abhängigkeiten existieren oder wenn mehrere Anweisungen zum Übersetzen notwendig sind: Diese müssen bei Verwendung einer Makefile nur einmal eingegeben werden, was den Schreibaufwand meist erheblich reduziert.
Ein weiterer Vorteil von make
liegt darin, dass nur die Dateien übersetzt
werden, die seit dem letzten Übersetzen verändert wurden. Dabei liest make
nicht den Inhalt der Datei aus, sondern orientiert sich am Änderungsdatum. Dies
spart Zeit und bewirkt, dass keine Datei unnötigerweise übersetzt wird. Falls
sich jedoch, beispielsweise in einer C-Quellcode-Datei, Abhängigkeiten von
anderen Dateien ergeben können, so muss diese C-Datei ebenfalls erneut
gespeichert werden, damit die Änderungen wirksam werden.
Makros
Innerhalb eines Makefiles können so genannte Makros definiert werden, die dazu dienen, eine beliebig lange Zeichenkette durch einen Makro-Namen als Kurzbezeichnung zu ersetzen. Üblicherweise werden die Makro-Namen dabei zur besseren Lesbarkeit in Großbuchstaben geschrieben.
Ein Makro kann anschließend an beliebiger Stelle wieder durch den gespeicherten
Text ersetzt werden, indem man den Makro-Namen in runde Klammern setzt und das
Dollar-Zeichen $
davor schreibt. So lässt sich das obige Makefile-Beispiel
auch folgendermaßen schreiben:
# Makefile-Beispiel 2:
DEST = hallo
SOURCE = hallo-welt.c
CC = gcc
CFLAGS = -o
$(DEST): $(SOURCE)
$(CC) $(CFLAGS) $(DEST) $(SOURCE)
Die Verwendung von Makros kann einerseits die Lesbarkeit eines Makefiles erhöhen, andererseits auch die Portierbarkeit auf andere Systeme erleichtern, indem beispielsweise nur der Name des Compilers bei der Makro-Definition ausgetauscht werden muss, aber nicht bei jedem einzelnen Ziel-Anweisungs-Block.
Standard-Makros, Suffix- und Muster-Regeln
Neben eigenen Makros können in Makefiles die vier folgenden vordefinierten Makros verwendet werden:
Makro | Bedeutung |
$@ | Der Name des Ziels |
$? | Alle angegebenen Quelldateien, die jünger als das Ziel sind |
$< | Der Name der Quelldatei, welcher die Anweisung ausgelöst hat |
$* | Analog, aber ohne Dateiendung |
- Die beiden Makros
$@
und$?
können immer dann eingesetzt werden, wenn wie in den obigen beiden Beispielen ein Ziel explizit angegeben wird. - Die beiden Makros
$<
und$*
hingegen werden ausschließlich für so genannte Suffix- oder Muster-Regeln verwendet.
Eine Suffix-Regel kann wiederum immer dann definiert werden, wenn ein bestimmter
Dateityp von einem anderen Dateityp abhängt; beispielsweise hängen
C-Objekt-Dateien mit der Endung .o
stets von gleichnamigen C-Quelldateien
mit der Endung .c
ab. Eine Suffix-Regel gibt dann allgemein an, wie man aus
einer beliebigen Ausgangsdatei die entsprechende Zieldatei erzeugt.
Beispielsweise kann eine einfache Suffix-Regel zur Erzeugung von .o
-Dateien
aus .c
-Dateien mittels des gcc
-Compilers folgendermaßen aussehen:
.c.o:
gcc $<
Möchte man beispielsweise eine Datei hallo-welt.c
compilieren, so ist dies
bei Verwendung der obigen Makefile mittels make hallo-welt.o
möglich. Bei
diesem Aufruf wird automatisch nach der zur Objekt-Datei .o
passenden
Quelldatei .c
gesucht, anschließend wird der Compiler mit dem Namen dieser
Datei aufgerufen.
Anstelle von Suffix-Regeln können (meist leichter lesbar!) auch Muster-Regeln
mittels des %
-Zeichens definiert werden. Das %
-Zeichen steht dabei für
eine beliebige Zeichenkette. Eine zur obigen Suffix-Regel äquivalente
Muster-Regel lautet damit:
%.o: %.c
gcc $<
Mittels solcher Regeln lässt sich das Übersetzen von Dateien erheblich vereinfachen, wenn beispielsweise alle Dateien in einem Ordner mit den gleichen Optionen compiliert werden sollen; so muss nicht für jedes Ziel eine extra Regel definiert werden.
Standard-Ziele
In einer Makefile muss nicht jedes Ziel einer Datei entsprechen. Es gibt auch so genannte Standard-Ziele, bei denen bestimmte Aktionen ausgeführt werden sollen, die sich aus dem Namen des Ziels ergeben. Einige solcher Ziele, die häufig in Makefiles auftreten, sind folgende:
Ziel | Bedeutung |
all |
Ziel zum Erzeugen aller anderen Regeln |
clean |
Löschen aller Zwischen- und Zieldateien |
new |
Neuerstellen aller Zieldateien (entspricht clean plus all ) |
usage |
Bedienungs-Text ausgeben |
Das Ziel all
wird zudem standardmäßig von make
verwendet, wenn kein
anderes Ziel angegeben wird. Somit kann jederzeit anstelle von make all
auch
nur make
eingegeben werden.
Anmerkungen:
[1] | Mehrere Anweisungen werden beispielsweise dann in einzelne Zeile geschrieben, wenn ein Pfadwechsel mittels cd stattfindet; dieser bezieht sich nur auf die jeweilige Zeile, bei der nächsten Zeile entspricht der Pfad wieder dem Verzeichnis der Makefile. Zu lange Zeilen (Faustregel: Über 80 Zeichen) können, wenn sie mit dem
Backslash-Zeichen |
[2] | Wird der Inhalt einer Makefile unter einem anderen Dateinamen
gespeichert, so muss make mit der Option -f dateiname aufgerufen
werden. |