*.csproj/*.vbprojなどのファイル(プロジェクトファイル)は、ビルドの設定と動作を定義するためのファイルで、.NETのビルドエンジンMSBuildによって処理されるXML形式のファイルです。

プロジェクトファイルはProject要素をルート要素として、プロパティアイテムターゲット・タスク条件などを表すXML要素・属性から構成されます。 ここではそれらの基本的な要素や、その背景となるMSBuildの概念など、MSBuildプロジェクトファイルに共通する事項について解説します。

また、プロジェクトファイルを編集・拡張する際に必要となる、プロジェクトファイルで使用されるプロパティとアイテムについて解説します。 あわせて、コマンドラインインターフェイスであるdotnetコマンド(.NET CLI)およびmsbuildコマンドについても必要に応じて触れています。

ここでは、SDKスタイルのプロジェクトあるいは.NET Core形式と呼ばれる、.NET Core/.NET 5以降で用いられる形式のプロジェクトファイル(以下.NET形式)を中心に扱います。

.NET Frameworkで用いられる形式のプロジェクトファイル(以下.NET Framework形式)については、基本的な要素と概念を含むほとんどの部分は.NET形式のものと共通しますが、一部のプロジェクト設定(プロパティやアイテム)は.NET Framework形式では使用できないもの・当てはまらないものもあります。

プロジェクトファイルの基本事項とMSBuildの概念

プロジェクトファイルはXMLで記述されるファイル形式です。 プロジェクトファイルはフレームワークによって2種類の定義があり、一つは<Project Sdk="...">で始まる.NET形式のプロジェクトファイル(ドキュメントではSDKスタイルあるいは.NET Core形式と記載されている)と、もう一つは<Project ToolsVersion="...">で始まる.NET Framework形式の2種類が存在します。

.NET Framework形式では多くの指定値を明示的に記述する必要があるため必要最低限でも記述量が多くなる一方、.NET形式ではよく使われる指定値はデフォルト値として定義されているため、比較すると記述量が少なく大幅に簡略化されています。

.NET形式および.NET Framework形式のプロジェクトファイルは、どちらもビルドエンジンMSBuildによって解析・処理・実行されるファイル形式であるMSBuildプロジェクトファイルをベースとする形式です。 そのため、初期値や定義済みの設定(プロパティやアイテム)、MSBuildのバージョンごとにサポートされる機能の違いを除けば、基本的な構造・動作・機能はどちらも共通しています。

MSBuildプロジェクトファイルは、単に設定値に基づくビルドを行うだけでなく、ビルド前後に設定値に基づく何らかの追加処理を行う、逆に何らかの処理の結果に基づいて設定値の決定などを行うことができます。 そのため、MSBuildプロジェクトファイルは単に設定値を羅列した設定ファイルではなく、データ定義とデータ処理の両方を行うことができるビルドスクリプトとして動作します。

またMSBuildプロジェクトファイルは、何らかの成果物の生成(コンパイル)を目的としたビルドスクリプトとしてだけでなく、外部コマンドの実行と結果の取得組み合わせて定形処理を行うバッチファイルとして用いることもできます。 このためMSBuildプロジェクトファイルは、XML形式で記述される一種のプログラミング言語・スクリプト言語と見ることもできます。

.NET Framework形式のプロジェクトファイルに対するコマンドラインでのビルド・実行はmsbuildコマンドを用いることができますが、.NET形式では主にdotnetコマンドを用います。 dotnetコマンドではプロジェクトファイルに対するビルド・実行だけでなく、他のプロジェクトやパッケージの参照など、プロジェクトファイルに対するよく使われる変更操作も一部サポートされています。

ここでは.NET形式および.NET Framework形式のプロジェクトファイルの概念や構造・機能など、基本的な部分について解説します。 以下で解説する事項はMSBuildプロジェクトファイルの仕様に基づくものであるため、.NET形式・.NET Framework形式のどちらにも共通する事項となっていますが、例として使用している一部の定義済みプロパティ・定義済みアイテム.NET形式でのみ使用できるものとなっている場合がある点に注意してください。

プロジェクトファイルの作成・実行

.NET形式のプロジェクトファイルを作成する場合は、dotnet newコマンドを使用することができます。 このコマンドでは、プロジェクトファイル(*.csproj/*.vbproj)のほか、テンプレート生成されるソースコードファイルなど、プロジェクトのファイル一式が作成されます。

.NET形式のプロジェクトを作成する
# 言語にC#を使用してコンソールアプリケーションを作成するプロジェクト"HelloWorld"をカレントディレクトリに作成する
dotnet new console --language 'C#' --name HelloWorld

# 言語にC#を使用してクラスライブラリを作成するプロジェクト"HelloLibrary"をカレントディレクトリに作成する
dotnet new classlib --language 'C#' --name HelloLibrary

# 言語にVBを使用してWindows Formsアプリケーションを作成するプロジェクト"HelloWorld"を作成する
# プロジェクトはディレクトリHelloWorldProject\HelloWorldに作成する
dotnet new winforms --language VB --name HelloWorld --output HelloWorldProject\HelloWorld

# `dotnet new`コマンドのヘルプを表示する
dotnet help new

このほか、Visual StudioなどのIDEで新規プロジェクトを作成することにより、.NET形式・.NET Framework形式のプロジェクトファイルを作成することができます。

クラスライブラリのプロジェクトを作成する方法・クラスライブラリを使用するプロジェクトの作成についてはクラスライブラリの作成 §.コマンドラインでの作成手順を参照してください。


作成したプロジェクトをビルドし、生成された実行可能ファイルを実行するには、IDE上のビルドメニュー・実行メニューを実行するか、次のコマンドで実行することができます。

.NET形式のプロジェクトファイルではdotnet buildあるいはdotnet runコマンドを使ってビルド・実行することができます。 .NET Framework形式のプロジェクトファイルではmsbuildコマンドを使ってビルド・実行します。

.NET形式のプロジェクトをビルド・実行する
# プロジェクトファイルHelloWorld.csprojをビルドする
dotnet build HelloWorld.csproj

# カレントディレクトリからプロジェクトファイルを探してビルドする
dotnet build

# プロジェクトファイルHelloWorld.csprojのビルド成果物を実行する
dotnet run -p HelloWorld.csproj

# カレントディレクトリからプロジェクトファイルを探してビルド成果物を実行する
dotnet run

# 同上、ただし再ビルドが必要な場合でも以前に生成済みのビルド成果物を実行する
dotnet run --no-build

# `dotnet build`, `dotnet run`コマンドのヘルプを表示する
dotnet help build
dotnet help run
.NET Framework形式のプロジェクトをビルド・実行する
# プロジェクトファイルHelloWorld.csprojをビルドする
msbuild HelloWorld.csproj

# プロジェクトファイルHelloWorld.csprojのビルド成果物を実行する
msbuild HelloWorld.csproj /target:Run

# プロジェクトファイルHelloWorld.csprojのビルドして、成果物を実行する
msbuild HelloWorld.csproj /target:Build;Run

# プロジェクトファイルHelloWorld.csprojの以前のビルド成果物を削除・再ビルドしてから実行する
msbuild HelloWorld.csproj /target:Rebuild;Run

特にオプションで指定しない場合、デフォルトでは通常Debug構成でビルド・実行されます。 構成については§.ビルド構成 (Configurationプロパティ)を参照してください。

最小限のMSBuildプロジェクトファイル (Hello, world!)

ソースコードのコンパイルやビルド成果物の生成を一切行わない、実行可能な最小限のMSBuildプロジェクトファイルは次のような内容になります。 MSBuildプロジェクトファイルの拡張子は任意で、ここでは*.msbuild.xmlとしています。

HelloWorld.msbuild.xml: 最小限のMSBuildプロジェクトファイル
<Project DefaultTargets="Build">
  <!-- ビルド(Build)の動作を定義する -->
  <Target Name="Build">
    <!-- 重要度'high'でメッセージを出力する -->
    <Message Text="Hello, world!" Importance="high"/>
  </Target>
</Project>

このプロジェクトをビルドするには次のようにします。 ビルドするといっても、このプロジェクトではコンパイル対象ファイルやコンパイラ呼び出し等を一切定義していないため、ビルド成果物は何ら生成されず、単にメッセージが出力されるのみとなります。

MSBuildプロジェクトファイルのビルドとビルド結果
`msbuild`コマンドでMSBuildプロジェクトファイルを*ビルド*する
>msbuild -nologo -v:minimal HelloWorld.msbuild.xml
  Hello, world!

`dotnet build`コマンドでMSBuildプロジェクトファイルを*ビルド*する
>dotnet build -nologo HelloWorld.msbuild.xml
  Hello, world!

ビルドに成功しました。
    0 個の警告
    0 エラー

経過時間 00:00:00.10

`dotnet msbuild`コマンドでも同様に*ビルド*することができる
`dotnet`コマンドで`msbuild`コマンドのコマンドライン引数を使用したい場合に用いる
>dotnet msbuild -nologo HelloWorld.msbuild.xml
  Hello, world!

プロジェクトファイルの基本構造 (<Project>)

プロジェクトファイルは、<Project>要素をルート要素とするXML文書として記述します。 (Project 要素 (MSBuild) - Visual Studio | Microsoft Docs)

MSBuildで処理されるプロジェクトファイルでは、XML宣言(<?xml ... ?>)は省略可能です。 また、XML名前空間(xmlns)の指定も省略することができますが、Project要素のXML名前空間はhttp://schemas.microsoft.com/developer/msbuild/2003と定められているため、明示的に指定する場合はこれを指定します。

<Project>要素は、ビルドに関する設定を記述するプロパティ(PropertyGroup)や、ビルド時に参照されるパッケージや他のプロジェクトファイル、その他の外部ファイルなどの選択を記述するアイテム(ItemGroup)などから構成されます。 設定だけでなく、何らかの処理を定義するターゲット(Target)を記述することもできます。

プロジェクトファイルの基本構造
<!-- このプロジェクトが使用するSKDとしてMicrosoft.NET.Sdkを選択する -->
<Project Sdk="Microsoft.NET.Sdk">

  <!-- 'プロパティ'の定義 -->
  <PropertyGroup>
    <!-- プロジェクトの出力結果の種類をexe(実行可能ファイル)にする -->
    <OutputType>Exe</OutputType>
  </PropertyGroup>

  <!-- 'アイテム'の定義 -->
  <ItemGroup>
    <!-- プロジェクトが参照するパッケージにSystem.Text.Encoding.CodePagesを追加する -->
    <PackageReference Include="System.Text.Encoding.CodePages" Version="4.7.1" />
  </ItemGroup>

</Project>

.NET形式のプロジェクトでは、<Project>要素のSdk属性に使用するSDK(Software Development Kit)を選択します。 SDKを選択することにより、ビルドや実行などの既定の動作やコンパイラ等のツールのパス、その他各種設定のデフォルト値などがインポートされます。

コンソールアプリケーション等ではSdk属性Microsoft.NET.Sdkを指定します。 .NET 5より前ではWindows Formsを使用する場合はMicrosoft.NET.Sdk.WindowsDesktopを指定する必要がありましたが、.NET 5以降ではMicrosoft.NET.Sdkとなり、単にプロパティUseWindowsFormsを指定するだけで使用できるようになっています。

プロパティ (<PropertyGroup>)

ビルドに関する設定は、プロパティとして定義します。 プロパティは変数のように名前付きで扱うことができる値、あるいは名前と値のペア(name-value pair)を構成するものです。 プロパティは<PropertyGroup>要素の子要素として定義し、子要素の名前がプロパティ名となります。 (MSBuild プロパティ - Visual Studio | Microsoft Docs)

プロパティに設定されている値は、$(プロパティ名)とすることで参照・展開することができます。 未定義のプロパティの場合でもヌル参照とはならず、単に空の文字列として展開されます。 同じ名前のプロパティを再定義することで、プロパティの値を変更することができます。

プロパティを定義する・値を再設定する
  <!-- プロパティを定義する -->
  <PropertyGroup>
    <!-- OutputTypeプロパティ(プロジェクトの出力結果の種類)を定義して値を'exe'(実行可能ファイル)にする -->
    <OutputType>Exe</OutputType>

    <!-- DefineConstantsプロパティ(コンパイラに渡すコンパイラ定数)を定義して値を設定する -->
    <DefineConstants>TEST;DEBUG</DefineConstants>

    <!-- DefineConstantsプロパティの値に追記して変更する(コンパイラ定数にDEBUG_LOGを追加する) -->
    <DefineConstants>$(DefineConstants);DEBUG_LOG</DefineConstants>
  </PropertyGroup>

  <!-- PropertyGroupは任意回・任意の順序で記述することができる -->
  <PropertyGroup>
    <!-- 独自のプロパティを定義する -->
    <Foo>Foo</Foo> <!-- $(Foo) = "Foo" -->
    <FooBar>$(Foo)-Bar</FooBar> <!-- $(FooBar) = "Foo-Bar" -->
    <FooBarBaz>$(FooBar)-Baz</FooBarBaz> <!-- $(FooBarBaz) = "Foo-Bar-Baz" -->
  </PropertyGroup>

コンパイラに渡すパラメータなどの設定値や実行時のパスなど、予約済みプロパティとして定められているものがあります。 また予約済みプロパティは既定値が設定されている場合もあります。 そういったプロパティについては§.予約済み・定義済みのプロパティとアイテムを参照してください。 これらのプロパティと一致しない名前である限り、独自にプロパティを定義して任意に値を設定することもできます。

また、条件(Condition属性)を指定することにより、特定の条件の場合のみプロパティを定義する、あるいは条件ごとにプロパティで定義される値を変えるといったことができます。

コマンドラインでのプロパティの定義 (-p,-property)

msbuildおよびdotnet buildコマンドでは、プロパティをコマンドライン引数で指定することができます。 コマンドライン引数で指定した場合、新たにプロパティを定義できるほか、プロジェクトファイルで定義されているプロパティを上書きすることもできます。 コマンドライン引数はオプション-p/-propertyを使用し、プロパティをname=valueの形式で指定します。

dotnetコマンドでは-c/--configuration(ビルド構成(Configuration))、-f/--frameworkターゲットフレームワーク(TargetFramework)など、特定のプロパティに対応する専用のコマンドラインオプションが個別に用意されているものもあるため、これを用いることもできます。

dotnetコマンドでプロパティを定義してビルド・実行する
# プロパティFooに値BARを設定(または上書き)して、
# ビルド構成Releaseでビルドする
dotnet build -p:Foo=BAR -c Release HelloWorld.csproj

# 上記で生成したRelease構成のビルド成果物を実行する
# (--no-build: 実行に際して再ビルドしない)
dotnet run -c Release --no-build
msbuildコマンドでプロパティを定義してビルド・実行する
# プロパティFooに値BARを設定(または上書き)して、
# ビルド構成Releaseでビルド・実行する
msbuild -p:Foo=BAR -p:Configuration=Release /target:Build;Run HelloWorld.csproj

# Release構成の既存のビルド成果物を実行する
msbuild -p:Configuration=Release /target:Run HelloWorld.csproj

コマンドライン引数で複数のコンパイラ定数などを指定する場合、バージョンによっては区切り文字の;, ,が正しく解釈されない場合があるようです。 この場合、URLエンコードして%3B, %2Cにエスケープします。 詳細は§.コンパイラ定数 (<DefineConstants>)を参照してください。

環境プロパティ(環境変数に基づくプロパティ)

プロジェクトファイルが読み込まれる際、環境変数は自動的にプロパティとして定義されます(環境プロパティ)。 このため、例えば環境変数LANGは、プロジェクトファイルではプロパティ$(Lang)として参照・値を展開することができます。 プロパティとして参照する場合、環境変数名とプロパティ名の大文字小文字の違いは無視されるようです。

プロジェクトファイルで環境変数と同じ名前のプロパティが定義されている場合(プロジェクトファイルで環境プロパティが再定義される場合)、その値はプロジェクトファイルでの定義で上書きされます。 つまり、プロパティは「環境変数 < プロジェクトファイル < コマンドライン引数」の優先順位で値が上書きされます。

環境変数が指定されていない場合、環境プロパティは単に空の文字列として展開されるため、Condition属性を使用して環境変数が指定されていない場合はデフォルト値で上書きするようにすることができます。

環境プロパティを参照する・値を再設定する
  <PropertyGroup>
    <!--
      環境変数LOG_DIRでログディレクトリが指定されていない場合、
      プロパティを再定義してデフォルトのディレクトリを指定する
    -->
    <Log_Dir Condition=" '$(LOG_DIR)' == '' ">/var/log/</Log_Dir>
  </PropertyGroup>

  <!-- ビルド(Buildターゲット)の実行前にこのターゲットを実行させる -->
  <Target Name="PrintEnvironmentProperties" BeforeTargets="Build">
    <!-- 環境変数LANGの値を表示する -->
    <Message Text="Lang: $(Lang)" Importance="high"/>

    <!-- ログディレクトリ(LOG_DIR)の指定値を表示する -->
    <Message Text="Log_Dir: $(Log_Dir)" Importance="high"/>

    <!-- データディレクトリ(DATA_DIR)の指定値を表示する -->
    <Message Text="Data_Dir: $(Data_Dir)" Importance="high"/>
  </Target>
環境変数を指定してビルドする
環境変数DATA_DIRのみを指定してビルドする
(環境変数LOG_DIRに対応するプロパティはデフォルト値が使用される)
$DATA_DIR=./data/ dotnet msbuild -nologo -v:minimal
  Lang: ja_JP.UTF-8
  Log_Dir: /var/log/
  Data_Dir: ./data/

環境変数DATA_DIRとLOG_DIRを指定してビルドする
$DATA_DIR=./data/ LOG_DIR=./log/ dotnet msbuild -nologo -v:minimal
  Lang: ja_JP.UTF-8
  Log_Dir: ./log/
  Data_Dir: ./data/

環境変数とコマンドライン引数の両方で同一のプロパティの値を指定してビルドする
(最も優先度の高いコマンドライン引数の指定値が使用される)
$LOG_DIR=./log/ dotnet msbuild -nologo -v:minimal -p:Log_Dir=~/.tmp/log/
  Lang: ja_JP.UTF-8
  Log_Dir: ~/.tmp/log/
  Data_Dir: 

アイテム (<ItemGroup>)

ビルド時に参照されるパッケージや他のプロジェクトファイル、成果物や出力ディレクトリに含める外部ファイルなどは、アイテムとして定義します。 アイテムは<ItemGroup>要素の子要素として定義し、子要素の名前がアイテム名となります。 MSBuildのドキュメントでは、アイテムではなく項目と訳されているようです。 (MSBuild 項目 - Visual Studio | Microsoft Docs)

プロパティとアイテムは、どちらも名前が与えられた値、ある種の変数のようなものという点は同じです。 一方、プロパティでは何らかの(スカラ値)を定義するのに対し、アイテムは何らかの複数の値(ベクタ値)あるいは値のリストを定義します。 また、プロパティでは要素のテキストで値を定義するのに対し、アイテムではアイテムとして含める対象を属性で選択します

アイテムに含める対象を選択するにはInclude属性を使用します。 Include属性とともにExclude属性を指定することで、選択の際に除外する対象を指定することもできます。 条件(Condition属性)を指定することにより、特定の条件の場合のみアイテムを定義する、あるいはアイテムに含めるといったことができます。

プロパティに設定されている値は、@(アイテム名)とすることで参照・展開することができます。 また、@(アイテム名, '区切り文字')とすることで任意の区切り文字で連結した状態で展開することもできます。 未定義のアイテムの場合でもヌル参照とはならず、単に空のリストあるいは空の文字列として展開されます。

アイテムを定義する
  <!-- アイテムを定義する -->
  <ItemGroup>
    <!-- PackageReferenceアイテム(参照パッケージ)にSystem.Text.Encoding.CodePagesを含める -->
    <PackageReference Include="System.Text.Encoding.CodePages" />
    <!-- PackageReferenceアイテムにMicrosoft.NET.Test.Sdkを含める(追加する) -->
    <PackageReference Include="Microsoft.NET.Test.Sdk" />
    <!-- PackageReferenceアイテムにMicrosoft.NET.Test.Sdkを含める(ただし、MSBuildRuntimeTypeが'Mono'(Mono上で実行されるMSBuild)の場合のみ) -->
    <PackageReference Include="NUnit3TestAdapter" Condition="'$(MSBuildRuntimeType)' == 'Mono'" />
  </ItemGroup>

  <!-- ItemGroupは任意回・任意の順序で記述することができる -->
  <ItemGroup>
    <!-- プロジェクトファイルのあるディレクトリ、およびそのサブディレクトリ以下にある.csファイルをすべて選択する -->
    <SourceFile Include="**\*.cs"/>
    <!-- プロジェクトファイルのあるディレクトリの外にあるディレクトリから.csファイルを選択してSourceFileに追加する-->
    <SourceFile Include="..\src\**\*.cs"/>
    <!-- ⚠ディレクトリ区切り文字'\'は、Linux等では自動的に'/'へ置換される -->

    <!--
      プロジェクトファイルのあるディレクトリ*直下の*サブディレクトリのみから拡張子が.txtのファイルを選択する
      ただし、拡張子が.bak.txtのファイルは除外する
    -->
    <TextFile Include="*\*.txt" Exclude="*\*.bak.txt"/>

    <!-- ';'で区切ることにより、複数の値を同時に含めることもできる -->
    <FooBarBaz Include="Foo;Bar"/>
    <FooBarBaz Include="Baz"/>
  </ItemGroup>

  <PropertyGroup>
    <!-- アイテムFooBarBazの値をプロパティに展開する(';'で連結された状態で展開される) -->
    <FooBarBazText1>@(FooBarBaz)</FooBarBazText1> <!-- = "Foo;Bar;Baz" -->
    <!-- アイテムFooBarBazを区切り文字', 'で展開する -->
    <FooBarBazText2>@(FooBarBaz, ', ')</FooBarBazText2> <!-- = "Foo, Bar, Baz" -->
    <!-- アイテムFooBarBazの各値をカッコ()で括った状態で展開する -->
    <FooBarBazText3>(@(FooBarBaz, ') ('))</FooBarBazText3> <!-- = "(Foo) (Bar) (Baz)" -->
  </PropertyGroup>

プロパティと同様、コンパイル対象のファイルを表すアイテムなどは予約済みアイテムとして定められているものがあります。 そういったアイテムについては§.予約済み・定義済みのプロパティとアイテムを参照してください。 これらのアイテムと一致しない名前である限り、独自にアイテムを定義して任意に値を設定することもできます。

アイテムはリストであるため通常複数個の値が設定されますが、アイテム名は複数形ではなく単数形とすることがほとんどのようです。

条件分岐

条件 (@Condition)

プロパティアイテムの定義、ターゲットやタスクの実行では、Condition属性を指定することにより条件付きでの定義・実行とすることができます。 例えば、ビルド構成がDebugの場合のみビルド対象とするファイルを定義したり、特定のプラットフォーム向けのビルドでのみ必要となるパッケージ参照を追加したりする場合には、Condition属性でその条件を指定します。

Condition属性で指定する条件式では、プロパティの値を参照することができます。 条件式では、演算子として==, !=, And, Or, !(否定)などを使用することができ、また文字列比較や文字列加工のメソッド(StartsWithTrim)などを用いることもできます。 (詳細:MSBuild の条件 - Visual Studio | Microsoft Docs)

  <PropertyGroup>
    <!--
      ビルド構成(Configurationプロパティ)がDebugと等しい場合のみ、
      コンパイラ定数(DefineConstantsプロパティ)にDEBUG_LOGを追加する
    -->
    <DefineConstants Condition=" '$(Configuration)' == 'Debug' ">$(DefineConstants);DEBUG_LOG</DefineConstants>

    <!--
      Copyrightプロパティが空の文字列(=未定義)の場合のみ、
      CopyrightYearプロパティとAuthorsプロパティの値を展開して著作権表示の文字列を構成する
    -->
    <Copyright Condition=" '$(Copyright)' == '' ">Copyright © $(CopyrightYear) $(Authors)</Copyright>
  </PropertyGroup>

  <ItemGroup>
    <!--
      ターゲットフレームワーク(TargetFrameworkプロパティ)が.NET Framework 4.x('net4'で始まる)場合を除き、
      参照パッケージ(PackageReferenceアイテム)にSystem.Text.Encoding.CodePagesを含める
    -->
    <PackageReference Include="System.Text.Encoding.CodePages" Condition="! $(TargetFramework.StartsWith('net4'))" />
  </ItemGroup>

Condition属性はPropertyGroup要素・ItemGroup要素自体にも指定することができます。

  <!-- ビルド構成(Configuration)によらず共通で定義するプロパティを記述する -->
  <PropertyGroup>
  </PropertyGroup>

  <!-- ビルド構成がDebugの場合のみ定義するプロパティを記述する -->
  <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
  </PropertyGroup>

  <!-- ビルド構成がReleaseの場合のみ定義するプロパティを記述する -->
  <PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
  </PropertyGroup>

また、文字列クラスのメソッドだけでなく、Regex.IsMatchメソッドなどの静的メソッドを使用することもできるため、プロパティの値が正規表現にマッチするかどうかを条件とすることもできます。

Condition属性でプロパティが正規表現にマッチするかどうかを条件に指定する
  <ItemGroup>
    <!--
      ターゲットフレームワーク(TargetFrameworkプロパティ)が.NET Framework 1.x.y〜4.x.y('net1(x(y))'〜'net4(x(y))')の場合を除き、
      参照パッケージ(PackageReferenceアイテム)にSystem.Text.Encoding.CodePagesを含める
    -->
    <PackageReference
      Include="System.Text.Encoding.CodePages"
      Condition="! $([System.Text.RegularExpressions.Regex]::IsMatch(
        $(TargetFramework),
        '^net[1-4][0-9]*'
      ))"
    />
  </ItemGroup>

上記の例の場合、TargetFrameworkからTargetFrameworkIdentifierを取得する目的にMSBuildの関数GetTargetFrameworkIdentifierを使うことができるため、次のように簡略化することができます。

GetTargetFrameworkIdentifier関数を使ってTargetFrameworkからTargetFrameworkIdentifierを取得する
  <ItemGroup>
    <!--
      ターゲットフレームワークの識別子(TargetFrameworkIdentifier)が'.NETFramework'の場合を除き、
      参照パッケージ(PackageReferenceアイテム)にSystem.Text.Encoding.CodePagesを含める
    -->
    <PackageReference
      Include="System.Text.Encoding.CodePages"
      Condition=" '$([MSBuild]::GetTargetFrameworkIdentifier( $(TargetFramework) ))' != '.NETFramework' "
    />
  </ItemGroup>

その他使用できる静的メソッドや、MSBuild固有の関数として定義されているものはプロパティ関数 - Visual Studio | Microsoft Docsにて一覧として挙げられています。

Condition属性を指定する以外に、Choose要素を用いることで構造化された条件分岐を行うこともできます。

条件構造 (<Choose>+<When>/<Otherwise>)

Condition属性は、いわばPerlやRuby等における後置if(run() if condition;)のようなものです。 条件付きとしたい要素が多い場合、そのすべてにCondition属性を指定する必要があり、記述が煩雑化しやすくなります。 複数のCondition属性で指定する条件が共通する場合は、Choose要素を使うことで条件分岐の記述を構造化・簡略化できます。 (MSBuild の条件構造 - Visual Studio | Microsoft Docs)

Choose要素は、if文あるいはswitch文のように条件に基づいて分岐させることができる要素です。 Choose要素は、それ自体には条件を記述せず、if/else ifに相当するWhen要素、elseに相当するOtherwise要素を包摂する要素となります。 When要素はChoose要素の子要素として1個以上記述することができ、それぞれのWhen要素に条件となるCondition属性を指定します。 When要素のどの条件にも一致しない場合の分岐先として、Otherwise要素を記述することもできます。

<Choose>要素での条件分岐
<Choose>
  <When Condition=" '$(Property)' == 'value1' ">
  </When>
  <When Condition=" '$(Property)' == 'value2' ">
  </When>
  <Otherwise>
  </Otherwise>
</Choose>
if文での条件分岐
if (property == "value1") {
}
else if (property == "value2") {
}
else {
}

WhenOtherwise要素内でさらにChoose要素を記述して条件分岐を入れ子にすることができる一方、それ以外ではPropertyGroup要素またはItemGroup要素のみがChoose要素の子要素となることができます。 つまり、Choose要素内ではプロパティとアイテムの定義のみを条件分岐できます。 Condition属性とは異なり、ターゲットやタスクの実行分岐のためにChoose要素を使用することはできません

Choose要素でターゲットやタスクの実行分岐を行いたい場合は、条件に一致した場合に何らかの独自のプロパティを定義しておき、実行箇所においてCondition属性でそのプロパティをチェックするなどします。

Choose/When/Otherwise要素を使ってプロパティ定義の条件分岐・タスクの実行分岐を行う
  <Choose>
    <!-- 構成(Configuration)が'Debug'の場合 -->
    <When Condition=" '$(Configuration)' == 'Debug' ">
      <PropertyGroup>
        <!-- コンパイラ定数にDEBUG_FOOとDEBUG_BARを追加する -->
        <DefineConstants>$(DefineConstants);DEBUG_FOO;DEBUG_BAR</DefineConstants>
        <!-- 整数演算でのオーバーフロー・アンダーフロー発生時に例外OverflowExceptionをスローさせる -->
        <CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
      </PropertyGroup>
    </When>
    <!-- 構成(Configuration)が'Release'の場合 -->
    <When Condition=" '$(Configuration)' == 'Release' ">
      <PropertyGroup>
        <!-- 整数演算でのオーバーフロー・アンダーフローを許容する -->
        <CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
        <!-- デバッグシンボルの生成を行わない -->
        <DebugSymbols>false</DebugSymbols>
        <DebugType>none</DebugType>
      </PropertyGroup>
    </When>
    <!-- 上記のいずれにも一致しない場合 -->
    <Otherwise>
      <PropertyGroup>
        <!-- 独自のプロパティConfigurationErrorを定義して、エラーメッセージを表示させる -->
        <ConfigurationError>configuration '$(Configuration)' is not defined</ConfigurationError>
      </PropertyGroup>
    </Otherwise>
  </Choose>

  <!-- Buildが実行される前、かつプロパティConfigurationErrorの値が空の文字列以外の場合に実行されるターゲットを定義 -->
  <Target Name="ReportConfigurationError" BeforeTargets="Build" Condition=" '$(ConfigurationError)' != '' ">
    <!-- ConfigurationErrorプロパティに設定された値をエラーメッセージとして表示する -->
    <Error Text="$(ConfigurationError)"/>
  </Target>

ターゲット(<Target>)・タスク(<Task>)

ターゲット(target)とは、ビルドを行う(Build)、以前のビルド成果物を削除する(Clean)、ビルドした成果物を実行する(Run)など、プロジェクトに対する何らかの動作を定義するものです。

より具体的には、ターゲットはコンパイラ呼び出しやコマンドの実行、ファイルのコピーや削除など、タスク(task)と呼ばれる一連の処理をひとまとめにして構成したものです。 dotnet buildではBuildタスク、dotnet runコマンドではRunタスクが実行されるなど、一つのプロジェクトファイルに対して複数の動作を実行できるのは、一連の処理がターゲットとして定義されているためです。 (MSBuild ターゲット - Visual Studio | Microsoft Docs, MSBuild タスク - Visual Studio | Microsoft Docs)

ターゲットは他のターゲットとの依存性(dependency)を定義することができ、例えばRunする際は先にBuildして成果物を生成する、といったように、あるターゲットを実行する際の前提として必要となる別のターゲットを自動的に実行させることができます。

Buildなどの定義済みのターゲットのほか、<Target>要素を使って独自にターゲットを定義することができます。 独自にターゲットを定義する場合、BeforeTargets属性やAfterTargets属性でBuildなどの他のターゲットを指定することで、そのターゲットの前後に実行するよう指定することができます。 これを利用して、例えばビルド前後に独自の処理を追加する、といったことができます。 このほか、ルート要素<Project>InitialTargets属性でターゲットを指定すれば、毎回最初に行うべき処理を行うように定義することもできます。 これらの属性で複数のターゲットを指定する場合、Target1;Target2;Target3...のようにターゲット名を;で区切って指定します。

タスクには、任意の実行可能ファイルやコマンドを実行するExecタスクや、メッセージ・警告・エラーを出力するMessage/Warning/Errorタスクなどがあります。 CallTargetタスクを用いることで、任意のターゲットをタスクとして呼び出すこともできます。

ターゲットおよびタスクには、実行の条件をCondition属性で指定することもできます。

ターゲットとタスク
<!-- InitialTargets属性で最初に実行するターゲットを指定できる -->
<Project Sdk="Microsoft.NET.Sdk" InitialTargets="RecordTime">
  <!--
    OSが'Unix'の場合のみ実行されるタスクを定義する
    (InitialTargetsとして指定されているため、BuildやCleanほか、どのターゲットが指定された場合でも実行される)
  -->
  <Target Name="RecordTime" Condition=" '$(OS)' == 'Unix' ">
    <!-- Execタスクでコマンドを実行する -->
    <Exec Command="touch timestamp.txt" />
  </Target>

  <!--
    Buildタスクが実行される前に実行されるタスクを定義する
  -->
  <Target Name="PrintCompilerParameters" BeforeTargets="Build">
    <!-- コンパイラに渡されるコンパイル対象ファイル(Compileアイテム)を表示する -->
    <Message Text="source files: @(Compile)"/>

    <!-- コンパイラに指定されるコンパイラ定数(DefineConstantsプロパティ)を、重要度'high'で表示する -->
    <Message Text="compiler constants: $(DefineConstants)" Importance="high"/>
  </Target>

タスクによっては出力パラメータが定義されているものがあります。 タスクをメソッドと見た場合、タスクの出力パラメータはout引数やreturnによるメソッドの戻り値に相当するものです。

タスクの出力パラメータは<Output>要素で取得することができ、この要素で指定したプロパティにタスクの処理結果を格納させることができます。 通常は省略可能となっているため、タスクの実行だけ行い、出力パラメータは無視して破棄することもできます。 出力パラメータを使った具体例は§.Execタスク(コマンドの実行)を参照してください。

定義済みのタスクは複数用意されているほか、Taskクラスから派生して独自にタスクを定義することもできます。

Message/Warning/Errorタスク(メッセージの出力)

プロジェクトファイルを直接編集する際、プロパティアイテムとして設定されている内容を確認する目的に使えるのがMessageタスクです。 これはConsole.WriteLineのように実行中のログを出力するためのタスクです。

MessageタスクではText属性で出力する文字列を指定します。 単に文字列を指定できるほか、$(プロパティ名)あるいは@(アイテム名)とすることでプロパティおよびアイテムに設定されている値を展開して表示することもできます。

Importance属性で出力の重要度を指定します。 重要度にはhigh/normal/lowのいずれかを指定することができ、省略した場合はnormalとして出力します。 dotnet runコマンドを実行した場合のビルド時出力などは重要度normalでも出力されなくなるため、常に出力させたいような場合は重要度をhighにします。

WarningタスクおよびErrorタスクを使うことでもログを出力することができ、これらのタスクを使った場合は警告あるいはエラーとしてメッセージを出力することができます。 これらのタスクで出力した警告・エラーは、コンパイル時の警告・エラーと同様に計上された上で結果が表示されます。

Message・Warning・Errorの各タスクを使ってメッセージを出力する
<!-- InitialTargets属性でプロジェクトが読み込まれた際にDebugPrintターゲットを実行するように指定する -->
<Project Sdk="Microsoft.NET.Sdk" InitialTargets="DebugPrint">
  <Target Name="DebugPrint">
    <!-- メッセージをデフォルトの重要度で表示する -->
    <Message Text="Hello, world!"/>

    <!-- 現在の構成(Configurationプロパティ)を、重要度'high'で表示する -->
    <Message Text="configuration: '$(Configuration)'" Importance="high"/>

    <!-- コンパイラに渡されるコンパイル対象ファイル(Compileアイテム)を表示する -->
    <Message Text="source files: @(Compile)"/>

    <!-- 警告メッセージを表示する -->
    <Warning Text="Hello, warning!"/>

    <!-- エラーメッセージを表示する -->
    <Error Text="Hello, error!"/>
  </Target>

Execタスク(コマンドの実行)

Execタスクを用いることにより、任意の実行ファイルを実行することができます。 Execタスクを用いることで、外部のバッチファイルやシェルスクリプトとして記述したものを実行する、あるいは何らかのコマンドを直接実行することにより、独自の処理や外部ツールを実行させることができます。

定義済みのタスクを含むすべてのタスクは、Taskクラスの派生クラスとして実装されているため、独自のタスクを定義したい場合にはこのクラスを派生して実装することになりますが、Execタスクを使えば既存のコマンドやスクリプトをそのまま使って処理を行うことができます。

Execタスクでは、Command属性で実行するコマンドライン、あるいはバッチファイル・シェルスクリプトなどの実行可能ファイルを指定します。 コマンドラインにダブルクオーテーション"を含む場合は実体参照&quot;に置き換えます。

Execタスクを使ってコマンドを実行する
  <Target Name="RunCommand">
    <!-- `echo`コマンドを実行する -->
    <Exec Command="echo &quot;Hello, world!&quot;"/>
  </Target>

Execタスクでは、EnvironmentVariables属性で環境変数を、WorkingDirectoryで作業ディレクトリ(コマンドを実行する際のデフォルトディレクトリ)を指定することができます。

また、Execタスクでコマンドの出力(標準出力・標準エラー)をキャプチャする場合は、ConsoleToMSBuild属性にtrueを指定し、Execタスクの出力パラメータConsoleOutputを取得するようにします。 また、コマンドの終了コードは、Execタスクの出力パラメータExitCodeから取得できます。

タスクの出力パラメータは<Exec>要素の子要素<Output>で取得することができ、TaskParameter属性で取得したい出力パラメータの名前、PropertyName属性で出力パラメータの内容を格納するプロパティの名前を指定します。 コマンドの出力を取得したい場合はTaskParameterConsoleOutputを、終了コードを取得したい場合はExitCodeを指定します。

Execタスクを使ってコマンドを実行し、結果を取得する
  <!-- 以下はLinuxのechoコマンドを使用する場合の例。 DOSのechoコマンドを実行する場合は修正が必要になる。 -->
  <Target Name="RunEcho" Condition=" '$(OS)' == 'Unix' ">
    <!--
      以下のパラメータを指定してコマンドを実行する
      Command="...": `echo`コマンドを実行する(コマンド中でダブルクオーテーションを記述する場合は&quot;にエスケープする)
      ConsoleToMSBuild="true": 標準出力と標準エラーをキャプチャする
      EnvironmentVariables="...": コマンドに渡す環境変数を指定する(複数指定する場合はセミコロン;で区切る)
      EchoOff="true": タスク実行のメッセージとコマンドの出力をオフにする(標準出力・標準エラーのキャプチャには影響しない)
    -->
    <Exec
      Command="echo &quot;${HELLO}, ${WORLD}!&quot;"
      ConsoleToMSBuild="true"
      EnvironmentVariables="HELLO=Hello;WORLD=MSBuild"
      EchoOff="true"
    >
      <!-- コマンドの標準出力・標準エラーをプロパティEchoOutputに格納する -->
      <Output TaskParameter="ConsoleOutput" PropertyName="EchoOutput" />
      <!-- コマンドの終了コードをプロパティEchoExitCodeに格納する -->
      <Output TaskParameter="ExitCode" PropertyName="EchoExitCode" />
    </Exec>

    <!-- Execタスクの出力パラメータの内容を表示する -->
    <Message Text="output: $(EchoOutput)" Importance="high"/>
    <Message Text="exit code: $(CommandExitCode)" Importance="high"/>
  </Target>
Execタスクを使ってGit HEADのコミットハッシュ値を取得する
  <Target Name="GitRetrieveHeadHash">
    <!--
      以下のパラメータを指定してコマンドを実行する
      Command="...": 実行するコマンド(git rev-parse)を指定
      ConsoleToMSBuild="true": 標準出力と標準エラーをキャプチャする
      WorkingDirectory="...": コマンドを実行する際の作業ディレクトリとして、
                              プロジェクトファイルのあるディレクトリ$(MSBuildProjectDirectory)からの相対パスを指定する
      EchoOff="true": タスク実行のメッセージとコマンドの出力をオフにする(標準出力・標準エラーのキャプチャには影響しない)
    -->
    <Exec
      Command="git rev-parse HEAD"
      ConsoleToMSBuild="true"
      WorkingDirectory="$(MSBuildProjectDirectory)\..\src\"
      EchoOff="true"
    >
      <!-- コマンドの実行結果をプロパティGitHeadHashに格納する -->
      <Output TaskParameter="ConsoleOutput" PropertyName="GitHeadHash" />
    </Exec>

    <!-- コマンドの実行結果(GitHeadHashプロパティの値)を表示する -->
    <Message Text="hash: $(GitHeadHash)" Importance="high"/>
  </Target>

作業ディレクトリやコマンドに指定するパスを構築する際に必要となるプロジェクトファイルのパスターゲット実行時のパスなど、パスに関する定義済みプロパティについては§.ディレクトリとパスに関する予約済みプロパティを参照してください。

ビルド構成 (Configurationプロパティ)

ビルド構成(build configuration)、あるいは単に構成とは、一連のビルド時の設定やオプション、出力先ディレクトリなどのプロパティをひとまとめにしてグループ化する概念です。

ビルド構成はMSBuildの概念ではなく、単にConfigurationプロパティとして定義される値(DebugReleaseなど)と、その値をもとに条件付きで定義される一連のプロパティ・アイテムの総称です。 しかし、.NET形式・.NET Framework形式のプロジェクトファイルでは、ビルド設定をグループ化し、また容易にそれを切り替えられるようにするための概念として使用されています。

.NET形式のプロジェクトファイルではDebugReleaseの二種類の構成がデフォルトで定義され、IDE等で作成した.NET Framework形式のプロジェクトファイルでもこの二種類の構成が自動的に生成されます。 これらの構成はDebug構成Release構成のように呼ばれ、またその構成を使ったビルドとビルド成果物はDebugビルドReleaseビルドのように呼ばれます。

ビルド構成を定義する
  <!-- ビルド構成に関わらず共通のプロパティを定義する -->
  <PropertyGroup>
    <!-- プロジェクトの出力結果の種類を指定する -->
    <OutputType>Exe</OutputType>

    <!-- コンパイラに渡すコンパイラ定数を指定する -->
    <DefineConstants>ENABLE_FEATURE_FOO</DefineConstants>
  </PropertyGroup>

  <!-- Debug構成のみ有効になるプロパティを定義する -->
  <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
    <!-- Debug構成の場合のみ、以下のコンパイラ定数を追加する -->
    <DefineConstants>$(DefineConstants);DEBUG_FEATURE_FOO;DEBUG_LOG</DefineConstants>
  </PropertyGroup>

  <!-- Release構成のみ有効になるプロパティを定義する -->
  <PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
    <!-- Release構成では、デバッグシンボルを生成しない -->
    <DebugSymbols>false</DebugSymbols>
  </PropertyGroup>

Debug構成とRelease構成の主な違いとして、デフォルト設定のDebugビルドではビルド成果物としてデバッグ情報(.pdbファイル)等が出力される一方、Releaseビルドでは出力されなくなります。 また、ビルド成果物は構成によって個別の出力ディレクトリ(bin\Debug\またはbin\Release\)に分けて出力されます。

dotnetコマンドでは、構成を指定してビルド・実行するための専用のオプションが用意されています。 構成を指定してビルド・実行するにはdotnet build -c [Debug|Release]のように-c/--configurationオプションで使用する構成を指定します。

DebugとRelease以外のビルド構成を独自に定義することもできます。 例として、エミュレータ向けビルドと実機向けビルド、機能制限ビルドとフル構成ビルドなど、任意に構成を定義することができます。 Visual Studioに存在する構成マネージャのように、IDE上で構成を定義することもできます。

ビルド構成に従ってコンパイラに渡すコンパイラ定数を変えたいような場合は、上記の例のようにDefineConstantsプロパティを指定します。

予約済み・定義済みのプロパティとアイテム

MSBuildでは、パスなどの実行時情報やランタイム情報などの値を参照するためのプロパティが用意されています。 また、.NET形式・.NET Framework形式のプロジェクトファイルでは、プロジェクト設定のプロパティ名・ソースファイルや参照パッケージのアイテム名など、名前があらかじめ定められているもの、あるいは既定値が設定済みで定義されているプロパティ・アイテムが存在します。

予約済みのプロパティ・アイテムは、名前と値が設定され、かつ値の再設定(上書き・オーバーライド)ができない参照専用のプロパティ・アイテムです。 対して定義済み(既知)のプロパティ・アイテムは、必要に応じて値を再設定することができるプロパティ・アイテムです。

MSBuildプロジェクト共通のプロパティ

ここではMSBuildプロジェクトに共通するプロパティについて解説します。

ディレクトリとパスに関する予約済みプロパティ

以下はディレクトリとパスに関するプロパティの抜粋です。 これらのプロパティは予約済みであるため、設定されている値を変更・上書きすることはできません。

ディレクトリとパスに関するプロパティ
プロパティ名 意味 値の例
MSBuildStartupDirectory ビルドを開始したときのカレントディレクトリ
あるいはMSbuildコマンドを実行したときのディレクトリ
このプロパティは終端のディレクトリ区切り記号を含まない
C:\Users\user
MSBuildThisFileで始まるプロパティ 現在のプロジェクトファイルのパス
このプロパティを参照しているプロジェクトファイル自身のパスを表す
(以下はプロジェクトファイルのフルパスがC:\Users\user\app\project.csprojの場合の例)
MSBuildThisFileFullPath 同上、フルパス C:\Users\user\app\project.csproj
MSBuildThisFileDirectory 同上、ディレクトリ部分のみ
このプロパティは終端のディレクトリ区切り記号を含む
C:\Users\user\app\
MSBuildThisFile 同上、ファイル名のみ project.csproj
MSBuildThisFileName 同上、拡張子を除いたファイル名のみ project
MSBuildThisFileExtension 同上、ファイル名の拡張子のみ .csproj
MSBuildProjectで始まるプロパティ ビルドを開始したプロジェクトファイルのパス
エントリポイントとして読み込まれたプロジェクトのパスはMSBuildProject*、そこから読み込まれたサブプロジェクトなどのパスはMSBuildThisFile*でそれぞれ取得できる
(以下はプロジェクトファイルのフルパスがC:\Users\user\app\project.csprojの場合の例)
MSBuildProjectFullPath 同上、フルパスのみ C:\Users\user\app\project.csproj
MSBuildProjectDirectory 同上、ディレクトリ部分のみ
このプロパティは終端のディレクトリ区切り記号を含まない
C:\Users\user\app
MSBuildProjectFile 同上、ファイル名のみ project.csproj
MSBuildProjectName 同上、拡張子を除いたファイル名のみ project
MSBuildProjectExtension 同上、ファイル名の拡張子のみ .csproj
プロパティ名 意味 値の例

実行環境情報に関する予約済みプロパティ

以下は実行環境の情報にプロパティの抜粋です。 これらのプロパティは予約済みであるため、設定されている値を変更・上書きすることはできません。

実行環境情報に関するプロパティ
プロパティ名 意味 値の例
MSBuildRuntimeType 現在MSBuildを実行しているランタイムの種類を表す文字列 Core:.NET Core/.NET 5以降
Full:4.8までの.NET Framework
Mono: Mono
MSBuildBinPath 現在実行しているMSBuildの実行可能ファイルのパス
MSBuildVersion 現在実行しているMSBuildのバージョン
MSBuildToolsPath 現在実行しているMSBuildを含むツール一式のインストールパス
MSBuildToolsVersion 現在実行しているMSBuildを含むツール一式のバージョン
プロパティ名 意味 値の例

プロジェクト設定のプロパティとアイテム

ここでは.NET形式・.NET Framework形式のプロジェクトファイルで使用される、プロジェクト設定に関するプロパティとアイテムについて解説します。 コンパイラに指定するパラメータや入力ファイルは、プロジェクト設定としてプロパティとアイテムで指定することができます。

ビルド対象のファイル

ビルド対象のファイル、また対象から除外するファイルの指定は以下のアイテムで指定します。 IDE上では、ビルドアクションでファイルがどのアイテムに該当するかを指定することができます。

ビルド対象・ビルド対象外のファイルを指定するアイテム
アイテム 意味・目的 既定の属性値(.NET形式のプロジェクトファイル)
Include Exclude Remove
<Compile> コンパイル対象となるソースファイル(*.csや*.vb)を指定する **/*.cs(csprojの場合)
**/*.vb(vbprojの場合)
**/*.user
**/*.*proj
**/*.sln
**/*.vssscc
-
<EmbeddedResource> アセンブリにリソースとして埋め込むファイルを指定する **/*.resx -
<None> ビルド処理の対象外とするファイルを指定する **/* **/*.cs
**/*.vb
**/*.resx
<Content> ビルド成果物として出力ディレクトリにコピーするファイルを指定する - - -

