# Eclipse - Ant Skript - jar erstellen mit Referenced Libraries - build.xml



## prototype0815 (23. Jul 2014)

Hallo liebe XML Luets,

zu Anfang gleich ma, ich bin blutiger Anfänger was XML angeht. Ich habe Stunden gebraucht um folgendes Skript zu schreiben...
[XML]<?xml version="1.0"?>
<project name="make jar" default="jarbuilder">																<!-- default gibt das "default" target an -->
    <description>
    Kompiliert den aktuellen Stand des Projekts und verpackt ihn in ein .jar-Archiv
    </description>

    <target name="jarbuilder">
        <jar destfile="maxi6.jar" basedir="bin" excludes="*.html,*.applet, *.jbx, *.MF">
        	<manifest>
        		<attribute name="Main-Class" value="Run"/>
        		<attribute name="Trusted-Only" value="true"/>
        		<attribute name="Permissions" value="all-permissions"/>
        		<attribute name="Application-Name" value="Paul Maxi6"/>
        	</manifest>
        </jar>    	
    </target>
</project>[/XML]
wie die meisten von euch mit ein paar Blicken erkennen werden, baut mir das Skript eine .jar Datei aus allen Dateien im <projectlocation>\bin Verzeichnis zusammen, und erstellt sogleich eine MANIFEST.MF Datei.

Was ich nun nach einigen Stunden recherche und vergeblichen Versuchen nicht zum laufen bekommen hab ist folgendes...

Dieses Ant Skript soll mir die Referenced Libraries die im Build Path angegeben sind, mit in die .jar packen. Damit diese auch wirklich ausführbar ist, denn sonst funktioniert diese teilweise oder gar nicht.

Was ich schon ausprobiert hab, und was auch sehr vielversprechend aussieht ist folgendes:
*Die .classpath meines Projekts sieht so aus:*
[XML]<?xml version="1.0" encoding="UTF-8"?>
<classpath>
	<classpathentry kind="src" path="src"/>
	<classpathentry kind="lib" path="C:/Program Files (x86)/Java/jcifs_1.2.25/jcifs-1.2.25.jar"/>
	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/jdk1.7.0_51"/>
	<classpathentry kind="output" path="bin"/>
</classpath>[/XML]
*der Verfasser eines Posts fügte hinzu*

```
You could use ant to parse that file looking for these classpathentry elements with kind lib.
```

*Als Lösung dieses Problems hat jemand folgendes vorgeschlagen:*

```
Use the xmlproperty task to read the .classpath into property values.
```
[XML]<xmlproperty file=".classpath" collapseAttributes="true" delimiter=";" />[/XML]

```
Then set that value in the path
```
[XML]<path id="eclipse.classpath">
    <pathelement path="${classpath.classpathentry.path}"/>
</path>


<target name="compile" depends="init">

    <javac srcdir="${src}" destdir="${build}" updatedProperty="compiled">
        <classpath refid="eclipse.classpath"/>
    </javac>
</target>[/XML]

Ich verstehe leider nicht was die letzten beiden Code Schnipsel machen, desweiteren trat bei den meisten Versuchen dieser Fehler auf:

```
\build.xml:9: jar doesn't support the nested "xmlproperty" element.
```
natürlich nicht immer mit "xmlproperty", aber eben *"jar doesn't support the nested .... element"*

Ich wäre echt happy wenn mir jemand weiterhelfen kann.

LG proto :toll:


----------



## turtle (23. Jul 2014)

> Dieses Ant Skript soll mir die Referenced Libraries die im Build Path angegeben sind, mit in die .jar packen.


Davon rate ich ab. 

Nun kann "niemand" eine beispielsweise neue oder fehlerbereingte Version einer Library, die du verwendest, nutzen.

Dieses wird oft so gemacht, das alle externen Bibliotheken in einem lib-Verzeichnis NEBEN der jar stehen.

Im Manifest musst du dann den Classpath angeben, damit die Libraries gefunden werden können.

In einem Beispiel von mir sieht das dann so aus:
[XML]<property name="log4j" value="log4j-1.2.16.jar" />
<property name="log4jLib" value="./lib/${log4j}" />
<manifest>
	<attribute name="Main-Class" value="MainKlasse" />
	<attribute name="Class-Path" value=". haupt.jar ${log4jLib}" />
</manifest>[/XML]
Dies ergibt im Manifest folgendes

```
Class-Path: . haupt.jar ./lib/log4j-1.2.16.jar
```


----------



## prototype0815 (23. Jul 2014)

