Zmake and ANT

Zmake and ANT

Inhalt


Topic=.Zmake.

pStyle=std

.

1 Zmake-Zielsetzung

Topic=.Zmake.motivation.

pStyle=std

Zmake setzt auf ANT auf =>Eclipse - ANT auf. ANT ist der XML-like Maker aus dem Eclipse-Umfeld. ANT hat einige Vorteile:

  • XML-Syntax ist besser als die von klassischen makern bekannte, auch besser lesbar und pflegbar

  • Es lassen sich sehr gut Nebenaufgaben wie mkdir, delete usw erledigen.

Wenn man aus a, b und c nach einem komplexen Algorithmus D und E 'maken' möchte, dann ist ANT jedenfalls die geeignete Wahl! Wenn man aber heute aus a, b und c D und E maken möchte, morgen aber aus k, l und m Q und P, und übermorgen nach dem adäquaten Algorithmus noch was anderes, dann ist die Pflege des ANT-xml-Files schon nervig. Die make-Aufgaben stellen oft diejenigen Bearbeiter, die eigentlich gar nicht XML und ANT wollen sondern nur ihre Ergebnisse maken. Hier greift nun Zmake ein.

Zmake ermöglicht die Formulierung der make-Ziele nach möglichst einfach zu formulierenden Regeln. Die Abbildung von a, b und c nach D und E ist ein zu benennender Algorithmus. Wie er genau funktioniert, ist dem make-wollendem egal. Zmake basiert auf einem syntaktisch einfachem Textfile. Aus diesem Textfile wird ein ANT.xml-Makefile generiert. Was genau generiert wird, ist in einem XSLT-Script beschrieben, das aber von dem End-User nicht gepflegt und auch nicht angesehen werden braucht, nur vom jeweils Tool-Verantwortlichen. Hier wird die Arbeit des ANT-xml-Formulierens hineingesteckt. Aber nicht bezogen auf die End-User-Belange, sondern allgemein hauseigen, projektspezifisch (domain specific) bereitgestellt.

2 Beispiel für einen Zmake-File

Topic=.Zmake.SamleZmake.

pStyle=std

Ein Beispiel sei aus dem Bereich ByteDataAccess herausgegriffen. Hier geht es um die Umsetzung eines C(++)-Headerfiles in einen java-Quellfile, um auf Strukturen, die im C-Headerfile definiert werden, javamäßig zuzugreifen. Headerfiles müssen nach *.java konvertiert werden. Das ist nicht ganz trivial, aber immer auf die selbe Art lösbar. Dem End-User interessiert nicht das wie sondern nur das was. Dem zufolge schreib er in einem Zmake-Script:

 JavaSrc:myPackage/subPkg/_File1_h.java := CHeader2JavaByteCoding(../incl/File1.h);
 JavaSrc:myPackage/subPkg/_File2_h.java := CHeader2JavaByteCoding(../../src/incl/File2.h);

Ziel des Makens ist es, aus File1.h und File2.h an verschiedenen Speicherorten zwei passende java-Files zu erstellen. Der Algorithmus ist als CHeader2JavaByteCoding benannt - und fertig.

Der daraus erzeugte ANT.xml ist wesenlich komplexer. Er enthält die Auflösung des Algorithmus.

3 Schritte zur Konvertierung eines Zmake-Steuerfiles nach ANT.xml

Topic=.Zmake.Zmake2Ant.

pStyle=std

Der Gesamtablauf ist in javadoc-src:_org/vishia/zbnfXml/Zmake.java programmiert. Die main-Routine dieser Klasse lässt sich mit entsprechenden Argumenten aus der Kommandozeile, meist in einem vorbereitetem batchfile oder shell-script, rufen. Der Aufruf kann wie folgt aussehen (batchfile, windows):

 set INPUT=MyZmakeScript.zmake
 call setANT_HOME.bat
 %JAX_EXE% org.vishia.zbnfXml.Zmake %INPUT% -tmp:../tmp -xslt4ant:XmlDocu_xsl/XmakeAnt.xslp
 if errorlevel1 goto :error
 call %ANT_HOME%\bin\ant -f ../tmp/ANT.xml  -DcurDir="%CD%"

Der Batchfile setANT_HOME.bat ist dazu da, Umgebungsvariable zu setzen. Es werden keine vom System gesetzte Umgebungsvariablen vorausgesetzt. Das ist insoweit wichig, als das Batchfile/script auch auf einem unvorbereitetem PC / in einem unvorbereitetem User läuft. Alles was an Umgebung notwendig ist: Java, Eclipse-Ant, die jar-Files, kann sich auch auf einem Netzlaufwerk befinden. Auf dem PC, auf dem dieses Scrip aufgerufen wird, braucht also nichts vorhanden zu sein, nicht einmal Java oder standardgemäß eine andere Java-Version. Lediglich die Auffindbarkeit des setANT_HOME.bat und dessen Richigkeit muss gewährleistet sein.

