Eclipse Ant build.xml Could not find the main class. Program will exit.

Speed up ant build: - done reading - Top 15 Ant Best Practices - done reading - done reading - done reading
Tell Ant to use Eclipse compiler

Sample 1

How can we compile only modified files
How can we deploy only modified files
How can we optimize fileset
Ant fileset modified
Use fork. If you have several build targets you can use fork=yes to execute the target(s) externally:
How can we capture the time it takes to execute each target

How can we print a message?

<echo>I got here</echo>

How can we conditionally delete a directory?

    <condition property="optimize_srm_dev_deployment">
            <equals arg1="srm" arg2="${}"/>
            <available file="${basedir}\webapp\html" type="dir"/>
    <echo if:true="${optimize_srm_dev_deployment}">Temporarily optimizing developer build deployment for SRM.</echo>
    <delete dir="${basedir}\webapp\html" if:true="${optimize_srm_dev_deployment}"/>

How can we optimize ant?

  • Skip unnecessary targets
  • Use faster and smarter tasks in your build if available, and don't use dummy tasks in your builds. If a task doesn't do a dependency check, or doesn't do a correct and proper dependency check, replace that task with a smarter version, if available.. If not available, extend the existing tasks to do smart dependency checking if possible. This will enable you to perform fast incremental builds.
  • Use a faster compiler such as Jike
  • Divide your project into highly cohesive and loosely coupled modules. Always analyze your code to extract dependencies between packages and layers. Then you can indicate which dependencies are wrong and refactor your system's design. Break your system into smaller highly cohesive and loosely coupled components, and extract shared or common components as separate modules. Java classes must be packaged correctly and placed in their proper layer in the system architecture. Classes in different layers should have correct external dependencies on each other. For example, the user interface layer code should not have dependency on business layer code. By cutting wrong dependencies, it prevents needless recompilation of code in other layers when code is modified in just one layer. When components are separate from each other, a developer working on a component only runs that component's build and automated test process, which ensures that no extra rebuilds and test cases from other modules execute. Many free tools and packages perform this kind of analysis. For example, you can use the JDepend tool, which analyzes dependencies between packages and generates reports for you. These reports contain metrics like afferent couplings (packages that use a package) and efferent couplings (packages that a package depends upon). You can run this tool from both the command line and Ant. It provides both graphical and textual outputs. Running it from Ant is as easy as adding the following code snippet into your Ant file (first you will need to download the JDepend package). See
  • Execute tasks and targets in parallel when it make sense

How can we skip unnecessary target using touch?

<project name="sample-build" default="" basedir=".">
    <target name="init-skip-properties" description="" depends="init">

    <target name="create-database" description="" depends="init-skip-properties">
        <sql src=" MySQL.sql" ... />
        <touch file="create-database.timestamp"/>

    <target name="middlegen" description="" depends="create-database" unless="middlegen.skip">
            <cmp20> ... </cmp20>
        <touch file="middlegen.timestamp"/>

In the above example, the third target (middlegen) depends on the second target (create-database), which depends on the first target (init-skip-properties). When any target is executed, the first target (init-skip-properties) is always executed first. In this target, the uptodate Ant task sets a property (middlegen.skip) to true if a target file or a set of target files is more current than a source file or a set of source files. Notice that the first target (init-skip-properties) does not contain a touch task. Only the second target (create-database) and third target (middlegen) contains the touch task. These touch task changes the modification time of a file and possibly creates it at the same time. Notice that the second target (create-database) is always executed (because it does not contains a "if" or "unless" attribute), and therefore the timestamp of its "timestamp" file (create-database.timestamp) is always updated. However, the touch task and other task (middlegen) in the third target may or may not get executed because this target has a "unless" attribute. In this example, if the second target (create-database) is executed, the next time the third target (middlegen) is executed, it realize that it needs to runs its tasks because the second target had been executed (the timestamp on these files are now different). Otherwise, if the second target is never executed directly by the user without going through the third target, … We can also skip the second target (create-database) by adding:

<uptodate srcfile="MySQL.sql" targetfile="create-database.TimeStamp" property="create-database.skip" value="true"/>

to the first task, and change the second target (create-database) definition to:

<target name="create-database" description="" depends="init" unless="create-database.skip" >

