Copyright © 1995 by O'Reilly/International Thomson Verlag

Bitte denken Sie daran: Sie dürfen zwar die Online-Version ausdrucken, aber diesen Druck nicht fotokopieren oder verkaufen.

Wünschen Sie mehr Informationen zu der gedruckten Version des Buches "Linux - Wegweiser zur Installation & Konfiguration", dann klicken Sie hier.


Kapitel 6

Die Makefiles

Irgendwann in Ihrem Zusammenleben mit Linux werden Sie wahrscheinlich auf make stoßen -- selbst wenn Sie gar nicht programmieren möchten. Sicherlich werden Sie einmal den Kernel ändern und neu erstellen, und dazu brauchen Sie make . Wenn Sie Glück haben, müssen Sie sich nicht durch die Makefiles wühlen -- wir wollten uns mit diesem Buch allerdings auch an die Pechvögel wenden. In diesem Abschnitt wollen wir Ihnen deshalb so viel von der feinsinnigen make -Syntax vermitteln, daß ein Makefile Sie nicht mehr einschüchtern kann.

In einigen unserer Beispiele werden wir das aktuelle Makefile für den Linux-Kernel benutzen. Darin sind viele der mächtigen Erweiterungen enthalten, die zur GNU-Version von make gehören; das gibt uns Gelegenheit, sowohl einige dieser Erweiterungen als auch das Standard- make zu beschreiben. In Managing Projects with make von Andrew Oram und Steve Talbott finden Sie eine gute Einführung in make .

Die GNU-Erweiterungen werden in der Manual-Page zu GNU- make ausführlich beschrieben.

Die meisten Benutzer betrachten make als ein Hilfsmittel, um aus Quelltexten Objektdateien und Bibliotheken zu erzeugen sowie Objektdateien zu ausführbaren Dateien zu machen. Wenn man es abstrakter betrachtet, ist make ein vielseitiges Programm, das aus gewissen Abhängigkeiten (prerequisites) bestimmte Ziele (targets) erzeugt. Das Ziel kann eine ausführbare Datei sein, ein PostScript-Dokument oder was auch immer. Die Abhängigkeiten können C-Code, eine Textdatei im TEX-Format usw. sein.

Es ist nicht schwierig, einfache Shell-Skripts zu schreiben, die gcc -Befehle aufrufen, um ausführbare Programme zu erzeugen. make dagegen kann noch mehr: Es weiß, welche Ziele neu erstellt werden müssen und welche nicht. So muß beispielsweise eine Objektdatei nur dann erneut kompiliert werden, wenn die zugrundeliegende Quelldatei geändert wurde.

Ein Beispiel: Nehmen wir an, daß ein Programm aus drei C-Quelltexten besteht. Sie könnten nach jeder Änderung in einer der Quelldateien mit dem Befehl:

papaya$ gcc -o foo foo.c bar.c baz.c

alle drei Dateien erneut kompilieren, um eine neue ausführbare Datei zu erzeugen. Das wäre allerdings eine große Zeitverschwendung, da Sie ja nur eine Quelldatei geändert haben. (Dies gilt ganz besonders dann, wenn das fragliche Programm aus mehr als nur einer Handvoll von Quelldateien besteht.) Was Sie wirklich erreichen möchten, ist die Neukompilierung der einen geänderten Datei zu einer Objektdatei sowie das erneute Binden aller Objektdateien zur ausführbaren Datei. make kann diesen Vorgang für Sie automatisieren.

Was make macht

Grundsätzlich unterstützt make Sie dabei, eine Zieldatei in kleinen Schritten zu erzeugen. Wenn ein Programm aus vielen Quellcodedateien besteht, können Sie eine davon ändern und eine neue ausführbare Datei erzeugen, ohne alle Quelldateien neu kompilieren zu müssen. make erreicht diese Flexibilität, indem es sich merkt, welche Dateien zu Ihrem Ziel gehören.

Hier zeigen wir Ihnen ein triviales Makefile. Nennen Sie es makefile oder Makefile und speichern Sie die Datei in dem Verzeichnis ab, in dem auch die Quellcodedateien stehen.

edimh: main.o edit.o
        gcc -o edimh main.o edit.o

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

edit.o: edit.c
        gcc -c edit.c

