Hello!
 
I just want to give comments about Ant and my suggestions about the upcoming
Ant2. To give some background about me, I am a Java programmer since early
1997 and wrote several commercial applications of >600k code each. I have quite
some experience with 'make' and are using 'ant' for several weeks now.
 
Some general thoughts first; you can skip these and start below where the
underlined headings are.
 
Both make and ant serve to ease the job of creating files out of other files.
You have for example source code and want a jar file of compiled code out of
it.
 
'make' uses a bottom-up approach. You give several rules that tell make how to
generate files out of other files, e.g.
 
  %.class: %.java
    $(JAVAC) $(JAVAFLAGS) $*.java
 
this says "if you want a .class-file, you need a .java-file. Then you apply
this command to it". The same happens with jar-files:
 
  myapp.jar: A.class B.class C.class
    jar cvf myapp.jar A.class B.class C.class
 
When you run make, you tell it what you want and make checks the rules how to
reach the goal. I think this is the way Prolog works. You give it a set of
rules and then ask it to create something based on this rule, but I can be
completely wrong, as I don't know any Prolog :-)
 
With ant, you have a more top-down and programmatic approach. You state
exactly the steps to reach the goal. You can do the same thing with make, by
just using non-file targets like this
 
  <target name="a" depends="b">
    // do a
  </target>
 
  <target name="b"/>
    // do b
  </target>
 
is with make like
 
  a: b
    // do a
 
  b:
    // do b
 
What ant lacks compared to make is the dependency based on files, but later
more on this.
 
So, comparing just the dependencies, make is more powerful than ant, but this
is not all ;-)
 
What I like most of ant are these directory tasks. Ant is MUCH faster than
make when it comes to compiling sourcecode, because it compiles all files at
once and knows how to handle directory-trees.
make was written for C programs and deals very badly with directories. Most of
the time, each directory needs its own makefile. As Java uses directories more
frequently than C, this is one of the main drawbacks of make when writing Java
applications.
 
You are still reading? Ok, here are my suggestions for Ant2. I am a friend of
KISS (keep it simple stupid). I like to reduce problems to the very necessary,
because I don't want to learn much. Everything should be as intuitively as
possible.
 
1. filesets
------------
Ant deals with file conversion. You have input files and outputfiles and tasks
what to do with them. Right now, both writing build.xml files and tasks
itselves it more complicated than necessary.
 
Each task can have input-files, output-files. Some of the build-in tasks just
need one of them, like 'mkdir' or 'delete'. Nethertheless, the syntax should
be similar, as it is obvious that 'delete' does not create files.
 
A possibility would be
 
  <mytask in="...." out="..."/>
 
(this could also be 'from' and 'to') or
 
  <mytask>
    <fileset type="in">
      ...
    </fileset>
    <fileset type="out">
      ...
    </fileset>
  </mytask>
 
Right now, the semantics using several filesets is confusing. If you have
(version 1)

  <mytask>
    <fileset>
      <include name="b"/>
      <include name="a"/>
    </fileset>
  </mytask>
 
then both 'a' and 'b' are sorted and given to the task as one fileset, thats
ok. But if you have (version 2)
 
  <mytask>
    <fileset>
      <include name="b"/>
    </fileset>
    <fileset>
      <include name="a"/>
    </fileset>
  </mytask>
 
then 'a' and 'b' are not sorted and given to the task in two separate calls as
two separate filesets. This is the same as (version 3)
 
  <mytask>
    <fileset>
      <include name="b"/>
    </fileset>
  </mytask>
  <mytask>
    <fileset>
      <include name="a"/>
    </fileset>
  </mytask>
 
and should not be like this, as I can write it like this if I want it. My
suggestion is:
 
version 1: all files are sorted
version 2: files are sorted within the filesets, but not sorted across them and
  given to the task as one large fileset
version 3: several filesets, several calls to the task
 
Additionally an option 'parallel="false"' that switches to 'one file at a time'
mode.
 
2. mappers
-----------
Mappers allow ant to do 'shortcuts' by not applying tasks if the outfiles are
newer then the infiles. Right now, the usage of mappers is very limited. You
cannot give them to all tasks and together with the strange behaviour of version
2, you cannot use it to 'cat' (UNIX cat) several files together if you need a
certain order. If you have
 
  <cat target="targetfile">
    <fileset>
      <include name="b"/>
    </fileset>
    <fileset>
      <include name="a"/>
    </fileset>
    <mapper type="merge" to="targetfile"/>
  </cat>
 
then the mapper will prohibit the cat of 'a', because the targetfile exists and
is newer as 'a' :-(
 
My suggestion is, that a mapper is possible for every task and that it is
evaluated only once. You can specify input-files and a mapper and maybe
outputfiles and a mapper, but it should not be allowed to specify all three,
input-, output-files and mapper.
 
The mapper will create the corresponding filesets and will be used to check if
the task needs to be run or is up to date. The task itself gets the in/outfiles
as if they were given and also access to the mapper.
 
3. fileset-code for tasks
--------------------------
When writing a task, accessing the filesets and mapper is rather complicated.
Code like
 
  fs.getDirectoryScanner( project )
 
where 'project' is inherited from a super class is not very object oriented.
Also, the files should be accessible as an 'Iterator' over 'File'. As there is
only one fileset, the Iterator itself should be sufficient. There is only one
mapper, so Code can be like this:
 
public class MyTask extends Task {
  public void execute() throws BuildException {
    for( Iterator i = getInputFiles(); i.hasNext(); ) {
      File
        fileInput  = (File) i.next(),
        fileOutput = mapToOuput( fileInput );
 
      System.out.println( fileInput.toString() + "->" fileOutput.toString() );
    }
  }
}

The mapper will create the corresponding filesets and will be used to check if
the task needs to be run or is up to date. The task itself gets the in/outfiles
as if they were given and also access to the mapper.
 
3. fileset-code for tasks
--------------------------
When writing a task, accessing the filesets and mapper is rather complicated.
Code like
 
  fs.getDirectoryScanner( project )
 
where 'project' is inherited from a super class is not very object oriented.
Also, the files should be accessible as an 'Iterator' over 'File'. As there is
only one fileset, the Iterator itself should be sufficient. There is only one
mapper, so Code can be like this:
 
public class MyTask extends Task {
  public void execute() throws BuildException {
    for( Iterator i = getInputFiles(); i.hasNext(); ) {
      File
        fileInput  = (File) i.next(),
        fileOutput = mapToOuput( fileInput );
 
      System.out.println( fileInput.toString() + "->" fileOutput.toString() );
    }
  }
}
 
I didn't dig into the 'XXXScanner', but this should be possible and fascilate
writing tasks a lot. Note that 'File' can be a plain file or a directory and
that it does not need to exist.
 
4. shortcuts for targets
-------------------------
Sometimes it is quite hard to convince Ant that a target does not need to be
rebuilt. What about a mapper for the target itself, just state what files this
target needs and what file(s) it creates.
 
The code for checking the mappers does exist and adding a mapper to a target
gives no conflicts.
 
 
So, thank you for reading this. I would like to get some response from you, 
whatyou think
about this. I don't want to start implemeting something unless someonesays that 
it is
worth it.
 
Greetings,
 
Kurt
-- 
-------------------------------------------------------------
Impossible doesn't exist!             Unm�glich gibt's nicht!
Difficult exists.                           Schwierig gibt's.

Reply via email to