A build is a run of targets. A target is a named list of tasks (and of property and item changes); a task is one step, such as copying files or running the compiler, implemented by a .NET class. MSBuild first reads the whole project and its imports (evaluation: properties, items and imports, in file order), then runs the targets that were asked for (execution), in an order the targets’ attributes decide.
How targets are ordered
The targets to build are those named on the command line (-t:A;B), or the
project’s DefaultTargets, or the first target. Targets in
InitialTargets (of the project and of every import) always run first. For each target
MSBuild then:
- checks its
Condition; when it is false, the target is skipped and so are itsDependsOnTargets; - runs the targets in
DependsOnTargets, left to right, each at most once in the whole build; - runs the targets whose
BeforeTargetsnames it; - runs its own tasks, in order;
- runs the targets whose
AfterTargetsnames it.
<Project DefaultTargets="A" InitialTargets="Init">
<Target Name="Init"><Message Text="Init" /></Target>
<Target Name="A" DependsOnTargets="B;C"><Message Text="A" /></Target>
<Target Name="B"><Message Text="B" /></Target>
<Target Name="C"><Message Text="C" /></Target>
<Target Name="D" BeforeTargets="A"><Message Text="D (before A)" /></Target>
<Target Name="E" AfterTargets="A"><Message Text="E (after A)" /></Target>
</Project>
A target runs once. A task that fails stops its target and the build, unless
ContinueOnError turns the failure into a warning
(true or WarnAndContinue) or an error that lets the build go
on (ErrorAndContinue); ErrorAndStop or false is the
default. After a failure the OnError elements of the target run their
ExecuteTargets; OnError must come after every task.
Incremental builds
A target with Inputs and Outputs is skipped when every
output is newer than every input. MSBuild then logs that the target was skipped
because its outputs are up to date. When only some outputs are out of date, MSBuild can
run the target for just those (partial builds) if the two lists are
transformations of one another, which is why Inputs="@(Compile)" pairs with
Outputs="@(Compile->'$(IntermediateOutputPath)%(Filename).obj')".
A target without them always runs.
Returns says which items the target hands to a caller (an
MSBuild task running this project); when it is missing, the
Outputs are returned.
Inside a target
| Child | Does |
|---|---|
| A task element | Runs the task named by the element: <Copy SourceFiles="a" DestinationFolder="b" />. Attributes are the task’s parameters; Condition, ContinueOnError, Architecture and Runtime are MSBuild’s. |
Output (inside a task) | Stores an output parameter of the task: <Output TaskParameter="CopiedFiles" ItemName="Copied" /> or PropertyName. Exactly one of the two names is required. |
PropertyGroup, ItemGroup | Sets properties and adds or removes items while the target runs (their effect is not visible to evaluation, and Update and Remove work on the item list as it stands then). |
OnError | The targets to run after a failure; last in the target. |
Well-known targets
The common targets, imported by every .NET project, define these. A project hooks one with
BeforeTargets or AfterTargets, or replaces a …DependsOn
property.
| Target | Does |
|---|---|
Build | Compiles the project and what it depends on. |
Rebuild | Clean, then Build. |
Clean | Deletes the files the build made. |
Restore | Restores the NuGet packages (a separate evaluation, which is why package changes need a restore before a build sees them). |
Pack | Makes a NuGet package. |
Publish | Builds, then copies the program and what it needs to a publish folder. |
Compile, CoreCompile | Compiles the sources; CoreCompile runs the compiler. |
CoreBuild | The body of Build. |
BeforeBuild, AfterBuild | Empty targets for a project to hook (older projects override them). |
BeforeCompile, AfterCompile, BeforeClean, AfterClean, BeforeRebuild, AfterRebuild, BeforePublish, AfterPublish | Empty hooks around the targets they name. |
PrepareForBuild | Makes the output folders and checks the platform settings. |
ResolveReferences | Finds every reference: assemblies, packages, other projects. |
ResolveProjectReferences | Builds the referenced projects and finds their outputs. |
ResolveAssemblyReferences | Resolves assembly references to files (runs the ResolveAssemblyReference task). |
ResolvePackageAssets | Reads the NuGet assets file written by restore. |
PrepareResources | Prepares resource files for the compiler. |
CopyFilesToOutputDirectory | Copies the outputs and the files marked to copy into the output folder. |
IncrementalClean | Deletes files an earlier build made that this build did not. |
GetTargetPath, GetCopyToOutputDirectoryItems | Return the output path and the items to copy; they are what a referencing project asks for. |
GenerateBuildDependencyFile | Writes the .deps.json file. |
Run, VSTest, Test | Run the program (dotnet run) and the tests (dotnet test). |
The …DependsOn properties (BuildDependsOn,
CoreBuildDependsOn, CompileDependsOn, CleanDependsOn,
RebuildDependsOn, PublishDependsOn,
PrepareForBuildDependsOn, ResolveReferencesDependsOn) hold the
lists of targets a target depends on; a project adds to one
(<BuildDependsOn>MyStep;$(BuildDependsOn)</BuildDependsOn>).
Built-in tasks
These ship with MSBuild and are declared in Microsoft.Common.tasks and
the files it names. The parameters of each are in Microsoft’s task reference.
| Task | Does |
|---|---|
Copy, Move, Delete, Touch | Copy, move, delete files and set their times. |
MakeDir, RemoveDir | Create and delete folders. |
Exec | Runs a command in the shell. |
Message, Warning, Error | Log a message, a warning, an error (which fails the build). |
ReadLinesFromFile, WriteLinesToFile | Read lines into items, write items as lines. |
MSBuild | Builds other projects. |
CallTarget | Runs targets of this project. |
CreateItem, CreateProperty | Older ways to make items and properties inside a target (now the ItemGroup and PropertyGroup elements). |
Csc, Vbc | The C# and Visual Basic compilers (the F# compiler’s task, Fsc, comes with the F# SDK). |
ResolveAssemblyReference, ResolveComReference, ResolveNativeReference, ResolveNonMSBuildProjectOutput, ResolveSDKReference, ResolveKeySource, ResolveManifestFiles | Resolve the different kinds of reference to files. |
GenerateResource, AL, LC, SGen, TlbImp, AxImp, RegisterAssembly, UnregisterAssembly | Resource, assembly-linker, licence, serialisation, COM and registration tools. |
AssignCulture, AssignLinkMetadata, AssignProjectConfiguration, AssignTargetPath, CreateCSharpManifestResourceName, CreateVisualBasicManifestResourceName, FindAppConfigFile | Set metadata on items from their names and places. |
FindInList, FindUnderPath, RemoveDuplicates, CombinePath, ConvertToAbsolutePath | Search and normalise lists and paths. |
GetFileHash, VerifyFileHash, Hash | Hash files and text, and check a hash. |
DownloadFile, Unzip, ZipDirectory | Download and archive files. |
XmlPeek, XmlPoke, XslTransformation | Read, change and transform XML files. |
WriteCodeFragment | Writes a source file of attributes (how assembly information is generated). |
GetAssemblyIdentity, GetFrameworkPath, GetFrameworkSdkPath, GetReferenceAssemblyPaths, GetInstalledSDKLocations, FormatUrl, FormatVersion, RequiresFramework35SP1Assembly | Find frameworks and SDKs and format their names. |
GenerateApplicationManifest, GenerateDeploymentManifest, GenerateBootstrapper, GenerateLauncher, GenerateTrustInfo, SignFile, UpdateManifest | ClickOnce manifests and signing. |
Telemetry, AspNetCompiler, VCBuild | Telemetry events; the old web-site precompiler; the old C++ build. |
The native (C++) build and the Windows application packaging targets add many more
(CL, LIB, MIDL, RC, Mt,
BSCMake, SetEnv, GenerateAppxPackageRecipe,
MakeAppxPack and others). A task that is not in these lists is declared by a
UsingTask in an SDK or a package.
UsingTask and inline tasks
UsingTask says where a task is implemented. Give TaskName and
exactly one of AssemblyName (an assembly by name) or AssemblyFile
(a path), or, for a task defined in the file, a TaskFactory.
Architecture and Runtime choose the task host; Override
makes the declaration replace another with the same name.
<UsingTask TaskName="Stamp" TaskFactory="RoslynCodeTaskFactory"
AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll">
<ParameterGroup>
<Path ParameterType="System.String" Required="true" />
<Text ParameterType="System.String" Output="true" />
</ParameterGroup>
<Task>
<Code Type="Fragment" Language="cs">
Text = System.IO.File.ReadAllText(Path).Trim();
</Code>
</Task>
</UsingTask>
<Target Name="ShowStamp">
<Stamp Path="stamp.txt"><Output TaskParameter="Text" PropertyName="StampText" /></Stamp>
<Message Text="$(StampText)" />
</Target>
ParameterGroup declares its parameters (a type, whether it is required, whether it is an output), Task holds the code the factory compiles.The task factories are RoslynCodeTaskFactory (C# or Visual Basic compiled
with Roslyn, the current one), CodeTaskFactory (the older .NET Framework one),
XamlTaskFactory (a task described by XAML) and the default assembly
factory, used when TaskFactory is left out.
In the explorer
A project’s Targets tab lists every target with when it runs (dependencies and
hooks), the tasks it calls and its condition; below it, every task call with its
parameters and outputs, and every UsingTask.
Not described
Known, not yet covered
- Reference: the parameters of each task (Microsoft’s task reference lists them), and the targets and tasks that individual SDKs add.
Sources
Microsoft Learn, MSBuild
targets, tasks,
task
reference and inline
tasks; the names of the tasks and targets from Microsoft.Build.CommonTypes.xsd
and from the .NET SDK’s own Microsoft.Common.CurrentVersion.targets. The
ordering and failure behaviour were checked by running dotnet msbuild.