Ant - Das Apache Build-Werkzeug für Java

Ein Vergleich mit dem Make-System
Simon Lembke (WI4139)


... [ Seminar WS 2002/03 ] ... [ Ant ] ... [ Grundlagen von Ant ] ... [ Variablen / Properties ] ... [ Größere Projekte ] ...

Übersicht : Variablen / Properties


Zugriff auf Variablen

Es gibt bei Make zwei Typen von Variablen, die sich einzig in der Art der Auswertung unterscheiden, wenn sich in dem zugewiesenen Wert Variablen befinden. Beide Typen haben gemeinsam, das die Namen von Variablen aus allen Zeichen bestehen können mit Ausnahme von Doppelpunkt, Gleichheitszeichen und Raute. Allerdings sollten nur Buchstaben, Zahlen und Unterstriche verwendet werden, da alles andere in Zukunft vielleicht eine andere Bedeutung bekommen wird und die Makefiles dann nicht mehr kompatibel wären.
Um auf den Wert einer Variablen zuzugreifen benutzt man das $-Zeichen gefolgt vom Namen der Variablen in runden oder geschweiften Klammern:

$(var)
${var}

Der Einsatz von Variablen in Make unterliegt keinerlei Beschränkungen. Da eine reine Text-Substitution vorgenommen wird, kann eine Variable den Namen eines Befehls enthalten, und dann im Befehlsteil einer Regel stehen. Variablen können aber auch Ziel bzw. Quelle einer Regel darstellen.


Definition von Variablen

Variablen werden definiert indem man ihnen einen Wert zuweist. Dazu schreibt man den Namen der (neuen) Variablen gefolgt von einem Gleichheitszeichen und dem Wert. Das Besondere an diesen Variablen ist, dass ihr Wert bei jedem Lesen neu berechnet wird. Ein Beispiel macht das vielleicht klarer:

foo = foo
bar = $(foo) bar
foo = neu

In diesem Fall würde die Variable bar den Wert neu bar enthalten, da zunächst $(bar) nach $(foo) bar ausgewertet wird und erst danach der Wert von $(foo) eingesetzt wird. Dieses Verhalten ist zwar ganz nützlich um später im Makefile Teile eines Wertes zu verändern, macht das Makefile für andere aber schwerer lesbar und hat einen entscheidenden Nachteil:

classpath = $(classpath):./classes

Es ist so nicht möglich einen Wert an eine Variable anzuhängen. Im obigen Beispiel würde $(classpath) immer wieder zu $(classpath):./classes ausgewertet werden, wodurch man in einer klassischen Endlos-Schleife steckt.
Wie schon erwähnt gibt es aber noch einen zweiten Typen von Variablen, bei dem der Wert einer Variablen bei der Definition festgelegt wird, also so wie man es von gängigen Programmiersprachen kennt. Dazu verwendet man bei der Wertzuweisung einen Doppelpunkt gefolgt von einem Gleichheitszeichen zwischen dem Namen der Variablen und ihrem Wert.

foo := foo
bar := $(foo) bar
foo := neu

In diesem Fall würde die Variable bar den Wert foo bar enthalten und nicht, wie im vorigen Beispiel, foo neu. Der Grund liegt einfach darin, dass beim Zuweisen des Wertes an bar der aktuelle Wert von foo übernommen wird und nicht eine Referenz auf foo. Bei beiden Arten von Variablen ist es möglich einen Wert anzuhängen, indem man den Zuweisungsoperator += verwendet.


Variablen beim Aufruf setzen

Es gibt die Möglichkeit Variablen beim Aufruf von Make zu setzen. Dies kann z.B. nützlich sein, wenn man Einfluss auf den Build-Prozess nehmen will, ohne dafür das Makefile zu ändern. Angenommen es existieren zwei verschiedene C-Compiler auf unserem System: cc und gcc. Um nun Einfluss darauf zu nehmen, welcher Compiler verwendet wird, benutzen wir eine Variable, in der wir den Namen des Compilers speichern und schreiben unsere Regel folgendermaßen:

