Abhängige Projekte + Libraries hinzufügen

Hallo

Ich habe eine Java Applikation mit folgendem Ant Build File:

<path id="project-classpath">
    <fileset dir="${lib.dir}" includes="*.jar" />
</path>

<target name="remove release">
    <delete dir="${dist.dir}" />
</target>

<target name="clean build">
    <delete dir="${build.dir}" />
</target>

<target name="clean docs">
    <delete dir="${docs.dir}" />
</target>

<target name="compile" depends="clean build">
    <mkdir dir="${build.dir}" />
    <javac srcdir="${src.dir}" destdir="${build.dir}" debug="on" target="1.8" source="1.8">
        <classpath refid="project-classpath" />
        <compilerarg value="-Xlint:none" />
    </javac>
</target>

<target name="docs" depends="clean docs, compile">
    <mkdir dir="${docs.dir}" />
    <javadoc packagenames="src" sourcepath="${src.dir}" destdir="${docs.dir}">
        <fileset dir="${src.dir}">
            <include name="**" />
        </fileset>
    </javadoc>
</target>

<target name="build jar" depends="remove release, compile">
    <mkdir dir="${dist.dir}" />
    <jar destfile="${dist.dir}/myApp.jar">
        <manifest>
            <attribute name="Main-Class" value="com.something.main.Main" />
            <attribute name="Class-Path" value="." />
        </manifest>

        <fileset dir="${build.dir}" />
        <zipfileset dir="config" />
        <zipfileset excludes="META-INF/**" src="lib/matlabcontrol-4.1.0.jar" />
    </jar>
    <antcall target="clean build" />
</target>

<target name="complete build" depends="docs, build jar, clean build" />

Folgende Probleme habe ich mit meinem Build File:

  1. Meine Applikation hängt von einem anderen Projekt ab (required projects on the build path). Wie kann ich dieses Projekt zum Build File hinzufügen, so dass es nicht ins Javadoc aufgenommen wird?

  2. Mein lib Ordner enthält viele Libraries. Es existieren 2 Subfolder: lib/docs und lib/src (welche die Source und Javadoc Files der Libraries enthalten). Natürlich möchte ich in meinem .jar File diese 2 Ordner nicht haben.

I denke, dass

<zipfileset excludes="META-INF/**" src="lib/matlabcontrol-4.1.0.jar" />

die Matlabcontrol library hinzufügt.

Wie kann ich die restlichen Libraries hinzufügen?

  1. Mein .jar File wird wahrscheinlich ziemlich gross, da ich viele Libraries verwende. Ich möchte mein .jar File an ein Cluster senden, daher wäre es besser wenn es klein wäre.

Gibt es eine Möglichkeit zwei .jar Files zu erzeugen, wobei das einte .jar File nur die libs (und vielleicht das dependent project) enthält? Oder kann ich den lib Ordner direkt als Ordner belassen in dem Ordner wo das .jar File sich befindet?

  1. Bin nicht sooo firm in Ant, aber … diese “Projekt-Dependency” ist eigentlich eher eine Bequemlickeitsfunktion von IDEs. Für das Deployment (oder auch nur einen autmatischen build) sollte das vermutlich entweder als eigenes Projekt (grob: Mit einer eigenen Ant-File) existieren, oder schlicht zu einer JAR gebaut und zu den “libs” des eigentlichen Projekts hinzugefügt werden.

  2. Mehrere libraries in diese excludes einfügen sollte mit sowas wie
    <zipfileset excludes="META-INF/**" src="lib/matlabcontrol-4.1.0.jar,lib/other.jar,lib/yetAnother.jar" />
    möglich sein (ist aber auch nur schnell gewebsucht)

  3. JARs in JARs packen ist zwar manchmal recht bequem, kann aber ungünstige Konsequenzen haben. Ganz konkret wird die JAR ggf. riesig, und es kann leichter zu Versionskonflikten kommen. Wäre sowas wie
    A. Die haupt-JAR und
    B. Eine “dependencies.zip” mit ALLEN dependencies drin
    eine Option?

(Einige werden es vielleicht irritierend finden, wenn gerade ICH das frage, aber …: Hast du schon Maven in Betracht gezogen? Da ist das dependency management etwas glatter. Das “matlabcontrol” wäre da dann recht einfach, sauber und klar über
[xml]

matlabcontrol
matlabcontrol
4.1.0

[/xml]
hinzugefügt, ohne dass du dir über die dependencies dieser lib Gedanken machen oder gar diese JAR und ihre dependencies irgendwie selbst zusammenpacken müßtest…)

Vielen Dank für die Tipps.

zu 1. Die Projekt-Dependency existiert bereits als eigenes Projekt (im Eclipse Workspace), allerdings hate s kein Ant-File. Ich könnte es als Jar exportieren und im Haupt-Projekt einfügen. Wie würde das aber einem Ant-File funktionieren? Wie könnte ich dann das Projekt in mein Haupt-Projekt integrieren?

