mcpField
D
directory-build-organization

directory-build-organization

github.com/dotnet開発5.8k3.9k 回インストール1 日前に更新
リポジトリ

directory-build-organization について

.NETのビルド設定を整理し、NuGetのバージョンを一元管理する開発者向けのガイドです。.propsと.targetsの使い分け、ディレクトリ階層ごとのインポート、評価済み設定の確認方法を説明します。

主な機能

  1. 01.propsと.targetsの役割の区別
  2. 02Directory.Packages.propsによるバージョン集約
  3. 03階層別のビルドファイル構成
  4. 04TargetFramework条件の注意点
  5. 05プリプロセス出力による評価済み設定の確認

活用シーン

  1. 01複数プロジェクトで重複するビルド設定の集約
  2. 02NuGetパッケージバージョンの一元管理
  3. 03srcとtestの階層構成の計画
  4. 04インポート順や条件が反映されない問題の調査

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/dotnet/skills --skill directory-build-organization

インストール後、Claude Code で/directory-build-organizationを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
common-patterns.md
multi-level-examples.md
targetframework-props-pitfall.md

詳細

Directory.Build ファイルでビルドインフラストラクチャを整理する

意図の確認

  • 「〜すべきか」「どのように整理すべきか」「推奨して」「アドバイスして」などの依頼やレビュー依頼では、実際のプロジェクトファイルを確認し、提案する構成のみを返します。ユーザーから設定の適用、移動、一元化、または整理を明示的に依頼されない限り、ファイルを作成または編集しないでください。
  • 要約する前に、プロジェクト固有の各プロパティ、項目、またはターゲットがどのプロジェクトに残るかを確認してください。実際のファイル名を示し、兄弟ファイル名から推測しないでください。
  • 実際の .sln、.slnx、.proj、またはプロジェクトファイルがそのパスにあることを確認した後にのみ、検証コマンドを推奨してください。リポジトリルートにエントリポイントがない場合は、確認できたプロジェクト用のコマンドを示すか、エントリポイントが見つからなかったことを明記してください。
  • すべてのアドバイスでは、Microsoft.Common.props が各プロジェクトから上方向に検索し、最も近い Directory.Build.props を早い段階で自動的にインポートすることを説明してください。その後、プロジェクトの値で共有デフォルト値を上書きできます。Directory.Build.targets を推奨する場合は、同等の遅い Microsoft.Common.targets のインポートについても説明してください。

Directory.Build.props と Directory.Build.targets の違い

評価時にインポートされるタイミングが異なるため、どちらのファイルを使うかを理解することが重要です。

評価順序:

Microsoft.Common.props imports Directory.Build.props early
→ project body and package/project imports evaluate
→ Microsoft.Common.targets imports Directory.Build.targets late
.props を使う用途.targets を使う用途
プロパティのデフォルト値の設定カスタムビルドターゲット
共通項目の定義後から適用するプロパティの上書き
プロジェクトで上書き可能なプロパティビルド後の処理
アセンブリ/パッケージのメタデータ最終値に対する条件付きロジック
アナライザーの PackageReferencesSDK で定義されたプロパティに依存するターゲット

経験則: プロパティと項目は .props に、カスタムターゲットと後から適用するロジックは .targets に記述します。

.props はプロジェクトファイルより前にインポートされるため、プロジェクトからそこで設定した値を上書きできます。.targets はすべての処理の後にインポートされるため、最終的な決定権を持ちます。ただし、プロジェクトから .targets の値を上書きすることはできません。

⚠️ 重要:.props と .targets での TargetFramework の利用可否

.props ファイルで $(TargetFramework) を使ったプロパティ条件を指定すると、単一ターゲットのプロジェクトではプロパティが .props の評価時に空になるため、条件が暗黙に失敗します。TFM に依存するプロパティは、代わりに .targets に移動してください。ItemGroup と Target の条件には影響しません。