Alle nachfolgend benutzten Umgebungsvariablen sind also vom setANT_HOME.bat gesetzt. Der Link führt zu einem Beispiel dieses Files:

  • JAX_EXE ist ein Java-Aufruf mit gesetztem Classpath für XSLT-Konvertierung und für vishia-Zbnf. Dahinter wird als erstes Argument die mainclass angegeben, dann die Aufrufargumente. Ein Aufruf von Java mit Standard-jar ist als JAVA_EXE-Umgebungsvariable vorhanden.

  • ANT_HOME ist der Path zum ANT-Verzeichnis (meist innerhalb Eclipse).

  • XML_TOOLBASE: Diese Umgebungsvariable ist oben nicht aufgeführt, wird aber per default in Zmake verwendet. In dieser Umgebungsvariable ist der Path zu den Files angegeben, die als Tool-Files gelten. Tool.Files sind diejenigen Scripte, die der Anwender schon anpassen kann, die aber für alle vergleichbaren Belange beim Anwender identisch sein sollen. Hier kann eine Unterscheidung zwischen einem End-Anwender und einer System-Anwender erfolgen. Ersterer muss kein XML kennen. Zweiterer ist für den Inhalt der Files unter XML_TOOLBASE zuständig.

Folgendes Bild verdeutlicht das Grundprinzip des Makeablaufs:

Bild: Zmake.png Der grün gehaltene Bereich ist derjenige, der von Zmake besetzt ist. Der andere Bereich ist der ANT-Bereich. Die blauen Kästen sind Files des End-Anwenders, dabei dick umrahmt Quellen und Ergebnisse. Die dünn umrahmten Files sind temporär. Die gelben Kästen sind Files, die der System-Anwender pflegen kann, meist über die Umgebungsvariable XML_TOOLBASE erreichbar.

Der ANT.xml-Makefile steht im Schnittpunkt beider Bereiche, wird vom Zmake erzeugt und wird als temporär betrachtet. Um ihn zu erstellen sind zwei Scriptfiles notwendig:

  • ein zbnf-File, der die Syntax des hier als genctrl.txt bezeichneten Zmake-Inputfiles interpretiert und über ZBNF nach XML wandelt.

  • ein xsl-File, der den ANT.xml-File erzeugt. Dieser kann auch im XSLP-Format vorliegen. Das wird von Zmake automatisch erkannt, der notwendige xsl-File wird bei Bedarf erzeugt.

Was letzlich in der Anwendergenerierung im ANT-Bereich ablaufen soll, wird im xsl4ant.xsl festgelegt. Dieser File sieht auch ähnlich wie ein ANT.xml-File mit seinen <target> usw. aus, nur das diese <target> dort generiert werden. Der xsl4ant.xsl muss vom System-Anwender auf jeden Fall für die Anwenderbelange angepasst werden. Das ist die zu leistende Arbeit anstelle der Arbeit der Erstellung von ANT.xml-Files. Damit sieht man auch, dass sich Zmake nur lohnt, wenn verschiedene ähnliche ANT.xml-Files für verschiedene Inputsituationen für ähnliche Generierabläufe benötigt werden. Aber genau dann lohnt es sich, da Änderungen nur an einer Stelle gemacht werden müssen.

Die Namen der Files sind beispielhaft. Alle Files des Zmake können über entsprechende Kommandozeilenargumente oder Argumente beim Aufruf übergeben werden:

 invoke>%JAX_EXE% org.vishia.zbnfXml.Zmake [INPUT] [{OPTIONS}]
 * pathes to files or dirs are absolute or relativ from cmd line invocation.
 * TPATH means a path started from given -XML_TOOLBASE:PATH or XML_TOOLBASE in environment.
 * WPATH means a path started from given -tmp directory (WorkPATH).
 INPUT              The first argument without - is the input file.
 -i:INPUT           path to the input file alternatively to INPUT.
 -curdir:PATH       sets the curren dir alternatively to command line invocation path.
 -XML_TOOLBASE:PATH path to the XML_TOOLBASE, default it is getted from environment.
 -tmp:PATH          path of tmp dir, will be created if not exists, default=\"../tmp\".
 -tmpinputxml:WPATH name of the temporary file parsed from input, default=INPUT.zbnf.xml
 -tmpantxml:WPATH   ant.xml-file to generate, default=INPUT.ant.xml
 -zbnf4ant:TPATH    zbnf-file to parse the input
 -xslt4ant:TPATH    xslt-file to generate the ant.xml

