I use ant for creating .jar files in Eclipse.
I need to generate jar for my project which also contains source code along with the class file. How do we do it?
Another question: what is a debug jar and how to create it using ant? (have heard about it somewhere and trying to relate them both)
I would modify your jar task to include multiple filesets; one for the classes and one for the source files.
<jar destfile="${target.dir}/my-app.jar">
<fileset dir="${target.dir}/classes" />
<fileset dir="${src.dir}" includes="**/*.java"/>
</jar>
Packaging should be treated as a separate concern from compiling. This will give you more flexibility. For example, you may want to add other filesets to the jar (e.g. properties files), or you may want to package your sources in a jar file that is separate from your class files.
Simply copy the source files into the directory you're using for your jar creation. I've done it like this (notice the copy inside compile):
<?xml version="1.0" encoding="utf-8" ?>
<project name="project" default="jar" basedir=".">
<target name="compile" description="Compile source">
<mkdir dir="bin" />
<javac srcdir="src" includes="**" destdir="bin" (other compilation stuff here) />
<copy todir="bin">
<fileset dir="src" />
</copy>
</target>
<target name="jar" description="Package into JAR" depends="compile">
<jar destfile="project.jar" basedir="bin" compress="true" />
</target>
</project>
Related
I have been trying to use Ant to compile and ready a project for distribution. I have encountered several problems along the way that I have been finally able to solve but the solution leaves me very unsatisfied. First, let me explain the set-up of the project and its dependencies.
I have a project, lets call it Primary which depends on a couple of libraries such as the fantastic Guava. It also depends on another project of mine, lets call it Secondary. The Secondary project also features some dependencies, for example, JDOM2. I have referenced the Jar I build with Ant in Primary.
Let me give you the interesting bits of the build.xml so you can get a picture of what I am doing:
<project name="Primary" default="all" basedir=".">
<property name='build' location='dist' />
<property name='application.version' value='1.0'/>
<property name='application.name' value='Primary'/>
<property name='distribution' value='${application.name}-${application.version}'/>
<path id='compile.classpath'>
<fileset dir='libs'>
<include name='*.jar'/>
</fileset>
</path>
<target name='compile' description='Compile source files.'>
<javac includeantruntime="false" srcdir="src" destdir="bin">
<classpath refid='compile.classpath'/>
</javac>
<target>
<target name='jar' description='Create a jar file for distribution.' depends="compile">
<jar destfile='${build}/${distribution}.jar'>
<fileset dir="bin"/>
<zipgroupfileset dir="libs" includes="*.jar"/>
</jar>
</target>
The Secodnary project's build.xml is nearly identical except that it features a manifest as it needs to run:
<target name='jar' description='Create a jar file for distribution.' depends="compile">
<jar destfile='${dist}/${distribution}.jar' basedir="${build}" >
<fileset dir="${build}"/>
<zipgroupfileset dir="libs" includes="*.jar"/>
<manifest>
<attribute name="Main-Class" value="lu.tudor.ssi.kiss.climate.ClimateChange"/>
</manifest>
</jar>
</target>
After I got it working, trying for many hours to not include that dependencies as class files but as Jars, I don't have the time or insight to go back and try to figure out what I did wrong. Furthermore, I believe that including these libraries as class files is bad practice as it could give rise to licensing issues while not packaging them and merely including them in a directory along the build Jar would most probably not (And if it would you could choose not to distribute them yourself).
I think my inability to correctly assemble the class path, I always received NoClassDefFoundError for classes or libraries in the Primary project when launching Second's Jar, is that I am not very experienced with Ant. Would I require to specify a class path for both projects? Specifying the class path as . should have allowed me to simply add all dependencies to the same folder as Secondary's Jar, should it not?
You may use the MANIFEST.MF "Class-Path: " to cross-reference your jars.
If they are all in the same directory this will probably work as follows (using it in both projects!):
<target name='jar' description='Create a jar file for distribution.' depends="compile">
<pathconvert property="manifest.classpath" pathsep=" ">
<path refid="compile.classpath" />
<flattenmapper />
</pathconvert>
<jar destfile='${build}/${distribution}.jar'>
<fileset dir="bin"/>
<manifest>
<attribute name="Class-Path" value="${manifest.classpath}"/>
</manifest>
</jar>
</target>
This way you can tell the java runtime environment that your jar needs others to work, expecting them to be in the same directory as the jar you are trying to run.
As a result your primary.jar should have secondary.jar in it's classpath and secondary.jar should have guava.jar in it's classpath.
Another way to create the string may be ants manifestclasspath task (https://ant.apache.org/manual/Tasks/manifestclasspath.html) that can handle subdirectories.
If you are goin to use more and more libraries, you may want to have a closer look at ivy or even maven.
i want to create jar file with external jars and log4j.properties file using ant.i am having only source code alone.
Please let me know how to do this.
Thanks in advance.
This is a simple sketch to start with. You have to specify more details for us to give you a better answer, for example the project layout, the place where external jars and the log4j.properties file are.
<project name="demo" default="build">
<path id='external.classpath'>
<pathelement location='commons-io-1.3.2/commons-io-1.3.2.jar' />
</path>
<target name="build">
<javac debug='true' debuglevel='source,lines,vars' destdir='project\temp' source='1.5' target='1.5' includeAntRuntime='false' encoding='utf-8'>
<src path='src' />
<classpath refid='external.classpath' />
</javac>
<jar jarfile='build\foobar.jar' basedir='project\temp' />
<copy file='commons-io-1.3.2/commons-io-1.3.2.jar' todir='build'/>
<copy file='log4j.properties' todir='build'/>
</target>
</project>
I am building a project using Ant and Ivy. The build.xml file depends on ant-contrib, bean scripting framework, beanshell, and commons-logging.
Ant searches for libraries in several places, including ${user.home}/.ant/lib.
Is there any way in the build.xml file to have these libraries automatically download and install in the ${user.home}/.ant/lib directory if they are not already present, perhaps using Ivy itself?
Thanks, Ralph
The only jar you need in your ant lib is ivy :-)
Declare your dependencies as normal within your ivy.xml file. Make use of a configuration to collectively group the jars associated with ANT tasks:
<configurations>
<conf name="tasks" description="Ant tasks"/>
</configurations>
<dependencies>
<dependency org="ant-contrib" name="cpptasks" rev="1.0b5" conf="tasks->default"/>
<dependency org="junit" name="junit" rev="3.8" conf="tasks->default"/>
..
In your build.xml file you can create a path from this configuration
<ivy:resolve/>
<ivy:cachepath pathid="tasks.path" conf="tasks"/>
<taskdef name="task1" classname="??" classpathref="tasks.path"/>
<taskdef name="task2" classname="??" classpathref="tasks.path"/>
I happened on this question as I was reading the Ivy cachefileset documentation, which states:
Please prefer the use of retrieve +
standard ant path creation, which make
your build more independent from ivy
(once artifacts are properly
retrieved, ivy is not required any
more).
The Ivy cachepath documentation similarly states:
If you want to make your build more
independent from Ivy, you could
consider using the retrieve task. Once
the artifacts are properly retrieved,
you can use standard Ant path creation
which makes Ivy not necessary any
more.
So, it would seem a better answer would be to modify Mark's response to something that uses retrieve in conjunction with ant paths. Something along the lines of the following:
Mark's Response (modified)
<configurations>
<conf name="tasks" description="Ant tasks"/>
</configurations>
<dependencies>
<dependency org="ant-contrib" name="cpptasks" rev="1.0b5"
conf="tasks->default"/>
<dependency org="junit" name="junit" rev="3.8" conf="tasks->default"/>
..
In your build.xml file you can create a path from this config
<ivy:retrieve conf="tasks"
pattern="${dir.where.you.want.taskdef.jars}/[artifact]-[revision].[ext] />
<path id="tasks.path">
<fileset dir="${dir.where.you.want.taskdef.jars}">
<include name="**/*.jar"/>
</fileset>
</path>
<taskdef name="task1" classname="??" classpathref="tasks.path"/>
<taskdef name="task2" classname="??" classpathref="tasks.path"/>
This would even allow you to move the retrieve task into a separate ant file that deals with dependencies. Thereby, you don't have to rely on ivy after your dependencies are retrieved into their directories.
The intention of ivy is that you use it to pull down your jars (resolve & retrieve). Once you have them in place, you can switch back to using standard Ant.
Note: I would just pull these dependencies into the lib directory. That would simplify the retrieve task:
<ivy:retrieve conf="tasks" />
Also Note: visit the 'Path-like Structures' section of this page for more on "standard ant path creation"
I'd use ant to install everything INTO ant =D
Just use depends="init-ant-contrib, init-ivy"
<!-- ANT-CONTRIB Auto Installer -->
<available property="ant-contrib-exists"
file="${ant.library.dir}/ant-contrib-1.0b3.jar" />
<target name="download-ant-contrib" unless="ant-contrib-exists">
<mkdir dir="${ant.library.dir}" />
<get src="http://downloads.sourceforge.net/project/ant-contrib/ant-contrib/1.0b3/ant-contrib-1.0b3-bin.zip?r=http%3A%2F%2Fsourceforge.net%2Fprojects%2Fant-contrib%2Ffiles%2Fant-contrib%2F1.0b3%2F&use_mirror=cdnetworks-us-1"
dest="${ant.library.dir}/ant-contrib-1.0b3-bin.zip"
username="true" />
<unzip src="${ant.library.dir}/ant-contrib-1.0b3-bin.zip"
dest="${ant.library.dir}"
overwrite="no" />
<move todir="${ant.library.dir}">
<fileset file="${ant.library.dir}/ant-contrib/*.jar" />
<fileset file="${ant.library.dir}/ant-contrib/lib/*.jar" />
</move>
<delete file="${ant.library.dir}/ant-contrib-1.0b3-bin.zip" />
<delete dir="${ant.library.dir}/ant-contrib" />
</target>
<target name="init-ant-contrib" depends="download-ant-contrib">
<taskdef resource="net/sf/antcontrib/antcontrib.properties">
<classpath>
<pathelement location="${ant.library.dir}/ant-contrib-1.0b3.jar" />
</classpath>
</taskdef>
</target>
<!-- IVY Auto Installer -->
<property name="ivy.install.version" value="2.1.0-rc2" />
<condition property="ivy.home" value="${env.IVY_HOME}">
<isset property="env.IVY_HOME" />
</condition>
<property name="ivy.home" value="${user.home}/.ant" />
<property name="ivy.jar.dir" value="${ivy.home}/lib" />
<property name="ivy.jar.file" value="${ivy.jar.dir}/ivy.jar" />
<available file="${ivy.jar.file}" property="ivy-exists" />
<target name="download-ivy" unless="ivy-exists">
<mkdir dir="${ivy.jar.dir}" />
<!-- download Ivy from web site so that it can be used even without any special installation -->
<get src="http://repo2.maven.org/maven2/org/apache/ivy/ivy/${ivy.install.version}/ivy-${ivy.install.version}.jar"
dest="${ivy.jar.file}"
usetimestamp="true" />
</target>
<target name="init-ivy" depends="download-ivy">
<!-- try to load ivy here from ivy home, in case the user has not already dropped
it into ant's lib dir (note that the latter copy will always take precedence).
We will not fail as long as local lib dir exists (it may be empty) and
ivy is in at least one of ant's lib dir or the local lib dir. -->
<path id="ivy.lib.path">
<fileset dir="${ivy.jar.dir}" includes="*.jar" />
</path>
<taskdef resource="org/apache/ivy/ant/antlib.xml"
uri="antlib:org.apache.ivy.ant"
classpathref="ivy.lib.path" />
</target>
Now that you have ant-contrib & ivy, everything else should be a simple ivy.xml & ivy-resolve away:
<target name="resolve" depends="init-ivy">
<ivy:retrieve />
</target>
I'm sure you can find similar methods of installing whatever ant task you might need.
I would like to unjar multiple JAR files and then rebuild into one JAR using an ant build script. Is this possible?
Yes, it's possible with ant. A jar file is basically a zip with a special manifest file. So to unjar, we need to unzip the jars. Ant includes an unzip task.
To unzip/unjar all the jar files in your project:
<target name="unjar_dependencies" depends="clean">
<unzip dest="${build.dir}">
<fileset dir="${lib.dir}">
<include name="**/*.jar" />
</fileset>
</unzip>
</target>
Obviously you need to declare ${build.dir} and ${lib.dir} first. The line <include name="**/*.jar" /> tells ant to include all files that end up with the jar extension, you can tweak that include to suit your needs.
To pack everything into a jar, you use the jar task:
<target name="make_jar" depends="compile, unjar_dependencies">
<jar basedir="${build.dir}"
destfile="${dist.dir}/${project_name}.jar">
<manifest>
<attribute name="Main-Class" value="${mainclass}" />
</manifest>
<fileset dir="${build.dir}">
<include name="**/*.class" />
</fileset>
<fileset dir="${src.dir}">
<include name="applicationContext.xml" />
<include name="log4j.properties" />
</fileset>
</jar>
</target>
In this example, we include different filesets. In one fileset we are including all compiled classes. In another fileset we include two config files that this particular project depends upon.
Yes it is !
You have two possibilities :
Espen answer :
One possible solution that creates one
jar file from all the jar files in a
given directory:
<target name="dependencies.jar">
<jar destfile="WebContent/dependencies.jar">
<zipgroupfileset dir="lib/default/" includes="*.jar"
excludes="*.properties" />
</jar>
</target>
This is useful if you don't need to exclude content that are in some jars (like for example some properties configuration file that might override yours, etc). Here the excludes properties is filtering out files from the dir property.
Use zipfileset
The other solution is to use the zipfileset tag where the excludes property this time will filter out content from the jar to be merged.
<jar destfile="your_final_jar.jar" filesetmanifest="mergewithoutmain">
<manifest>
<attribute name="Main-Class" value="main.class"/>
<attribute name="Class-Path" value="."/>
</manifest>
<zipfileset
excludes="META-INF/*.SF"
src="/path/to/first/jar/to/include.jar"/>
</jar>
Of course you can combine the two tags (zipfileset and zipgroupfileset) inside the same jar tag to get the best of the two.
Yes, it's possible.
One possible solution that creates one jar file from all the jar files in a given directory:
<target name="dependencies.jar">
<jar destfile="WebContent/dependencies.jar">
<zipgroupfileset dir="lib/default/" includes="*.jar"
excludes="*.properties" />
</jar>
</target>
There is also a project devoted to repackage jars called JarJar. You can use it to repackage mutiple Jars into one. Depending on your requirements, you can even rename classes to prevent version conflicts.
From their getting started page:
In this example we include classes from jaxen.jar and add a rule that changes any class name starting with "org.jaxen" to start with "org.example.jaxen" instead (in our imaginary world we control the example.org domain):
<target name="jar" depends="compile">
<taskdef name="jarjar" classname="com.tonicsystems.jarjar.JarJarTask"
classpath="lib/jarjar.jar"/>
<jarjar jarfile="dist/example.jar">
<fileset dir="build/main"/>
<zipfileset src="lib/jaxen.jar"/>
<rule pattern="org.jaxen.**" result="org.example.#1"/>
</jarjar>
</target>
My goal is have my ant build script build a war file and include the jars that ivy knows this project depends on. The best code I could come up with at the moment is the following
<mkdir dir="dist/lib"/>
<ivy:retrieve pattern="dist/lib/[artifact].[ext]" sync="true"/>
<war destfile="dist/${ivy.module}.war" basedir="build" includes="**/*.class"
webxml="${war.webxml}">
<fileset dir="${war.web}"/>
<lib dir="dist/lib"/>
</war>
The problem with this code is it copies the jars twice. Once in to my dist/lib directory and again in to the war when it's created. It works but I can't shake the feeling there is a better way.
What I would like to do is something more like the following
<ivy:cachepath pathid="locpathref.classpath"/>
<war destfile="dist/${ivy.module}.war" basedir="build" includes="**/*.class"
webxml="${war.webxml}">
<fileset dir="${war.web}"/>
<lib refid="locpathref.classpath"/>
</war>
The problem is that the lib tag does not take in a refid of any kind. Any ideas or am I stuck with an extra set of file copies?
The problem here is that the lib tag is a custom fileset that targets it's files into the war archive's lib sub directory. It might be possible to write a custom war task but I don't think it's worth the effort.
If want to improve the manner in which ivy manages your war's dependencies might I suggest using configurations?
Create a configuration describing the run-time dependencies:
<ivy-module version="2.0">
<info organisation="apache" module="hello-ivy"/>
<configurations>
<conf name="build" description="Libraries needed to for compilation"/>
<conf name="war" extends="build" description="Libraries that should be included in the war file" />
</configurations>
<dependencies>
<dependency org="commons-lang" name="commons-lang" rev="2.0" conf="build->*,!sources,!javadoc"/>
<dependency org="commons-cli" name="commons-cli" rev="1.0" conf="build->*,!sources,!javadoc"/>
</dependencies>
</ivy-module>
Afterwards you retrieve them into a dedicated directory (using a pattern) which can be simply included using the war task's lib tag:
<ivy:retrieve pattern="${lib.dir}/[conf]/[artifact].[ext]"/>
<war destfile="${war.file}" webxml="${resources.dir}/web.xml">
<fileset dir="${resources.dir}" excludes="web.xml"/>
<lib dir="${lib.dir}/war"/>
</war>
The advantage of this approach is that you use the ivy conf attribute of each project dependency to ultimately decide if the jar gets included within the war file or not. The build file no longer cares.
In conclusion I understand that the point of your post was concern for multiple copies of your jar files... Using my suggested approach will further multiple your copies, but I would submit that this is not an issue provided you have a clean target to remove them afterwards.
If you're using Ant 1.8, you can use the technique described here:
http://www.beilers.com/2010/06/ivy-dependency-management-lessons-learned-and-ant-1-8-mapped-resources/
EXAMPLE:
<war destfile="${war.full.path}" webxml="WebContent/WEB-INF/web.xml" manifest="${manifest.path}">
<fileset dir="WebContent">
</fileset>
<classes dir="${build.dir}"/>
<mappedresources>
<restrict>
<path refid="classpath.CORE"/>
<type type="file"/>
</restrict>
<chainedmapper>
<flattenmapper/>
<globmapper from="*" to="WEB-INF/lib/*"/>
</chainedmapper>
</mappedresources>
<zipfileset dir="src" prefix="WEB-INF/classes">
<include name="**/resources/**/*.properties" />
<include name="**/resources/**/*.xml" />
</zipfileset>
</war>