1
votes

I want to use manifestclasspath Ant task. I have a very large build.xml file with a couple of imported other build files and when I run it I get this:

build.xml:1289: The following error occurred while executing this line:
build.xml:165: Property 'some.property' already set!

I am sure that this property is defined only in manifestclasspath task. Here is my code:

<manifestclasspath property="some.property" jarfile="some.jar">
    <classpath refid="some.classpath"/>
</manifestclasspath>

This code is located inside of <project>.

What am I doing wrong? Is there a way to add something like condition to set property only if it is not already set? I don't want to use custom Ant tasks such as Ant Contrib's if if there is other way around.

1
I recently came across the same issue. Do your build scripts use antcall like ours do? If so, then that's root of your problem (since antcall can cause targets already run to be run again).Richard Steele

1 Answers

1
votes

Antcall opens a new project scope, but by default, all of the properties of the current project will be available in the new project. Also if you used something like =

<antcall target="whatever">
  <param name="some.property" value="somevalue"/>
</antcall>

in the calling project then ${some.property} is also already set and won't be overwritten, as properties once set are immutable in ant by design. Alternatively, you may set the inheritAll attribute to false and only "user" properties (those passed on the command-line with -Dproperty=value) will be passed to the new project. So, when ${some.property} ain't no user property, then use inheritAll="false" and you're done.

btw. it's better to use a dependency between targets via depends="..." attribute than to use antcall, because it opens a new project scope and properties set in the new project won't get back to the calling target because it lives in another project scope..

Following a snippet, note the difference, first without inheritAll attribute

<project default="foo">
 <target name="foo">
  <property name="name" value="value1" />
  <antcall target="bar"/>
 </target>

 <target name="bar">
  <property name="name" value="value2" />
  <echo>$${name} = ${name}</echo>
 </target>
</project>

output :

[echo] ${name} = value1

second with inheritAll=false

 <project default="foo">
     <target name="foo">
      <property name="name" value="value1" />
      <antcall target="bar" inheritAll="false" />
     </target>

     <target name="bar">
      <property name="name" value="value2" />
      <echo>$${name} = ${name}</echo>
     </target>
    </project>

output :

[echo] ${name} = value2

some rules of thumb for antcall, it's rarely used for good reasons :
1. it opens a new project scope (starting a new 'ant -buildfile yourfile.xml yourtarget')
so it uses more memory, slowing down your build
2. depending targets of the called target will be called also !
3. properties don't get passed back to the calling target

In some cases it might be ok when calling the same 'standalone' target (a target that has no target it depends on) with different params for reuse. Normally macrodef or scriptdef are used for that purpose. So, think twice before using antcall which also puts superfluous complexity to your scripts, because it works against the normal flow.

Answer to your question in the comment, using a dependency graph instead of antcall
you have some target that holds all conditions and sets the appropriate properties which may be evaluated by targets via if and unless attributes to control the further flow

<project default="main">

 <target name="some.target">
  <echo>starting..</echo>
 </target>

 <!-- checking requirements.. -->
 <target name="this.target">
  <condition property="windowsbuild">
   <os family="windows"/>
  </condition>
  <condition property="windowsbuild">
   <os family="unix"/>
  </condition>
  <!-- ... -->
 </target>

 <!-- alternatively
  <target name="yet.another.target" depends="this.target" if="unixbuild">
 -->
 <target name="another.target" depends="this.target" unless="windowsbuild">
  <!-- your unixspecific stuff goes here .. -->
 </target>

 <!-- alternatively
  <target name="yet.another.target" depends="this.target" if="windowsbuild">
 -->
 <target name="yet.another.target" depends="this.target" unless="unixbuild">
  <!-- your windowspecific stuff goes here .. -->
 </target>