Dieses Makefile erzeugt aus den beiden Quelldateien main.c und edit.c ein Programm namens edimh . Sie können ein Makefile nicht nur für die C-Programmierung einsetzen; es können beliebige Befehle enthalten sein.

Das Makefile besteht aus drei Einträgen. Jeder davon enthält eine Abhängigkeiten -Zeile, aus der hervorgeht, wie eine Datei erzeugt wird. Die erste Zeile besagt also, daß edimh (der Name vor dem Doppelpunkt) aus den beiden Objektdateien main.o und edit.o (den Namen hinter dem Doppelpunkt) erzeugt wird. Für make bedeutet das, daß es die folgende gcc -Zeile immer dann ausführen soll, wenn eine dieser beiden Objektdateien geändert wurde. Die Zeilen, in denen Befehle stehen, müssen mit einem Tabulator beginnen (und nicht mit Leerzeichen).

Der Befehl:

papaya$ make edimh

führt die gcc -Zeile aus, wenn derzeit keine Datei namens edimh vorhanden ist. Diese Zeile wird aber auch dann ausgeführt, wenn edimh existiert, aber eine der Objektdateien neuer ist. In diesem Fall ist edimh das Ziel . Die Dateien hinter dem Doppelpunkt nennt man entweder Abhängigkeiten oder Vorbedingungen .

Die nächsten beide Einträge erfüllen denselben Zweck für die Objektdateien. Die Datei main.o wird erzeugt, wenn sie noch nicht existiert oder wenn die zugehörige Quelldatei main.c neuer ist. edit.o wird aus edit.c erzeugt.

Woher weiß make , ob eine Datei neu ist? Es liest den Zeitstempel, den das Dateisystem jeder Datei zuordnet. Mit dem Befehl ls -l können Sie sich den Zeitstempel anzeigen lassen. Da diese Zeiten auf eine Sekunde genau sind, kann make zuverlässig ablesen, ob Sie eine Quelldatei nach dem letzten Compilerlauf geändert haben, oder ob Sie eine Objektdatei kompiliert haben, nachdem die letzte Version der ausführbaren Datei erzeugt wurde.

Lassen Sie uns dieses Makefile testen und beobachten, was passiert:

papaya$ make edimh 
gcc -c main.c
gcc -c edit.c
gcc -o edimh main.o edit.o

Wenn wir jetzt main.c editieren und den Befehl noch einmal aufrufen, werden nur die notwendigen Dateien neu erzeugt und wir sparen etwas Zeit:

papaya$ make edimh 
gcc -c main.c
gcc -o edimh main.o edit.o

Es spielt keine Rolle, in welcher Reihenfolge die drei Einträge im Makefile stehen. make findet heraus, welche Dateien von welchen anderen abhängig sind und führt die Befehle in der richtigen Reihenfolge aus. Es ist bequemer, den Eintrag für edimh an die erste Stelle zu setzen, weil das die Datei ist, die per Voreinstellung erzeugt wird. Mit anderen Worten: Wenn Sie make aufrufen, erhalten Sie dasselbe Ergebnis wie mit make edimh.

Sehen wir uns ein etwas längeres Makefile an. Versuchen Sie herauszubekommen, was darin passiert:

install: all
        mv edimh /usr/local
        mv readimh /usr/local

all: edimh readimh

readimh: read.o edit.o
        gcc -o readimh main.o read.o

edimh: main.o edit.o
        gcc -o edimh main.o edit.o

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

edit.o: edit.c
        gcc -c edit.c

read.o: read.c
        gcc -c read.c

Als erstes sehen wir das Ziel install. Daraus wird nie eine Datei erzeugt werden; man nennt das ein unechtes Ziel (phony target), weil dieser Eintrag nur existiert, damit die Befehle darunter ausgeführt werden können. Bevor install ausgeführt wird, muß zuerst all aufgerufen werden, weil install von all abhängig ist. (Erinnern Sie sich, daß die Reihenfolge der Einträge keine Rolle spielt.)

Als nächstes wendet sich make also dem Ziel all zu. Dahinter stehen keine Befehle (das ist in Ordnung so), aber all ist abhängig von edimh und readimh. Dabei handelt es sich um echte Dateien; es sind zwei ausführbare Programme. make geht also die Liste der Abhängigkeiten solange durch, bis es zu den .c -Dateien kommt, die von nichts weiter abhängig sind. Anschließend wird make jedes einzelne Ziel gewissenhaft neu erzeugen.

