This past week I was taking a look at one of our build scripts as it appeared to be taking a bit longer than everyone wanted. Because I am very close to the file (authored about 50% of it) I decided that in place of just diving in and looking at the raw source I would instead run the script with the given options I needed and record the output (nant.exe -buildfile:Demo.xml SomeTargetName > Log.txt) and once the run was complete I would take a look at the output and look for ‘out of normal items’. Within a few minutes of scanning the file I noticed something ODD, we were compiling all of our code twice (just to be double sure it compiled correctly of course).
Now that I knew the issue, double compiling 5 solutions for each build, it was time to determine why we were doing this. As I started to follow the call chain I noticed something that was a bit interesting to me. It appeared that were we calling a target via a <Call> command vs a Depends command the entire call stack would be re-executed. A quick google search lead me to this page (here) which had the answer to my problem. Per the Nant documentation:
A target gets executed only once, even when more than one target depends on it (see the previous example). However, when the <call> task is used to execute a target, both the target and all its dependent targets will be re-executed.
Hum.. problem found, root caused determined. Now it was simply a matter of resolving the issue. SWEET
To better illustrate this scenario I have created a simple example (with screenshots to boot).
Imagine you have the following Nant script (sorry, could not get the XML to not be ‘xml’ and rather be code/text)
If you take a look at the script above you will see 2 things.
- I have a few targets that use Depends to call other targets
- I have one target (Target_Z) which simply does a call out to the other targets it needs
In order to understand how ‘Depends’ works and the fact that it will NOT double call a target lets take a look at the call stack if we invoke Target_A directly.
As you can see from the image, each target is only invoked once even though that Target_C is referenced by both Target_A and Target_B
Now, to understand how ‘<Call>’ works and the fact that it will double call targets let take a look at the call stack if were to invoke Target_Z directly.
As you can see from the image above, Since Z calls both A & B we get the repeating of each of their targets, so Target_B and Target_C are each called multiple times and this could be really bad on performance.
Now that you understand the difference between <Call> and ‘Depends’ use this information wisely and with caution.
Oh, by not double calling our compile for all 5 solutions we shaved about 4-5 minutes off of our CI build… NOT TOO BAD
Till next time,
11-20-2009 5:32 AM