Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save WeihanLi/7a41c217d24ca8c8d43197124f34379b to your computer and use it in GitHub Desktop.
Save WeihanLi/7a41c217d24ca8c8d43197124f34379b to your computer and use it in GitHub Desktop.
Visual Studio & MSBuild manual. Keywords: msbuild visual studio visualstudio

VISUAL STUDIO & MSBUILD MANUAL

Table of contents

Install

Where the fuck is MSBuild.exe?

MSBuild is usually shipped with .NET or Visual Studio. It's location may vary from users to users (fuck you Microsoft) and unfortunately, you have to figure that out yourself by googling the shit out of it. Here are a few location where you might be lucky to find it:

  • C:\Windows\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe
  • C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\MSBuild\15.0\Bin

How the fuck do I add msbuild to my freaking PATH?

Once you'ev found the path to MSBuild.exe, you need to add its path to the PATH environment variable so that you can use it in your terminal (the "terminal", the forbidden word for Microsoft idiots). Though it is in theory possible to set that PATH in the terminal with commands such as SETX or SET, there might a myriad of reasons where this would not work. The safest way to do it is the stupid Windows manual way:

  1. Open the control panel.
  2. Click on System and Security and then on System.
  3. In the left pane, click on Advanced system settings.
  4. At the very bottom of the pop up, click on Environment Variables
  5. Edit the Path variable and append the folder's path that contains the MSBuild.exe to it (e.g., ;C:\Windows\Microsoft.NET\Framework64\v4.0.30319\. Notice the use of ; to separate each path).

Getting started

Hello world CSPROJ file

MSBuild uses .csproj file to figure out what to do. The key concepts to grasps are:

  • Target: A target is the XML block that defines the series of steps to follow.
  • PropertyGroup: The property group are a way to define variables as well as conditional variables. Each property group defines one of more variables. They are executed sequentially to enable conditions (more about this later in the Configuring different MSBuild workflows with the CSPROJ and the PropertyGroup section).

Let's have a look to this following example:

my_proj.csproj

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
	<PropertyGroup>
		<ProjectDir>Hello</ProjectDir>
	</PropertyGroup>
	<!-- All configuration necessary to build the project -->
	<Target Name="HelloWorld">
		<Message Text="Hello"></Message>
		<Message Text="World"></Message>
		<Message Text="ProjectDir: $(ProjectDir)"></Message>
	</Target>
	<Target Name="BeforeBuild">
		<Message Text="Say: $(before_custom_msg)"></Message>
	</Target>
	<Target Name="AfterBuild">
		<Message Text="Say: $(after_custom_msg)"></Message>
	</Target>
</Project>

Let's run:

msbuild my_proj.csproj -t:HelloWorld 

This should return something similar to:

Microsoft (R) Build Engine version 4.6.1055.0
[Microsoft .NET Framework, version 4.0.30319.42000]
Copyright (C) Microsoft Corporation. All rights reserved.

Build started 6/09/2019 3:42:31 PM.
Project "C:\Documents\projects\temp\msbuild\my_proj.csproj" on node 1 (HelloWorld target(s)).
HelloWorld:
  Hello
  World
  ProjectDir: Hello
Done Building Project "C:\Documents\projects\temp\msbuild\my_proj.csproj" (HelloWorld target(s)).


Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:00.06

As you can see, we hard-coded the text Hello and World and we used a variable ProjectDir set to Hello in the property group.

It is possible to overide the ProjectDir variable as follow:

msbuild my_proj.csproj -t:HelloWorld -p:ProjectDir="Ola Mr"

Configuring different MSBuild workflows with the CSPROJ and the PropertyGroup

The following example shows the use of the Condition directive to set the Environment based on the value of the ProjectDir.

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
	<PropertyGroup>
		<ProjectDir>Hello</ProjectDir>
	</PropertyGroup>
	<PropertyGroup  Condition="$(ProjectDir) == 'Hello' ">
		<Environment>Prod</Environment>
	</PropertyGroup>
	<PropertyGroup  Condition="$(ProjectDir) == 'Ola Mr' ">
		<Environment>Dev</Environment>
	</PropertyGroup>
	<!-- All configuration necessary to build the project -->
	<Target Name="HelloWorld">
		<Message Text="Hello"></Message>
		<Message Text="World"></Message>
		<Message Text="ProjectDir: $(ProjectDir)"></Message>
		<Message Text="Environment: $(Environment)"></Message>
	</Target>
	<Target Name="BeforeBuild">
		<Message Text="Say: $(before_custom_msg)"></Message>
	</Target>
	<Target Name="AfterBuild">
		<Message Text="Say: $(after_custom_msg)"></Message>
	</Target>
</Project>

How to

How to check the .NET version?

msbuild -version

How to package your project?

msbuild your_project.csproj -t:Package -p:Configuration=Release -p:_PackageTempDir=C:\package\your_project -p:PackageLocation=C:\package_zip\your_project.zip

This command:

  1. Build your project using a specific configuration (-p:Configuration=Release).
  2. Package it (-t:Package) under C:\package\your_project (-p:_PackageTempDir=C:\package\your_project).
  3. Zip the package to a specific location (-p:PackageLocation=C:\package_zip\your_project.zip).