ich verstehe das nicht ganz, warum rätst du mir davon ab? Ich brauche ein möglichst variables Ant Skript, das mir eine .jar zusammenbaut die jemand anderes verwenden kann. Ohne die Libraries zu zu packen, geht das ja nicht. 
Ich gebe dir recht das niemand eine "fehlerbereinigte" Library nutzen kann, aber wraum sollte das auch jemand wollen? Ich bin der Entwickler und wenn ich ein neues Release meiner Software veröffentliche, mit einer überarbeiteten Version einer custom Library, dann steht diese anderen Personen zur Verfügung, und sonst nicht.
Verstehst du?* ich benötige unbedingt eine Methode um die Referenced Libraries mit in die jar zu packen.* 
Ich will auch nicht in jedem Projekt einen Ordner machen in den ich dann die custom Libraries hinein schmeisse. Oder gar noch einen "globalen" Ordner mit sämtlichen custom Libraries die ich für alle meine Projekte verwende.

Meine Überlegung dabei ist, sagen wir ich habe Software A, B, C und dazu custom Library 1, 2, 3

Software A benötigt lib 1,2

Software B benötigt lib 2,3

Software C benötigt lib 2

Mache ich nun je Projekt einen lib ordner dann habe ich lib2, drei mal auf meinem Rechner (unpraktisch) auch wenns nur um ein paar MB geht.

Mache ich einen globalen lib Ordner mit allen custom libraries, so werden alle Libraries in jedes Projekt hinein gepackt, ob ich sie benötige oder nicht. Dadurch werden meine jar´s unnötig groß.

Benutze ich die globale Variante, könnte ich meine build.xml für jedes Projekt individuell anpassen, was ich aber auf gar keinen Fall möchte.

Du siehst alle Varianten ausser die, das ich in meiner Classpath schaue welche Libraries das Projekt benötigt, sind bescheiden.


----------



## turtle (23. Jul 2014)

Ich gebe zu Protokoll, das du nunmehr nicht von einer Applikation redest, sondern von dreien.

Diese verwenden Libraries gemeinsam. Das Bundeln in einer JAR würde natürlich jede einzelne davon grösser machen, weil beispielsweise Lib2 in allen drei kopiert werden muss, genau so was du als Gegenargument bei mir angibst. Der Vorteil ist natürlich, das du so jede Applikation einzeln kontrollieren kannst

Habe ich zwar noch nie gemacht, habe aber Jar Jar Links gefunden, mit dem das gehen sollte, was du vorhast.

Und hier gibt es noch ein paar Infos zum Thema und besonders hinweisen möchte ich auf die Eclipse-Variante, die das ebenfalls kann.


----------



## prototype0815 (24. Jul 2014)

ok, wie du gleich sehen wirst hab ich es aufgegeben zu versuchen aus den Referenced Libraries raus zu bekommen was für .jar´s ich mit in meine Final.jar einbauen muss. Ich bin der Meinung das ich dafür noch zu wenig von Ant Skripts verstehe und das ich keinen guten Debugger dafür hab, eclipse nervt mich nur.

Hier meine build.xml:
[XML]<?xml version="1.0"?>
<project name="make jar" default="mainjarbuilder">
	<!-- default gibt das "default" target an -->

	<property name="one-jar.dist.dir" value="D:\Paul\PaulHostIP\.lib\one-jar-ant-task-0.97" />
	<import file="${one-jar.dist.dir}/one-jar-ant-task.xml" optional="true" />

	<property name="project.dir" value="${basedir}" />
	<property name="lib.dir" value="${project.dir}/.lib" />
	<property name="bin.dir" value="${project.dir}/bin" />
	<property name="dest.jarFileName" value="maxi6.jar" />

	<!-- Kompiliert den aktuellen Stand des Projekts und verpackt ihn in ein .jar-Archiv -->
	<target name="mainjarbuilder">
		<jar destfile="noFinal.jar" basedir="${bin.dir}" excludes="*.html,*.applet, *.jbx, *.MF">
			<manifest>
				<attribute name="Main-Class" value="Run" />
				<attribute name="Trusted-Only" value="true" />
				<attribute name="Permissions" value="all-permissions" />
				<attribute name="Application-Name" value="Paul Maxi6" />
			</manifest>
		</jar>
		<if>
			<available file="${lib.dir}" type="dir" />
			<then>
				<!-- antcall ruft das nächste Target auf, dies sollte eigentlich durch einen depends= Eintrag ebenfalls funktionieren -->
				<antcall target="onejar" />
			</then>
			<else>
				<move file="${project.dir}/noFinal.jar" tofile="${project.dir}/${dest.jarFileName}"/>
			</else>
		</if>
	</target>

	<!--	Depends gibt an das zuerst der "mainjarbuilder" ausgeführt worden sein muss, damit one-jar ausgeführt wird ( depends="mainjarbuilder" )  -->
	<target name="onejar">

		<!-- kann aus mehreren jar´s eine einzelne zusammenbauen -->
		<one-jar destfile="${dest.jarFileName}">
			<main jar="${project.dir}/noFinal.jar">
			</main>
			<lib>
				<fileset dir="${lib.dir}" />
			</lib>
			<manifest>
				<attribute name="Main-Class" value="Run" />
				<attribute name="Trusted-Only" value="true" />
				<attribute name="Permissions" value="all-permissions" />
				<attribute name="Application-Name" value="Paul Maxi6" />
			</manifest>
		</one-jar>
		<delete file="noFinal.jar" />
	</target>