詳しい説明は、targetframework-props-pitfall.md を参照してください。

Directory.Build.props

適した用途:言語設定、アセンブリ/パッケージのメタデータ、ビルド警告、コード分析、共通アナライザー。

<Project>
  <PropertyGroup>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
    <EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
    <Company>Contoso</Company>
    <Authors>Contoso Engineering</Authors>
  </PropertyGroup>
</Project>

ここには記述しないでください: プロジェクト固有の TFM、プロジェクト固有の PackageReferences、ターゲット/ビルドロジック、または SDK で定義された値に依存するプロパティ(.props の評価時には利用できません)。

Directory.Build.targets

適した用途:カスタムビルドターゲット、後から適用するプロパティの上書き(SDK プロパティに依存する値)、ビルド後の検証。

<Project>
  <Target Name="ValidateProjectSettings" BeforeTargets="Build">
    <Error Text="All libraries must target netstandard2.0 or higher"
           Condition="'$(OutputType)' == 'Library' AND '$(TargetFramework)' == 'net472'" />
  </Target>

  <PropertyGroup>
    
    <DocumentationFile Condition="'$(IsPackable)' == 'true'">$(OutputPath)$(AssemblyName).xml</DocumentationFile>
  </PropertyGroup>
</Project>

Directory.Packages.props(Central Package Management)

Central Package Management(CPM)を使うと、すべての NuGet パッケージバージョンの信頼できる情報源を一元化できます。詳しくは https://learn.microsoft.com/en-us/nuget/consume-packages/central-package-management を参照してください。

リポジトリルートの Directory.Packages.props で CPM を有効にします:

<Project>
  <PropertyGroup>
    <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
  </PropertyGroup>

  <ItemGroup>
    <PackageVersion Include="Microsoft.Extensions.Logging" Version="8.0.0" />
    <PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
    <PackageVersion Include="xunit" Version="2.9.0" />
    <PackageVersion Include="xunit.runner.visualstudio" Version="2.8.2" />
  </ItemGroup>

  <ItemGroup>
    
    <GlobalPackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.556" />
    <GlobalPackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="8.0.0" />
  </ItemGroup>
</Project>

Directory.Build.rsp

ディレクトリツリー配下のすべてのビルドに適用される、既定の MSBuild CLI 引数が含まれます。

Directory.Build.rsp の例:

/maxcpucount
/nodeReuse:false
/consoleLoggerParameters:Summary;ForceNoAlign
/warnAsMessage:MSB3277
  • 最新の .NET バージョンでは、msbuild と dotnet の両方の CLI で動作します
  • CI とローカルビルドのフラグを統一するのに適しています
  • 引数はそれぞれ別の行に記述します

複数階層の Directory.Build ファイル

MSBuild は、プロジェクトディレクトリから上の階層へたどって見つかった最初の Directory.Build.props(または .targets)のみを自動インポートします。複数階層を連結するには、内側のファイルの先頭で親ファイルを明示的にインポートします。ファイルの完全な例については、multi-level-examples を参照してください。

<Project>
  <Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))"
         Condition="Exists('$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))')" />

  
</Project>

レイアウト例:

repo/
  Directory.Build.props          ← repo-wide (lang version, company info, analyzers)
  Directory.Build.targets        ← repo-wide targets
  Directory.Packages.props       ← central package versions
  src/
    Directory.Build.props        ← src-specific (imports repo-level, sets IsPackable=true)
  test/
    Directory.Build.props        ← test-specific (imports repo-level, sets IsPackable=false, adds test packages)

成果物の出力レイアウト(.NET 8 以降)

Directory.Build.props で <ArtifactsPath>$(MSBuildThisFileDirectory)artifacts</ArtifactsPath> を設定すると、単一の artifacts/ フォルダー内に、プロジェクト名ごとに分けられた bin/、obj/、publish/ ディレクトリが自動的に生成されます。これにより、デフォルトで bin/obj の競合を回避できます。ディレクトリのレイアウトと追加のパターン(プロジェクトの種類に応じた条件付き設定、パック後の検証)については、common-patterns を参照してください。