WARNING: The zip folder structure mimics the path defined under _PackageTempDir (in our example, the folder structure will be Content\C_C\package\your_project). There is no straighforward way to fix this.

How to check the msbuild version?

Refer to script at How to check the msbuild version?

How to restore packages?

This has actually nothing to do with msbuild, but that's such a common requirement that we decided to document it. It assumes that you have the nuget.exe under source control in your project.

%cd%\.nuget\NuGet.exe restore %cd%\Go.App.Cordova.sln

Annexes

Macros

Visual Studio uses certain reserved names for its csproj variables. The list below is an exhaustive list. Those reserved variable names are referred as macro.

Macro Description
$(Configuration) The name of the current project configuration, for example, "Debug".
$(DevEnvDir) The installation directory of Visual Studio (defined as drive + path); includes the trailing backslash ''.
$(FrameworkDir) The directory into which the .NET Framework was installed.
$(FrameworkSDKDir) The directory into which you installed the .NET Framework. The .NET Framework could have been installed as part of Visual Studio or separately.
$(FrameworkVersion) The version of the .NET Framework used by Visual Studio. Combined with $(FrameworkDir), the full path to the version of the .NET Framework use by Visual Studio.
$(FxCopDir) The path to the fxcop.cmd file. The fxcop.cmd file is not installed with all Visual Studio editions.
$(IntDir) Path to the directory specified for intermediate files. If it's a relative path, intermediate files go to this path appended to the project directory. This path should have a trailing slash. It resolves to the value for the Intermediate Directory property. Don't use $(OutDir) to define this property.
$(OutDir) Path to the output file directory. If it's a relative path, output files go to this path appended to the project directory. This path should have a trailing slash. It resolves to the value for the Output Directory property. Don't use $(IntDir) to define this property.
$(Platform) The name of current project platform, for example, "Win32".
$(PlatformShortName) The short name of current architecture, for example, "x86" or "x64".
$(ProjectDir) The directory of the project (defined as drive + path); includes the trailing backslash ''.
$(ProjectExt) The file extension of the project. It includes the '.' before the file extension.
$(ProjectFileName) The file name of the project (defined as base name + file extension).
$(ProjectName) The base name of the project.
$(ProjectPath) The absolute path name of the project (defined as drive + path + base name + file extension).
$(PublishDir) The output location for the publish target; includes the trailing backslash ''. Defaults to the $(OutDir)app.publish\ folder.
$(RemoteMachine) Set to the value of the Remote Machine property on the Debug property page. See Changing Project Settings for a C/C++ Debug Configuration for more information.
$(RootNameSpace) The namespace, if any, containing the application.
$(SolutionDir) The directory of the solution (defined as drive + path); includes the trailing backslash ''. Defined only when building a solution in the IDE.
$(SolutionExt) The file extension of the solution. It includes the '.' before the file extension. Defined only when building a solution in the IDE.
$(SolutionFileName) The file name of the solution (defined as base name + file extension). Defined only when building a solution in the IDE.
$(SolutionName) The base name of the solution. Defined only when building a solution in the IDE.
$(SolutionPath) The absolute path name of the solution (defined as drive + path + base name + file extension). Defined only when building a solution in the IDE.
$(TargetDir) The directory of the primary output file for the build (defined as drive + path); includes the trailing backslash ''.
$(TargetExt) The file extension of the primary output file for the build. It includes the '.' before the file extension.
$(TargetFileName) The file name of the primary output file for the build (defined as base name + file extension).
$(TargetName) The base name of the primary output file for the build.
$(TargetPath) The absolute path name of the primary output file for the build (defined as drive + path + base name + file extension).
$(VCInstallDir) The directory that contains the C++ content of your Visual Studio installation. This property contains the version of the targeted Microsoft C++ (MSVC) toolset, which might be different that the host Visual Studio. For example, when building with $(PlatformToolset) = v140, $(VCInstallDir) contains the path to the Visual Studio 2015 installation.
$(VSInstallDir) The directory into which you installed Visual Studio. This property contains the version of the targeted Visual Studio toolset, which might be different that the host Visual Studio. For example, when building with $(PlatformToolset) = v110, $(VSInstallDir) contains the path to the Visual Studio 2012 installation.
$(WebDeployPath) The relative path from the web deployment root to where the project outputs belong. Returns the same value as RelativePath.
$(WebDeployRoot) The absolute path to the location of . For example, c:\inetpub\wwwroot.

Scripts

How to check the msbuild version?

@echo off
setlocal enabledelayedexpansion

call :check_dot_net 4.5
if !errorlevel! neq 0 exit /b !errorlevel!

endlocal

:: Example: call :check_dot_net 4.6
:check_dot_net
setlocal enabledelayedexpansion

set msbuild="%cd%\tools\msbuild.exe"
set required_dot_net_version=%1

set dot_net_version_ok=false
for /f %%x in ('%msbuild% -version') do (
	set v=%%x
	if "!v:~0,3!" == "!required_dot_net_version!" set dot_net_version_ok=true
)

if !dot_net_version_ok! == false echo ERROR - Invalid .NET version (expect !required_dot_net_version!). & endlocal & exit /b 1

endlocal
exit /b 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment