Antcall vs Depends

Occasionally, I see issues pop up on Java projects about builds not working properly.  They usually look like, “The build worked yesterday, but it doesn’t work today.  I was working on it, but I didn’t change anything related to the part that is failing.” or “I can’t figure out why, when I run this by itself, it passes.  When I run it as a part of a full build, it fails.”  Build errors are almost always caused by a misunderstanding of the function of “depends”.

How Not to Use Depends

This probably works, but only by chance.

<target name="test" depends="clean,compile,compile-test,test,service-test" />

Depends is not a list of tasks to be executed.  It’s a list of dependencies that must be satisfied before a target can be completed.  Execution is not guaranteed and side effects are common.  Take a close look at what each of the tasks in the following script is doing.

<target name="functional-test" depends="start-server,run-tests,stop-server" />
<target name="service-test" depends="start-server,run-service-tests,stop-server" />
<target name="test" depends="clean,compile,compile-test,functional-test,service-test" />

To a human, the intent is obvious.

  1. Clean and compile
  2. Start server
  3. Run functional tests
  4. Stop server
  5. Start server
  6. Run service tests
  7. Stop server

But Ant will not execute those tasks.  Since they were declared as dependencies, Ant evaluates them as such.  The functional tests will run as you would expect.  When it runs the service-test target, though, it will see the start and stop server tasks again.  As far as it’s concerned, those dependencies have already been satisfied, so it will skip start-server and stop-server.  Ant is evaluating the script correctly, but the script is wrong.

Dependencies are not tasks to be executed.  They are dependencies.  Once a dependency has been satisfied, it will not be executed again.

Antcall Is Not Evil

It exists for a reason.  Use it when it is useful.  Dependencies are dependencies, not task lists.  In this case, it would be impractical to try to write the script to use depends attributes to cause events to happen correctly.  It can be fixed very easily by using antcall.  Each antcall is evaluated separately, so you don’t have to worry about side effects like the script above.  It’s also easier to read.  You can see what’s intended to happen before this target and you can see what this target is intended to do.

<target name="functional-test" depends="start-server,run-tests,stop-server" />
<target name="service-test" depends="start-server,run-service-tests,stop-server" />
<target name="test" depends="clean,compile,compile-test">
  <antcall target="functional-test" />
  <antcall target="service-test" />
</target>

Use Your Own Judgement

Obviously, antcall should not be used instead of depends.  Depends is far more useful.  But don’t throw a tool like antcall away just because it doesn’t seem as cool or concise or elegant.

Posted in Java at September 17th, 2010. 4 Comments.