target-authoring について
カスタム MSBuild ターゲットを作成する開発者向けのスキルです。依存関係チェーン、拡張フック、ターゲット出力、命名、失敗時のクリーンアップを解説します。
主な機能
- 013段階ターゲットチェーンのパターン
- 02DependsOn の安全な拡張
- 03ターゲット順序機構の選択
- 04Returns と Outputs の使い分け
- 05ターゲットの命名規則
- 06OnError による失敗時のクリーンアップ
活用シーン
- 01既存のビルドチェーンへのターゲット追加
- 02SDK ターゲット前後への処理の挿入
- 03プロジェクト間でのクエリ結果の返却
- 04増分ビルドデータの古さの回避
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ dotnet/ skills --skill target-authoringインストール後、Claude Code で/target-authoringを入力して読み込まれたか確認します。
詳細
カスタムターゲットの作成パターン
MSBuild リポジトリの Microsoft.Common.CurrentVersion.targets にある標準的なパターンです。
3 段階のターゲットチェーン
主要なエントリーポイント(Build、Rebuild、Clean)はすべて、依存関係を列挙するプロパティに処理を委譲し、Before → Core → After とつながります。
<PropertyGroup>
<BuildDependsOn>
BeforeBuild;
CoreBuild;
AfterBuild
</BuildDependsOn>
</PropertyGroup>
<Target Name="Build"
Condition=" '$(_InvalidConfigurationWarning)' != 'true' "
DependsOnTargets="$(BuildDependsOn)"
Returns="@(TargetPathWithTargetPlatformMoniker)" />
<Target Name="BeforeBuild" />
<Target Name="AfterBuild" />
CoreBuild は $(CoreBuildDependsOn) に処理を委譲し、エラーハンドラーを含みます。
<Target Name="CoreBuild" DependsOnTargets="$(CoreBuildDependsOn)">
<OnError ExecuteTargets="_TimeStampAfterCompile;PostBuildEvent"
Condition="'$(RunPostBuildEvent)' == 'Always'" />
<OnError ExecuteTargets="_CleanRecordFileWrites" />
</Target>
ルール
- ハードコードされたターゲットではなく、プロパティ(
DependsOnTargets="$(MyTargetDependsOn)")に処理を委譲します。 - クリーンアップが失敗時にも実行されるよう、
OnErrorはオーケストレーションを行うターゲット内に記述します。 - 空の Before/After ターゲットは拡張ポイントです。ユーザーがオーバーライドするものであり、SDK がロジックを記述する場所ではありません。
チェーンの拡張 — 上書きせずに追加する
既存のチェーンにカスタムターゲットを追加する場合は、DependsOn プロパティに追加します。
<PropertyGroup>
<CompileDependsOn>$(CompileDependsOn);MyCodeGenTarget</CompileDependsOn>
</PropertyGroup>
<PropertyGroup>
<CompileDependsOn>MyCodeGenTarget</CompileDependsOn>
</PropertyGroup>
DependsOnTargets と BeforeTargets / AfterTargets
| 仕組み | 定義場所 | 最適な用途 |
|---|---|---|
DependsOnTargets | 依存関係を必要とするターゲット | ターゲットが他のターゲットを明示的に必要とする場合 |
BeforeTargets | 挿入するターゲット | 所有していないターゲットの前に挿入する場合 |
AfterTargets | 挿入するターゲット | 所有していないターゲットの後に挿入する場合 |
検証ターゲットは BeforeTargets を使って、すべてのエントリーポイントを捕捉します。
<Target Name="_CheckForInvalidConfigurationAndPlatform"
BeforeTargets="$(BuildDependsOn);Build;$(RebuildDependsOn);Rebuild;$(CleanDependsOn);Clean">
</Target>
ルール:
- ターゲットに特定の前提条件が必要な場合は、
DependsOnTargetsを使います。 - 自分が所有していないパイプラインに挿入する場合は、
BeforeTargets/AfterTargetsを使います。 - ターゲットファイルを管理していない場合は、
$(CompileDependsOn)を変更するよりもBeforeTargets="CoreCompile"を優先します。
Returns と Outputs
<Target Name="Build"
DependsOnTargets="$(BuildDependsOn)"
Returns="@(TargetPathWithTargetPlatformMoniker)" />
<Target Name="GetTargetPath" Returns="@(TargetPathWithTargetPlatformMoniker)" />
Returnsは、このプロジェクトを呼び出すときに MSBuild タスクが受け取る値を指定します。プロジェクト間の通信に使います。- 内部ターゲットの
Outputsはインクリメンタル処理(タイムスタンプのチェック)用です。最新状態の判定に使います。 - この 2 つの用途を混在させないでください。
GetTargetPathやGetTargetFrameworksなどのクエリターゲットでは、OutputsではなくReturnsを使います。
ターゲットの命名規則
| パターン | 意味 | 例 |
|---|---|---|
_PrefixedName | 内部/プライベートターゲット | _TimeStampBeforeCompile |
CoreXxx | 実際の実装 | CoreBuild、CoreCompile |
BeforeXxx / AfterXxx | 空の拡張フック | BeforeBuild、AfterCompile |
PrepareXxx | セットアップ/検証フェーズ | PrepareForBuild |
ResolveXxx | 検出/解決フェーズ | ResolveReferences |
GetXxx | 軽量なクエリ(副作用なし) | GetTargetPath |
カスタムターゲットの完全なテンプレート
<PropertyGroup>
<MyFeatureDependsOn>
_ValidateMyFeatureInputs;
BeforeMyFeature;
CoreMyFeature;
AfterMyFeature
</MyFeatureDependsOn>
</PropertyGroup>
<Target Name="MyFeature"
DependsOnTargets="$(MyFeatureDependsOn)"
Returns="@(MyFeatureOutput)" />
<Target Name="BeforeMyFeature" />
<Target Name="AfterMyFeature" />
<Target Name="CoreMyFeature"
Inputs="$(MSBuildAllProjects);@(MyFeatureInput)"
Outputs="$(IntermediateOutputPath)myfeature.generated.cs">
<Exec Command="my-tool.exe -o $(IntermediateOutputPath)myfeature.generated.cs" />
<ItemGroup>
<Compile Include="$(IntermediateOutputPath)myfeature.generated.cs" />
<FileWrites Include="$(IntermediateOutputPath)myfeature.generated.cs" />
</ItemGroup>
</Target>
<Target Name="_ValidateMyFeatureInputs">
<Error Text="MyFeatureInput items are required."
Condition="'@(MyFeatureInput)' == ''" />
</Target>
よくある落とし穴
DependsOnプロパティを上書きすると、SDK のターゲットが気づかれないまま失われます。 追加する際は、必ず$(ExistingProperty)を含めてください。- クエリターゲットで
Outputsを使うと、MSBuild が「最新状態」と判断してターゲットをスキップし、古いデータを返します。Returnsを使ってください。 .propsにターゲットを定義すると、SDK ターゲットのBeforeTargetsがフックできる対象がまだありません。 ターゲットを.targetsに移してください。- オーケストレーションを行うターゲットで
OnErrorを忘れると、ビルドエラー時にファイル追跡が失敗し、その後のインクリメンタルビルドに支障をきたします。
コメント
Markdown 対応