You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@ant.apache.org by Mark Rose <ma...@gforce.com> on 2000/08/11 19:12:37 UTC

Re: Newbie question [long]

David,

Make sure you read Steven Bodewig's great reply. I won't rehash what
he's said, but instead give a brief summary of how I think about Ant
build files. (Warning: I haven't run each example here. They are
paraphrased from working Ant build files I am using.)

The basics
----------
A typical structure of an Ant build.xml file is this:


<?xml version="1.0" encoding="ISO-8859-1"?>

<project name="gforcecentral" default="main" basedir="../..">
  <property name="some.name" value="some value"/>
  ...

  <target name="main" depends="a, b">
    <task attribute="value" .../>
    ...
  </target>

  <target name="a">
    ...
  </target>

  ...
</project>


Some things to note:
- The build file is an XML file. Make sure it loads correctly in an XML
editor. (This is sometimes easier than figuring out the error from Ant
output.) There are pointers to a DTD for basic Ant build scripts in the
Ant FAQ.
- You can name the build file anything you want. build.xml is the
default (like makefile). You specify an alternate build file with the
"-buildfile" option on the command line.
- Properties are kind of like macros in makefiles. The main
difference--in Ant 1.1 at least--is that they're evaluated top-to-bottom
before Ant does any building, so one property can't change its value
during the build. You can override the property definitions on the
command line, a la make.
- Targets can appear in any order, as in makefiles. The "main" target is
not necessarily the first, however. It's whichever target you name as
the default in the <project> element.
- Targets can depend on other targets--as in makefiles--but targets
don't depend on files. This is a key difference from makefiles!

You may now ask, "But how does Ant know how to minimalize builds if
targets don't depend on files?" In Ant, the logic for this is built-in
to each task (with some OO inheritance, of course, to reduce code). For
example, let's say we want to copy some files. A target to do this might
be:

<target name="copy-some-files">
  <copydir src="some/path/src"
           dest="another/path/dest"/>
</target>

(Note that some/path/src and another/path/dest are interpreted relative
to the basedir property defined in the <project> element. This is true
for all
tasks that take pathnames as attributes, I believe.)

The first time you run Ant with this target, the destination directory
will be created, and all files will be copied, recursively, from the
subtree some/path to the subtree another/path. If you run it again,
however, no files will be copied because all are up-to-date. The code
for the <copydir> task checks the dates on the source and destination
files, only copying files if they are out-of-date.

Other tasks that do this date-and-time checking are <javac>, <copyfile>,
and <jar>. (And likely many more, but these are the only ones I have
experience with.)


Building Java projects
----------------------
So if your project is just Java files that need to be compiled and put
into a jar file in a destination directory, you could do it in one
target:

<!-- Paths for the sources, the .class files area, and the
     distribution area -->
<property name="src.root" value="../src"/>
<property name="classes.root" value="../classes"/>
<property name="dist.root" value="../dist"/>

<!-- The classpath to use for Java compiles. We don't depend on
     anything right now, so just the sources and classes. -->
<property name="base.classpath" value="${src.root};${classes.root}"/>

<target name="main">
  <javac srcdir="${src.root}"
         destdir="${classes.root}"
         classpath="${base.classpath}"
         debug="on"
         target="1.2"/>
  <mkdir dir="${dist.root}/>
  <jar jarfile="${dist.root}/result.jar"
       basedir="${classes.root}"/>
</target>

Notes:
- Use XML comments: <!-- ... -->
- Property evaluation is done using ${propertyname}, kind of like
$(macroname) in makefiles.
- Property values can be overridden on the command line to Ant, using
-Dpropertyname=value, a la javac.
- The <mkdir> task has built-in logic to only create the directory if it
doesn't exist, so you don't have to put any checks in the build
script--nor can you!
- If you run Ant on this build file, it does what you'd expect from a
well-written makefile, only doing steps that are necessary to build
things that are out-of-date.


More make-like targets
----------------------
OK, that's the basics, but what about other things you do with
makefiles? For starters, I always like a "clean" target. You can do that
in the build script like this:

<target name="clean">
  <deltree dir="${classes.root}"/>
</target>

Or add an "immaculate" target to delete the distribution as well:

<target name="immaculate" depends="clean">
  <delete file="${dist.root}/result.jar"/>
</target>

(or <deltree dir="${dist.root}/>, perhaps)


Building mixed projects
-----------------------
OK, but what if you have projects that are mixed Java and C++, like me?
I have had good results using <exec> to invoke external makefiles for
the C++. Here's an example from a Windows build (hence DOS stuff):

<target name="some-c-project">
  <exec command='set "PATH=${msvc5.path}" &amp;&amp;
                 set "LIB=${msvc5.libpath}" &amp;&amp;
                 set "INCLUDE=${msvc5.incpath}" &amp;&amp;
                 nmake -nologo -f sample.mak'
        dir="../src/c-project"
        failonerror="true"/>
</target>

You need to set failonerror to "true", so that Ant will stop the build
if the makefile encounters an error.

Of course, it's cheating a little to use Ant to invoke makefiles, but
until Ant has built-in tasks to do C++ compiles, I see little choice,
unless you want to insert all the cc commands in the Ant script. (And
then you don't get minimalized builds.)


Some final notes
----------------
- Some tasks create directories as needed, others seem not to. If you
have problems, add <mkdir> tasks as needed.
- Some dependency checking is beyond the scope of Ant right now. For
example, at my company we generate some Java code by running other Java
programs. There's no way to check whether the generated Java is
up-to-date, so you end up with some files compiled every time you run
Ant. (Thankfully only a few.)
- There are a lot of properties available that aren't in the
documentation. Run Ant with the "-verbose" flag to see all the
properties that Ant is setting. java.class.path may be useful, for
example.


Hope this helps,
Mark
-- 
Mark Rose                     gForce
408.213.2211                  Enterprise eLearning Solutions
mailto:mark@gforce.com                         Get there faster.

                              http://www.gforce.com