対象として含めるファイルの指定にはIncludeなどの属性を使用します。 これらの属性では、ワイルドカードとして?, *, **を使用することができ、複数のディレクトリ・ファイルを指定することができます。

.NET形式のプロジェクトファイルでは、各アイテムには既定値での属性IncludeExcludeRemoveが暗黙的に指定されています。 このため、例えば<Compile>アイテムでは、プロジェクトファイルのあるディレクトリを基点としたディレクトリツリー内のソースファイルが自動的に含められます。 明示的にアイテムに含めるファイルを指定したい場合は、EnableDefaultItemsなどのプロパティfalseを指定します。

コンパイル対象のソースファイル (<Compile>)

コンパイル対象のソースファイルはCompileアイテムに含めます。 .NET形式のプロジェクトファイルでは、プロジェクトファイルのあるディレクトリを基点としたディレクトリツリー内のソースファイルが自動的に含められます

そのためCompileアイテムは、主にプロジェクトのディレクトリツリー外にあるソースファイルをコンパイル対象に含めたいような場合、ディレクトリツリー内にあるが構成によって除外したいファイルがある場合などに指定します。

コンパイル対象のファイルを追加・除外する(Compileアイテム)
  <ItemGroup>
    <!--
      プロジェクトファイルのディレクトリツリー外にあるソースファイルをコンパイル対象に追加する
      (同ディレクトリツリー内にあるソースファイルは自動的に追加される)
    -->
    <Compile Include="..\Common\CommonExtensions.cs" />

    <!--
      Link属性(メタデータ)でプロジェクト内における仮想的なパスを指定できる
      (IDE上のプロジェクトツリーにおける配置等で使用される)
    -->
    <Compile Include="..\Common\CommonAssemblyInfo.cs" Link="Common\CommonAssemblyInfo.cs" />

    <!--
      指定したソースファイルをコンパイル対象から除外する
      (Include属性の代わりにRemove属性を使用する)
    -->
    <Compile Remove="Ignore\This\Dir\*.cs" />
  </ItemGroup>

  <!-- ビルド(Buildターゲット)が実行される前にコンパイル対象のファイルを一覧表示したい場合は次のようにする -->
  <Target Name="PrintCompile" BeforeTargets="Build">
    <Message Text="Compile: @(Compile, ' ')" Importance="high"/>
  </Target>