Can we use <uptodate> inside <condition>?


<condition property="target3-skip">
        <uptodate srcfile="target1.timestamp" targetfile="target3.timestamp" />
        <uptodate srcfile="target2.timestamp" targetfile="target3.timestamp" />

In this example, we are comparing the timestamp from target1 against the timestamp for target3.

When should we consider skipping a target?

The technique of skipping unnecessary targets is more appropriate for those parts of a build where it does phases of automatic code generation one after another without manual intervention occurs among these phases, and targets works against their previous target's output.

How can we configure Ant to use a different compiler such as Jike?

Jikes is much faster than the standard javac compiler and does better dependency checking. However, Jikes is less portable than javac because Jikes is written in C++. To configure Ant to use Jikes as a compiler, set the build.compiler property in your file to Jikes. If you set the build.compiler.fulldepend property, then Jikes does a full dependency check.

Full dependency analysis of Jikes is more reliable because it also checks the classes used by the out-of-date class and up to any indirection level.

To illustrate the concept of full dependency analysis in Jikes, assume that we have three classes,,, and Class A has a dependency on B, and B has a dependency on C. The full dependency analysis of Jikes causes the recompilation of C when we modify C and then run Jikes on A. Without the fulldepend option, the compiler doesn't look beyond the immediately adjacent dependencies to find classes lower in the hierarchy where the source has changed. In our example, if we run Jikes without the fulldepend option, then jikes A won't trigger a recompilation of C.

How fast is Jikes?

Jikes is so fast that performing a complete recompilation (cleaning all class files and then compiling) is usually recommended. I should also mention that you can use Jikes to generate dependency information for use with make.

Can we use Jikes to generate dependency information for use with make?

Yes. Jikes is so fast that performing a complete recompilation (cleaning all class files and then compiling) is usually recommended. I should also mention that you can use Jikes to generate dependency information for use with make.

What is the purpose of the depend Ant task?

Ant uses only the names of the source and class files to find the classes that need a rebuild when using normal compilers. It will not scan the source and therefore will have no knowledge about nested classes, classes named differently from the source file, and so on. You can use Ant's depend task to solve this problem. The depend task does dependency checking based on criteria other than just existence/modification times. It works by determining which classes are out of date with respect to their sources and then removing the class files of any other classes that depend on the out-of-date classes. To determine the class dependencies, the depend task analyzes the class files and does not parse the source code in any way. It relies upon the class references encoded into the class files by the compiler. This approach is generally faster than parsing the Java source. Once depend discovers all of the class dependencies, it inverts this relationship to determine, for each class, the other classes dependent upon them. This affects list is used to discover which classes are invalidated by the out-of-date class. The class files of the invalidated classes are removed, triggering the compilation of the affected classes. The depend task supports the attribute closure, which controls whether depend will either consider only direct class-class relationships or transitive, indirect relationships. This task can be used as a completion for compilers that don't provide good or proper dependency analysis.

For Ant's javac task, make sure that both the output and the source files are in the same directory structure; that is, the source files are located in a directory structure identical to their packaging. Otherwise, the dependency check won't work because it searches for a class file's Java source in the same directory relative to the source directory where the class file is located relative to the output base directory. The compiler will do a complete recompile every time you execute the javac task.

You can acquire the functionality of the depend task from javac by setting the depend attribute with compilers that support it, but the depend option with normal javac compilers is known to be buggy.

Note that some compilers do more optimized and accurate dependency checking—for example, Eclipse's incremental compiler is able to recompile single methods.


How can we execute tasks in parallel?

You can run tasks in parallel in Ant using the parallel task. Tasks nested in a parallel task execute in their own thread, thereby reducing build time by leveraging available processing resources:

    <task1 ...> 
    <task2 ...> 

This task is typically used for testing. The application server runs in one thread and the test harness runs in another thread. Note: To run tasks in parallel, they should have no dependencies on each other.

What is the purpose of the apply task?

If you want to execute a system command on some sources only when they are updated, you can use the apply task. Somehow it acts like make's rule concept. If you specify a nested mapper and the dest attribute, the timestamp of each source file is compared to the timestamp of a target file defined by the nested mapper element and searched for in the given dest. Then, the command executes only for updated sources. When calling system commands from Ant, remember that using system commands in Ant reduces that build file's portability.

