peteris.rocks

Cross Platform Builds on Windows and Mono with MSBuild

Last updated on

This is a guide on how to create a MSBuild file that can be used to build your C#/.NET project in Visual Studio, without Visual Studio on Windows or with xbuild on mono in a single step.

Additionally, you can use NuGet packages and they will be automatically restored at build time.

There's also support for running unit tests.

Build file

If your solution is called Project.sln, name your build file as Project.Build.msbuildproj.

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <PropertyGroup>
    <SolutionDir>$(MSBuildThisFileDirectory)</SolutionDir>
    <Configuration Condition=" '$(Configuration)'=='' ">Release</Configuration>
    <NuGetExe Condition=" '$(NuGetExe)'=='' ">packages/nuget.exe</NuGetExe>
    <NuGetExeDir>packages/</NuGetExeDir>
    <NuGetDownloadAddress Condition=" '$(NuGetDownloadAddress)'=='' ">http://nuget.org/nuget.exe</NuGetDownloadAddress>
    <NuGetCommand Condition=" '$(NuGetCommand)'=='' AND '$(OS)' == 'Windows_NT'">"$(NuGetExe)"</NuGetCommand>
    <NuGetCommand Condition=" '$(NuGetCommand)'=='' AND '$(OS)' != 'Windows_NT' ">mono --runtime=v4.0.30319 "$(NuGetExe)"</NuGetCommand>
    <Properties>Configuration=$(Configuration);SolutionDir=$(SolutionDir)</Properties>
  </PropertyGroup>

  <ItemGroup>
    <Solution Include="*.sln" />
    <TestProjects Include="**\*.Tests.csproj" />
  </ItemGroup>

  <UsingTask TaskName="DownloadFile" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll" Condition=" '$(OS)' == 'Windows_NT' ">
    <ParameterGroup>
      <Address ParameterType="System.String" Required="true"/>
      <OutputFilename ParameterType="System.String" Required="true" />
    </ParameterGroup>
    <Task>
      <Reference Include="System" />
      <Code Type="Fragment" Language="cs">
        <![CDATA[
            new System.Net.WebClient().DownloadFile(Address, OutputFilename);
        ]]>
      </Code>
    </Task>
  </UsingTask>

  <Target Name="DownloadNuGet">
    <MakeDir Directories="$(NuGetExeDir)" Condition=" !Exists('$(NuGetExeDir)') " />
    <DownloadFile Address="$(NuGetDownloadAddress)" OutputFilename="$(NuGetExe)" Condition=" '$(OS)' == 'Windows_NT' AND !Exists('$(NuGetExe)')" />
    <Exec Command="wget $(NuGetDownloadAddress) -O $(NuGetExe)" Condition=" '$(OS)' != 'Windows_NT' AND !Exists('$(NuGetExe)') " />
  </Target>

  <Target Name="RestorePackages" DependsOnTargets="DownloadNuGet">
    <Exec Command="$(NuGetCommand) restore &quot;%(Solution.Identity)&quot;" />
  </Target>

  <Target Name="Clean">
    <MSBuild Targets="Clean" Projects="@(Solution)" Properties="$(Properties)" />
  </Target>

  <Target Name="Build" DependsOnTargets="RestorePackages">
    <MSBuild Targets="Build" Projects="@(Solution)" Properties="$(Properties)" />
  </Target>

  <Target Name="Rebuild" DependsOnTargets="RestorePackages">
    <MSBuild Targets="Rebuild" Projects="@(Solution)" Properties="$(Properties)" />
  </Target>

  <Target Name="RunTests" DependsOnTargets="Build">
    <MSBuild Targets="RunTests" Projects="@(TestProjects)" Properties="$(Properties)" />
  </Target>

</Project>

This will build your solutions (*.sln) restoring NuGet packages beforehand (also downloading nuget.exe if necessary using .NET on Windows and wget on Linux). You can also clean, rebuild or just restore packages. If you have any projects with .Tests in the name, there's target for running tests.

Building

On Windows with MSBuild

By default MSBuild.exe is located at C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe and it's not in your PATH by default.

msbuild Project.Build.msbuildproj

On Linux with mono and xbuild

You will need to have the latest mono and xbuild packages installed.

xbuild Project.Build.msbuildproj

Visual Studio

You don't need Project.Build.msbuildproj in Visual Studio since it's just a wrapper. Newest versions of Visual Studio can automatically restore NuGet packages. But you can launch it from Visual Studio as an External Tool. Go to Tools -> External Tools and add MSBuild.exe with Project.Build.msbuildproj as a parameter. You can then launch it from the

Parameters

Parameters for msbuild and xbuild are the same.

Clean your project

msbuild Project.Build.msbuildproj /t:Clean

Build in Debug configuration

msbuild Project.Build.msbuildproj /p:Configuration=Debug

Restore NuGet packages only

msbuild Project.Build.msbuildproj /t:RestorePackages

Override variables

msbuild Project.Build.msbuildproj /p:NuGetExe=".nuget/nuget.exe"