明示的なアイテムの選択 (<EnableDefaultItems>)

.NET形式のプロジェクトファイルでは、Compileなどのアイテムには暗黙的なInclude属性が指定されているため、明示的に指定しなくても自動的にファイルが選択されます。

一方、例えばCompileアイテムでは、ディレクトリツリー内にコンパイル対象ではないソースファイルが配置されている場合など、暗黙的(自動的)な選択では不都合が起こる状況もあり得ます。 こういった場合は、EnableDefaultCompileItemsプロパティにfalseを指定することでCompileアイテムでの暗黙的な選択を行わないようにすることができます。

EnableDefaultCompileItemsプロパティにfalseを指定した場合は、コンパイル対象となるファイルすべてを明示的にCompileアイテムで選択する必要があります。

コンパイル対象のファイルを明示的に指定する(EnableDefaultCompileItemsプロパティ・Compileアイテム)
  <PropertyGroup>
    <!-- Compileアイテムでの暗黙的なファイル選択を行わないようにする -->
    <EnableDefaultCompileItems>false</EnableDefaultCompileItems>
  </PropertyGroup>

  <ItemGroup>
    <!-- Compileアイテムに含めるファイルを明示的に選択する -->
    <Compile Include="AssemblyInfo.cs"/>
    <Compile Include="Main.cs"/>
    <!-- srcディレクトリ以下にある*.csファイルをすべて選択する -->
    <Compile Include="src\**\*.cs"/>
    <!--
      上記以外のファイルは暗黙的には選択されない
      (ビルド時に自動生成されるアセンブリ属性ファイル(AssemblyAttributes.cs)などは引き続き自動的に追加される)
    -->
  </ItemGroup>

  <!-- ビルド(Buildターゲット)が実行される前にコンパイル対象のファイルを一覧表示したい場合は次のようにする -->
  <Target Name="PrintCompile" BeforeTargets="Build">
    <Message Text="Compile: @(Compile, ' ')" Importance="high"/>
  </Target>

