Targets group tasks together in a particular order and allow sections of the build process to be called from the command line. Targets are often grouped into logical sections to allow for project file expansion and to increase readability. For example, one target may delete all files in the output directory to prepare for the build, while another compiles the inputs for the project and places them in the empty directory.
Declaring Targets in the Project File
Targets are declared in the project file with the Target element. For example, the following XML creates a target named Compile, which then calls the Csc task with the Compile item collection.
<Target Name="Compile> <Csc Sources="@(Compile)" /> </Target>
Targets can also use the Condition attribute. If the specified condition evaluates to false, the target will not run, and the MSBuild engine will not run the targets specified in the DependsOnTargets attribute. For more information on conditions, see MSBuild Conditions.
In more advanced scenarios targets can describe relationships between each other and perform dependency analysis, which allows whole sections of the build process to be skipped if that target is up-to-date. You can declare the targets that must run before a specific target by using the DependsOnTargets attribute. When a target is run, the MSBuild engine will automatically run any targets listed in this attribute first. For more information, see How to: Build Incrementally.
A target will never run twice during a single build. Once run, a target is assumed to have completed its work and will not be run again, even if a subsequent target in the build depends on it.
Breaking up the project file this way allows for sections of the file to be changed without affecting others. For example, one way of building a project with resources is to place the GenerateResource and Csc tasks in the same target, for example:
<Target Name="Build"> <GenerateResource Sources="alpha.resx; beta.txt" <Output TaskParameter="OutputResources" ItemName="Resources"/> </GenerateResource> <Csc Sources="hello.cs" Resources="@(Resources)" OutputAssembly="hello.exe"/> </Target>
Using this approach, the project builds as required, but the target is becoming large and inflexible. If you later wanted to add other tasks to run between GenerateResource and Csc, putting them all in one target would make the project file very difficult to read. In addition, authoring such large targets with so many tasks makes it difficult to perform good incremental builds — builds in which only those targets that have not been built before or targets that are out of date are rebuilt. Large targets also prevent you from running targets to perform specific tasks. In the example above, there is no way to generate resources without compiling.
A better way of authoring a project file is to use multiple targets and explicitly express dependencies between them. This approach also gives you the ability to run any of the targets separately and perform a smaller set of tasks rather than running a long list of tasks in one target every time you build. In this example, each task is in a separate target and the DependsOnTargets attribute specifies that the Resources target must run before the Build target can run.
<Target Name="Resources"> <GenerateResource Sources="alpha.resx; beta.txt" <Output TaskParameter="OutputResources" ItemName="Resources"/> </GenerateResource> </Target> <Target Name="Build" DependsOnTargets="Resources"> <Csc Sources="hello.cs" Resources="@(Resources)" OutputAssembly="hello.exe"/> </Target>