Can you spot the error in this Ant build.xml file..:-)
Posted : May 27, 2004 at 3:02 pm [America/Los_Angeles]
I came across an interesting article written by Grant Bremer titled “Flexible User and Environment Ant Configuration” on the OnJava site the other day. Without caring to look into the sample code that was made available as part of the article, I decided to jump in and try out his suggestions. Here’s the Ant build file used for a very simple “HelloWorld” project of mine. However, there is something fundamentally wrong with the build file. Basically, it does not work. Can you see it?
build.xml file
---------------
<?xml version="1.0"?>
<project name="helloworld" basedir="." default="all">
<target name="start">
<tstamp/>
<available file="${basedir}/local.properties" property="local.properties.available"/>
</target>
<target name="properties-local" if="local.properties.available" depends="start">
<echo message="Loading local properties file"/>
<property file="${basedir}/local.properties"/>
</target>
<target name="properties" depends="properties-local">
<echo message="Loading build properties file"/>
<property file="build.properties"/>
<echo message="Loading environment variables"/>
<property environment="env"/>
</target>
<!-- Compile-time classpath -->
<path id="compile.classpath">
<fileset dir="${project.lib.dir}">
<include name="*.jar" />
</fileset>
</path>
<!-- Runtime classpath -->
<path id="runtime.classpath">
<fileset dir="${project.lib.dir}">
<include name="*.jar" />
</fileset>
</path>
<!-- Initialize -->
<target name="init" description="Prepare build directory" depends="properties">
<mkdir dir="${build.dir}" />
<mkdir dir="${build.classes.dir}" />
<mkdir dir="${build.app.dir}" />
<mkdir dir="${dist.dir}" />
</target>
<!-- Compile -->
<target name="compile" depends="init" description="Compile source">
<javac srcdir="${project.src.dir}"
destdir="${build.classes.dir}"
debug="${javac.debug}"
deprecation="${javac.deprecation}"
optimize="${javac.optimize}"
verbose="${javac.verbose}"
classpathref="compile.classpath" />
</target>
<!-- Jar things up -->
<target name="jar" depends="compile" description="creates the archive">
<jar destfile="${dist.dir}/${deploy.app.name}.jar" basedir="${build.classes.dir}">
<manifest>
<attribute name="Main-Class" value="${deploy.app.main}" />
</manifest>
</jar>
</target>
<!-- Run -->
<target name="run" depends="jar" description="Execute the app">
<java jar="${dist.dir}/${deploy.app.name}.jar" fork="true">
<classpath>
<path refid="runtime.classpath" />
</classpath>
</java>
</target>
<!-- clean -->
<target name="clean" description="cleans the output directories">
<delete dir="${build.dir}"/>
<delete dir="${dist.dir}"/>
</target>
<target name="all" depends="clean, run" description="Clean and compile all components"/>
</project>
The error message that I get is:
….
….
compile:
[javac] Compiling 3 source files to E:\development-root\java\myapps\helloworld\build\classes
BUILD FAILED: E:\development-root\java\myapps\helloworld\build.xml:50: E:\development-root\java\myapps\helloworld\${project.lib.dir} not found.
Total time: 1 second
Just to help you out, the error is not because of missing local.properties or build.properties.
Ok, here’s another teaser. If you run the ant command with the ‘verbose’ setting on, this is what you get (only the first few and relevant lines shown):
E:development-rootjavamyappshelloworld>ant -verbose all
Apache Ant version 1.6.1 compiled on February 12 2004
Buildfile: build.xml
Detected Java version: 1.4 in: E:development-roottoolsj2sdk1.4.2_04jre
Detected OS: Windows XP
parsing buildfile E:development-rootjavamyappshelloworldbuild.xml
with URI = file:///E:/development-root/java/myapps/helloworld/build.xml
Project base dir set to: E:development-rootjavamyappshelloworld
Property ${project.lib.dir} has not been set
Property ${project.lib.dir} has not been set
...
...
Notice, the last two lines. Ok, if you’ve cracked it by now, you’re more familiar with the way Ant parses it’s build.xml file than I am. I am not 100% sure how this internally works, but here’s my theory:
Since my <path> elements that define compile.classpath and runtime.classpath were outside any <target> elements, Ant tried parsing those first. It saw a reference to ${project.lib.dir} twice and realized that no such property existed. At least, not yet. Since the build.properties or local.properties (which are part of a <target>) were not parsed yet, Ant assumed that $project.lib.dir was actually a directory name and set the compile.classpath and runtime.classpath values accordingly.
If you want to test this out, download this, unzip it and then run ‘ant all’ at your prompt (assuming you’ve Ant installed and available in your PATH variable)
I had two ways of fixing the problem:
1. Move the <path> definitions inside the <properties> target Or
2. Replace the targets that Grant proposes in his article with two lines that look something like:
<property file=”${basedir}/local.properties”/>
<property file=”${basedir}/build.properties”/>
For now, I have taken the first approach as I kind of like the approach which Grant proposes.
Note:
To be fair to Grant, while the snippet of the Ant build file in his article misled me somewhat, the sample code had the targets set up correctly so as to include the <path> definitions inside the <properties> target
- Anand
Category: Application Development |
4 Comments »
Anand,
Your option 2 is the “right way”; the properties will be parsed at load time, then, as opposed to run time.
I’m personally fond of this idiom:
<project name=... > <property name="user.properties" value="user.properties" /> <property file="${basedir}/${user.properties}" /> <property file="${basedir}/build.properties" /> ... </project>This lets me have “sets” of properties which I can pick between when I launch Ant; this works well with our continuous build environment, for example.
Posted by: Robert Watkins at May 27, 2004 @ 4:45 pm
See, the only reason I was using the other approach was the fact that it explicitly states which property files were found and processed. The approach which you’re suggesting (which btw is something I am more used to also) will “silently” process (or not) the property files that are listed.
But then again, if I had issues, I could always turn ant’s verbose mode on and see which property files were being processed.
Anyway, thanks for the input Robert..:-)
Posted by: Anand Sharma at May 27, 2004 @ 5:10 pm
An excellent point, Anand, something I believe I should have covered in my article. In the article sample code, I define a path element for my project libraries, but I do so *after* I have loaded the build.properties and the local.properties within a target element. I would submit that I have avoided the problem above through habit and because I the existing code that I’ve written from past projects.
Posted by: Grant Bremer at May 27, 2004 @ 5:44 pm
No worries. Great article btw..:-)
Posted by: Anand Sharma at May 27, 2004 @ 8:14 pm
Leave a Comment