zu 2. Das Problem damit ist, dass ich dann jede einzelne Library auflisten muss…

zu 3. Das mit Maven habe ich schon oft gehört, aber ich möchte für dieses Projekt jetzt nicht noch dafür Zeit investieren und lieber bei Ant bleiben.

Eine dependencies.zip oder dependencies.jar wäre eine Lösung. Wie genau kriege ich das hin?

Nochmal: Ich hatte nur (nachdem ich schon viel über Maven geflucht hatte) mal für eine Sache kurz Ant ausprobiert, … bin dann aber (trotz des vorherigen Fluchens) wieder bei Maven gelandet, deswegen sind diese Aussagen nicht als “Ant Best Practices” zu sehen, sondern eher als allgemeine Hinweise.

  1. Du hast ein Hauptprojekt (“Main”). Dieses Projekt benötigt mehrere JARs, und verweist (in der IDE) auf ein anderes Projekt (“Used”). Bisher klingt es, als sollte das “Used”-Projekt (aus Sicht des Build-Prozesses des Main-Projektes) nur eine ganz normale Dependency sein (wie die JARs auch). Der bisherigen Beschreibung nach sollte/könnte also erst das “Used”-Projekt gebaut werden (unabhängig vom Main-Projekt), damit danach das Main-Projekt gebaut werden kann. Konkret könnte das z.B. gelöst werden, indem in der build.xml des Main-Projektes mit
    <ant dir="../Used"/> (siehe https://ant.apache.org/manual/Tasks/ant.html )
    erstmal ein Build-Prozess für das Used-Projekt angestoßen wird. Da kommt dann irgendwo eine JAR raus, die (wie alle anderen JARs) vom Main-Projekt verwendet werden kann.

  2. Da bin ich wohl kurz durcheinander gekommen: Du hattest erst gemeint, dass du bestimmte Ordner NICHT im JAR haben willst? Etwas geraten gehe ich jetzt davon aus, dass sich das wirklich nur auf die Struktur bezog. Also dass für die Verzeichnisse


Root
    lib
        first.jar
        second.jar
    src
        first-src.jar
        second-src.jar

die Struktur IM Archiv dann einfach


Root
    first.jar
    second.jar

sein sollte.

Wie auch immer: Der Doku auf ZipFileSet Type nach sollten Wildcards möglich sein. Sowas wie
<zipfileset excludes="META-INF/**" src="lib/*.jar" />
wäre also mal einen Versuch wert.
(Hoffentlich grätscht hier jemand dazwischen, der sich mit Ant auskennt, falls ich kompletten Mist erzähle…!?)

  1. Ja, die allgegenwärtige Frage: “Investiere ich noch 2 (oder, im schlimmsten Fall 8) Tage, um es mit dem aktuellen Ansatz zum Laufen zu bringen, oder investiere ich 8 (oder, im besten Fall 2) Tage, um es mit einem ganz anderen (und potentiell besseren, Nachhaltigeren) Ansatz zum Laufen zu bringen?”. Konkret könnte ich da im Moment leider auch nur an java - Including external jar-files in a new jar-file build with Ant - Stack Overflow verweisen (da eine JAR Datei auch nur eine ZIP ist (mit einer anderen Dateiendung) sollte sich das aber eigentlich “relativ leicht” mit den Ant-Bordmitteln abdecken lassen…)

Die ersten zwei Punkte sollte ich wohl hinbekommen.

Der letzte Punkt mit den zwei jar files scheint wohl etwas schwieriger zu sein. Geht das denn mit Maven leicht? Also eine Jar für die libraries (dependencies) und eine Jar für den Rest (so dass ich dann jeweils nur die kleinere Jar deployen muss). By the way, in dem von dir erwähnten Link, wird eine einzige Jar erstellt (ich möchte aber ja die dependencies und mein eigentlisches Programm trennen).

Das Problem ist v.a. die xuggle-xuggler-5.4.jar. Diese ist 40MB gross. Ohne diese library wäre es kein Problem alles in einem jar zu haben. Diese Library brauche ich nur an einen ganz bestimmten Ort in meiner Applikation und in der Jar wird sie auch nicht gebraucht (brauche sie nur lokal). D.h. im Code brauche ich zwar diese Library, allerdings wird dieser Code-Teil im Jar-Fall nie ausgeführt. Allerdings kann ich die library auch nicht entfernen, da ich sonst einen compilation Error bekomme.

Gibt es da eine Möglichkeit die library zu excluden, so dass die Applikation trotzdem läuft?

Auch wenn es lästig wird, betone ich nochmal, dass ich kein Ant-Experte bin.

Aber ich hätte jetzt vermutet, dass man, wenn man neben der Haupt-JAR noch eine weitere (mit den dependencies) haben will, man einfach ein weiteres … in seine Buildfile schreiben kann. Falls das GAR nicht klappt, probier’ ich es mal aus - wäre so ersmtal schwer zu glauben.

Viele Konzepte von Maven und Ant sind ähnlich, aber bei Maven ist das ganze noch mehr auf Modularität (mit Plugins) und einen Standardisierten Prozess ausgerichtet. Dort würde man dann, wenn man eine spezielle dependencies.zip erstellen will, eine Ausführung des assembly-Plugins in den Buildprozess einfügen. (Klingt cool, ne? Auf deutsch: Man googlet nach den passenden Stichworten, findet Create a zip with all dependencies with Maven - Stack Overflow , kopiert das zu sich rüber und pfriemelt rum, bis es geht :smiley: - wie schon angedeutet, ich bin kein Maven-Fan. Einen Prozess (den Build) in einer Datei zu beschreiben, die keine “Reihenfolge” kennt (nämlich XML) ist IMHO prinzipbedingt mit Krämpfen verbunden. Aber Maven hat genug Vorteile, um viele dieser Krämpfe zu rechtfertigen. (Und bei Ant ist’s schließlich nicht anders)).


Dies beschriebene Abhängigkeit zu einer 40MB JAR ist natürlich ein Brocken. Irgendwelche einfachen Workarounds könnte es da geben (auch wenn mir spontan keiner einfällt).
Auf höherer, abstrakter Ebene wäre es vielleicht “besser”, das anders anzugehen:

(Vielleicht liest diesen Thread ja DOCH nochmal jemand (außer mir)…)

Dass du kein Ant-Experte bist, habe ich kapiert. :smiley: Du kennst dich als nicht Ant-Experte aber trotzdem ziemlich gut aus. :wink:

ich habe das mit den 2 Jars wie folgt probiert:

		<jar destfile="${dist.dir}/myApp.jar">
			<manifest>
				<attribute name="Main-Class" value="com.something.main.Main" />
				<attribute name="Class-Path" value="." />
			</manifest>

			<fileset dir="${build.dir}" />
			<zipfileset dir="config" />
		</jar>
		<jar destfile="${dist.dir}/libraries.jar">
			<zipgroupfileset dir="lib" excludes="META-INF/**" includes="*.jar"/>
			<zipgroupfileset dir="../../dependentProject/dist" excludes="META-INF/**" includes="*.jar"/>
		</jar>

Das funktioniert leider nicht. Wenn ich myApp.jar starte werden die libraries nicht gefunden. Muss ich vielleicht noch etwas Zusätzliches ins manifest file der myApp.jar schreiben?

Edit: Hab da vielleicht grad die Lösung gefunden: Ant – How To Create A Jar File with external libraries

Jar in Jar geht nicht so einfach, dazu brauchst du einen speziellen ClassLoader, mit dem normalen von Java klappt das nicht.

Zu deinem Link, bevor du Ant + Ivy einsetzt kannst du auch gleich nach Maven wechseln IMHO.
2 Projekte mit Abhaengigkeiten von einem zum anderen ist immer bloed mit Ant…

Wie setzt du den classpath?
Im Manifest oder per classpath parameter in der commandozeile?
Seit Java 6 oder 7 werden Wildcards im classpath parameter unterstuetzt, ein MANIFEST laesst man sich am besten generieren.

Muss dazu sagen dass ich kein Ant Profi bin :smiley:
Bin schon seit langem von Ant weg wie 99,9% aller Java Entwickler, deswegen gibt es hier so wenige Antworten IMHO.

[QUOTE=BlackHawk]Das funktioniert leider nicht. Wenn ich myApp.jar starte werden die libraries nicht gefunden. Muss ich vielleicht noch etwas Zusätzliches ins manifest file der myApp.jar schreiben?
[/quote]
Häh…moment, erstmal: Die beiden Dateien werden richtig erstellt!?

Und die Frage, wie man das ganze dann “lauffähig” macht, ist ja nochmal eine andere. Ich bin davon ausgegangen, dass du die dependencies einfach nur als “paket” ausliefern willst, die dann derjenige, der das verwendet, selbst entpacken und zu seinem classpath hinzufügen soll. Von einer JAR auf andere JARs zu verweisen, die in einer ZIP liegen, ist schon frickeliger. Die Lösung scheint in dem verlinkten Beitrag ja beschrieben zu sein (den ich jetzt nicht gelesen haben, nur gesehen, dass es da erwähnt wird: ) händewedel da muss irgendwas in die Manifest.mf geschrieben werden. (Dass die JARs in einer ZIP liegen, könnte eine Hürde sein, aber da man diese ZIP auch JAR nennen könnte, sollte das noch mehr händewedel schon irgendwie gehen :smiley: (sorry…)

Ich habe mir Maven gestern angeschaut, war aber nicht begeistert. Finde Ant besser.

Ich werde jetzt alles in eine Jar packen, so funktioniert es jetzt wenigstens problemlos. Trotzdem vielen Dank für die Hilfe hier.