[X] Build-Systeme Teil 2: Apache Ant
-
Ich bedanke mich für die Korrektur. Eine Frage dennoch: Welches Wort kennt ihr Deutschen nicht? "hier"?
MfG SideWinder
-
dahier
Duden schrieb:
da|hier (österr., sonst veraltet für an diesem Ort)
:xmas2:
-
Mein Fehler, sollte eigentlich "daher" heißen
MfG SideWinder
-
LOL!
EDIT: Kannst du ja verbessern, wenn du die endgültige Version erstellst!
-
@Side
Sorry, dass ich erst jetzt damit komme, aber was hältst du von nem Abschnitt/Verweis zu "Installation von Ant"?
-
Kann ich mich ab Mittwoch drum kümmern.
MfG SideWinder
-
Build-Systeme Teil 2: Apache Ant
Inhalt: Voraussetzungen Einführung Basiswissen Ein Beispielprojekt Property-Dateien Implementierung der Build-Datei Implementierung der Sub-Targets Ein paar Dinge mehr What comes next... Anhang Quellen
Voraussetzungen:
- Kenntnisse über Build-Systeme im Allgemeinen (Erhältlich im 1. Teil dieser Serie)
- Basis-Kenntnisse im Bereich XML (Erhältlich auf http://www.w3schools.com)
- Um die Beispiele sofort ausprobieren zu können ist Ant zu installieren (Siehe http://ant.apache.org/manual/install.html#installing)Einführung:
Herzlich Willkommen beim 2. Teil unserer Artikel-Serie über Build-Systeme. Nachdem GPC die theoretischen Grundlagen für mich erledigt hat, werde ich euch das Build-Tool Apache Ant näher bringen. Das von der Apache Software Foundation frei zur Verfügung gestellte Build-System ist reich an Funktionalität und einfach einzusetzen. Ant bezeichnet sich selbst als "Make[1] without wrinkles", was das Build-System meiner Meinung nach sehr treffend beschreibt.Einige Vorteile von Ant sind:
-> Eine sehr mächtige BuiltIn-Bibliothek mit oft benötigten Funktionen
-> Ant ist in reinem Java geschrieben und daher auf nahezu allen modernen Plattformen einsetzbar
-> Dank XML sind die Build-Dateien gut strukturiert und wartbarAndere Build-Systeme gehen meist den Weg eingespeiste Befehle auf der Shell des Systems auszuführen, das hat den Vorteil, dass sie für jede Programmiersprache gleich gut aber auch gleich schlecht eingesetzt werden können. Ant geht einen anderen Weg: Befehle werden über eine BuiltIn-Bibliothek angeboten, das vereinfacht die Anwendung ungemein und ermöglicht mächtige Features mit wenigen Zeilen einzubinden. Jede Medaille hat aber auch ihre Kehrseite: Die BuiltIn-Bibliothek ist nahezu ausschließlich auf Java ausgelegt, was Ant auf diese Sprache einschränkt.
Hinweis: Die BuiltIn-Bibliothek ist mit eigenen Modulen erweiterbar. Ant wäre also durchaus in der Lage auch mit anderen Programmiersprachen als Java eingesetzt zu werden. Der Aufwand ist allerdings nicht gerechtfertigt, ein anderes Build-Tool liegt da näher.
Was diese BuiltIn-Bibliothek alles leistet wird spätestens bei folgendem Beispiel deutlich:
Auftraggeber schrieb:
Sämtliche Source-Dateien liegen auf einem CVS-Server[2], die neueste Version ist natürlich vor dem Build von dort zu beziehen. Danach soll der eigentliche Build-Prozess von statten gehen. Wird dieser korrekt beendet sollen automatisierte Tests am Ergebnis durchgeführt werden (Kurzfassung der Ergebnisse per Mail an den Projektleiter). Zu guter letzt soll die computergenerierte Entwickler-Dokumentation erneuert werden und der fertige Build mit der richtigen Build-Nummer auf einen Web-Server geladen werden.
Mit einem auf Shellbefehlen basierendem Build-System würde man hier gehörig ins Schwitzen kommen, mit Ant reichte es in diesem Fall einen Ferialpraktikanten einzustellen.
Um auch anderen zu zeigen wie einfach Ant in ein bestehendes System zu integrieren ist, möchte ich mein Wissen - learning by doing - an einem Beispielprojekt weitergeben.
Basiswissen
Nach den theoretischen Grundlagen kommen wir nun zur praktischen Anwendung. Im Gegensatz zu Make werden Ant die auszuführenden Targets im XML-Schema zugeführt. Der grundlegende Aufbau gleicht dem der meisten Build-Systeme:- Projekt (= Projekt) - Target (= Ziel) Typisches Beispiel: build, create_docs - Task (= Aufgabe) Typisches Beispiel: javac
Während die Targets von uns definiert werden, verwenden wir Tasks aus der BuiltIn-Bibliothek.
Kommen wir also zur Build-Datei. Die Datei heißt gewöhnlich build.xml und liegt im Projekt-Root-Verzeichnis. Durch Übersetzen des oben gezeigten Schemas in XML erhalten wir folgenden Grundaufbau:
<?xml version="1.0"?> <project name="MeinProjekt"> <target name="Ziel"> <task param="value" /> <task param="value" /> ... </target> ... </project>
Hinweis: Kommentare können im XML-Format gemacht werden:
<!-- Kommentar --> <!-- Auch mehrzeilig möglich. -->
Ein Beispielprojekt:
Damit wir den genauen Aufbau der Build-Datei nicht am Trockendock der Theorie erlernen müssen, muss ein fiktiver Taschenrechner als Beispielprojekt herhalten. Die Source-Dateien liegen relativ zur Build-Datei im Verzeichnis source. Mehr ist noch nicht vorhanden. In Zukunft möchten wir im Verzeichnis /docs stets die aktuelle JavaDoc für unser Projekt haben und im Verzeichnis release jeweils die aktuelle Jar-Datei für unseren Taschenrechner (mit aktueller Build-Nummer im Namen).Property-Dateien:
Bevor wir uns jetzt allerdings an die Implementierung machen können muss ich noch ein kurzes Wort über Property-Dateien verlieren. Sehr oft hat man es in Build-Dateien mit Konstanten zu tun (Pfade, Dateien, Bezeichner, etc.), damit diese nicht hardcoded in der Build-Datei - sicherlich auch noch redundant und unauffindbar für Änderungen - ihr Dasein fristen, werden sie in Property-Dateien zusammengefasst. Diese tragen die Endung ".properties" und man verwendet für die Standard-Property-Datei analog zur "build.xml" den Namen "build.properties".Ein Property selbst ist nicht mehr als ein Key-Value-Paar bestehend aus Konstanten-Name (Key) und -Wert (Value) getrennt durch ein Gleich-Zeichen. Alle Konstanten aus unserem Beispielprojekt ergeben folgende Property-Datei:
project.name=Taschenrechner project.version=1.2 path.source=source path.dest=classes path.docs=docs path.release=release
Implementierung der Build-Datei:
Nun denn, wollen wir unserem Taschenrechner ein ordentliches Build-System verpassen. Erweitern wir den Rahmen aus dem letzten Kapitel und wir erhalten folgende Build-Datei:<?xml version="1.0"?> <!-- Unser Projekt name ... Projektname basedir ... Basis-Verzeichnis für alle relativen Pfadangaben default ... Standard-Target, das ausgeführt wird, wenn Ant ohne Parameter gestartet wird --> <project name="Taschenrechner" basedir="." default="full"> <!-- Kleine Beschreibung wozu die vorliegende Build-Datei gut ist --> <description> Automatisierung des Build-Prozesses für Taschenrechner 1.2 </description> <!-- Laden unserer Property-Datei für Zugriff auf Konstanten (Details folgen unten) --> <property file="build.properties" /> <!-- Legt die richtig hochgezähle Build-Nummer in eine Konstante (Details folgen unten) --> <buildnumber /> <!-- Unser Standard-Target name ... Target-Name depends ... Abhängigkeiten von anderen Targets, diese müssen ausgeführt worden sein *bevor* full ausgeführt wird --> <target name="full" depends="compile,javadoc,jar"> </target> <!-- Sub-Targets --> <target name="compile"> ... </target> <target name="javadoc"> <!-- Nicht abhängig von compile - JavaDoc wird aus den Source-Dateien erzeugt und nicht aus den compilierten Class-Dateien! --> ... </target> <target name="jar" depends="compile"> ... </target> </project>
Es hat sich einiges getan an unserer Basis-Datei. Wir haben das Gesamt-Target in 3 Sub-Targets aufgeteilt. Zudem haben wir einige globale Tasks (= Tasks ohne Zugehörigkeit zu einem Target) angelegt, diese werden unabhängig vom gewählten Target immer ausgeführt. Gehen wir die Tasks also Schritt für Schritt durch:
[b]Name: description[/b] Attribute: - Inhalt: Beschreibung des Projekts
Dieser Task wird von Ant ignoriert, er dient lediglich der Beschreibung, damit ein Entwickler weiß, um welche Datei es sich handelt.
[b]Name: property[/b] Attribute: file ... Datei-Name Inhalt: -
Dieser Task lädt unsere Property-Datei die wir im vorangegangenen Kapitel angelegt haben. Ab jetzt können wir mit ${key} auf die Konstanten zugreifen.
[b]Name: buildnumber[/b] Attribute: - Inhalt: -
Dieser Task legt im Verzeichnis eine zusätzliche Datei "build.number" an und speichert dort die aktuelle Build-Nummer. Wird die Build-Datei von Ant abermals ausgeführt findet der Task die Datei und erhöht die Build-Nummer. Zudem legt der Task die aktuelle Build-Nummer automatisch in das Property "build.number", auf das wir dann mit Hilfe von ${build.number} zugreifen können.
Implementierung der Sub-Targets:
Eigentlich hat man jetzt schon genügend Basiswissen um mit Ant vernünftig zu arbeiten. Die gesamte BuiltIn-Bibliothek ist sehr detailliert im Manual[->1] beschrieben. Dennoch möchte ich noch einige Feinheiten zeigen, daher erstmal die fehlenden Teile unserer Build-Datei:<target name="compile"> <echo>Compiling (Beispiel-Konsolen-Ausgabe)</echo> <javac srcdir="${path.source}" destdir="${path.dest}" failonerror="true" /> </target> <target name="javadoc"> <javadoc sourcepath="${path.source}" destdir="${path.docs}" packagenames="*" access="private" source="1.5" use="true" windowtitle="${project.name}" /> </target> <target name="jar" depends="compile"> <jar basedir="${path.dest}" destfile="${path.release}/${project.name}-${project.version}.${build.number}.jar" > <manifest /> </jar> </target>
Endlich greifen wir ordentlich auf die BuiltIn-Bibliothek von Ant zurück. Zuerst wieder eine kleine Übersicht über die benützten Tags:
[b]Name: echo[/b] Attribute: - Inhalt: Nachricht
Gibt eine Nachricht auf der Konsole aus.
[b]Name: javac[/b] Attribute: srcdir ... Pfad in dem unsere Java-Dateien liegen destdir ... Pfad in den die Class-Dateien kommen sollen Inhalt: -
Dieser Task ruft den Java-Compiler auf.
[b]Name: javadoc[/b] Attribute: sourcepath ... Pfad in dem unsere Java-Dateien liegen destdir ... Pfad in dem die fertige JavaDoc landen soll packagenames ... Packages die dokumentiert werden sollen (* = alle Packages) access ... Bis zu welchem Grad soll dokumentiert werden (private = Alle Methoden, public = Nur öffentliche Methoden, etc.) source ... Java-Version des Source use ... Soll ein Use-File erstellt werden? windowtitle ... Kommt in den <title>-Tag der HTML-Dokumente Inhalt: -
Dieser Task ruft den JavaDoc-Builder auf, er lässt sich sehr detailliert konfigurieren über Ant. Alle Attribute findet man im Ant-Manual.
[b]Name: jar[/b] Attribute: basedir ... Pfad in dem die Class-Dateien liegen destfile ... Angabe des Pfad- und Dateinamens an dem die fertige Jar-Datei gespeichert werden soll Inhalt: -
Ruft den Jar-Packer auf.
[b]Name: manifest[/b] Attribute: - Inhalt: -
Weist den Jar-Packer darauf hin, auch eine Manifest-Datei zu erzeugen.
Damit haben wir erst einmal unsere Build-Datei fertiggestellt, mit einem Aufruf von:
ant
im Verzeichnis der build.xml führt Ant das Default-Target für uns aus, ein bestimmtes Target kann natürlich ebenfalls mit angegeben werden:
ant javadoc
Ein paar Dinge mehr:
-> Manchen Tasks kann ein bestimmtes Attribut gesetzt werden, in dem man etwas in den Body des Tags schreibt. So muss man z. B. nicht <echo message="Blubb" /> schreiben sondern kann bequem <echo>Blubb</echo> verwenden
-> Viele Tasks besitzen ein Attribut failonerror, das - wenn auf "true" gesetzt - den gesamten Ant-Build-Prozess beendet wenn ein Fehler auftritt (so kann man z. B. verhindern, dass trotz Fehler im Compile-Vorgang ein Release auf einen Webserver geladen wird)
-> Einige Tasks unterstützen Sub-Tasks, so verhilft uns der Task <manifest> im <jar>-Task zu einer Manifest-Datei (siehe oben), diese Sub-Tags fallen unter den Begriff "Nested Tags"Den Start von Ant auch noch automatisieren...
...ist ebenfalls kein Problem. Alle gängigen Betriebssysteme bietet heutzutage Möglichkeiten dazu: Unix - cronjob, Windows - Geplante Tasks.Erweiterung von Ant:
Ant ist über Java-Klassen erweiterbar. So gibt es externe 3rd-Party-Module zum fertigen Download aber man ist auch in der Lage eigene Module zu entwickeln. Das würde allerdings den Rahmen des Artikels sprengen (Bei Interesse zeige ich es vielleicht in einem zukünftigen Artikel).What comes next...
Im nächsten Artikel unserer Serie wird Talla uns MSBuild näher bringenAnhang:
[1] Make ist ebenfalls ein Build-Tool, mehr Informationen zu Make findet man auf http://de.wikipedia.org/wiki/Make .
[2] CVS ist ein sehr verbreitetes Version-Control-System. Version-Control-Systeme ermöglichen eine nachvollziehbare und merge-konfliktfreie gleichzeitige Entwicklung an Software von mehreren Entwicklern, mehr Informationen zu CVS findet man auf https://www.cvshome.org .
[3] Ant erlaubt es Tasks mittels Java selbst zu schreiben, mehr Informationen findet man im Ant-Manual auf http://ant.apache.org/manual/develop.html#writingowntask .Quellen:
[1] http://ant.apache.org/manual/index.html
-
Hab alle Punkte jetzt mal in eine Art "vorläufig endgültige" Version gepackt.
GPC schrieb:
@Side
Sorry, dass ich erst jetzt damit komme, aber was hältst du von nem Abschnitt/Verweis zu "Installation von Ant"?Sicher das man da was schreiben soll? Man entpackt Ant und fügt das Ant\Bin dem Pfad hinzu... Für ganz penible kann man auch noch ANT_HOME setzen. Aber eventuell ein paar Zeilen. Werd ich morgen dann machen
BTW: Da wir offenbar niemanden mehr haben der am Forum frickelt, wird das mit den XML-Kommentaren eine dumme Sache. Ich werd nochmal Druck machen.
MfG SideWinder
-
Hallo,
SideWinder schrieb:
GPC schrieb:
@Side
Sorry, dass ich erst jetzt damit komme, aber was hältst du von nem Abschnitt/Verweis zu "Installation von Ant"?Sicher das man da was schreiben soll? Man entpackt Ant und fügt das Ant\Bin dem Pfad hinzu... Für ganz penible kann man auch noch ANT_HOME setzen. Aber eventuell ein paar Zeilen. Werd ich morgen dann machen
Hm, vllt. zwei Sätze und ein Link auf die Installations-Anleitung von der Apache Foundation.
BTW: Da wir offenbar niemanden mehr haben der am Forum frickelt, wird das mit den XML-Kommentaren eine dumme Sache. Ich werd nochmal Druck machen.
Mach das, momentan sieht man die Kommentare ein bisserl schlechte
Btw. Kennst du maven? Ist ebenfalls von der Apache Foundation, ziemlich heißes Teil. Noch mächtiger als Ant. Vllt. werd ich noch was dazu schreiben. Mal sehen...
-
Maven ist noch eine Ebene höher als Ant, da musst du nicht einmal mehr wissen wie du compilierst. Du sagst bloß nur noch "compile" und der weiß aus der Projekt-Konfiguration wo die einzelnen Verzeichnisse sind und sucht sich das alles selbst zusammen. Hab aber noch nie damit gearbeitet. Aber ein Artikel drüber wäre in der Tat nett
Hm, vllt. zwei Sätze und ein Link auf die Installations-Anleitung von der Apache Foundation.
sth like that, werd am Abend noch einen Absatz einbauen :xmas1:
MfG SideWinder
-
SideWinder schrieb:
sth like that, werd am Abend noch einen Absatz einbauen :xmas1:
wenn ich korrigieren soll, dann solltest du den absatz langsam mal einbauen.
Mr. B
-
Hab den Absatz wieder gelöscht, und stattdessen einen Punkt unter Voraussetzungen hinzugefügt. Ist das soweit okay? Wenn GPC das reicht kannst du dann die RK durchführen MrB :xmas1:
MfG SideWinder
-
wäre das dann die letzte version, die hier gepostet wurde?
Mr. B
-
Mr. B schrieb:
wäre das dann die letzte version, die hier gepostet wurde?
Mr. B
Ja, die Version die hier auf Seite 4 des Threads steht.
MfG SideWinder
-
okay... was soll ich machen? soll ich anfangen oder noch aufn kommentar von GPC warten???
Mr. B
-
Mr. B schrieb:
okay... was soll ich machen? soll ich anfangen oder noch aufn kommentar von GPC warten???
Mr. B
Fang an, im Notfall musst du später doch noch einen zusätzlichen Absatz korregieren. Der Rest bleibt aber auf jeden Fall wie er ist
MfG SideWinder
-
Ist inhaltlich, soweit ich es sehe, alles in Ordnung. So hab ich mir das gedacht mit dem Install-Verweis
-
Build-Systeme Teil 2: Apache Ant
Inhalt: Voraussetzungen Einführung Basiswissen Ein Beispielprojekt Property-Dateien Implementierung der Build-Datei Implementierung der Sub-Targets Ein paar Dinge mehr What comes next... Anhang Quellen
Voraussetzungen:
- Kenntnisse über Build-Systeme im Allgemeinen (Erhältlich im 1. Teil dieser Serie)
- Basis-Kenntnisse im Bereich XML (Erhältlich auf http://www.w3schools.com)
- Um die Beispiele sofort ausprobieren zu können, ist Ant zu installieren (Siehe http://ant.apache.org/manual/install.html#installing)Einführung:
Herzlich Willkommen beim 2. Teil unserer Artikelserie über Build-Systeme. Nachdem GPC die theoretischen Grundlagen für mich erledigt hat, werde ich euch das Build-Tool Apache Ant näher bringen. Das von der Apache Software Foundation frei zur Verfügung gestellte Build-System ist reich an Funktionalität und einfach einzusetzen. Ant bezeichnet sich selbst als "Make[1] without wrinkles", was das Build-System meiner Meinung nach sehr treffend beschreibt.Einige Vorteile von Ant sind:
-> Eine sehr mächtige BuiltIn-Bibliothek mit oft benötigten Funktionen
-> Ant ist in reinem Java geschrieben und daher auf nahezu allen modernen Plattformen einsetzbar
-> Dank XML sind die Build-Dateien gut strukturiert und gut zu wartenAndere Build-Systeme gehen meist den Weg, eingespeiste Befehle auf der Shell des Systems auszuführen, was den Vorteil hat, dass sie für jede Programmiersprache gleich gut, aber auch gleich schlecht eingesetzt werden können. Ant geht einen anderen Weg: Befehle werden über eine BuiltIn-Bibliothek angeboten; das vereinfacht die Anwendung ungemein und ermöglicht mächtige Features mit wenigen Zeilen einzubinden. Jede Medaille hat aber auch ihre Kehrseite: Die BuiltIn-Bibliothek ist nahezu ausschließlich auf Java ausgelegt, was Ant auf diese Sprache einschränkt.
Hinweis: Die BuiltIn-Bibliothek kann man mit eigenen Modulen erweitern. Ant wäre also durchaus in der Lage auch mit anderen Programmiersprachen als Java eingesetzt zu werden. Der Aufwand ist allerdings nicht gerechtfertigt, ein anderes Build-Tool liegt da näher.
Was diese BuiltIn-Bibliothek alles leistet, wird spätestens bei folgendem Beispiel deutlich:
Auftraggeber schrieb:
Sämtliche Source-Dateien liegen auf einem CVS-Server[2]. Die neueste Version ist natürlich vor dem Build von dort zu beziehen. Danach soll der eigentliche Build-Prozess vonstatten gehen. Wird dieser korrekt beendet, sollen automatisierte Tests am Ergebnis durchgeführt werden (Kurzfassung der Ergebnisse per Mail an den Projektleiter). Zu guter Letzt soll die computergenerierte Entwicklerdokumentation erneuert werden und der fertige Build mit der richtigen Build-Nummer auf einen Webserver geladen werden.
Mit einem auf Shellbefehlen basierenden Build-System würde man hier gehörig ins Schwitzen kommen, mit Ant reichte es in diesem Fall***,*** einen Ferialpraktikanten einzustellen.
Um auch anderen zu zeigen, wie einfach Ant in ein bestehendes System zu integrieren ist, möchte ich mein Wissen - learning by doing - an einem Beispielprojekt weitergeben.
Basiswissen
Nach den theoretischen Grundlagen kommen wir nun zur praktischen Anwendung. Im Gegensatz zu Make werden bei Ant die auszuführenden Targets im XML-Schema zugeführt. Der grundlegende Aufbau gleicht dem der meisten Build-Systeme:- Projekt (= Projekt) - Target (= Ziel) Typisches Beispiel: build, create_docs - Task (= Aufgabe) Typisches Beispiel: javac
Während die Targets von uns definiert werden, verwenden wir Tasks aus der BuiltIn-Bibliothek.
Kommen wir also zur Build-Datei. Die Datei heißt gewöhnlich build.xml und liegt im Projekt-Root-Verzeichnis. Durch Übersetzen des oben gezeigten Schemas in XML erhalten wir folgenden Grundaufbau:
<?xml version="1.0"?> <project name="MeinProjekt"> <target name="Ziel"> <task param="value" /> <task param="value" /> ... </target> ... </project>
Hinweis: Kommentare können im XML-Format gemacht werden:
<!-- Kommentar --> <!-- Auch mehrzeilig möglich. -->
Ein Beispielprojekt:
Damit wir den genauen Aufbau der Build-Datei nicht am Trockendock der Theorie erlernen müssen, muss ein fiktiver Taschenrechner als Beispielprojekt herhalten. Die Source-Dateien liegen relativ zur Build-Datei im Verzeichnis source ~muss nach dem "relativ" nicht ein wörtchen folgen?~. Mehr ist noch nicht vorhanden. In Zukunft möchten wir im Verzeichnis /docs stets die aktuelle JavaDoc für unser Projekt haben und im Verzeichnis release jeweils die aktuelle Jar-Datei für unseren Taschenrechner (mit aktueller Build-Nummer im Namen).Property-Dateien:
Bevor wir uns jetzt allerdings an die Implementierung machen können, muss ich noch ein kurzes Wort über Property-Dateien verlieren. Sehr oft hat man es in Build-Dateien mit Konstanten zu tun (Pfade, Dateien, Bezeichner, etc.), damit diese nicht hardcoded in der Build-Datei - sicherlich auch noch redundant und unauffindbar für Änderungen - ihr Dasein fristen, werden sie in Property-Dateien zusammengefasst. Diese tragen die Endung ".properties" und man verwendet für die Standard-Property-Datei analog zur "build.xml" den Namen "build.properties".Ein Property selbst ist nicht mehr als ein Key-Value-Paar bestehend aus Konstanten-Name (Key) und -Wert (Value) getrennt durch ein Gleichzeichen. Alle Konstanten aus unserem Beispielprojekt ergeben folgende Property-Datei:
project.name=Taschenrechner project.version=1.2 path.source=source path.dest=classes path.docs=docs path.release=release
Implementierung der Build-Datei:
Nun denn, wollen wir unserem Taschenrechner ein ordentliches Build-System verpassen. Erweitern wir den Rahmen aus dem letzten Kapitel, so erhalten wir folgende Build-Datei:<?xml version="1.0"?> <!-- Unser Projekt name ... Projektname basedir ... Basis-Verzeichnis für alle relativen Pfadangaben default ... Standard-Target, das ausgeführt wird, wenn Ant ohne Parameter gestartet wird --> <project name="Taschenrechner" basedir="." default="full"> <!-- Kleine Beschreibung, wozu die vorliegende Build-Datei gut ist --> <description> Automatisierung des Build-Prozesses für Taschenrechner 1.2 </description> <!-- Laden unserer Property-Datei für Zugriff auf Konstanten (Details folgen unten) --> <property file="build.properties" /> <!-- Legt die richtig hochgezähle Build-Nummer in eine Konstante (Details folgen unten) --> <buildnumber /> <!-- Unser Standard-Target name ... Target-Name depends ... Abhängigkeiten von anderen Targets, diese müssen ausgeführt worden sein *bevor* full ausgeführt wird --> <target name="full" depends="compile,javadoc,jar"> </target> <!-- Sub-Targets --> <target name="compile"> ... </target> <target name="javadoc"> <!-- Nicht abhängig von compile - JavaDoc wird aus den Source-Dateien erzeugt und nicht aus den kompilierten Class-Dateien! --> ... </target> <target name="jar" depends="compile"> ... </target> </project>
Es hat sich einiges getan an unserer Basisdatei. Wir haben das Gesamt-Target in 3 Sub-Targets aufgeteilt. Zudem haben wir einige globale Tasks (= Tasks ohne Zugehörigkeit zu einem Target) angelegt. Diese werden unabhängig vom gewählten Target immer ausgeführt. Gehen wir die Tasks also Schritt für Schritt durch:
[b]Name: description[/b] Attribute: - Inhalt: Beschreibung des Projekts
Dieser Task wird von Ant ignoriert. Er dient lediglich der Beschreibung, damit ein Entwickler weiß, um welche Datei es sich handelt.
[b]Name: property[/b] Attribute: file ... Datei-Name Inhalt: -
Dieser Task lädt unsere Property-Datei, die wir im vorangegangenen Kapitel angelegt haben. Ab jetzt können wir mit ${key} auf die Konstanten zugreifen.
[b]Name: buildnumber[/b] Attribute: - Inhalt: -
Dieser Task legt im Verzeichnis eine zusätzliche Datei "build.number" an und speichert dort die aktuelle Build-Nummer. Wird die Build-Datei von Ant abermals ausgeführt findet der Task die Datei und erhöht die Build-Nummer. Zudem legt der Task die aktuelle Build-Nummer automatisch in das Property "build.number", auf das wir dann mit Hilfe von ${build.number} zugreifen können.
Implementierung der Sub-Targets:
Eigentlich hat man jetzt schon genügend Basiswissen, um mit Ant vernünftig zu arbeiten. Die gesamte BuiltIn-Bibliothek ist sehr detailliert im Manual[->1] beschrieben. Dennoch möchte ich noch einige Feinheiten zeigen, daher erstmal die fehlenden Teile unserer Build-Datei:<target name="compile"> <echo>Compiling (Beispiel-Konsolen-Ausgabe)</echo> <javac srcdir="${path.source}" destdir="${path.dest}" failonerror="true" /> </target> <target name="javadoc"> <javadoc sourcepath="${path.source}" destdir="${path.docs}" packagenames="*" access="private" source="1.5" use="true" windowtitle="${project.name}" /> </target> <target name="jar" depends="compile"> <jar basedir="${path.dest}" destfile="${path.release}/${project.name}-${project.version}.${build.number}.jar" > <manifest /> </jar> </target>
Endlich greifen wir ordentlich auf die BuiltIn-Bibliothek von Ant zurück. Zuerst wieder eine kleine Übersicht über die benutzten Tags:
[b]Name: echo[/b] Attribute: - Inhalt: Nachricht
Gibt eine Nachricht auf der Konsole aus.
[b]Name: javac[/b] Attribute: srcdir ... Pfad, in dem unsere Java-Dateien liegen destdir ... Pfad, in den die Class-Dateien kommen sollen Inhalt: -
Dieser Task ruft den Java-Compiler auf.
[b]Name: javadoc[/b] Attribute: sourcepath ... Pfad, in dem unsere Java-Dateien liegen destdir ... Pfad, in dem die fertige JavaDoc landen soll packagenames ... Packages, die dokumentiert werden sollen (* = alle Packages) access ... Bis zu welchem Grad soll dokumentiert werden (private = Alle Methoden, public = Nur öffentliche Methoden, etc.) source ... Java-Version des Source use ... Soll ein Use-File erstellt werden? windowtitle ... Kommt in den <title>-Tag der HTML-Dokumente Inhalt: -
Dieser Task ruft den JavaDoc-Builder auf. Er lässt sich sehr detailliert konfigurieren über Ant. Alle Attribute findet man im Ant-Manual.
[b]Name: jar[/b] Attribute: basedir ... Pfad, in dem die Class-Dateien liegen destfile ... Angabe des Pfad- und Dateinamens, an dem die fertige Jar-Datei gespeichert werden soll Inhalt: -
Ruft den Jar-Packer auf.
[b]Name: manifest[/b] Attribute: - Inhalt: -
Weist den Jar-Packer darauf hin, auch eine Manifest-Datei zu erzeugen.
Damit haben wir erst einmal unsere Build-Datei fertiggestellt mit einem Aufruf von:
ant
Im Verzeichnis der build.xml führt Ant das Default-Target für uns aus. Ein bestimmtes Target kann natürlich ebenfalls mit angegeben werden:
ant javadoc
Ein paar Dinge mehr:
-> Manchen Tasks kann ein bestimmtes Attribut gesetzt werden, indem man etwas in den Body des Tags schreibt. So muss man z. B. nicht <echo message="Blubb" /> schreiben, sondern kann bequem <echo>Blubb</echo> verwenden.
-> Viele Tasks besitzen ein Attribut failonerror, das - wenn auf "true" gesetzt - den gesamten Ant-Build-Prozess beendet, wenn ein Fehler auftritt (so kann man z. B. verhindern, dass trotz Fehler im Compile-Vorgang ein Release auf einen Webserver geladen wird)
-> Einige Tasks unterstützen Sub-Tasks. So verhilft uns der Task <manifest> im <jar>-Task zu einer Manifest-Datei (siehe oben). Diese Sub-Tags fallen unter den Begriff "Nested Tags".Den Start von Ant auch noch automatisieren...
...ist ebenfalls kein Problem. Alle gängigen Betriebssysteme bieten heutzutage Möglichkeiten dazu: Unix - cronjob, Windows - Geplante Tasks.Erweiterung von Ant:
Ant ist über Java-Klassen erweiterbar. So gibt es externe 3rd-Party-Module zum fertigen Download, aber man ist auch in der Lage eigene Module zu entwickeln. Das würde allerdings den Rahmen des Artikels sprengen (bei Interesse zeige ich es vielleicht in einem zukünftigen Artikel).What comes next...
Im nächsten Artikel unserer Serie wird Talla uns MSBuild näher bringenAnhang:
[1] Make ist ebenfalls ein Build-Tool, mehr Informationen zu Make findet man auf http://de.wikipedia.org/wiki/Make .
[2] CVS ist ein sehr verbreitetes Version-Control-System. Version-Control-Systeme ermöglichen eine nachvollziehbare und merge-konfliktfreie, gleichzeitige Entwicklung an Software von mehreren Entwicklern. Mehr Informationen zu CVS findet man auf https://www.cvshome.org .
[3] Ant erlaubt es, Tasks mittels Java selbst zu schreiben, mehr Informationen findet man im Ant-Manual auf http://ant.apache.org/manual/develop.html#writingowntask .Quellen:
[1] http://ant.apache.org/manual/index.html
-
Insgesamt recht fehlerfrei. Eine Anmerkung ist jedoch im Text enthalten. Such mal nach kleinem Text, dann musst du dir nich alles durchlesen.
Zwei Dinge seien jedoch gesagt:
Sch**** auf den Bindestrich und schreib mal Wörter einfach so zusammen. Ich habe das jetzt mal bei allen englischen Wörtern durchgehen lassen, aber so was wie "Webserver" oder "Subtask" kann man eigentlich zusammenschreiben. Da bindet der Bindestrich nicht mehr, sondern da trennt er wohl eher.
Außerdem ist mir oft aufgefallen, dass du manchmal einfach zwei Hauptsätze mit nem Komma verbindest. Das ist so nicht erlaubt. Entweder du setzt ein "und" dazwischen, was auf Dauer sehr grässlich klingt, oder du setzt ab und an einfach mal nen Punkt!
Mr. B
-
Build-Systeme Teil 2: Apache Ant
Inhalt: Voraussetzungen Einführung Basiswissen Ein Beispielprojekt Property-Dateien Implementierung der Build-Datei Implementierung der Sub-Targets Ein paar Dinge mehr What comes next... Anhang Quellen
Voraussetzungen:
- Kenntnisse über Build-Systeme im Allgemeinen (Erhältlich im 1. Teil dieser Serie)
- Basis-Kenntnisse im Bereich XML (Erhältlich auf http://www.w3schools.com)
- Um die Beispiele sofort ausprobieren zu können, ist Ant zu installieren (Siehe http://ant.apache.org/manual/install.html#installing)Einführung:
Herzlich Willkommen beim 2. Teil unserer Artikelserie über Build-Systeme. Nachdem GPC die theoretischen Grundlagen für mich erledigt hat, werde ich euch das Build-Tool Apache Ant näher bringen. Das von der Apache Software Foundation frei zur Verfügung gestellte Build-System ist reich an Funktionalität und einfach einzusetzen. Ant bezeichnet sich selbst als "Make[1] without wrinkles", was das Build-System meiner Meinung nach sehr treffend beschreibt.Einige Vorteile von Ant sind:
-> Eine sehr mächtige BuiltIn-Bibliothek mit oft benötigten Funktionen
-> Ant ist in reinem Java geschrieben und daher auf nahezu allen modernen Plattformen einsetzbar
-> Dank XML sind die Build-Dateien gut strukturiert und gut zu wartenAndere Build-Systeme gehen meist den Weg, eingespeiste Befehle auf der Shell des Systems auszuführen, was den Vorteil hat, dass sie für jede Programmiersprache gleich gut, aber auch gleich schlecht eingesetzt werden können. Ant geht einen anderen Weg: Befehle werden über eine BuiltIn-Bibliothek angeboten; das vereinfacht die Anwendung ungemein und ermöglicht mächtige Features mit wenigen Zeilen einzubinden. Jede Medaille hat aber auch ihre Kehrseite: Die BuiltIn-Bibliothek ist nahezu ausschließlich auf Java ausgelegt, was Ant auf diese Sprache einschränkt.
Hinweis: Die BuiltIn-Bibliothek kann man mit eigenen Modulen erweitern. Ant wäre also durchaus in der Lage auch mit anderen Programmiersprachen als Java eingesetzt zu werden. Der Aufwand ist allerdings nicht gerechtfertigt, ein anderes Build-Tool liegt da näher.
Was diese BuiltIn-Bibliothek alles leistet, wird spätestens bei folgendem Beispiel deutlich:
Auftraggeber schrieb:
Sämtliche Source-Dateien liegen auf einem CVS-Server[2]. Die neueste Version ist natürlich vor dem Build von dort zu beziehen. Danach soll der eigentliche Build-Prozess vonstatten gehen. Wird dieser korrekt beendet, sollen automatisierte Tests am Ergebnis durchgeführt werden (Kurzfassung der Ergebnisse per Mail an den Projektleiter). Zu guter Letzt soll die computergenerierte Entwicklerdokumentation erneuert werden und der fertige Build mit der richtigen Build-Nummer auf einen Webserver geladen werden.
Mit einem auf Shellbefehlen basierenden Build-System würde man hier gehörig ins Schwitzen kommen, mit Ant reichte es in diesem Fall, einen Ferialpraktikanten einzustellen.
Um auch anderen zu zeigen, wie einfach Ant in ein bestehendes System zu integrieren ist, möchte ich mein Wissen - learning by doing - an einem Beispielprojekt weitergeben.
Basiswissen
Nach den theoretischen Grundlagen kommen wir nun zur praktischen Anwendung. Im Gegensatz zu Make werden bei Ant die auszuführenden Targets im XML-Schema zugeführt. Der grundlegende Aufbau gleicht dem der meisten Build-Systeme:- Projekt (= Projekt) - Target (= Ziel) Typisches Beispiel: build, create_docs - Task (= Aufgabe) Typisches Beispiel: javac
Während die Targets von uns definiert werden, verwenden wir Tasks aus der BuiltIn-Bibliothek.
Kommen wir also zur Build-Datei. Die Datei heißt gewöhnlich build.xml und liegt im Projekt-Root-Verzeichnis. Durch Übersetzen des oben gezeigten Schemas in XML erhalten wir folgenden Grundaufbau:
<?xml version="1.0"?> <project name="MeinProjekt"> <target name="Ziel"> <task param="value" /> <task param="value" /> ... </target> ... </project>
Hinweis: Kommentare können im XML-Format gemacht werden:
<!-- Kommentar --> <!-- Auch mehrzeilig möglich. -->
Ein Beispielprojekt:
Damit wir den genauen Aufbau der Build-Datei nicht am Trockendock der Theorie erlernen müssen, muss ein fiktiver Taschenrechner als Beispielprojekt herhalten. Die Source-Dateien liegen relativ zur Build-Datei im Verzeichnis source. Mehr ist noch nicht vorhanden. In Zukunft möchten wir im Verzeichnis /docs stets die aktuelle JavaDoc für unser Projekt haben und im Verzeichnis release jeweils die aktuelle Jar-Datei für unseren Taschenrechner (mit aktueller Build-Nummer im Namen).Property-Dateien:
Bevor wir uns jetzt allerdings an die Implementierung machen können, muss ich noch ein kurzes Wort über Property-Dateien verlieren. Sehr oft hat man es in Build-Dateien mit Konstanten zu tun (Pfade, Dateien, Bezeichner, etc.), damit diese nicht hardcoded in der Build-Datei - sicherlich auch noch redundant und unauffindbar für Änderungen - ihr Dasein fristen, werden sie in Property-Dateien zusammengefasst. Diese tragen die Endung ".properties" und man verwendet für die Standard-Property-Datei analog zur "build.xml" den Namen "build.properties".Ein Property selbst ist nicht mehr als ein Key-Value-Paar bestehend aus Konstanten-Name (Key) und -Wert (Value) getrennt durch ein Gleichzeichen. Alle Konstanten aus unserem Beispielprojekt ergeben folgende Property-Datei:
project.name=Taschenrechner project.version=1.2 path.source=source path.dest=classes path.docs=docs path.release=release
Implementierung der Build-Datei:
Nun denn, wollen wir unserem Taschenrechner ein ordentliches Build-System verpassen. Erweitern wir den Rahmen aus dem letzten Kapitel, so erhalten wir folgende Build-Datei:<?xml version="1.0"?> <!-- Unser Projekt name ... Projektname basedir ... Basis-Verzeichnis für alle relativen Pfadangaben default ... Standard-Target, das ausgeführt wird, wenn Ant ohne Parameter gestartet wird --> <project name="Taschenrechner" basedir="." default="full"> <!-- Kleine Beschreibung, wozu die vorliegende Build-Datei gut ist --> <description> Automatisierung des Build-Prozesses für Taschenrechner 1.2 </description> <!-- Laden unserer Property-Datei für Zugriff auf Konstanten (Details folgen unten) --> <property file="build.properties" /> <!-- Legt die richtig [kor]hochgezählte[/kor] Build-Nummer in eine Konstante (Details folgen unten) --> <buildnumber /> <!-- Unser Standard-Target name ... Target-Name depends ... Abhängigkeiten von anderen Targets, diese müssen ausgeführt worden sein *bevor* full ausgeführt wird --> <target name="full" depends="compile,javadoc,jar"> </target> <!-- Sub-Targets --> <target name="compile"> ... </target> <target name="javadoc"> <!-- Nicht abhängig von compile - JavaDoc wird aus den Source-Dateien erzeugt und nicht aus den kompilierten Class-Dateien! --> ... </target> <target name="jar" depends="compile"> ... </target> </project>
Es hat sich einiges getan an unserer Basisdatei. Wir haben das Gesamt-Target in 3 Sub-Targets aufgeteilt. Zudem haben wir einige globale Tasks (= Tasks ohne Zugehörigkeit zu einem Target) angelegt. Diese werden unabhängig vom gewählten Target immer ausgeführt. Gehen wir die Tasks also Schritt für Schritt durch:
[b]Name: description[/b] Attribute: - Inhalt: Beschreibung des Projekts
Dieser Task wird von Ant ignoriert. Er dient lediglich der Beschreibung, damit ein Entwickler weiß, um welche Datei es sich handelt.
[b]Name: property[/b] Attribute: file ... Datei-Name Inhalt: -
Dieser Task lädt unsere Property-Datei, die wir im vorangegangenen Kapitel angelegt haben. Ab jetzt können wir mit ${key} auf die Konstanten zugreifen.
[b]Name: buildnumber[/b] Attribute: - Inhalt: -
Dieser Task legt im Verzeichnis eine zusätzliche Datei "build.number" an und speichert dort die aktuelle Build-Nummer. Wird die Build-Datei von Ant abermals ausgeführt findet der Task die Datei und erhöht die Build-Nummer. Zudem legt der Task die aktuelle Build-Nummer automatisch in das Property "build.number", auf das wir dann mit Hilfe von ${build.number} zugreifen können.
Implementierung der Sub-Targets:
Eigentlich hat man jetzt schon genügend Basiswissen, um mit Ant vernünftig zu arbeiten. Die gesamte BuiltIn-Bibliothek ist sehr detailliert im Manual[->1] beschrieben. Dennoch möchte ich noch einige Feinheiten zeigen, daher erstmal die fehlenden Teile unserer Build-Datei:<target name="compile"> <echo>Compiling (Beispiel-Konsolen-Ausgabe)</echo> <javac srcdir="${path.source}" destdir="${path.dest}" failonerror="true" /> </target> <target name="javadoc"> <javadoc sourcepath="${path.source}" destdir="${path.docs}" packagenames="*" access="private" source="1.5" use="true" windowtitle="${project.name}" /> </target> <target name="jar" depends="compile"> <jar basedir="${path.dest}" destfile="${path.release}/${project.name}-${project.version}.${build.number}.jar" > <manifest /> </jar> </target>
Endlich greifen wir ordentlich auf die BuiltIn-Bibliothek von Ant zurück. Zuerst wieder eine kleine Übersicht über die benutzten Tags:
[b]Name: echo[/b] Attribute: - Inhalt: Nachricht
Gibt eine Nachricht auf der Konsole aus.
[b]Name: javac[/b] Attribute: srcdir ... Pfad, in dem unsere Java-Dateien liegen destdir ... Pfad, in den die Class-Dateien kommen sollen Inhalt: -
Dieser Task ruft den Java-Compiler auf.
[b]Name: javadoc[/b] Attribute: sourcepath ... Pfad, in dem unsere Java-Dateien liegen destdir ... Pfad, in dem die fertige JavaDoc landen soll packagenames ... Packages, die dokumentiert werden sollen (* = alle Packages) access ... Bis zu welchem Grad soll dokumentiert werden (private = Alle Methoden, public = Nur öffentliche Methoden, etc.) source ... Java-Version des Source use ... Soll ein Use-File erstellt werden? windowtitle ... Kommt in den <title>-Tag der HTML-Dokumente Inhalt: -
Dieser Task ruft den JavaDoc-Builder auf. Er lässt sich sehr detailliert konfigurieren über Ant. Alle Attribute findet man im Ant-Manual.
[b]Name: jar[/b] Attribute: basedir ... Pfad, in dem die Class-Dateien liegen destfile ... Angabe des Pfad- und Dateinamens, an dem die fertige Jar-Datei gespeichert werden soll Inhalt: -
Ruft den Jar-Packer auf.
[b]Name: manifest[/b] Attribute: - Inhalt: -
Weist den Jar-Packer darauf hin, auch eine Manifest-Datei zu erzeugen.
Damit haben wir erst einmal unsere Build-Datei fertig gestellt mit einem Aufruf von:
ant
Im Verzeichnis der build.xml führt Ant das Default-Target für uns aus. Ein bestimmtes Target kann natürlich ebenfalls mit angegeben werden:
ant javadoc
Ein paar Dinge mehr:
-> Manchen Tasks kann ein bestimmtes Attribut gesetzt werden, indem man etwas in den Body des Tags schreibt. So muss man z. B. nicht <echo message="Blubb" /> schreiben, sondern kann bequem <echo>Blubb</echo> verwenden.
-> Viele Tasks besitzen ein Attribut failonerror, das - wenn auf "true" gesetzt - den gesamten Ant-Build-Prozess beendet, wenn ein Fehler auftritt (so kann man z. B. verhindern, dass trotz Fehler im Compile-Vorgang ein Release auf einen Webserver geladen wird)
-> Einige Tasks unterstützen Sub-Tasks. So verhilft uns der Task <manifest> im <jar>-Task zu einer Manifest-Datei (siehe oben). Diese Sub-Tags fallen unter den Begriff "Nested Tags".Den Start von Ant auch noch automatisieren...
...ist ebenfalls kein Problem. Alle gängigen Betriebssysteme bieten heutzutage Möglichkeiten dazu: Unix - cronjob, Windows - Geplante Tasks.Erweiterung von Ant:
Ant ist über Java-Klassen erweiterbar. So gibt es externe 3rd-Party-Module zum fertigen Download, aber man ist auch in der Lage eigene Module zu entwickeln. Das würde allerdings den Rahmen des Artikels sprengen (bei Interesse zeige ich es vielleicht in einem zukünftigen Artikel).What comes next...
Im nächsten Artikel unserer Serie wird Talla uns MSBuild näher bringenAnhang:
[1] Make ist ebenfalls ein Build-Tool, mehr Informationen zu Make findet man auf http://de.wikipedia.org/wiki/Make .
[2] CVS ist ein sehr verbreitetes Version-Control-System. Version-Control-Systeme ermöglichen eine nachvollziehbare und merge-konfliktfreie, gleichzeitige Entwicklung an Software von mehreren Entwicklern. Mehr Informationen zu CVS findet man auf https://www.cvshome.org .
[3] Ant erlaubt es, Tasks mittels Java selbst zu schreiben, mehr Informationen findet man im Ant-Manual auf http://ant.apache.org/manual/develop.html#writingowntask .Quellen:
[1] http://ant.apache.org/manual/index.html