property-patterns について
MSBuildプロパティの標準的なパターンを記録したリファレンススキルです。既定値、条件、値の結合、パス、評価順序を扱い、MSBuildプロジェクトファイルの保守に役立ちます。
主な機能
- 01上書き可能な条件付き既定値
- 02入れ子の条件付きプロパティグループ
- 03セミコロンによるプロパティ結合
- 04パス正規化パターン
- 05ターゲットフレームワークとバージョンのガード
- 06評価順序とフォールバックの指針
活用シーン
- 01呼び出し側が上書きできる既定値の定義
- 02定数や警告コードの安全な追加
- 03プロジェクトファイル間のパス正規化
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ dotnet/ skills --skill property-patternsインストール後、Claude Code で/property-patternsを入力して読み込まれたか確認します。
詳細
MSBuild プロパティのパターン
MSBuild リポジトリにおける、標準的なプロパティの定義と操作のパターンです。
条件付きの既定値 — 基本パターン
呼び出し元が上書きできるよう、プロパティがまだ設定されていない場合にのみ設定します。
<PropertyGroup>
<Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
<Platform Condition="'$(Platform)' == ''">AnyCPU</Platform>
<BuildInParallel Condition="'$(BuildInParallel)' == ''">true</BuildInParallel>
</PropertyGroup>
ルール
- 常に両辺を引用符で囲みます:
'$(Prop)' == '' .props:上書き可能な既定値を作成します。.targets:フォールバックを作成します。- 条件のないプロパティは、先にインポートされた内容から上書きできません。
入れ子になった条件付きグループ
関連するプロパティを共通の条件の下にまとめます。
<PropertyGroup Condition="$(TargetFramework.StartsWith('net4'))">
<DefineConstants>$(DefineConstants);FEATURE_APARTMENT_STATE</DefineConstants>
<DefineConstants>$(DefineConstants);FEATURE_APM</DefineConstants>
<FeatureAppDomain>true</FeatureAppDomain>
</PropertyGroup>
<PropertyGroup Condition="'$([MSBuild]::GetTargetFrameworkIdentifier('$(TargetFramework)'))' == '.NETCoreApp'">
<NetCoreBuild>true</NetCoreBuild>
<DefineConstants>$(DefineConstants);RUNTIME_TYPE_NETCORE</DefineConstants>
</PropertyGroup>
各プロパティで同じ条件を繰り返さないよう、PropertyGroup に外側の Condition を指定します。
警告: 単一ターゲットのプロジェクトでは、プロジェクト本体が評価されるまで、
.propsファイル内の$(TargetFramework)は空です。TargetFrameworkを条件にしたプロパティグループは、値を常に利用できる.targetsファイル(またはプロジェクトファイル自体)に配置してください。
結合 — セミコロンによる連結
リストを保持するプロパティではセミコロンを使用します。値を追加する際は、必ず既存の値を含めてください。
<PropertyGroup>
<DefineConstants>$(DefineConstants);MY_FEATURE</DefineConstants>
<NoWarn>$(NoWarn);NU5131;IDE0005</NoWarn>
<LibraryTargetFrameworks>$(FullFrameworkTFM);$(LatestDotNetCoreForMSBuild);netstandard2.0</LibraryTargetFrameworks>
</PropertyGroup>
パスの正規化と末尾のスラッシュ
<PropertyGroup>
<OutDir Condition="'$(OutDir)' != '' and !HasTrailingSlash('$(OutDir)')">$(OutDir)\</OutDir>
</PropertyGroup>
<PropertyGroup>
<TargetRefPath>$([MSBuild]::NormalizePath('$(TargetDir)', 'ref', '$(TargetFileName)'))</TargetRefPath>
</PropertyGroup>
<PropertyGroup>
<MSBuildProjectExtensionsPath
Condition="'$([System.IO.Path]::IsPathRooted('$(MSBuildProjectExtensionsPath)'))' == 'false'">
$([System.IO.Path]::Combine('$(MSBuildProjectDirectory)', '$(MSBuildProjectExtensionsPath)'))
</MSBuildProjectExtensionsPath>
</PropertyGroup>
推奨されるパス関数
| 関数 | 用途 |
|---|---|
$([MSBuild]::NormalizePath(...)) | パスを結合して正規化します(クロスプラットフォーム対応) |
$([System.IO.Path]::Combine(...)) | パスの各要素を結合します |
$([System.IO.Path]::IsPathRooted(...)) | 絶対パスかどうかを確認します |
HasTrailingSlash(...) | 末尾にスラッシュがあるかどうかを確認します |
$([MSBuild]::GetDirectoryNameOfFileAbove(...)) | ディレクトリツリーを上にたどります |
$(MSBuildThisFileDirectory) | 現在のファイルがあるディレクトリ |
ターゲットフレームワーク検出ヘルパー
<PropertyGroup Condition="'$([MSBuild]::GetTargetFrameworkIdentifier('$(TargetFramework)'))' == '.NETCoreApp'">
<NetCoreBuild>true</NetCoreBuild>
</PropertyGroup>
<PropertyGroup Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net472'))">
<UseFrozenVersions>true</UseFrozenVersions>
</PropertyGroup>
<PropertyGroup Condition="$([MSBuild]::IsOSPlatform('windows'))">
<DefineConstants>$(DefineConstants);TEST_ISWINDOWS</DefineConstants>
</PropertyGroup>
ガードプロパティ
二重インポートを防ぐため、ファイルがインポート済みであることを示します。
<PropertyGroup>
<MySDKPropsImported>true</MySDKPropsImported>
</PropertyGroup>
<Import Project="MySDK.props" Condition="'$(MySDKPropsImported)' != 'true'" />
MSBuild のバージョンによる機能の切り替え
<PropertyGroup Condition="$([MSBuild]::AreFeaturesEnabled('17.10'))">
<UseNewBehavior>true</UseNewBehavior>
</PropertyGroup>
フォールバックチェーン
まず優先するソースから設定し、次にフォールバックします。
<PropertyGroup>
<TlbExpPath>$([Microsoft.Build.Utilities.ToolLocationHelper]::GetPathToDotNetFrameworkSdkFile('tlbexp.exe'))</TlbExpPath>
<TlbExpPath Condition="'$(TlbExpPath)' == ''">$(_NetFxToolsDir)TlbExp.exe</TlbExpPath>
</PropertyGroup>
後勝ち — 評価順序
MSBuild はプロパティを上から下へ評価します。最後に割り当てられた値が有効になります。
<MyProp>value1</MyProp>
<MyProp>value2</MyProp>
<MyProp Condition="'$(MyProp)' == ''">value3</MyProp>
後からインポートされる .targets のプロパティは、先にインポートされる .props およびプロジェクトファイル内のプロパティを上書きします。
よくある落とし穴
- 引用符で囲まれていない条件(
$(X)==true)は、プロパティが空の場合に失敗します。常に両辺を引用符で囲んでください。 - DefineConstants の上書き(
<DefineConstants>MY_CONST</DefineConstants>)を行うと、それまでの定数がすべて失われます。必ず$(DefineConstants);を使って追加してください。 - ハードコードされた絶対パスは移植性を損ないます。
$(MSBuildThisFileDirectory)または$([MSBuild]::NormalizePath(...))を使用してください。 - 既定値に
Conditionがないと、プロパティを上書きできなくなります。既定値として設定する値にはCondition="'$(Prop)' == ''"を追加してください。
コメント
Markdown 対応