1

Suppose I have a simple build script with the following 4 targets:

  1. build - Compile's the project's code, depends on init
  2. init - Sets up the build environment, depends on nothing
  3. clean - Deletes all files generated by build and init, depends on nothing
  4. all - Simply cleans and then builds, depends on clean and build

    <project>
        <target name="build" depends="init">
            <echo>Building the project</echo>
        </target>
    
        <target name="init">
            <echo>Setting up the build environment</echo>
        </target>
    
        <target name="clean">
            <echo>Deleting all generated files</echo>
        </target>
    
        <target name="all" depends="build,clean">
            <echo>Full build complete!</echo>
        </target>
    </project>
    

The problem here is that the order of init and clean is ambiguous in Ant. If clean is called, it needs to run before all other targets, including init. However, init cannot have depends="clean" because we don't always want to run clean.

I realize that reversing the order of build and clean in the all target's dependencies (i.e. depends="clean,build") would technically get them to run in that order, however I don't consider this to be a satisfactory solution. Ant will still consider these targets to be siblings on the dependency tree, and will not actually enforce this order at all.

Another "solution" of course is to just hard code the ordering by using sequential <antcall/> tasks. This might be what I have to eventually fall back on, but it's something I'm trying to avoid (for multiple reasons that probably aren't worth expanding on).

Also, I'm aware that Gradle has exactly this feature built in (believe me, I'm jealous of it), but at this point my company's project is deeply entrenched in Ant, so switching really isn't an option.

EDIT - To give a better idea of the sort of thing I'm looking for, here's an example using features that I wish Ant had:

<condition property="init.depends.list" value="clean" else="">
    <contains string="${ant.project.call-graph}" substring="clean" />
</condition>

<target name="clean" />

<target name="init" depends="${init.depends.list}" />

After reading the manual page on Ant's bindtargets task, I'm starting to think Ant's target dependency list is immutable as part of its core design philosophy, so there might actually be no good answer to this question.

CAustin
  • 4,525
  • 13
  • 25

2 Answers2

1

If you want to ensure that init never runs before clean. Then you can use a property to serve as a flag:

<target name="init">
    <property name="init-called" value="true"/>
</target>

<target name="clean">
    <fail if="init-called" message="init ran before clean"/>
</target>

If init runs before clean, the init-called property will be set and the <fail> task will fail the build.

Another option is to have all depend on two targets: enable-clean-target and init. enable-clean-target would set a property that would be used by the if attribute of the clean target:

<target name="enable-clean-target">
    <property="run-clean" value="true"/>
</target>

<target name="clean" if="run-clean">
    <!-- ... -->
</target>

<target name="init" depends="clean">
    <!-- ... -->
</target>

<target name="all" depends="enable-clean-target, init">
    <!-- ... -->
</target>

The init target explicitly depends on clean, but clean will only run if enable-clean-target ran earlier in the build.

Chad Nouis
  • 6,861
  • 1
  • 27
  • 28
  • This would reliably prevent the targets from running in the incorrect order, but I'm looking for a way tell Ant how to run them in the correct order in the first place. In other words, this assertion may fail as intended, but then what? – CAustin Jul 22 '16 at 02:55
  • @CAustin I've added another example that makes use of the `if` attribute of ``. – Chad Nouis Jul 22 '16 at 14:24
  • I appreciate the effort, but this just adds a small layer of complexity without fixing the underlying logical problem. If I were to switch around the dependencies listed for `all`, `init` would be called first, which would depend on `clean`, which would fail to run because `run-clean` hasn't been set yet. I'm looking for a solution that is completely agnostic to the order in which targets are listed in the `depends` attribute. – CAustin Jul 27 '16 at 00:58
  • From the [Ant FAQ](https://ant.apache.org/faq.html#stop-dependency): "The list of dependencies is generated by Ant before any of the targets are run." So, no, there's no way to dynamically alter the dependency graph of an Ant build during a build. – Chad Nouis Jul 27 '16 at 15:46
0

From the Ant Targets documentation:

Ant tries to execute the targets in the depends attribute in the order they appear (from left to right). Keep in mind that it is possible that a target can get executed earlier when an earlier target depends on it.

So unless your init and clean targets become more complex with additional dependencies, you can count on the ordering to be in order. So depends="clean,build" would work reliably.

David St Denis
  • 813
  • 6
  • 9