</project>
[/XML]
ich hab ein Problem bei der <if> Verzweigung. Seit ich diese eingebaut hab Funktioniert es nicht mehr richtig. Es sollte entweder eine <one-jar> bauen oder eine normale <jar>, je nachdem ob der ".lib" Ordner in meinem Projekt existiert oder nicht.
Aber da mein Debugger nur mist anzeigt, brauche ich dafür bisl Hilfe.


----------



## prototype0815 (24. Jul 2014)

die build.xml ist fertig, leider aber nur auf die Art und Weise das ich einen Ordner in jedem Projekt anlegen musste, indem die jeweiligen custom libraries (.jar) liegen.
Knifflig waren folgende Punkte:

one-jar-ant-task-0.97.jar in Eclipse einbinden, damit man aus mehreren JARs eine einzige machen kann
ant-contrib-1.0b3.jar in Eclipse einbinden, benötigt man für <if> Verzweigungen oder <for> Schleifen in der build.xml

der restliche Quelltext der build.xml war schnell mit ein paar Posts von StackOverflow vervollstandigt. Allerdings Poste ich meine Lösung hier, weil die Mitglieder dieses Forums mich aktiv unterstützt haben, und weil manche der englischen Sprache nicht so mächtig sind, diejenigen sind sicher auch froh über eine deutschsprachige Anlaufstelle für ihre Probleme.

hier nun die fertige build.xml
[XML]<?xml version="1.0"?>
<project name="make jar" default="mainjarbuilder">
	<!-- default gibt das "default" target an -->

	<property name="one-jar.dist.dir" value="D:\Paul\PaulHostIP\.externalToolBuilders\one-jar-ant-task-0.97" />
	<import file="${one-jar.dist.dir}/one-jar-ant-task.xml" optional="true" />

	<!-- die folgende Zeile ist festehend und so zu übernehmen-->
	<taskdef resource="net/sf/antcontrib/antcontrib.properties" />

	<property name="project.dir" value="${basedir}" />
	<property name="lib.dir" value="${project.dir}/.lib" />
	<property name="bin.dir" value="${project.dir}/bin" />
	<property name="dest.jarFileName" value="maxi6.jar" />

	<!-- Kompiliert den aktuellen Stand des Projekts und verpackt ihn in ein .jar-Archiv -->
	<target name="mainjarbuilder">
		<jar destfile="noFinal.jar" basedir="${bin.dir}" excludes="*.html,*.applet, *.jbx, *.MF">
			<manifest>
				<attribute name="Main-Class" value="Run" />
				<attribute name="Trusted-Only" value="true" />
				<attribute name="Permissions" value="all-permissions" />
				<attribute name="Application-Name" value="Paul Maxi6" />
			</manifest>
		</jar>
		<if>
			<available file="${lib.dir}" type="dir" />
			<then>
				<!-- antcall ruft das nächste Target auf, dies sollte eigentlich durch einen depends= Eintrag ebenfalls funktionieren -->
				<antcall target="onejar" />
			</then>
			<else>
				<move file="${project.dir}/noFinal.jar" tofile="${project.dir}/${dest.jarFileName}" />
			</else>
		</if>
	</target>

	<!--	Depends gibt an das zuerst der "mainjarbuilder" ausgeführt worden sein muss, damit one-jar ausgeführt wird ( depends="mainjarbuilder" )  -->
	<target name="onejar">

		<!-- kann aus mehreren jar´s eine einzelne zusammenbauen -->
		<one-jar destfile="${dest.jarFileName}">
			<main jar="${project.dir}/noFinal.jar">
			</main>
			<lib>
				<fileset dir="${lib.dir}" />
			</lib>
			<manifest>
				<attribute name="Main-Class" value="Run" />
				<attribute name="Trusted-Only" value="true" />
				<attribute name="Permissions" value="all-permissions" />
				<attribute name="Application-Name" value="Paul Maxi6" />
			</manifest>
		</one-jar>
		<delete file="noFinal.jar" />
	</target>
</project>
[/XML]


----------

