Search notes:

MS Build project file

MS Build uses project files to describe building instructions.
Additionally, it also allows to describe build-rules that then can be reused on various targets.
These project files are XML files and similar in nature to Apache Ant or Nant.
The MS Build project file format is used by Visual Studio to store information about projects it manages.
Project files can be evaluated (or run) on the command line (cmd.exe, PowerShell) with MSbuild.exe.

Most simple project file

A project file (with suffix .csproj) needs at least a <Project> and a <Target> tag with a Name attribute.
Thus the (possibly) most simple project file becomes
<Project>
   <Target Name="xyz" />
</Project>
Github repository about-MSBuild, path: /project-files/most-simple/file.csproj
Apparently, the <Project> tag can be augmented with a namespace:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

Compiling a C-Sharp file

The <Csc> tag as a child of <Target> compiles the file(s) indicated in its Sources attribute with a C# compiler.
In the following example, the source file prog.cs will be compiled:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <Target Name="Compile a file">
       <Csc Sources="prog.cs"/>
   </Target>

</Project>
Github repository about-MSBuild, path: /project-files/compile-a-file/compile.csproj

Specifying source files (Item types / Items / <ItemGroup>)

An <ItemGroup> contains items (that typically represent files to be compiled etc.). The value of these items is later referred to with the @(item-name) syntax.
The following *.csproj file compiles src_1.cs and src_2.cs. Note: the individual source file names need to be separated with semicolons (;).
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <ItemGroup>
      <source-files Include="src_1.cs;src_2.cs" />
  </ItemGroup>

  <Target Name="Compile sources">
      <Csc Sources="@(source-files)"/>
  </Target>

</Project>
Github repository about-MSBuild, path: /project-files/variables/proj.csproj
Alternatively, each file can be specified in its own tag (that share the same name):
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <ItemGroup>
       <source-files Include="src_1.cs" />
       <source-files Include="src_2.cs" />
  </ItemGroup>

   <Target Name="Compile sources">
       <Csc Sources="@(source-files)"/>
   </Target>

</Project>
Github repository about-MSBuild, path: /project-files/ItemGroup/same-named-items/proj.csproj
It also possible to use wildcards to specify the source files:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <ItemGroup>
      <source-files Include="*.cs" />
  </ItemGroup>

   <Target Name="Compile sources">
      <Csc Sources="@(source-files)"/>
   </Target>

</Project>
Github repository about-MSBuild, path: /project-files/ItemGroup/wildcards/proj.csproj
Possible wildcards are: *, ?, /**/*.cs etc.

Printing messages

The <Message> task allows to print information:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <Target Name="Say something"   >
       <Message Text="Hello world."                                         />

       <Message Text="some text with low importance"    Importance="low"    /> <!-- not printed by default -->
       <Message Text="some text with normal importance" Importance="normal" />
       <Message Text="some text with high importance"   Importance="high"   />
   </Target>

</Project>
Github repository about-MSBuild, path: /project-files/tasks/Message/say-things.csproj
When executed, it prints the messages as shown in the image balow.
Note, that by default, messages with low importance are not printed. Messages with high importance are rendered slightly brighter than normally important messages:

Targets

A <Target> allows to bundle multiple tasks. A project file might contain multiple targets. When running MS Build, it determines which targets it invokes.
The following project file defines three targets. By default, (only) the first target es executed:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <Target Name="tgt_1">
       <Message Text="Target one is being executed" />
   </Target>

   <Target Name="tgt_2">
       <Message Text="Target two is being executed" />
   </Target>

   <Target Name="tgt_3">
       <Message Text="Target three is being executed" />
   </Target>

</Project>
Github repository about-MSBuild, path: /project-files/Target/simple/proj.csproj
However, msbuild.exe has the -t command line option that allows to execute another target:
P:\ath\to\project> msbuild
P:\ath\to\project> msbuild -t:tgt_2
P:\ath\to\project> msbuild -t:tgt_2 -t:tgt_1

Targets with dependencies

The DependsOnTargets attribute of the <Target> element allows to specifiy targets that need to be executed before the target with this attribute is executed. This allows to formulate dependency-rules in a project file.
In the following example, tgt_2 is dependent on tgt_1 while tgt_4 is depdent on tgt_3 and tgt_2. Because the dependency rules are transitive, tgt_4 is also dependent on tgt_1.
In addtion, the following project file uses the DefaultTargets attribute of <Project> to control which target(s) need to be built in absence of a -t flag:
<Project
   DefaultTargets="tgt_2"
   xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
