I was presenting my Introduction to MSBuild session last Thursday night at the Visual Studio Team System Public User Group (VSTSPUG). We were discussing the application of Conditions to Targets that were in a DepensdsOnTargets list. One of the attendees asked me:
“You have Target A that is a dependent of Target B. Target A also has a condition on it. When Target B fires, it invokes Target A first and Target A is skipped because its Condition evaluates to False. Does Target B continue running or is it stopped because Target A’s Conditon was False?”
I replied that Target B would run because the DependsOnTargets tells MSBuild to “Attempt to run” the dependent targets. If Target A is skipped, it is considered to have completed successfully for Target B’s dependency purposes.
In a follow-up question I was asked:
“… if Target A doesn’t get run when Target B calls it because its Condition is False, then what happens if it is a dependent of another target, say Target C, and when Target C is run the Condition evaluates to True?”
In this case, Target A would be run because its Condition is True and it was skipped the last time. A Target will only be run once per build, so this is Target A’s “run” since it was skipped earlier.
Here is an example project that shows this. In it you have 4 targets, Test, Test2, WillRun and WontRun. There is also a property, RunDependent, that is used to control target WontRun.
Test is run first. It depends on WillRun and WontRun. Target WontRun will run only if RunDependent is True. When it is called as a dependency of Test, its Conditon evaluates to False so it will be skipped. WillRun runs successfully. Test then modifies RunDependent to be True.
Test2 is run next. It also depends on WillRun and WontRun. When Test2 kicks off, MSBuild looks at the dependency list and sees that WillRun already ran, so it is skipped. It also notices that WontRun was skipped last time so it fires it. WontRun’s Condition is evaluated and now resolves to True, so it runs. Test 2 then runs.
Here’s the code:
<Project DefaultTargets="Test;Test2" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> <RunDependent>FalseRunDependent> PropertyGroup> <Target Name="WillRun"> <Message Text="WillRun ran..."/> Target> <Target Name="WontRun" Condition=" '$(RunDependent)'=='True' "> <Message Text="WontRun ran..."/> Target> <Target Name="Test" DependsOnTargets="WontRun;WillRun"> <Message Text="Test Ran"/> <CreateProperty Value="True"> <Output TaskParameter="Value" PropertyName="RunDependent"/> CreateProperty> Target> <Target Name="Test2" DependsOnTargets="WontRun;WillRun"> <Message Text="Test2 Ran"/> Target>Project>
And here’s the output:
Microsoft (R) Build Engine Version 2.0.50727.42
[Microsoft .NET Framework, Version 2.0.50727.42]
Copyright (C) Microsoft Corporation 2005. All rights reserved.
Build started 4/22/2007 9:36:23 PM.
Project “C:test2.proj” (default targets):
Time Elapsed 00:00:00.01