EnableDefaultCompileItemsプロパティはCompileアイテムのみに対して適用されます。 他のアイテムに対して適用する場合は、以下のプロパティを指定します。

デフォルトのアイテム選択を指示するプロパティと対象となるアイテム
プロパティ 対象となるアイテム
EnableDefaultItems 以下のすべて
EnableDefaultCompileItems Compile
EnableDefaultEmbeddedResourceItems EmbeddedResource
EnableDefaultNoneItems None
EnableDefaultContentItems Content

ビルド成果物となるファイル (<Content>)

コンパイル対象ではないものの、ビルド成果物として出力ディレクトリにコピーしたいファイルはContentアイテムに含めます。 実行可能ファイルの実行時に必須の設定ファイルや構成ファイル(*.config)、LICENSEファイルやREADMEファイルなど、ビルド成果物として出力したいファイルや、パッケージ化する際に同梱したいファイルがある場合にこのアイテムとして指定します。

ビルド成果物となるファイルを追加する(Contentアイテム)
  <ItemGroup>
    <!-- ビルド時に出力ディレクトリにコピーしたいLICENSEやREADME、設定ファイルなどを追加する -->
    <Content Include="LICENSE" />
    <Content Include="README.md" />

    <!-- Visible属性(メタデータ)をfalseにすれば、IDE上では表示されなくなる -->
    <Content Include="..\conf\default.json" Visible="false" />
  </ItemGroup>