test.o : test.c
   $(CC) -c test.c

Nun können wir entweder die Variable CC am Anfang des Makefiles setzen, oder sie direkt beim Aufruf von Make definieren. Dazu schreibt man die Zuweisung des Wertes direkt in die Befehlszeile, z.B.:

make CC=gcc test.o

Dieser Aufruf würde bewirken, dass der GNU C-Compiler gcc verwendet wird. Variablen, die beim Aufruf von Make gesetzt werden, können von normalen Zuweisungen im Makefile nicht mehr überschrieben werden. Wenn man dies dennoch machen will, muss man der entsprechenden Zuweisung ein override voranstellen.


Properties bei Ant

Im Gegensatz zu den Variablen bei Make können Properties nur als Werte von Task-Attributen eingesetzt werden. Außerdem können Properties nur gesetzt, nicht aber überschrieben werden. Der Zugriff auf den Wert einer Property erfolgt auch in Ant über das $-Zeichen gefolgt vom Namen der Property in geschweiften Klammern, z.B.:

${foo}

Zum Setzen der Properties wird das Tag <property> verwendet, das dazu verschiedene Möglichkeiten anbietet. Property ist eigentlich ein Task, kann im Gegensatz zu anderen Tasks aber auch außerhalb eines Targets angegeben werden. Diese Properties werden dann gesetzt, bevor irgendein Target ausgeführt wird und stehen danach in allen Targets zur Verfügung.


Properties setzen

Der übliche Weg ist sowohl den Namen als auch den Wert der Property anzugeben:

<property name=“foo“ value=“bar“ />

Danach existiert eine Property foo mit dem Wert bar. Properties im Value-Attribut werden sofort durch deren Wert ersetzt. Sollte die Property zu diesem Zeitpunkt noch nicht existieren wird jedoch nicht ein leerer String eingesetzt, sondern der Name der Property bleibt im Wert stehen.

<property name=“foo“ value=“foo ${bar}” />

Wenn die Property bar zu zuvor nicht definiert wurde, erhält foo den Wert foo ${bar}. Wenn anstelle von value das Attribut location verwendet wird, interpretiert Ant den Wert als Pfad relativ zum basedir und erweitert ihn automatisch zu einem absoluten Pfad. Sollte der Pfad bereits absolut sein bleibt er unverändert. In beiden Fällen passt Ant das Trennzeichen, also „/“ bzw. „\“, an das System an.

Alternativ dazu kann man auch eine ganze Reihe von Properties aus einer externen Datei einlesen. Dazu wird das Attribut file anstelle von name und value benutzt.

<property file=“build.properties“ />

Dadurch werden alle Properties, die in der Datei build.properties angegeben sind, übernommen und stehen wie lokal definierte zur Verfügung. Der Aufbau der Datei muss dabei dem in java.utils.Properties beschriebenen entsprechen.
Eine weitere Möglichkeit ist, die Umgebungsvariablen in das Build-File einzubinden. Dazu gibt es das Attribut environment. Über den Wert, den man diesem Attribut gibt, kann man dann in Punktnotation auf die einzelnen Umgebungsvariablen zugreifen.

<property environment=“env“/>

Danach kann man mit ${env.PATH} zum Beispiel den Systempfad verwenden.


Beispiel mit Properties

Mit Hilfe der Properties können wir das kleine Beispiel aus der Beschreibung der Tasks wie folgt erweitern:

<project name=“Test“ default=“compile“ basedir=“.“>
  <property name=“src“ location=“src“ />
  <property name=“classes“ location=“classes“ />
  <target name=”compile” 
    depends=”init” 
    description=”Die Quellen kompilieren”>
    
    <javac srcdir=“${src}“ destdir=“${classes}“ />
  </target>
</project>

... [ Seminar WS 2002/03 ] ... [ Ant ] ... [ Grundlagen von Ant ] ... [ Variablen / Properties ] ... [ Größere Projekte ] ...