Lassen Sie uns einen Testdurchlauf starten (eventuell brauchen Sie Root-Berechtigung, um die Dateien im Verzeichnis /usr/local installieren zu können):

papaya$  make install 
gcc -c main.c
gcc -c edit.c
gcc -o edimh main.o edit.o
gcc -c read.c
gcc -o readimh main.o read.o
mv edimh /usr/local
mv readimh /usr/local

Dieses Makefile bewältigt also einen kompletten Durchlauf zur Erzeugung und Installation aller Dateien. Es erzeugt zuerst die Dateien, die für edimh benötigt werden. Dann erzeugt es die Objektdatei, die zusätzlich für die Erzeugung von readmh gebraucht wird. Wenn diese beiden ausführbaren Dateien erstellt sind, ist das Ziel all erfüllt. Anschließend kann make mit dem Ziel install weitermachen, also die ausführbaren Dateien an ihren endgültigen Speicherort verschieben.

Viele Makefiles, darunter auch die, die Linux erzeugen, enthalten eine ganze Reihe unechter Ziele, mit denen Routineaufgaben erledigt werden. Das Makefile für den Linux-Kernel enthält z.B. Befehle, die temporäre Dateien löschen:

clean:  archclean
        rm -f kernel/ksyms.lst
        rm -f core `find .  -name '*.[oas]' -print`
        .
        .
        .

Dort finden Sie auch Befehle, um eine Liste mit Objektdateien samt den Header-Dateien, von denen sie abhängig sind, zu erzeugen. (Dies ist eine komplizierte und wichtige Aufgabe -- wenn eine Header-Datei geändert wird, soll sichergestellt werden, daß die Objektdateien, die davon abhängig sind, neu kompiliert werden.)