アセンブリに埋め込まれるリソース (<EmbeddedResource>)

アセンブリ(*.exeや*.dll)に埋め込まれるリソースとしたいファイルは、EmbeddedResourceアイテムに含めます。 

アセンブリにリソースとして埋め込むファイルを追加する(EmbeddedResourceアイテム)
  <ItemGroup>
    <!-- アセンブリにリソースとして埋め込みたいファイルを追加する -->
    <EmbeddedResource Include="resources\logo.png" />

    <!-- LogicalName属性(メタデータ)で、リソース読み込みの際に使用するキー(論理名)を明示的に指定できる -->
    <EmbeddedResource Include="resources\messages.txt" LogicalName="messages.txt" />

    <!-- Visible属性(メタデータ)をfalseにすれば、IDE上では表示されなくなる -->
    <EmbeddedResource Include="resources\default.dic" Visible="false" />
  </ItemGroup>

アセンブリのリソースとしてファイルを埋め込みむ方法・読み込んで使用する方法についてはリソースの埋め込みと読み込みで詳しく解説しています。 また、リソースの論理名を指定するLogicalName属性と、同属性を指定しなかった場合のデフォルト動作についてはリソースの埋め込みと読み込み §.埋め込むリソースの論理名を定義するを参照してください。

ビルド処理対象外のファイル (<None>)