4 Zmake-Syntax und Scripte für Standardanwendungen

Topic=.Zmake.ZmakeStd.

pStyle=std

Der Zmake-Translator ist so gebaut, dass eine beliebige Inputsyntax in textueller Form benutzt werden kann, wobei beliebige ANT-Scripte und damit Verarbeitungsroutinen des Makens erzeugt werden können. Mit den Argumenten -zbnf4ant, und -xslt4ant ist beides frei kofigurierbar. Demzufolge kann man beliebige anwenderspezfische Make-Sprachen unterstützen (Stichwort DSL = Domain Specific Language).

Dennoch gibt es immer wieder kehrende Anwendungen und eine zweckmäßige Systematik der Schreibweise. Dazu gibt es das ZBNF-Script:_xsl/ZmakeStd.zbnf und das zugehörige XSL-Script:_xsl/ZmakeStd.xslp. Beide Scripte lassen sich auch als Import in ein übergeordnetes anwendungsspezifisches Script einbauen.

4.1 Grundsätzliche Syntax

Topic=.Zmake.ZmakeStd.syntax.

pStyle=std

Die Zmake-Files mit ZmakeStd.zbnf und ZmakeStd.xslp verarbeitet haben folgenden grundsätzlichen Aufbau:

 ::beliebiger Text
 call setANT_HOME.bat
 %JAX_EXE% org.vishia.zbnfXml.Zmake input_zmake.bat -tmp:../tmp
 call %ANT_HOME%\bin\ant -f ../tmp/ant_input_zmake.xml -DcurDir="%CD%"
 exit /B 0
 ZMAKE_RULES:

Der eigentliche Inhalt folgt nach dem Schlüsselwort ZMAKE_RULES:. Aller Inhalt davor wird ignoriert. Damit können die Regeln insbesondere in batchfiles nach den entsprechenden Aufrufbefehlen stehen. Man braucht also nicht zwei verschiedene Files. In der Aufrufzeile %JAX_EXE% wird dann der eigene Filename als erstes Argument angegeben. Man kann auch einen extra File für die Syntaxregeln haben, in dem dann zu Anfang das Schlüsselwort ZMAKE_RULES: steht.

Der Inhalt besteht aus Regeln der Form

 targetfile := routine(target="NAME", sourcefiles, param="value", $variable);

Alle Tätigkeiten des makens (Regeln) sind als routine in funktionaler Schreibweise notiert. Jede Regel wird im ANT.xml auf mindestens ein <target> umgesetzt. Typischerweise entstehen in den Routinen aus mehreren sourcefiles genau ein targetfile. Abweichungen sind aber möglich, bedingt durch die Funktionalität der Routine. Zumeist wird ein Abhängigkeitstest der Files generiert: Das Datum der sourcefiles wird mit dem targetfile verglichen; die Funktionalität innerhalb der routine wird nur aufgerufen, wenn die sourcefiles neuerer sind. Das ist aber abhängig von der routine selbst und nur eine zumeist-Regel.

Die Syntax im ZBNF-Script:_xsl/ZmakeStd.zbnf ist nicht auf bestimmte Verarbeitungsroutinen spezialisiert sondern ist allgemein gehalten. Die Umsetzung auf konkrete ANT-<target> erfolgt im XSL-Script:_xsl/ZmakeStd.xslp. Dort erfolgt die Fein-Ausprogrammierung der Funktionalität einer Routine.

Die Routinen werden nacheinander wie notiert ausgeführt. Im ANT.xml wird dazu eine Abhängigkeit der erzeugten Routinen-<target> vom default-<target> formuliert. Damit erübrigt sich auf dem Level des Zmake-Scripts eine Abhängigkeitsbeschreibung der einzelnen Routinen (Targets) untereinander. Bestimmte Routinen, die andere Routinen voraussetzen, übernehmen eine Abhängigkeits-Information entweder durch Angabe bestimmter Parameter, oder aus den sourcefiles. Beispiel: Bei einer Link-Routine werden die Quellfiles (zweckmäßig in einer Variable fileset(...)) angegeben. Damit kann der XSLT-Umsetzer die Namen der Objectfiles generieren und automatische Abhängigkeiten zu compilierenden Targets erzeugen, ohne dass der End-Anwender noch etwas tun muss. Die Intelligenz steckt also in der ZmakeStd.xslp-Umsetzung. Allerdings ist dort auch fest geregelt, wie die Umsetzung erfolgt. Aus End-Anwendersicht kann man dann nicht mehr, um im Beispiel beim Compilieren/Linken zu bleiben, die Namen der Objectfiles beliebig unabhängig von denen der Sourcefiles wählen. Aber, ein Sourcefile kann mit .c oder .cpp oder auch anders enden, diese Freiheit ist gegeben.

