Caching Behaviour in Orcas msbuild

Greetings MSBuilders!

Orcas MSBuild introduces a new parameter for the CallTarget and MSBuild task called “UseResultsCache”. Enabling this feature allows the MSBuild engine to cache the built target results like the outputs attribute from the target. At this point you may be wondering why do we need to cache the results of a target. Well - we have also introduced a new parameter in the MSBuild task called “UnloadProjectsOnCompletion”. Enabling this feature will cause the MSBuild engine to unload the project from memory once it has completed building. In version 2, once a project is loaded it is resident in memory. When building lots of project, this can cause memory usage problems. To prevent using lots of memory we introduced the unloading of projects when it has completed building. The drawback to this feature is that once the project has been unloaded than you cannot load it again (you will get an error). In your build process you may often have targets that you may need to call to gather some information even after the project has been unload and to support this we introduced target result caching. If the results of a target has been cached than even if the project is unloaded we will be able to retrieve the results.

For example in Microsoft.Common.Targets we have targets like GetCopyToOutputDirectoryItems and GetTargetPath which could get called after the project is unloaded - for instance from another project referencing this unloaded project (which may have already completed build and unload). The referencing project calls the GetCopyToOutputDirectoryItems and GetTargetPath targets. If the results of these targets where not cached than we would error. However if you look at Microsoft.Common.Targets we use CallTarget and UseResultsCache to cache the results before the build is completed (During the CoreBuild target) so rather than getting an the cached results are returned back to the referencing project.

Example:

a.proj

<Project xmlns="https://schemas.microsoft.com/developer/msbuild/2003">

<Target Name="default">

<Message Text="Project: a.proj Target: default" />

</Target>

<Target Name="Normal" Outputs="Someoutput from second target">

<Message Text="Project: a.proj Target: second" />

</Target>

</Project>

b.proj

<Project xmlns="https://schemas.microsoft.com/developer/msbuild/2003">

<Target Name="default">

<Message Text="Project: b.proj Target: default" />

<MSBuild Projects="a.proj" Targets="default" UnloadProjectsOnCompletion="true" />

<MSBuild Projects="a.proj" Targets="Normal" UnloadProjectsOnCompletion="true" >

<Output TaskParameter="TargetOutputs" PropertyName="TargetOutput"/>

</MSBuild>

<Message Text="Output from project: b.proj target: second = $(TargetOutput)" />

</Target>

</Project>

Building project b.proj using the command line “msbuild.exe b.proj /tv:3.5” will generate an error :

a.proj : error MSB4161: Project " a.proj" was loaded and unloaded during the current

build. Reloading a project during the build can result in errors or an inconsistent build state. Either avoid unloading

project " a.proj" or cache the evaluation results of target(s) "Normal" before unloading the project.

If you now change a.proj to –

<Project xmlns="https://schemas.microsoft.com/developer/msbuild/2003">

<Target Name="default">

<Message Text="Project: a.proj Target: default" />

<CallTarget Targets="Normal" UseResultsCache="true"/>

</Target>

<Target Name="Normal" Outputs="Someoutput from second target">

<Message Text="Project: a.proj Target: second" />

</Target>

</Project>

Building project b.proj using the command line “msbuild.exe b.proj /tv:3.5” will succeed and you will see the output of target Normal from project a being printed from project b.

[Author: Jay, MSBuild Software Engineer ]