<apply executable="cc" dest="src/C" >
    <arg value="-c"/>
    <arg value="-o"/>
    <fileset dir="src/C" includes="*.c"/>
    <mapper type="glob" from="*.c" to="*.o"/>

Sample build.xml:

<?xml version="1.0"?>
<project name="HelloWorld" default="dist" basedir=".">
    <property name="src" value="."/>
    <property name="build" value="build"/>

    <target name="init">
        <mkdir dir="${build}"/>

    <target name="compile" depends="init">
        <javac srcdir="${src}" destdir="${build}"/>

    <target name="clean">

    <target name="dist" depends="clean,compile">
        <!-- Do something here, such as packaging and deploying -->

When starting a project, it is a good idea to follow the suggestion in the ant documentation of using 3 directories:

  • src: for the project source files
  • build: for compiled / output files produced by ant
  • lib: for class libraries and dependency files

First make the src directory:

mkdir src

Now put the source files into the appropriate directory (in this case: src/packageName/

package packageName;
public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello World");

Also creates the src/

    log4j.rootLogger=DEBUG, stdout

Now compile and run:

mkdir build/classes
javac -sourcepath src -d build/classes src/packageName/
java -cp build/classes packageName.HelloWorld

How can we create an executable JAR file?

Creating a jar file is not difficult. But creating a startable jar file needs more steps:

  1. creates a manifest file containing the start class
  2. creates the target directory
  3. archives the files
echo Main-Class: packageName.HelloWorld > manifest
mkdir build/jar
jar cfm build/jar/HelloWorld.jar manifest -C build/classes .
java -jar build/jar/HelloWorld.jar
<project name="HelloWorld" basedir="." default="main">
    <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="main-class"  value="oata.HelloWorld"/>
    <property name="lib.dir"     value="lib"/>
    <property name="report.dir"  value="${build.dir}/junitreport"/>
    <path id="classpath">
        <fileset dir="${lib.dir}" includes="**/*.jar"/>

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

    <target name="compile">
        <mkdir dir="${classes.dir}"/>
        <javac srcdir="${src.dir}" destdir="${classes.dir}" classpathref="classpath"/>
        <copy todir="${classes.dir}">
            <fileset dir="${src.dir}" excludes="**/*.java"/>

    <target name="jar" depends="compile">
        <mkdir dir="${jar.dir}"/>
        <jar destfile="${jar.dir}/${}.jar" basedir="${classes.dir}">
                <attribute name="Main-Class" value="${main-class}"/>

    <target name="run" depends="jar">
        <java fork="true" classname="${main-class}">
                <path refid="classpath"/>
                <path location="${jar.dir}/${}.jar" id="application"/>

    <target name="clean-build" depends="clean,jar"/>
    <target name="main" depends="clean,run"/>

    <target name="junit" depends="jar">
        <mkdir dir="${report.dir}"/>
        <junit printsummary="yes">
                <path refid="classpath"/>
                <path refid="application"/>

            <formatter type="xml"/>

            <batchtest fork="yes" todir="${report.dir}">
                <fileset dir="${src.dir}" includes="*"/>
    <target name="junitreport">
        <junitreport todir="${report.dir}">
            <fileset dir="${report.dir}" includes="TEST-*.xml"/>
            <report todir="${report.dir}"/>

<!-- Copyright (c) 2002 by ObjectLearn. All Rights Reserved. -->
<project name="webmodulebuilder"  default="BatchProcesses"  basedir=".">

    <!-- set global properties for this build -->
    <property name="dist" value="C:/BatchProcesses" />
    <property name="war" value="C:\app\current\warname.war" />
    <property name="parsers" value="C:\Parsers" />

    <target name="BatchProcesses">
        <!-- Start of CopyDataFromProduction -->
        <delete file="${dist}/BackgroundProcesses.jar"/>
          <delete dir="${dist}/empty"/>
          <mkdir dir="${dist}/empty"/>
          <jar destfile="${dist}/BackgroundProcesses.jar" basedir="${dist}/empty">
              <zipgroupfileset dir="${war}/WEB-INF/lib" includes="json-1.0.jar"/>
              <zipgroupfileset dir="${war}/WEB-INF/lib" includes="log4j-1.2.14.jar"/>
              <zipgroupfileset dir="${war}/WEB-INF/lib" includes="spring-beans-2.0.8.jar"/>
              <zipgroupfileset dir="${war}/WEB-INF/lib" includes="spring-context-2.0.8.jar"/>
              <zipgroupfileset dir="${war}/WEB-INF/lib" includes="spring-core-2.0.8.jar"/>
              <zipgroupfileset dir="${war}/WEB-INF/lib" includes="spring-dao-2.0.8.jar"/>
              <zipgroupfileset dir="${war}/WEB-INF/lib" includes="spring-jdbc-2.0.8.jar"/>
              <zipgroupfileset dir="${war}/WEB-INF/lib" includes="commons-logging-1.0.jar"/>
              <zipgroupfileset dir="${war}/WEB-INF/lib" includes="commons-lang-2.4.jar"/>
              <zipgroupfileset dir="${parsers}/oracle" includes=""/>
              <zipgroupfileset dir="${parsers}/commons" includes="commons-io-1.2.jar"/>
          <sleep seconds="1"/>
          <delete dir="${dist}/CopyDataFromProduction"/>
          <mkdir dir="${dist}/CopyDataFromProduction"/>
          <jar destfile="${dist}/CopyDataFromProduction/CopyDataFromProduction.jar" basedir="${dist}/empty">
                  <attribute name="Main-Class" value="com.quantros.qsupport.CopyDataFromProduction"/>
              <zipfileset excludes="**/META-INF/**" src="${dist}/BackgroundProcesses.jar"/>
          <copy todir="C:\\copy-data-from-production-to-training">
            <fileset dir="${dist}/CopyDataFromProduction/" includes="CopyDataFromProduction.jar"/>

Now we can clean, compile, and run:


We reuse the path to our own jar file as defined in run-target by giving it an ID. The printsummary=yes lets us see more detailed information than just a "FAILED" or "PASSED" message. How much tests failed? Some errors? Printsummary lets us know. The classpath is set up to find our classes. To run tests the batchtest here is used, so you could easily add more test classes in the future just by naming them *

In the target junit, we generate xml reports. In the target junitreport, we create a browsable HTML-report for all generated xml-log files in the report directory. Now you can open the ${report.dir}\index.html and see the result (looks something like JavaDoc). Generating the HTML report needs some time and you dont need the HTML report just for testing.

      <delete dir="${dist}/empty"/>
      <mkdir dir="${dist}/empty"/>
      <delete dir="${dist}/PublishACELibrary"/>
      <mkdir dir="${dist}/PublishACELibrary"/>
      <mkdir dir="${dist}/PublishACELibrary/conf"/>
      <copy file="${project.dir}/misc/conf/PublishACELibrary.conf" tofile="${dist}/PublishACELibrary/conf/config.txt"/>
      <exec executable="jar" dir="${dist}/PublishACELibrary" output="${dist}/out.txt" error="${dist}/err.txt">
          <arg value="cvfm PublishStandards.jar ${project.dir}/misc/manifestFiles/"/>
          <arg value="-C c:\parsers"/>
          <arg value="${dist}/release/quantros.war/WEB-INF/classes/com/quantros/qsupport/BatchProcess.class"/>
          <arg value="${dist}/release/quantros.war/WEB-INF/classes/com/quantros/qsupport/acestandardstool/PublishStandards.class"/>
      <jar destfile="${dist}/BackgroundProcesses.jar" basedir="${dist}/empty">
          <zipgroupfileset dir="${deploy.dir}/${war}/WEB-INF/lib" includes="*.jar"/>
          <fileset dir="${deploy.dir}/${war}/WEB-INF/classes"/>
      <sleep seconds="1"/>
      <jar destfile="${dist}/PublishACELibrary/PublishStandards.jar" basedir="${dist}/empty">
              <attribute name="Main-Class" value="com.quantros.qsupport.acestandardstool.PublishStandards"/>
          <zipgroupfileset dir="${deploy.dir}/${war}/WEB-INF/lib" includes="*.jar"/>
          <zipfileset excludes="**/META-INF/**" src="${dist}/BackgroundProcesses.jar"/>

The above approach combine all the jar files into one jar file, sleep for 1 second (to avoid some warning), and then it extract the jar file (using zipfileset) and filter out the META-INF folder. If we want to avoid the 1 second sleep, we may be able to use zipgroupfileset task together with the filesetmanifest attribute of the jar command. The filesetmanifest attribute of the jar command defines the behavior for the jar command when a manifest is found in a zipfileset or zipgroupfileset. Valid values are "skip", "merge", and "mergewithoutmain". The mergewithoutmain value will merge everything except for the Main section of the manifest. Default value is "skip"

How can we exclude certain source files from compilation?

<javac optimize="yes" debug="no" srcdir="${src}"
    destdir="${dist}/${war}/WEB-INF/classes" target="1.2">
    <classpath refid="project.classpath" />
    <exclude name="com/path/to/"/>

How can we run ant from Windows command line?

setx JAVA_HOME "C:\Program Files\Java\jdk1.7.0_45"
cd c:\svn\all\qetls (this directory contains the build.xml file)
C:\Dev\apache-ant-1.9.2\bin\ant dist (dist is the name of the ant target that we want to run)

How can we configure Eclipse ant to run using the verbose flag?

  1. Click on Run -> External Tools -> External Tools Configurations
  2. Select appropriate build.xml file from the left panel
  3. On the right panel, select the Main tab if it is not already selected
  4. In the Arguments text box, type -verbose
  5. Click on Close

How can we output the classpath for debugging?

<path id="application.classpath">
 <pathelement path="${java.class.path}"/>
  <fileset dir=".">
   <include name="lib/*.jar"/>

Then comes situations where you want to see the list of jars files contained in this classpath. Following simple Ant target will echo the content of the classpath variable ('application.classpath').

<target name="printClassPath">
 <property name="appClasspath" 
 <echo message="classpath= ${appClasspath}"/>

How can we capture the output to a log file?

If you turn on the debug flags, the output by ant can be really lengthy and verbose, and when it scrolls past a certain point, we cannot see the scrolled text. We can either increase the Eclipse buffer or configure ant to log its output to a file, you can add the following:

<record action="start" name="filename.txt" loglevel="verbose" append="false"/>
<record action="stop" name="filename.txt"/>

I added this around the ant javac command:

    <format property="timestamp" pattern="yyyy-MM-dd_HH-mm-ss"/>
<record name="c:\Khai\antlog-${timestamp}.txt" action="start" loglevel="verbose"/>
    <echo>Class path: ${java.class.path}</echo>
    <javac debug="${javac.debug}" deprecation="${javac.deprecation}" source="${javac.source}" target="${}" encoding="${javac.encoding}" srcdir="${src}" destdir="${dist.dir}/${war}/WEB-INF/classes" includeantruntime="false" verbose="false" fork="true">
        <classpath refid="project.classpath"/>
        <compilerarg line="${javac.compilerargs}"/>
<record name="c:\Khai\antlog.txt" action="stop" loglevel="verbose"/>

To log everything, start the recorder as the first statement in the init target, and end the recorder as the last statement in the deploy target.

You can also use the -logfile option but somehow it does not seem to work when running from inside Eclipse, or shell redirection methods such as > or tee.

How can we display the classpath?

<echo message="Classpath = ${java.class.path}"/>
<for list="${toString:classpath}" param="pathitem" delimiter=";">
<echo>pathitem == @{pathitem}${line.separator}</echo>

How can we force javac to recognize a classpath?

        <javac debug="${javac.debug}" deprecation="${javac.deprecation}" source="${javac.source}" target="${}" encoding="${javac.encoding}" srcdir="${src}" destdir="${dist.dir}/${war}/WEB-INF/classes" includeantruntime="false">
            <!--<classpath refid="project.classpath"/>-->
            <classpath path="${parsers_home}/commons/commons-codec-1.5.jar;${parsers_home}/commons/commons-lang-2.4.jar;C:\Tomcat6-SSO\lib\servlet-api.jar;${java.class.path}"></classpath>
            <compilerarg line="${javac.compilerargs}"/>
                <pathelement location="${basedir}/../crypto/${dist.dir}/${war}/WEB-INF/classes"/>

                <fileset dir="${parsers_home}/commons-fileupload/"  includes="*.jar" />
                <fileset dir="${parsers_home}">
                    <include name="**/*.jar"/>
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License