MSBuild is Microsoft’s build system for Visual Studio. Visual Studio project files (*.csproj, *.vbproj) do not only describe the project structure, but are also build scripts for MSBuild. They’re executed when you click the run button in the IDE, but they can also be called via the MSBuild command line utility.
> MSBuild.exe Project.csproj
These project files / build scripts are in XML format, comparable to Ant scripts in the Java land.
Edit project files
You can edit these files in any text editor, of course. But if you want to edit them within Visual Studio, you have to unload the project first:
- Right click on the project in the Solution Explorer -> Unload Project
- Right click on the project in the Solution Explorer -> Edit MyProject.csproj
After you’re done editing you can reload the project again via the context menu.
Targets and tasks
The concepts of MSBuild are comparable to many other build systems: a build script contains a set of named targets, and each target consists of a sequence of task calls.
A project can have one or more default targets, referenced by the DefaultTargets attribute of the Project root element:
<Project DefaultTargets="Build" ...>
Multiple targets can be separated by semicolons.
Targets are declared via Target tags containig the task calls:
<Target Name="Clean"> <Delete Files="xyz.tmp" /> ... </Target>
MSBuild comes with a set of common tasks, such as Message, Copy, Delete, Exec, …
If you need more tasks you should have a look at these community provided task collections:
Both are available as NuGet packages and can be checked into your code repository alongside the project for self-containment. For the Extension Pack you have to set the ExtensionTasksPath property correctly before importing the tasks, for example:
<PropertyGroup> <ExtensionTasksPath Condition="'$(ExtensionTasksPath)' == ''">$(MSBuildProjectDirectory)\packages\MSBuild.Extension.Pack.1.5.0\tools\net40</ExtensionTasksPath> </PropertyGroup> <Import Project="$(ExtensionTasksPath)MSBuild.ExtensionPack.tasks">
Properties are defined within PropertyGroup tags, containing one or many property tags. The names of these tags are the property names and the tag contents are the property values. Properties are referenced via $(PropertyName). A property definition can have an optional Condition attribute, which determines whether a property should be set or not. The condition ‘$(PropertyName)’ == ”, for example, checks if a property is not yet set.
Here’s an example build target that uses the ZIP compression task from the Extension Pack and some properties to create a ZIP file artifact from the build results:
<Target Name="AfterBuild"> <MSBuild.ExtensionPack.Compression.Zip TaskAction="Create" CompressPath="$(OutputPath)" ZipFileName="bin\$(ProjectName)-$(BuildNumber).zip" /> </Target>
You can also set property values from the outside via the MSBuild call:
> MSBuild.exe /t:Build /p:Configuration=Release;BuildNumber=1234 Project.csproj
- The /t switch determines which targets to run. Multiple targets can be separated by semicolons.
- The /p switch sets properties in the form of PropertyName=value, also separated by semicolons.
This way you can pass environment variables like $BUILD_NUMBER from your Continuous Integration system (e.g. Jenkins) to your build script:
> MSBuild.exe /t:Build /p:Configuration=Release;BuildNumber=$BUILD_NUMBER Project.csproj
Now you could use the MSBuild.ExtensionPack.Framework.AssemblyInfo task to write the $(BuildNumber) property into your AssemblyInfo file.