Die Angabe target= ist optional, ansonsten wird der ANT-target-Name aus der targetfile-Angabe zusammengebaut. Da der ANT-target-Name eindeutig sein muss, kann eine direkte Angabe aber hilfreich sein. Wie genau dieser Targetname verarbeitet wird, ist wiederum in der jeweiligen Routine im ZmakeStd.xslp geregelt. Eine Routinen kann zu mehreren Targets führen, diese beginnen dann mit dem angegebenen Namen.

Als sourcefiles können mehrere Files angegeben werden, auch mit wildcard-Angaben, siehe folgendes Kapitel. Wildcards dürfen auch gegebenenfalls, je nach Routine, im targetfile stehen.

Parameter sind dadurch gekennzeichnet, dass ein Identifier mit einem = gepaart ist, der Wert des Parameters muss in Anführungszeichen stehen. Der Parser muss solche Angaben von den sourcefiles-Angaben unterscheiden. Es wird vorausgesetzt, dass keine Filenamen notwendig sind, die mit dieser Parameterangabe verwechselt werden können. Die Namen der Parameter können aus ZmakeStd.zbnf-Syntax-Sicht beliebig sein. Jedoch wird von bestimmten Routinen immer nur bestimmte Parameter erwartet. Das wird nicht beim Parsen, sondern erst beim Generieren des ANT.xml getestet. Das ist aber fast in der gleichen Sekunde. Im ZmakeAnt.xslp wird aber nicht auf das Vorhandensein falscher Parameter getestet.

Letzlich werden auch Variable verarbeitet. Variable benennen ein <variable name="variable">...</variable>-Element im XML-File nach der zbnf-Konvertierung. Typischerweise werden die Variablen für File-sets oder parameter benutzt. Das ist im übernächstem Abschnitt dargestellt.

4.2 Angabe von File-Pathes im ZmakeStd

Topic=.Zmake.ZmakeStd.filePath.

pStyle=std

Der Zerlegung von Pfadangaben zu Files ist Beachtung zugedacht worden. Bei den Pfadangaben werden Pfadanteil, Filename und Extension getrennt geparst. Zusätzlich ist der Pfadanteil aufspaltbar in einen Basis-Anteil und einen lokalen Pfad-Anteil. Insbesondere mit letztem Mechanismus ist eine freizügige Selektierung von einzelnen Files möglich. Das soll im folgenden Beispielen gezeigt werden:

