How to include an external jar lib in my Ant build - java

I have the following build.xml:
<project>
<target name="clean">
<delete dir="./build"/>
</target>
<target name="compile">
<mkdir dir="./build/classes"/>
<javac srcdir="./src" destdir="./build/classes"/>
</target>
<target name="jar">
<mkdir dir="./build/jar"/>
<jar destfile="./build/jar/DependencyFinder.jar" basedir="./build/classes">
<manifest>
<attribute name="DependencyFinder" value="main"/>
</manifest>
</jar>
</target>
<target name="run">
<java jar="./build/jar/DependencyFinder.jar" classname="${main-class}" fork="true"/>
</target>
</project>
Here is my directory structure:
/build
/lib
/MagicFolder
/Src
/build.xml
Folder src contains .java files.
Path to MagicFolder should be an input parameter.
lib has external .jar library which should be included in my build.
build folder which will have compiled .jar and.class` files
QUESTION:
How should I change my build.xml? My build.xml should:
Add external lib ./lib/jbl.jar
When I run my application put 2 input parametrs for my application

If you need to add a jar to classpath to compile the code (sorry, it isn't quite clear what you're asking for), then you need to change <javac> task to look like this:
<javac srcdir="./src" destdir="./build/classes">
<classpath>
<pathelement path="lib/jbl.jar"/>
</classpath>
</javac>
Or if you need to add contents of jbl.jar to the jar you are creating, then you need to change your <jar> task to look like this:
<jar destfile="./build/jar/DependencyFinder.jar" basedir="./build/classes>
<zipgroupfileset dir="lib" includes="jbl.jar" />
<manifest>
<attribute name="DependencyFinder" value="main"/>
<attribute name="Main-Class" value="org.ivanovpavel.YourMainClass"/>
</manifest>
</jar>
To add arguments to <java> call, use nested <arg> elements:
<target name="run">
<java jar="./build/jar/DependencyFinder.jar:lib/jbl.jar" classname="dependencyfinder.DependencyFinder">
<arg value="Alexander Rosenbaum"/>
<arg value="Dmitry Malikov"/>
</java>
</target>

There are two ways to run a java program. Using the "jar" option is the most convenient and is called an executable jar, however in order to make it work you need to specify both the Main class and classpath in the manifest file as follows:
<jar destfile="${jar.file}" basedir="${classes.dir}">
<manifest>
<attribute name="Main-Class" value="${jar.main.class}" />
<attribute name="Class-Path" value="${jar.classpath}" />
</manifest>
</jar>
For a more detailed answer on how to do this see:
Execute Java programs in a consistent environment

try with this:
<target name="jar" depends="clean,compile" >
<jar destfile="./build/jar/DependencyFinder.jar">
<fileset dir="./lib" includes="jbl.jar,mysql*.jar" />
<fileset dir="./build/classes" excludes="**/form/*.class,**/orm/*.class,**/org/w3/xmldsig/*.class"/>
</jar>
</target>

Related

Setting up class path in ANT build

Situation:
I am new to making ant builds and I have managed to write one that builds the JAR and moves necessary files (Such as images and libraries) into an output folder.
Problem:
When I try to run the new JAR it complains that it cant find the main method (I have it specified in the manifest tag in the ANT script). I have done some research and I think its because I need to define a class-path for the compiled class' to go to but I haven't been able to get it working.
build.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project name="formula_manager" default="rebuild">
<property name="out" value="${basedir}/out/FormulaManager"/>
<target name="clean">
<delete dir="${out}"/>
<mkdir dir="${out}"/>
</target>
<target name="build" description="Build all artifacts">
<property name="tmp" value="${out}/temp"/>
<mkdir dir="${tmp}"/>
<property name="tmpJar" value="${tmp}/Formula Manager.jar"/>
<property name="tmpFolder" value="${tmp}/FormulaManager"/>
<jar destfile="${tmpJar}" duplicate="preserve" filesetmanifest="mergewithoutmain">
<zipfileset dir="${out}"/>
<zipfileset src="${basedir}/resources/pdfbox-app-1.8.10.jar"/>
<zipfileset src="${basedir}/resources/ftp4j-1.7.2.jar"/>
<manifest>
<attribute name="Main-Class" value="com.zakscode.FormulaManager.Main"/>
</manifest>
</jar>
<copy file="${tmpJar}" tofile="${tmp}/Formula Manager.jar"/>
<mkdir dir="${out}"/>
<copy todir="${out}">
<fileset dir="${tmp}"/>
</copy>
<copy file="icon.png" todir="${out}" />
<copy file="splash.png" todir="${out}" />
<copy file="logo.png" todir="${out}" />
<copy file="configuration.properties" todir="${out}" />
<mkdir dir="${out}/resources" />
<copydir src="resources" dest="${out}/resources" />
<!-- Delete temporary files -->
<delete dir="${tmp}"/>
</target>
<target name="rebuild" depends="clean, build"/>
</project>
Output:
$ java -jar "Formula Manager.jar"
Error: Could not find or load main class com.zakscode.FormulaManager.Main
Edit:
I opened up the JAR in 7zip and none of the class files are there which is why the main method cant be loaded. So how do I fix this in my build.xml?
Setting
Main-Class = "com.zakscode.FormulaManager.Main"
assumes that you have the following message defined:
public static void main(String[] args)
in a class named com.zakscode.FormulaManager.Main (method has to be "main", not "Main"). When defining Main-Class, you don't include the main method name, you specify the class that contains main, so if your main method is in FormulaManager, then you set Main-Class as follows:
Main-Class = "com.zakscode.FormulaManager"

Ant does not include generated class files to packaged jar, until I do a Project->Clean in Eclipse

I ran into some strange behaviour that seems to be connected to Eclipse and it's way to refresh the workspace.
I'm using an Ant build file to create my class-files and to create a package from that class-file. This functionality is working fine.
This is the target doing the work:
<target name="package" depends="compile,javaDoc">
<jar destfile="${dist.dir}/MyApplication.jar" basedir="${build.dir}" includes="**/*.class">
<zipgroupfileset dir="${lib.dir}" includes="*.jar" />
<manifest>
<attribute name="Main-Class" value="MyApplication" />
</manifest>
</jar>
</target>
Now I want to add functionality to first clean the directories where the class-files and the jar file are beeing generated.
This is the target code:
<target name="clean" description="Removes all *.class and *.jar files. Also deletes the java doc files.">
<delete dir="${build.dir}" />
<delete dir="${dist.dir}" /></target>
This target also works fine.
Now I would like the package target dependent on the clean target, so that the folders are first cleaned before the packaging is beeing done.
This would look like this:
<target name="package" depends="clean,compile,javaDoc">
<jar destfile="${dist.dir}/MyApplication.jar" basedir="${build.dir}" includes="**/*.class">
<zipgroupfileset dir="${lib.dir}" includes="*.jar" />
<manifest>
<attribute name="Main-Class" value="MyApplication" />
</manifest>
</jar>
</target>
The problem is, that this target does not include the generated class files into the jar. Even on the file system the generated class files are not displayed. Only after I go to Project->Clean in Eclipse and clean the project the class files become visible on the filesystem.
Any help is appreciated.
My compile target looks like this:
<target name="compile" depends="init" description="Compiles the source file to the created directory.">
<javac classpathref="classpath" srcdir="${dist.dir}" destdir="${build.dir}" includeantruntime="false" />
</target>
fixing the error in the compile target worked.
That is the working version:
<target name="compile" depends="init" description="Compiles the source file to the created directory.">
<javac classpathref="classpath" srcdir="${src.dir}" destdir="${build.dir}" includeantruntime="false" /></target>

Ant build creates incorrect relative paths to jars when generating manifest

I'm using Ant to build my Java application and to generate the MANIFEST.MF file automatically so it includes all the jars in my lib directory.
This seems to work but the problem is that instead of writing them as lib/some.jar, it includes my Eclipse project's name: MyProject/lib/some.jar.
This is ofcourse incorrect and causes none of the jars to be found when run as a standalone app.
Build.xml (important part is at the end):
<?xml version="1.0"?>
<project name="fidea_migration" default="dist">
<path id="compile.classpath">
<fileset dir="lib">
<include name="*.jar"/>
</fileset>
</path>
<target name="clean" description="cleaning the old deliverables">
<delete includeemptydirs="true">
<fileset dir="bin" includes="**/*"/>
</delete>
<delete includeemptydirs="true">
<fileset dir="_deliverables" includes="**/*"/>
</delete>
</target>
<target name="prepare" description="preparing the deliverables folders">
<mkdir dir="_deliverables/lib"/>
</target>
<path id="jarlib">
<fileset dir="lib/">
<include name="**/*.jar"/>
</fileset>
</path>
<manifestclasspath property="lib.list" jarfile=".">
<classpath refid="jarlib" />
</manifestclasspath>
<target name="compile" depends="clean, prepare" description="compiling java sources">
<mkdir dir="bin"/>
<javac srcdir="src/main/java" destdir="bin">
<classpath refid="compile.classpath"/>
</javac>
</target>
<target name="dist" depends="compile" description="creating binary distribution">
<copy todir="_deliverables/lib">
<fileset dir="lib"/>
</copy>
<copy todir="_deliverables">
<fileset dir="src/main/resources">
</fileset>
</copy>
<jar jarfile="_deliverables/lib/app.jar" basedir="bin">
<manifest>
<attribute name="Class-Path" value="${lib.list}"/>
</manifest>
</jar>
</target>
</project>
Example of how my Manifest looks:
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.8.4
Class-Path: MyProject/lib/All-MB.jar MyProject/lib/activation.jar MyProject/lib/aspectjrt.jar
Any idea on how to fix this so it just shows xxx.jar instead of MyProject/lib/xxx.jar (so without "MyProject/lib/")?
Cheers,
Bart
manifestclasspath expects the jarfile attribute to point to the location of the JAR file (which probably doesn't exist yet, but that's fine). Since you're creating the JAR file at _deliverables/lib/app.jar and you're also copying all the lib JARs from lib to _deliverables/lib then
<manifestclasspath property="lib.list" jarfile="lib/app.jar">
<classpath refid="jarlib" />
</manifestclasspath>
should do the trick, and will create an eventual Class-Path with the right relative paths, i.e. All-MB.jar activation.jar aspectjrt.jar etc. etc.
You must set your project Dir inside your build.xml as,
<property name="projectDir" value=".." />
After this, you must try to work on everything with relative path. Currently, the reason behind problem is that the absolute path is being used.

Ant Script Example

I would like to make a very simple ant script that does 1 thing, which is to bulid a jar file. But when I try to use a very simple example, it fails due to dependancies on jars that my source depends on. So, How you you specify jars that there are jars that need to be in the class path when building an Ant target.
<project name="project" default="default">
<property name="src.dir" value="src"/>
<property name="build.dir" value="build"/>
<property name="classes.dir" value="${build.dir}/classes"/>
<property name="jar.dir" value="${build.dir}/jar"/>
<property name="lib.dir" value="//tomcat/common/lib"/>
<description> description </description>
<!-- =================================
target: default
================================= -->
<target name="default" depends="compile" description="description">
<jar destfile="/path/to/dir/Library.jar">
</jar>
</target>
<target name="compile">
<mkdir dir="${classes.dir}"/>
<javac srcdir="${src.dir}" destdir="${classes.dir}"/>
</target>
</project>
Your question isn't entirely clear - I suspect you mean you want to compile your source (with the javac task) and then build a jar file from the results. If that's not the case, I don't see where your source dependencies come into it. If that is the case, then the jar task is irrelevant.
In the javac task, use the classpath attribute to specify other jar dependencies.
Here's an ANT script generated by using the Eclipse Runnable JAR Export Wizard. This is a project that updates stats on a Google Spreadsheet for a small fantasy baseball league with some friends. It gets the stats by scraping ESPN.com player pages.
Class-Path attribute inside the manifest element is used to set the classpath used by the jar. This defaulted "." but I had to add my src path explicitly so that log4j would pick up log4j.properties.
zipfileset elements are external jars used by my source that I wanted to be included with my jar. I suspect this might be what you're looking for.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project default="create_run_jar" name="Create Runnable Jar for Project cob_fantasy_baseball">
<!--this file was created by Eclipse Runnable JAR Export Wizard-->
<!--ANT 1.7 is required -->
<target name="create_run_jar">
<jar destfile="C:/workspace/cob_fantasy_baseball/cob_fantasy_baseball.jar" filesetmanifest="mergewithoutmain">
<manifest>
<attribute name="Built-By" value="${user.name}"/>
<attribute name="Main-Class" value="com.me.cob_fantasy_baseball.UpdateCobStats"/>
<attribute name="Class-Path" value=".;src/com/me/cob_fantasy_baseball"/>
</manifest>
<fileset dir="C:/workspace/cob_fantasy_baseball/classes"/>
<zipfileset excludes="META-INF/*.SF" src="C:/workspace/gdata/java/lib/gdata-core-1.0.jar"/>
<zipfileset excludes="META-INF/*.SF" src="C:/workspace/gdata/java/lib/gdata-spreadsheet-2.0.jar"/>
<zipfileset excludes="META-INF/*.SF" src="C:/workspace/jericho-html-2.6/lib/jericho-html-2.6.jar"/>
<zipfileset excludes="META-INF/*.SF" src="C:/workspace/apache-log4j-1.2.15/log4j-1.2.15.jar"/>
<zipfileset excludes="META-INF/*.SF" src="C:/workspace/jaf-1.1.1/activation.jar"/>
<zipfileset excludes="META-INF/*.SF" src="C:/workspace/javamail-1.4.2/mail.jar"/>
<zipfileset excludes="META-INF/*.SF" src="C:/workspace/javamail-1.4.2/lib/smtp.jar"/>
<fileset dir="C:/workspace/cob_fantasy_baseball/src/com/me/cob_fantasy_baseball"/>
</jar>
</target>
</project>
Also, here's a link to the Ant documentation for the jar task: http://ant.apache.org/manual/Tasks/jar.html
Based on your example you can just put libs inside javac:
<javac srcdir="${src.dir}" destdir="${classes.dir}">
<classpath>
<pathelement location="${lib.dir}/lib1.jar"/>
<pathelement location="${lib.dir}/lib2.jar"/>
</classpath>
</javac>
Here is the ant file we use to build the Timeline opensource project. It is pretty straight forward. It doesn't build a jar, but it does use libraries to minimize JS files.
http://simile-widgets.googlecode.com/svn/timeline/trunk/build.xml
Larry

Apache ant manifest class-path?

I have a standard project layout for a java project:
project /
src /
source_file_1.java
...
source_file_N.java
build /
classes /
source_file_X.class
...
jar /
MyJar.jar
lib /
SomeLibrary.jar
SomeOtherLibrary.jar
As far as I can tell, I am building the project correctly with Ant. I need to set the class-path attribute in the Manifest file so my classes can use the required libraries.
The following relevant information from build.xml
<target name="compile" depends="init">
<javac srcdir="src" destdir="build\classes">
<classpath id="classpath">
<fileset dir="lib">
<include name="**/*.jar" />
</fileset>
</classpath>
</javac>
</target>
<target name="jar" depends="compile">
<jar destfile="build\jar\MyJar.jar" basedir="build\classes" >
<manifest>
<attribute name="Built-By" value="${user.name}" />
</manifest>
</jar>
</target>
Any push in the right direction is appreciated. Thanks
Assuming the libraries do not change location from compiling to executing the jar file, you could create a path element to your classpath outside of the compile target like so:
<path id="compile.classpath">
<fileset dir="lib" includes="**/*.jar"/>
</path>
Then you can use the created path inside your javac task in place of your current classpath.
<classpath refid="compile.classpath"/>
You can then use the path to set a manifestclasspath.
<target name="jar" depends="compile">
<manifestclasspath property="jar.classpath" jarfile="build\jar\MyJar.jar">
<classpath refid="compile.classpath"/>
</manifestclasspath>
<jar destfile="build\jar\MyJar.jar" basedir="build\classes" >
<manifest>
<attribute name="Built-By" value="${user.name}" />
<attribute name="Class-Path" value="${jar.classpath}"/>
</manifest>
</jar>
</target>
The manifestclasspath generates a properly formatted classpath for use in manifest file which must be wrapped after 72 characters. Long classpaths that contain many jar files or long paths may not work correctly without using the manifestclasspath task.
Looking at my NetBeans-generated build file, I found this snippet in the -do-jar-with-libraries task:
<manifest>
<attribute name="Main-Class" value="${main.class}"/>
<attribute name="Class-Path" value="${jar.classpath}"/>
</manifest>
So in other words, it looks like you just need to add another attribute to the manifest task that you already have.
See also the Manifest Task documentation.

Categories

Resources