How to: Build Incrementally
When you build a large project, it is important that previously built components that are still up-to-date are not rebuilt. If all targets are built every time, each build will take a long time to complete. To enable incremental builds (builds in which only those targets that have not been built before or targets that are out of date, are rebuilt), the Microsoft Build Engine (MSBuild) can compare the timestamps of the input files with the timestamps of the output files and determine whether to skip, build, or partially rebuild a target. However, there must be a one-to-one mapping between inputs and outputs. You can use transforms to enable targets to identify this direct mapping. For more information on transforms, see MSBuild Transforms.
A target can be built incrementally if the inputs and outputs are specified in the project file.
To specify inputs and outputs for a target
Use the Inputs and Outputs attributes of the Target element. For example:
<Target Name="Build" Inputs="@(CSFile)" Outputs="hello.exe">
MSBuild can compare the timestamps of the input files with the timestamps of the output files and determine whether to skip, build, or partially rebuild a target. In the following example, if any file in the @(CSFile) item collection is newer than the hello.exe file, MSBuild will run the target; otherwise it will be skipped:
<Target Name="Build" Inputs="@(CSFile)" Outputs="hello.exe"> <Csc Sources="@(CSFile)" OutputAssembly="hello.exe"/> </Target>
When inputs and outputs are specified in a target, either each output can map to only one input or there can be no direct mapping between the outputs and inputs. In the previous Csc Task, for example, the output, hello.exe, cannot be mapped to any single input – it depends on all of them.
A target in which there is no direct mapping between the inputs and outputs will always build more often than a target in which each output can map to only one input because MSBuild cannot determine which outputs need to be rebuilt if some of the inputs have changed.
Tasks in which you can identify a direct mapping between the outputs and inputs, such as the LC Task, are most suitable for incremental builds, unlike tasks such as Csc and Vbc, which produce one output assembly from a number of inputs.
The following example uses a project that builds Help files for a hypothetical Help system. The project works by converting source .txt files into intermediate .content files, which then are combined with XML metadata files to produce the final .help file used by the Help system. The project uses the following hypothetical tasks:
GenerateContentFiles: Converts .txt files into .content files.
BuildHelp: Combines .content files and XML metadata files to build the final .help file.
The project uses transforms to create a one-to-one mapping between inputs and outputs in the GenerateContentFiles task. For more information, see MSBuild Transforms. Also, the Output element is set to automatically use the outputs from the GenerateContentFiles task as the inputs for the BuildHelp task.
This project file contains both the Convert and Build targets. The GenerateContentFiles and BuildHelp tasks are placed in the Convert and Build targets respectively so that each target can be built incrementally. By using the Output element, the outputs of the GenerateContentFiles task are placed in the ContentFile item collection, where they can be used as inputs for the BuildHelp task. Using the Output element in this way automatically provides the outputs from one task as the inputs for another task so that you do not have to list the individual items or item collections manually in each task.
Although the GenerateContentFiles target can build incrementally, all outputs from that target always are required as inputs for the BuildHelp target. MSBuild automatically provides all the outputs from one target as inputs for another target when you use the Output element.
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" > <ItemGroup> <TXTFile Include="*.txt"/> <XMLFile Include="\metadata\*.xml"/> </ItemGroup> <Target Name = "Convert" Inputs="@(TXTFile)" Outputs="@(TXTFile->'%(Filename).content')"> <GenerateContentFiles Sources = "@(TXTFile)"> <Output TaskParameter = "OutputContentFiles" ItemName = "ContentFiles"/> </GenerateContentFiles> </Target> <Target Name = "Build" DependsOnTargets = "Convert" Inputs="@(ContentFiles);@(XMLFiles)" Outputs="$(MSBuildProjectName).help"> <BuildHelp ContentFiles = "@(ContentFiles)" MetadataFiles = "@(XMLFile)" OutputFileName = "$(MSBuildProjectName).help"/> </Target> </Project>