Angenommen, es stehen mehrere Files in einem Ordner, dabei aber in Unterordner gegliedert. Eine Konvertierung soll den Input-Filenamen, aber ohne Extension als Bestandteil des Output-Namens verwenden. Zusätzlich soll auch der lokale Pfad ab dem Basisordner berücksichtigt werden. Dann kann man folgendes notieren:

 PathOutput/*.out := routine
 ( PathInput:localPath/path/file.ext
 , PathInput:localPath/path2/file2.ext
 , OtherPathInput:localPath2/file.ext
 );

Die Routine kann mehrere Outputfiles erzeugen. Diese werden im PathOutput mit der angegebenen extension gespeichert. Anstatt des * wird der Input-File-Path eingesetzt. Und zwar jeweils der Anteil nach dem :, also der localPath.... Es sollen also folgende Outputfiles entstehen.

 PathOutput/localPath/path/file.out
 PathOutput/localPath/path2/file2.out
 PathOutput/localPath2/file.out

Der : ist der Trenner zwischen dem Base-path und dem lokalem Path. Eine Laufwerksangabe wird eigenständig berücksichtigt. Dabei steht der Doppelpunkt immer an zweiter Stelle nach dem Laufwerksbuchstaben. Nur wenn ein Basepath aus nur einem Buchstaben bestehen werden würde, gäbe es Konflikte. Berücksichtigt wird auch eine absolute oder relative Angaben. Bei einer relativen Angabe muss im ANT.xml-Script meist noch ein ${curDir} angegeben werden, bei absoluten Pfaden stört dies.

Zur Slash / Backslash-Problematik (Windows): Da auf der Basis ANT gearbeitet wird, kann überall der Slash / verwendet werden. Ein Backslash \ kann teilweise auch verwendet werden, in den Scripts ist das berücksichtigt. Es ist aber nicht zu empfehlen. In neuen Windows-Versionen wird teilweise selbst bei Systembefehlen (cmdline) der Slash mittlerweile akzeptiert.

Im Script ZmakeStd.zbnf wird die Zerlegung der Filepath-Angaben formuliert. Die Verwendung der Path-Bestandteile ist im ZbnfStd.xslp spezifisch zu den einzelnen Routinen programmiert. Im Beispiel ist gezeigt, dass Files auch aus verschiedenen Input-Pathes in den gleichen Output-Path angeordnet werden können. Wie die Zerlegung erfolgt und wie damit verfahren werden kann, wird in ZmakeIntern.html#Topic.Zmake.internZbnf.FilePath erläutert.

4.3 Variablen und Filesets

Topic=.Zmake.ZmakeStd.variable.

pStyle=std

Für Bearbeitungen des selben Files mit verschiedenen Routinen sollen nicht die selben Files jeweils mehrfach aufgeführt werden, sondern nur einmal. Dazu ist eine Schreibweise

 $variable = fileset(filepath, filepath);

vorgesehen. Die Variable nimmt hier nur die Informationen auf, einschließlich der Zerlegung der File-pathes in die Bestandteile. Die Verarbeitung der Variablen wird dann in den entsprechenden Routinen besorgt.

Variablen können weitere Informationen aufnehmen, der Mechanismus kann erweitert werden. Bisher sind nur das fileset() berücksichtigt.

4.4 Routinen zur File-Behandlung

Topic=.Zmake.ZmakeStd.fileRoutine.

pStyle=std

Die folgenden Routinen zur Filenbehandlung bieten ein komplexes Level oberhalb des üblichen copy, mkdir und delete.

4.4.1 Kopieren neuerer Files

Topic=.Zmake.ZmakeStd.fileRoutine.copyNewerFiles.

pStyle=std

Die Leistung, Files nur dann zu kopieren, wenn sie neuer sind als die jeweiligen Zielfiles, wird im ANT mit der ANT-Tasl <copy> bereits berücksichtigt. Die vorliegende Umsetzung auf Zmake vereinfacht die Formulierung der Aufgabe in der Form:

 targetpath/** := copyNewerFiles(target="Target", srcpath="srcpath", sourcefiles, $fileset);

Anstatt targetpath/** kann auch ein bestimmter File oder so etwas wie targetpath/*.ext angegeben werden. Dann werden die entsprechenden sourcefiles umbenannt. Anstatt des * im targetpath wird dann der localpath aus dem sourcefile eingesetzt, wie es im Abschnitt #Topic.Zmake.ZmakeStd.filePath beschrieben ist. Bei einer Angabe targetpath/**.ext werden die Angaben des local path und filename ohne extension vom Inputfile benutzt, die angegebene Extension des Outputfiles aber gesetzt.

Bei der Angabe mehrerer sourcefiles werden pro Sourcefile je eine ANT-Task <copy> erzeugt. Bei den Sourcefiles kann es ebenfalls wieder Wildcards geben in der Form path/**.ext, path/file*.ext oder path/file*.*.

4.4.1.1 Beispiele Kopieren verschiedener Files mit und ohne Pfad in ein Zielverzeichnis

Topic=.Zmake.ZmakeStd.fileRoutine.copyNewerFiles..

pStyle=std

 test1/** := copyNewerFiles(task="test1", ../Xml/docuSrc:UmlDocu.topic.txt
                                        , ../Xml/html:UmlDocu.html);

Hierbei werden aus zwei verschiedenen Verzeichnissen zwei verschiedene Files geholt, die aber im Zielverzeichnis flach nebeneinander liegen sollen. Das wird ausgedrückt durch die Lage des : in den Quellverzeichnisangaben vor dem Filenamen ausgedrückt. Es wird das folgende ANT-Target erzeugt:

 <target name="test1">
     <copy todir="${curDir}/test1/">
        <fileset dir="${curDir}/../Xml/docuSrc/">
           <include name="UmlDocu.topic.txt"/>
        </fileset>
     </copy>
     <copy todir="${curDir}/test1/">
        <fileset dir="${curDir}/../Xml/html/">
           <include name="UmlDocu.html"/>
        </fileset>
     </copy>
 </target>

Im nächsten Beispiel sollen die selben Files mit ihren lokalen Pfaden kopiert werden. Der Unterschied ist die Lage des ::

 test2/** := copyNewerFiles(task="test2", ../Xml:docuSrc/UmlDocu.topic.txt, ../Xml:html/UmlDocu.html);

wird zu

 <target name="test2">
     <copy todir="${curDir}/test2/">
        <fileset dir="${curDir}/../Xml/">
           <include name="docuSrc/UmlDocu.topic.txt"/>
        </fileset>
     </copy>
     <copy todir="${curDir}/test2/">
        <fileset dir="${curDir}/../Xml/">
           <include name="html/UmlDocu.html"/>
        </fileset>
     </copy>
 </target>

Das selbe Ergebnis lässt sich erzielen, indem man für alle Sourcefiles ein gemeinsames Basisverzeichnis angibt. Das ist bei mehr als zwei Files eine Schreibvereinfachung.

 test2/** := copyNewerFiles(task="test2a", srcpath="../Xml", docuSrc/UmlDocu.topic.txt, html/UmlDocu.html);
4.4.1.2 Beispiele für Kopieren ganzer, auch mehrerer Verzeichnisbäume in ein Zielverzeichnis

Topic=.Zmake.ZmakeStd.fileRoutine.copyNewerFiles..

pStyle=std

 test3/** := copyNewerFiles(task="test3", ../Xml/docuSrc:**);

ANT-<copy> kann hier nicht direkt etwa mit einem Attribut dir="..." arbeiten sondern löst dies über ein <fileset>. Ein <fileset> ist grundsätzlich viel leistungsfähiger. Hier wird das dir= angegeben, wie es vor dem /** steht. Das <include>-Element enthält dann die Information: Alle files in allen sub-Verzeichnissen:

 <target name="test3">
   <copy todir="${curDir}/test3/">
     <fileset dir="${curDir}/../Xml/docuSrc/">
       <include name="**/*"/>
     </fileset>
   </copy>
 </target>