depend dep:
        touch tools/version.h
        for i in init/*.c;do echo -n "init/";$(CPP) -M $$i;done >
.tmpdepend
        .
        .
        .

Einige dieser Shell-Befehle werden ziemlich komplex; wir werden uns im Abschnitt » Mehrfach-Befehle « weiter unten in diesem Kapitel noch mit den Befehlen in Makefiles befassen.

Einige Syntaxregeln

Die größten Probleme rund um die Makefiles verursacht immer die Syntax -- jedenfalls für Neulinge. Also gut, wir sagen es geradeheraus: Die Syntax von make ist ganz einfach idiotisch. Wenn Sie Leerstellen einfügen, wo Tabulatoren stehen sollten (oder umgekehrt), geht das Ding in die Hose; die Fehlermeldungen dazu sind eher verwirrend.

Setzen Sie vor eine Befehlszeile immer einen Tabulator -- keine Leerstellen. Setzen Sie niemals einen Tabulator vor irgendeine der anderen Zeilen.

Sie können an beliebiger Stelle in einer Zeile ein Nummer-Zeichen (#) schreiben, um einen Kommentar einzuleiten. Alles hinter dem Zeichen wird ignoriert.

Wenn Sie ein Backslash an das Ende einer Zeile setzen, wird die nächste Zeile eine Fortsetzungszeile. Das funktioniert mit besonders langen Befehlen ebenso wie für alle anderen Zeilen in Makefiles.

Lassen Sie uns einige der mächtigen Fähigkeiten von make betrachten, die insgesamt eine Art Programmiersprache darstellen.

Makros

Wenn Programmierer einen Dateinamen oder sonstigen String innerhalb eines Makefiles mehr als einmal benutzen, tendieren sie dazu, daraus ein Makro zu machen. Das ist einfach eine Zeichenfolge, die mit Hilfe von make zu einer anderen Zeichenfolge expandiert. Sie könnten z.B. den Anfang unseres trivialen Makefiles so formulieren:

OBJECTS = main.o edit.o

edimh: $(OBJECTS)
        gcc -o edimh $(OBJECTS)

Wenn make loslegt, wird es einfach überall da main.o edit.o einsetzen, wo Sie $(OBJECTS) angegeben haben. Wenn Sie dem Projekt eine weitere Objektdatei hinzufügen möchten, brauchen Sie dies nur in der ersten Zeile der Datei anzugeben. Die Zeile mit den Abhängigkeiten und die Befehle werden dementsprechend angepaßt.

Vergessen Sie die Klammern nicht, wenn Sie $(OBJECTS) ansprechen. Makros sehen vielleicht ein wenig wie Shell-Variablen aus (etwa $HOME oder $PATH), aber sie sind doch anders.

Sie können ein Makro innerhalb einer anderen Makrodefinition einsetzen. Ein Beispiel:

ROOT = /usr/local
HEADERS = $(ROOT)/include
SOURCES = $(ROOT)/src

In diesem Fall wird HEADERS zum Verzeichnis /usr/local/include expandiert, und SOURCES wird zu /usr/local/src . Falls Sie ein Programmpaket auf Ihrem System installieren, das nicht in /usr/local stehen soll, müssen Sie nur ein anderes Verzeichnis finden und dieses in der ROOT-Zeile eintragen.

Sie müssen übrigens für die Namen von Makros keine Großbuchstaben verwenden, aber diese Konvention hat sich überall durchgesetzt.

Ein Zusatz zum GNU- make gibt Ihnen die Möglichkeit, eine Makrodefinition zu erweitern. Benutzen Sie dazu den String := statt des Gleichheitszeichens:

DRIVERS        =drivers/block/block.a

ifdef CONFIG_SCSI
DRIVERS := $(DRIVERS) drivers/scsi/scsi.a
endif

Die erste Zeile enthält eine normale Makrodefinition, die dem Makro DRIVERS den Wert drivers/block/block.a zuweist. Die nächste Definition erweitert das Makro um die Datei drivers/scsi/scsi.a; diese Erweiterung findet allerdings nur dann statt, wenn auch CONFIG_SCSI definiert ist. Die komplette Zuweisung lautet in diesem Fall:

drivers/block/block.a drivers/scsi/scsi.a

Wie aber definieren Sie CONFIG_SCSI? Fügen Sie es einfach in das Makefile ein und weisen Sie ihm einen beliebigen Wert zu:

CONFIG_SCSI = yes

Wahrscheinlich ist es aber einfacher, die Definition auf der Befehlszeile von make vorzunehmen -- und so wird's gemacht:

papaya$ make CONFIG_SCSI=yes   ziel

Eine Feinheit bei der Benutzung von Makros ist das undefinierte Makro. Wenn ein Makro nicht definiert wird, bekommt es eine leere Zeichenfolge zugewiesen (d.h., es steht nichts an der Stelle, an der das Makro stehen sollte). Damit haben Sie aber auch die Möglichkeit, ein Makro als Environment-Variable zu definieren. Wenn Sie also z.B. CONFIG_SCSI nicht im Makefile definieren, könnten Sie folgendes in Ihre Datei .bashrc einfügen (wenn Sie bash benutzen):

export CONFIG_SCSI=yes

Für die csh oder tcsh schreiben Sie folgendes in die Datei .cshrc :

setenv CONFIG_SCSI yes

Damit haben Sie für alle Compilerläufe das Makro CONFIG_SCSI definiert.

Suffix-Regeln und Pattern-Regeln

Natürlich wollen Sie bei solchen Routineaufgaben wie der Erzeugung einer Objektdatei aus einer Quelldatei in Ihrem Makefile nicht jede Abhängigkeit einzeln definieren. Dazu besteht auch kein Grund. Die UNIX-Compiler bestehen auf einer einfachen Vereinbarung (eine Datei mit der Endung .c wird kompiliert, um eine Datei mit der Endung .o zu erzeugen); make benutzt Suffix-Regeln, um alle vorkommenden Dateien zu erfassen.

Sie könnten diese einfache Suffix-Regel in Ihr Makefile schreiben, um eine C-Quelldatei zu kompilieren:

.c.o:
        gcc -c ${CFLAGS} $<

Die Zeile .c.o: bedeutet: »Mache aus einer .c -Datei eine .o -Datei«. Das Makro CFLAGS besteht aus den gewünschten Compileroptionen -- etwa -g zum Debuggen oder -O für die Optimierung. Die Zeichenfolge $< steht für »die Eingabedatei«. An dieser Stelle wird also der Name Ihrer .c -Datei eingesetzt, wenn make diese Anweisung ausführt.

Lassen Sie uns diese Suffix-Regel testen. Die Befehlszeile übergibt die beiden Optionen -g und -O :

papaya$ make CFLAGS="-O -g" edit.o 
gcc -c -O -g edit.c

In Wirklichkeit brauchen Sie diese Suffix-Regel gar nicht in Ihr Makefile einzubauen, weil make bereits etwas ganz Ähnliches enthält. Es benutzt außerdem die CFLAGS, so daß Sie die Compileroptionen bestimmen können, indem Sie einfach diese Variable definieren. Das Makefile, das bei der Kompilierung des Kernels benutzt wird, enthält derzeit eine ganze Reihe von Optionen für den gcc :

CFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe

Da wir uns gerade mit Compileroptionen beschäftigen, wollen wir eine besonders erwähnen, die man sehr häufig zu sehen bekommt -- das ist die Option -D , mit der Symbole im Quellcode definiert werden. Es kann sein, daß Sie eine ganze Menge solcher Optionen an Ihr Makefile übergeben müssen, weil einige davon in den #ifdef-Zeilen recht häufig auftauchen; z.B. -DDEBUG oder -DBSD . Wenn Sie diese Optionen in der Befehlszeile übergeben, sollten Sie auf jeden Fall die komplette Reihe der Optionen mit Anführungszeichen oder Apostrophen klammern; daraufhin wird Ihre Shell alle Optionen als ein einziges Argument an Ihr Makefile übergeben:

papaya$  make CFLAGS="-DDEBUG -DBSD" ...

Das make von GNU benutzt außerdem etwas, das man Pattern-Regeln (Muster-Regeln) genannt hat; damit haben Sie weitergehende Möglichkeiten als mit den Suffix-Regeln. In einer Pattern-Regel ist das Prozentzeichen ein Platzhalter für »einen beliebigen String«. Mit folgender Regel können Sie also C-Quellen kompilieren:

%.o: %.c
        gcc -c -o $@ $(CFLAGS) $<

In diesem Fall steht die Ergebnisdatei an erster Stelle und die Eingabedatei erscheint hinter dem Doppelpunkt. Eine Pattern-Regel sieht also aus wie eine normale Abhängigkeiten-Zeile, enthält aber Prozentzeichen statt der Dateinamen.

Der String $< ist der Platzhalter für die Eingabedatei, und das $@ steht für die zu erzeugende Datei; hier wird also der Name der .o -Datei eingesetzt. Beide sind interne Makros, die make jedesmal definiert, wenn es eine Anweisung ausführt.

Ein anderes internes Makro ist $*, das den Namen der Eingabedatei ohne das Suffix erzeugt. Wenn die Eingabedatei also edit.c heißt, wird der String $*.s zu edit.s expandiert (eine Assemblercodedatei).

Ein Beispiel für eine nützliche Anwendung, das mit der Pattern-Regel aber nicht mit einer Suffix-Regel funktioniert: Hängen Sie die Zeichenfolge _dbg an den Namen der Ausgabedatei an, damit Sie später noch wissen, daß dieses Programm mit Debugging-Informationen kompiliert wurde:

%_dbg.o: %.c
        gcc -c -g -o $@ $(CFLAGS) $<

DEBUG_OBJECTS = main_dbg.o edit_dbg.o

edimh_dbg: $(DEBUG_OBJECTS)
        gcc -o $@ $(DEBUG_OBJECTS)

Jetzt können Sie alle Objektdateien einmal mit und einmal ohne Debugging-Informationen kompilieren. Weil die Dateinamen unterschiedlich sind, können Sie alle Versionen in einem Verzeichnis halten.

papaya$  make edimh_dbg 
gcc -c -g -o main_dbg.o  main.c
gcc -c -g -o edit_dbg.o  edit.c
gcc -o edimh_dbg  main_dbg.o edit_dbg.o

Mehrfach-Befehle

In einem Makefile können beliebige Shell-Befehle ausgeführt werden. Die Lage wird allerdings dadurch kompliziert, daß make jeden Befehl in einer anderen Shell ausführt. So gelangen Sie also nicht ans Ziel:

target:
        cd obj
        HOST_DIR=/home/e
        mv *.o $HOST_DIR

Weder der Befehl cd noch die Definition der Variablen HOST_DIR wirken sich auf die folgenden Befehle aus. Sie müssen das Ganze zu einem einzigen Befehl zusammenfassen. Die Shell benutzt das Semikolon als Trennzeichen zwischen Befehlen; die Befehlszeile sieht dann so aus:

target:
        cd obj ; HOST_DIR=/home/e ; mv *.o $$HOST_DIR

Noch eine Änderung: Wenn Sie innerhalb des Befehls eine Shell-Variable definieren und benutzen, müssen Sie zwei Dollarzeichen voranstellen. make erkennt daran, daß hier eine Shell-Variable und nicht ein Makro gemeint ist.

Vielleicht ist die Datei einfacher zu lesen, wenn Sie die einzelnen Bestandteile eines Mehrfach-Befehls jeweils in eine neue Zeile schreiben; schließen Sie dann jede Zeile mit einem Backslash ab, damit make das Ganze als eine zusammenhängende Zeile betrachtet:

target:
        cd obj ; \
        HOST_DIR=/home/e ; \
        mv *.o $$HOST_DIR

Kompliziert, aber sinnvoll.

Manche Makefiles enthalten wiederum einen make -Befehl; das nennt man rekursives make . So sieht es aus:

linuxsubdirs: dummy
        set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i; done

Das Makro $(MAKE) ruft make auf. Es gibt mehrere Anwendungen für geschachtelte make s. Unser Beispiel zeigt eine Möglichkeit -- ein Compilerlauf, der sich auf verschiedene Verzeichnisse erstreckt (dabei muß jedes dieser Verzeichnisse ein eigenes Makefile enthalten). Eine andere Anwendung ist die Definition von Makros in der Befehlszeile, so daß Compilerläufe mit unterschiedlichen Makrodefinitionen stattfinden können.

GNU- make bietet als Erweiterung ein weiteres mächtiges Interface mit der Befehlszeile. Sie können einen Shell-Befehl aufrufen und einem Makro das Ergebnis des Aufrufs zuweisen. Im Makefile zum Linux-Kernel wird diese Methode benutzt, aber wir wollen Ihnen hier ein einfaches Beispiel zeigen:

HOST_NAME = $(shell uname -n)

Damit weisen Sie dem Makro HOST_NAME den Namen Ihres Rechners im Netzwerk zu (nämlich die Ausgabe des Befehls uname -n ).

make befolgt ein paar Konventionen, die manchmal ganz praktisch sind. So erreichen Sie z.B. mit dem Klammeraffen (@) vor einem Befehl, daß make bei der Ausführung den Befehl selbst anzeigt:

        @if [ -x /bin/dnsdomainname ]; then \
           echo #define LINUX_COMPILE_DOMAIN \"`dnsdomainname`\"; \
         else \
           echo #define LINUX_COMPILE_DOMAIN \"`domainname`\"; \
         fi >> tools/version.h

Eine andere Möglichkeit besteht darin, einen Bindestrich vor einen Befehl zu setzen; damit weisen Sie make an, selbst dann fortzufahren, wenn der Befehl nicht ausgeführt werden konnte. Das kann z.B. dann nützlich sein, wenn make auch nach einem fehlgeschlagenen mv oder cp weiterarbeiten soll:

        - mv edimh /usr/local
        - mv readimh /usr/local

Andere Makefiles einbinden

Bei großen Projekten hat man es oft mit vielen Makefiles zu tun. Das erleichtert die gemeinsame Nutzung z.B. von Makrodefinitionen durch etliche Makefiles in verschiedenen Verzeichnissen. Mit der Anweisung:

include dateiname 

lesen Sie den Inhalt von Dateiname ein. Auch dies wird im Makefile des Linux-Kernels benutzt. Ein Beispiel:

include .depend

Wenn Sie sich die Datei .depend anschauen, finden Sie dort einige Makefile-Einträge; genauer gesagt Zeilen, in denen erklärt wird, daß Objektdateien von Header-Dateien abhängen. (Es könnte übrigens sein, daß .depend noch nicht existiert -- diese Datei wird durch einen weiteren Eintrag im Makefile erzeugt.)

Manchmal beziehen sich include-Zeilen auf Makros statt auf Dateinamen, etwa so:

include ${INC_FILE}

In diesem Fall muß INC_FILE entweder als Environment-Variable oder als ein Makro definiert sein. Auf diese Weise können Sie noch genauer bestimmen, welche Datei benutzt wird.


Inhaltsverzeichnis Vorherige Abschnitt Nächste Abschnitt