Tobber
Tobber

Reputation: 7541

Using "antcall" in included ant files

I have a shared ant script b.ant which internally use antcall. It calculates a property that the client scripts use. I use include instead of import client scripts to avoid unintentional overwriting of targets, but this gives me a problem with the antcall.

When using include all targets in b are prefixes, and depends attributes in b are updated accordingly. This is however not true for antcall. Is there a there are way to handle this, i.e. make antcall always call the "local" ant target?

I can workaround this by using import, but then I'll get all the overwrite problems. It is not possible to use depends instead of antcall.


Example files

I have two files:

a.ant

  <project>
    <include file="b.ant" as="b" />
    <target name="test-depends" depends="b.depend">
      <echo>${calculated-property}</echo>
    </target>
    <target name="test-call" depends="b.call">
      <echo>${calculated-property}</echo>
    </target>
  </project>

b.ant

<project>
  <target name="depend" depends="some-target">
    <property name="calculated-property" value="Hello World"/>
  </target>
  <target name="call">
    <antcall target="some-target" inheritrefs="true"/>
    <property name="calculated-property" value="Hello World"/>
  </target>
  <target name="some-target"/>
</project>

Example output

Calling test-depend works as expected but test-call fails with this output:

b.call:

BUILD FAILED
D:\ws\rambo2\ws-dobshl\ant-test\b.ant:6: The following error occurred while executing this line:
Target "some-target" does not exist in the project "null". 

Total time: 258 milliseconds

Upvotes: 0

Views: 2069

Answers (2)

Chad Nouis
Chad Nouis

Reputation: 7041

Give a name to the <project> in b.ant and then change the target of the <antcall>:

<project name="b"> <!-- Give the project a name -->
  <target name="depend" depends="some-target">
    <property name="calculated-property" value="In b.depend"/>
  </target>
  <target name="call">
    <!-- Specify the name of the project containing the target -->
    <antcall target="b.some-target" inheritrefs="true"/>
    <property name="calculated-property" value="In b.call"/>
  </target>
  <target name="some-target"/>
</project>

The result of ant -f a.ant test-call:

b.call:

b.some-target:

test-call:
     [echo] In b.call

BUILD SUCCESSFUL

With the changes to b.ant, the <include> in a.ant can be simplified by removing the as attribute:

<include file="b.ant" />

Upvotes: 1

David W.
David W.

Reputation: 107060

Ant is a dependency matrix specification language. Usually a bunch of <antcall/>, <ant/>, <include/> and <import/> is a sign of a poorly written build script. It's a developer trying to force Ant to act like a programming language.

For developer, it makes sense to break up a program into smaller files. Even Python and Perl scripts can benefit from this. However, breaking up an Ant build script usually causes problems. We had a developer who went through every project and broke up all the build.xml files into six or seven separate build files in order to improve the process. It basically broke the whole Ant dependency mechanism. To fix it, he then tossed in a bunch of <ant/> calls and <include> tasks. In the end, it meant that each target was called between 12 to 20 times.

Not using <import/> and <antcall/> isn't a hard and fast rule. But, I've been using Ant for years and rarely ever used these mechanisms. When I do, it's usually for a shared build file that multiple projects will use (which sounds like what you have) but instead of defining targets in my shared build file, I define macros. This eliminates the target namespace issues that you are having, and the macros work better because they act more like Ant tasks. This is especially true with the introduction of <local/> in Ant 1.8.

See if you can restructure the shared build file into using <macrodef/> instead of targets. It will make it much easier to include your shared build file.

Upvotes: 2

Related Questions