>

   <Target Name="tgt_1">
       <Message Text="Target one is being executed" />
   </Target>

   <Target Name="tgt_2" DependsOnTargets="tgt_1">
       <Message Text="Target two is being executed" />
   </Target>

   <Target Name="tgt_3">
       <Message Text="Target three is being executed" />
   </Target>

   <Target Name="tgt_4" DependsOnTargets="tgt_3;tgt_2">
       <Message Text="Target four is being executed" />
   </Target>

</Project>

Properties / <PropertyGroup>

The <PropertyGroup> tag contains properties. A property is simply a key/value pair. The tag-names within <PropertyGroup> correspond to the proporty names, their data to the property values.
The value of a property is referred to with the $(propertyName) syntax.
The following <PropertyGroup> defines a property named BuildDir whose value is bin:
<PropertyGroup>
    <BuildDir>bin</BuildDir>
</PropertyGroup>

Conditional property values

It's possible to put a condition on a property. The property only is assigned the respective value if the condition is true.
In the following example, the value of BuildDir is set to Debug\bin if the value of the property Configuration is equal to Debug:
<PropertyGroup>
    <BuildDir Condition=" '$(Configuration)' == 'Debug' ">debug\bin</BuildDir>
</PropertyGroup>

Reserved and well known properties

MSBuild defines some reserved and well known propertes. Some of these properties that I like are listed in the following project file:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

   <Target Name="Print some default properties">
       <Message Text="MSBuildBinPath          = $(MSBuildBinPath)"          />
       <Message Text="MSBuildExtensionsPath32 = $(MSBuildExtensionsPath32)" />
       <Message Text="MSBuildExtensionsPath64 = $(MSBuildExtensionsPath64)" />
       <Message Text="MSBuildVersion          = $(MSBuildVersion)"          />
       <Message Text="MSBuildProjectFullPath  = $(MSBuildProjectFullPath)"  />
       <Message Text="MSBuildProjectDirectory = $(MSBuildProjectDirectory)" />
       <Message Text="MSBuildProjectName      = $(MSBuildProjectName)"      />
       <Message Text="MSBuildProjectExtension = $(MSBuildProjectExtension)" />
   </Target>

</Project>
When executed, it might print something like
  MSBuildBinPath          = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin
  MSBuildExtensionsPath32 = C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild
  MSBuildExtensionsPath64 = C:\Program Files\MSBuild
  MSBuildVersion          = 16.3.2
  MSBuildProjectFullPath  = P:\ath\to\project\proj.csproj
  MSBuildProjectDirectory = P:\ath\to\project
  MSBuildProjectName      = proj
  MSBuildProjectExtension = .csproj
A complete list of such properties is on Microsoft's documentation page.

Specifying property-values when the build is invoked

The command line option -property:name=value allows to specify property values on the command line when MSBuild is invoked.

Tasks and Targets

Tasks to be executed appear as child-tags in a <Target> tag:
<Target Name="…">
  <Csc Sources="@(src)" />
  <AnotherTaskName …    />
</Target>
Typically, a task implements the ITask interface.

MS Build SDKs

MS Build 15.0 introduced an SDK-style(?) XML format: the SDK used is indicated with the value of the Sdk attribute of the <Project> tag:
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
  …
</Project>
Apparently, with such an Sdk, MS build, creates an in-memory(?) version of the .csproj where it implicitly places two <Import> tags into the .csproj file and removes the Sdk attribute from the <Project> tag.
This in-memory version then becomes something like
<Project DefaultTargets="Build">
  <Import Project="Sdk.props"   Sdk="Microsoft.NET.Sdk.WindowsDesktop">
   …
  <Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk.WindowsDesktop">
</Project>
These two <Import> statements reference two files that are found below the directory C:\Program Files\dotnet\sdk\SDK-VERSION\Sdks\SDK.NAME\Sdk: Sdk.props and Sdk.targets.
It is the content of these two files that is imported in the respective place.
Of course, the imported text also contains <Import> tags so that it becomes quite hard to track what is actually produced.
Luckily, msbuild.exe allows to show the content of the preprocessed project file with the -pp option which names the file to be written:
C:\> msbuild -pp:preprocessed.xml
The available SDKs for .NET Core seem to be:

Misc

.NET Core used project.json instead of *.csproj. With Visual Studio 2017, the *.csproj is (also?) supported.

Index