Dieses Beispiel variiert nimmt auch mehrere Verzeichnisbäume ohne, oder hier mit den zugehörigen lokalen Pfaden:

 test4/** := copyNewerFiles(task="test4", ../Xml:docuSrc/**, ../Xml:html/**);

wird in ANT abgebildet mit

 <target name="test4">
   <copy todir="${curDir}/test4/">
      <fileset dir="${curDir}/../Xml/">
         <include name="docuSrc/**/*"/>
      </fileset>
   </copy>
   <copy todir="${curDir}/test4/">
      <fileset dir="${curDir}/../Xml/">
         <include name="html/**/*"/>
      </fileset>
   </copy>
 </target>

Eine Schreibvereinfachung lässt sich auch hier wieder erreichen mit Angabe von

 test4/** := copyNewerFiles(task="test4a", srcpath="../Xml", docuSrc/**, html/**);

Selbst ein Mix aus Angabe von srcpath="..." und einem Basispfad mit : getrennt klappt wie folgend gezeigt:

 test5/** := copyNewerFiles(task="test5", srcpath="../Xml", docuSrc:**, html/**);

In diesem Beispiel werden die Files aus docuSrc flach hinüberkopiert, da der : dahinter steht. Dagegen wird der html/**-Baum einschließlich des Verzeichnisses html übernommen:

 <target name="test5">
   <copy todir="${curDir}/test5/">
     <fileset dir="${curDir}/../Xml/docuSrc/">
       <include name="**/*"/>
     </fileset>
   </copy>
   <copy todir="${curDir}/test5/">
     <fileset dir="${curDir}/../Xml/">
       <include name="html/**/*"/>
     </fileset>
   </copy>
 </target>
4.4.1.3 Beispiele mit Umbenennen von Files

Topic=.Zmake.ZmakeStd.fileRoutine.copyNewerFiles..

pStyle=std

TODO

 test5/** := copyNewerFiles(task="test5", srcpath="../Xml", docuSrc:**, html/**);

4.4.2 Kopieren aber nicht bei Inhaltsgleichheit

Topic=.Zmake.ZmakeStd.fileRoutine.copyChangedPathFiles.

pStyle=std

Wenn Files ein Resultat eines Generierprozesses sind, dann ist es eine typische Situation, dass Files zwar mit neuerem Datum vorhanden sind, aber inhaltsgleich mit den vorigen Versionen. Da die meisten Tools für einen Test der Neuigkeit zunächst nur auf das Datum des Files schauen, würden die Files als neu erscheinen obwohl sie es nicht sind.

Abhilfe schafft ein vergleichendes Kopieren von der Generierposition generatepath auf eine Zielposition targetpath. Dabei werden nur diejenigen Files kopiert, deren Inhalt verschieden vom Original ist. Das erfolgt unabhängig vom Zeitstempel. Auf der Zielposition bleiben dann Files unberührt, wenn neu generierte (auf der Generierposition) identisch sind.

Der Aufruf erfolgt mit

 targetpath/** := copyChangedFiles(target="Target", srcpath="srcpath", sourcefiles, $fileset);

Dabei gibt es genau die gleichen Möglichkeiten der Fileauswahl wie bei copyNewerFiles.

Vor dem Kopieren wird Byte für Byte verglichen. Die Rechenzeit dazu ist bei den heute üblichen Computern nicht auffällig. Das Vergleichen und Kopieren wird mit einem speziellen Java-Programm javadoc-src:_org/vishia/ant/Zcopy realisiert. Dieses Programm baut intern auf org.apache.tools.ant.taskdefs.condition.FilesMatch auf. Die Zcopy-Routine ist ein Beispiel für direktes Aufrufen einer Java-Task. Sie ist grundsätzlich erweiterbar in der Richtung eines spezifischen Inhaltstestes. So kann ein Kopieren nicht erfolgen, wenn nur formale Änderungen in den Files vorgefunden wurden, wie Rückschreibe-Werte eines Source-Management-Tools oder wie Kommentare.

Die Aufrufsyntax ist identisch mit der von copyNewerFiles. Im generiertem ANT-Script wird aber nicht <copy> sonder die Java-class <Zcopy> aufgerufen. Diese wird deklariert am Anfang des ANT.xml:

  <taskdef name="Zcopy" classname="org.vishia.ant.Zcopy"/>

Aufgrund einer ZmakeStd-Zeile

 test5/** := copyChangedFiles(task="test5c", srcpath="../Xml", docuSrc:**, html/**);

ergibt sich dann folgender generierte ANT.xml-Code:

 <target name="test5c">
     <Zcopy todir="${curDir}/test5/" dir="${curDir}/../Xml/docuSrc/" file="**/*"/>
     <Zcopy todir="${curDir}/test5/" dir="${curDir}/../Xml/"         file="html/**/*"/>
  </target>

Zcopy arbeitet nicht mit den <fileset> sondern mit Attributen dir und file, wobei bei ..file wildcards angegeben werden können ähnlich wie in den <fileset> bzw. für die hier vorgestellten Zwecke genauso.

4.4.3 Zippen

Topic=.Zmake.ZmakeStd.fileRoutine.zip.

pStyle=std

Das Archivieren in ein zip-Archiv wird vom ANT standardgemäß geboten. Hier wird es ebenfalls unterstützt, auf dem Level der Filenagaben wie oben beschrieben:

 targetpathfile.zip := zipFiles(files, files);

Beim Zippen umfangreicher filetrees ist es angebracht, mit Wildchars zu arbeiten. Bei den files ist folgendes zulässig:

Angabe

Bedeutung

path/**

alle Files und Pathes unterhalb des Path

path/**

alle Files und Pathes unterhalb des Path

Dabei wird jedenfalls berücksichtigt, dass ein Base-Path nicht mit ins zip-Archiv kopiert wird, wohl aber darauf aufbauende Pathes. Im Folgenden Beispiel:

 targetpathfile.zip := zipFiles(pathBase1:path1/**, path2/**);

Erscheinen im zip-Archiv

 path1/**
 path2/**

4.4.4 Weiteres

Topic=.Zmake.ZmakeStd.fileRoutine..

pStyle=std

TODO

4.5 Ausführen von Kommandozeilen

Topic=.Zmake.ZmakeStd.cmd.

pStyle=std

Grundlage hierfür ist der Kommandozeileninterpreter des eingesetzten Betriebssystemes, bzw. adäquat dass, was ant als

 <exec executable="..."> <arg line="..."> ...

ausführen kann. Für die Formulierung der Kommandozeilen kann im ZmakeStd die Filesets benutzt werden. Das ist relativ leistungsfähig. Dazu ein Beispiel:

In einem Set werden Source-Files für eine Compilierung zusammengetstellt:

 $src_Rmos=fileset
 ( ../../OSAL/src_Rmos/os_atomic.c
 , ../../OSAL/src_Rmos/os_mem.c
 , ../../OSAL/src_Rmos/os_mutex.c
 , ../../OSAL/src_Rmos/os_sema.c
 , ../../OSAL/src_Rmos/os_socket.c
 , ../../OSAL/src_Rmos/os_sync.c
 , ../../OSAL/src_Rmos/os_thread.c
 , ../../OSAL/src_Rmos/os_time.c
 );

In einer Variable wird der Aufbau einer cmd-Zeile zum Compilieren angegeben:

 $RmosCC= "objRmos/" + @file + ".obj" :=
 cmd("rm-gcc.exe"), arg("-x c++ -c -Wa,-adhls=../make/lstRmos/" + $file + ".lst -fno-common -I src -I ../../OSAL/inc -I ../../../inc_Rmos -I d:/Progs/RM3DEV/INC " + $path + $file + $ext + " -o ../make/objRmos/" + $file + ".obj")
 ;

Der Aufruf des Comilers einzeln für alle Sourcefiles erfolgt dann mit

 ../make/objRmos/** := for($src_Rmos): exec { $RmosCC; };

Es werden also für alle Angaben des filesets (for($src_Rmos)) jeweils ein Target entsprechend der Kommandozeilenangabe in der Variable RmosCC zusammengebaut. Dabei erfolgt eine Zusammensetzung der Aufrufargumente als String, getrennt mit +, angebbar sind "stringliteral", Variablen und wieder eine for(fileset: string)-Angabe. Letztere wird für das Bilden einer Library wie folgt genutzt:

 ../make/libRmos/libOSAL.a := exec{ cmd("ar"), arg ("-r ../make/libRmos/libOSAL.a"), arg( for($src_Rmos: " ../make/objRmos/" + $file + ".obj") ); };

Die Variable sind Attribute aus den angegebenen Files des Filesets.

4.6 Routinen zur Verarbeitung von Headerfiles

Topic=.Zmake.ZmakeStd.HeaderProcessing.

pStyle=std

Headerfiles sind aus Sicht der C/C++-Entwicklung einfach die Definition von Strukturen und Konstanten und Deklaration von Funktion/Methodenaufrufen. Für eine übergreifende Verwendung: Datenaustausch, Dokumentation der Strukturen, Einlesen von Daten unter Java oder adäquaten Programmierumgebungen ist eine Verarbeitung von Headerfiles interessant. Dabei kann wiederum der ZBNF-Parser und XSLT-Generierungen eingesetzt werden. Die ZmakeStd-Scripts enthalten einige Konvertierungen, die innerhalb des vishia-Projektes entwickelt worden sind.

4.6.1 ZBNF-Parsen der Headerfiles

Topic=.Zmake.ZmakeStd.HeaderProcessing.Zbnf.

pStyle=std

Für eine weitere Verarbeitung müssen die Headerfiles erstmal in XML gewandelt werden. Das geschieht mit einer Routine:

 targetpath/*.zbnf.xml := zbnfCheader(target="CheaderXml", headerfiles);

Die Routine erzeugt pro headerfile ein ANT-<target> für das ZBNF-Parsen, mit Test der Neuigkeit (file-timestamp). Bezüglich Angabe der headerfiles gelten alle Ausführungen im Abschnitt Angabe von File-Pathes im ZmakeStd. Es wird also im targetpath gegebenenfalls ein Verzeichnisbaum erzeugt, wenn ein lokaler Pfad bei den headerfiles angegeben wurde. Die Extension (meist .h) wird bei den erzeugten Files nicht mit hinübergezogen und statt dessen die hier angegebene Extension erzeugt.

4.6.2 Konvertieren geparster Headerfiles nach XMI

Topic=.Zmake.ZmakeStd.HeaderProcessing.2XMI.

pStyle=std

Das XMI-Format (http://www.omg.org) ist ein Standardformat für Datenbeschreibungen auch für UML. Die geparsten Headerfiles können nach XMI gewandelt werden mit

 targetpath.xmi := genXmiFromZbnfCheader(zbnfCheaderTarget="CheaderXml", headerfiles);

Hierbei muss dasjenige Target (die Routine) angegeben werden, die für die zbnfCheader-Umsetzung zuständig ist. Das ist notwendig, weil diese Routinen nicht die targets für die ZBNF-Umsetzung selbst erzeugt sondern die gegebenenfalls noch anderweitig notwendigen erzeugten Headerfiles.zbnf.xml voraussetzt. Die Konvertierung nach XMI ist beschrieben in TODO

4.7 Weiteres

Topic=.Zmake.ZmakeStd..

pStyle=std

TODO

5 Anwendung für die Dokumentengenerierung aus XML,XMI

Topic=.Zmake.XmlDocuGen.

pStyle=std

Für die Dokumentengenerierung XmlDocuGen-Overview wird das Zmake-Prinzip verwendet. Der Inputfile für den Maker ist hier gleichzeitig derjenige File, der auch das Aussehen des Dokumentes bestimmt. Daher wird dieser File mehrfach verwendet. Sein Inhalt kann über XSLT sowohl in einen ANT.xml-Makefile als auch in einen XSL-Steuerfile für Dokumentenaufbereitung gewandelt werden. ...