ワークフロー:ビルドインフラストラクチャの整理

  1. すべての .csproj ファイルを監査する — ソリューション全体のすべての <PropertyGroup>、<ItemGroup>、カスタム <Target> を一覧にします。繰り返し使われている設定と、プロジェクト固有の設定を確認します。
  2. ルートに Directory.Build.props を作成する — 共通のプロパティのデフォルト値(LangVersion、Nullable、TreatWarningsAsErrors、メタデータ)をここに移動します。これらはプロジェクトファイルより前にインポートされるため、プロジェクト側で上書きできます。
  3. ルートに Directory.Build.targets を作成する — カスタムビルドターゲット、ビルド後の検証、SDK で定義された値に依存するプロパティ(例:単一ターゲットのプロジェクトにおける OutputPath、TargetFramework)をここに移動します。これらは SDK の後にインポートされるため、すべてのプロパティを利用できます。
  4. Directory.Packages.props を作成する — 一元管理されたパッケージ管理(ManagePackageVersionsCentrally)を有効にし、すべての PackageVersion エントリを記述して、.csproj ファイルの PackageReference 項目から Version= を削除します。
  5. 複数階層の構成を設定する — src/ フォルダーと test/ フォルダーに、異なる設定を持つ内側の Directory.Build.props ファイルを作成します。親ファイルとの連結には GetPathOfFileAbove を使用します。
  6. .csproj ファイルを簡素化する — 一元管理されたプロパティ、バージョン属性、重複したターゲットをすべて削除します。各プロジェクトには、そのプロジェクト固有の内容のみを記述します。
  7. 検証する — 見つかった .sln、.slnx、.proj、またはプロジェクトのパスを対象に、復元とビルドを実行します。例:dotnet restore <entrypoint> && dotnet build <entrypoint>。ルートのエントリポイントが存在しない場合は、リポジトリのルートからビルドできると主張せず、見つかった各プロジェクトを個別に検証します。最終的に統合された内容を確認するには、dotnet msbuild <project> -pp:output.xml を使用します。

トラブルシューティング

問題原因解決方法
Directory.Build.props が読み込まれないファイル名の大文字・小文字が異なる(Linux/macOS では完全一致が必要)大文字・小文字を含め、正確なファイル名が Directory.Build.props(大文字の D、B)であることを確認します
.props のプロパティがプロジェクトに反映されないプロジェクトがインポート後に同じプロパティを設定しているプロパティを Directory.Build.targets に移動し、プロジェクトの後に設定します
複数階層のインポートが機能しない内側のファイルで GetPathOfFileAbove を使ったインポートが抜けている内側のファイルの先頭に <Import> 要素を追加します(複数階層のセクションを参照)
SDK の値を使うプロパティが .props で空になる.props の評価時点では SDK のプロパティがまだ定義されていないSDK の後にインポートされる .targets に移動します
Directory.Packages.props が見つからないファイルがリポジトリのルートにない、または名前が完全一致していないDirectory.Packages.props という名前で、プロジェクトディレクトリと同じ階層かそれより上に配置する必要があります
$(TargetFramework) を使ったプロパティ条件が .props で一致しない単一ターゲットのプロジェクトでは、.props の評価時点で TargetFramework がまだ設定されていないプロパティを .targets に移動するか、代わりに遅い段階で評価される ItemGroup/Target の条件を使用します

診断: プリプロセス済みのプロジェクト出力を使うと、すべてのインポートと最終的なプロパティ値を確認できます。

dotnet msbuild -pp:output.xml MyProject.csproj

これにより、すべてのインポートがインラインに展開され、各プロパティがどこで設定されているか、最終的に評価された値が何かを正確に確認できます。

コメント