プロジェクトのファイルには含まれるものの、特に処理される必要のないファイルは、Noneアイテムに含めます。 このアイテムは、IDE上(例えばVisual Studioのソリューションエクスプローラ)で参照できるようにプロジェクトに含めたいファイルなどがある場合に指定します。 何らかのリファレンス・ドキュメントや、コンパイル対象ではない参照用のソースコードなどをこのアイテムに含めておくことができます。

アセンブリにリソースとして埋め込むファイルを追加する(EmbeddedResourceアイテム)
  <ItemGroup>
    <!-- ソリューションエクスプローラ等でプロジェクト内に表示させたいファイルを追加する -->
    <None Include=".gitattributes" />
    <None Include=".editorconfig" />

    <!--
      Link属性(メタデータ)でプロジェクト内における仮想的なパスを指定できる
      (IDE上のプロジェクトツリーにおける配置等で使用される)
    -->
    <None Include="..\libfoo\api-reference-v1.txt" Link="references\libfoo\api-v1.txt" />
    <None Include="..\libbar\docs\api.md"          Link="references\libbar\api.md" />
  </ItemGroup>

バージョン情報・アセンブリ情報

アセンブリバージョンなどのバージョン情報、プロジェクトファイルでのアセンブリ情報の定義、AssemblyInfoファイルの自動生成などに関しては、以下を参照してください。

コンパイラ定数 (<DefineConstants>)

コンパイラ定数を定義するにはDefineConstantsプロパティを使用します。

定義する定数が複数ある場合は、C#プロジェクトファイル(*.csproj)ではセミコロン;、VBプロジェクトファイル(*.vbproj)ではカンマ,で区切ります。 また、定数に値を持たせる場合はname=valueの形式で名前と値を指定します。 ただし、C#プロジェクトファイルで定数に値をもたせた場合は警告MSB3052が発生し、指定は無視され定数が定義されません

デフォルトではTRACEが共通して定義され、ビルド構成がReleaseの場合はRELEASE、DebugではDEBUGが追加で定義されます。 <DefineConstants>で定数を定義するとRELEASEまたはDEBUGのみが自動的に追加されます。

プロジェクトファイルのDefineConstants要素コンパイラ定数を定義する
  <PropertyGroup>
    <!-- コンパイラ定数を定義する -->
    <!-- FOO, BAR, BAZの3つを定義し、BARには値42、BAZには値hogeを持たせる -->
    <DefineConstants>FOO;BAR=42;BAZ=hoge</DefineConstants>
    <!-- (C#では値を持つ定数の定義は無視されるため、BARとBAZは定義されなくなる -->

    <!-- ビルド構成(Configuration)がDebugの場合に、DefineConstantsにDEBUG_FOOとDEBUG_BARを追加する -->
    <DefineConstants Condition=" '$(Configuration)' == 'Debug' ">$(DefineConstants);DEBUG_FOO;DEBUG_BAR</DefineConstants>

    <!-- <DefineConstants>を定義しない場合、デフォルトではTRACEと、構成に従ってDEBUG/RELEASEが定義される -->
  </PropertyGroup>

  <!-- ビルド(Buildターゲットの実行)の前に実際に定義される内容を確認したい場合は次のようにする -->
  <Target Name="PrintDefineConstants" BeforeTargets="Build">
    <Message Text="DefineConstants: $(DefineConstants)" Importance="high"/>
  </Target>
プロジェクトファイルのDefineConstants要素コンパイラ定数を定義する
  <PropertyGroup>
    <!-- コンパイラ定数を定義する -->
    <!-- FOO, BAR, BAZの3つを定義し、BARには値42、BAZには値hogeを持たせる -->
    <DefineConstants>FOO,BAR=42,BAZ=hoge</DefineConstants>

    <!-- ビルド構成(Configuration)がDebugの場合に、DefineConstantsにDEBUG_FOOとDEBUG_BARを追加する -->
    <DefineConstants Condition=" '$(Configuration)' == 'Debug' ">$(DefineConstants),DEBUG_FOO,DEBUG_BAR</DefineConstants>

    <!-- <DefineConstants>を定義しない場合、デフォルトではTRACEと、構成に従ってDEBUG/RELEASEが定義される -->
  </PropertyGroup>

  <!-- ビルド(Buildターゲットの実行)の前に実際に定義される内容を確認したい場合は次のようにする -->
  <Target Name="PrintDefineConstants" BeforeTargets="Build">
    <Message Text="DefineConstants: $(DefineConstants)" Importance="high"/>
  </Target>

dotnet buildなどのコマンドラインでのビルド時に、コマンドライン引数としてビルド構成・コンパイラ定数を指定することもできます。 コマンドライン引数での指定については、§.コマンドラインでのプロパティの定義 (-p,-property)を参照してください。

なお、コマンドライン引数で複数のコンパイラ定数を指定する場合、バージョンによって区切り文字;および,はURLエンコードした形式、つまり%3Bおよび%2Cに置き換える必要があるようです。 例として、dotnetコマンドでコンパイラ定数を指定してビルド・実行する場合は次のようにします。

コマンドライン引数でのコンパイラ定数の指定
# csprojの場合 (FOO;BAR;BAZの3つの定数を定義してビルド・実行する)
dotnet build -p:DefineConstants=FOO%3BBAR%3BBAZ sample.csproj && dotnet run -p sample.csproj --no-build

# vbprojの場合
dotnet build -p:DefineConstants=FOO%2CBAR%2CBAZ sample.vbproj && dotnet run -p sample.vbproj --no-build

.NET形式のプロジェクトファイルで定義されるコンパイラ定数

.NET形式のプロジェクトファイルでは、TargetFrameworkプロパティの値によって次のコンパイラ定数が自動的に追加定義されます。

TargetFrameworkプロパティによって追加定義されるコンパイラ定数
ターゲットフレームワーク TargetFrameworkプロパティ 定義されるコンパイラ定数
各バージョン共通で定義される定数 バージョン別に定義される定数
.NET
5〜
net5.x NET
NETCOREAPP
NET5_0
.NET Core
1.0〜3.1
netcoreapp1.xnetcoreapp3.x NETCOREAPP NETCOREAPP3_1, NETCOREAPP3_0, NETCOREAPP2_2, NETCOREAPP2_1, NETCOREAPP2_0, NETCOREAPP1_1, NETCOREAPP1_0
.NET Standard
1.0〜2.1
netstandard1.xnetstandard2.x NETSTANDARD NETSTANDARD2_1, NETSTANDARD2_0, NETSTANDARD1_6, NETSTANDARD1_5, NETSTANDARD1_4, NETSTANDARD1_3, NETSTANDARD1_2, NETSTANDARD1_1, NETSTANDARD1_0
.NET Framework
1.0〜4.8
net1xnet4xy NETFRAMEWORK NET48, NET472, NET471, NET47, NET462, NET461, NET46, NET452, NET451, NET45, NET40, NET35, NET20

整数演算でのオーバーフロー・アンダーフローの例外化 (<CheckForOverflowUnderflow>, <RemoveIntegerChecks>)

整数演算でのオーバーフロー・アンダーフローをチェックして、それを例外OverflowExceptionとしてスローさせるか、あるいはチェックを抑止してオーバーフロー・アンダーフローを許容するか、その動作を指定するには、CheckForOverflowUnderflow(C#)/RemoveIntegerChecks(VB)プロパティを指定します。

C#プロジェクトファイルでは、CheckForOverflowUnderflowtrueを指定するとチェックが有効となり例外がスローされるようになります。 VBプロジェクトファイルでは、RemoveIntegerCheckstrueを指定するとチェックが無効となり例外はスローされなくなります。

このプロパティによる動作の違いについては整数型のオーバーフローとチェックを参照してください。

XMLドキュメントの生成 (<DocumentationFile>)

ソースコードに記述されたXMLドキュメントコメントからXMLドキュメントを生成するには、DocumentationFileプロパティにて生成するXMLドキュメントのファイル名を指定します。

具体例についてはXMLドキュメントコメントを用いたドキュメントの作成 §.プロジェクトファイルでの設定を参照してください。

エントリポイントクラスの指定 (<StartupObject>)

コード中にMainメソッドの定義が複数ある場合に、どのクラスのMainメソッドをエントリポイントとして使用するかを指定するには、StartupObjectプロパティを指定します。

具体例についてはプロセス §.複数のMainメソッド (エントリポイントの指定)を参照してください。

その他

その他のプロパティとアイテムについては以下を参照してください。