mcpField
T
target-authoring

target-authoring

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

target-authoring について

カスタム MSBuild ターゲットを作成する開発者向けのスキルです。依存関係チェーン、拡張フック、ターゲット出力、命名、失敗時のクリーンアップを解説します。

主な機能

  1. 013段階ターゲットチェーンのパターン
  2. 02DependsOn の安全な拡張
  3. 03ターゲット順序機構の選択
  4. 04Returns と Outputs の使い分け
  5. 05ターゲットの命名規則
  6. 06OnError による失敗時のクリーンアップ

活用シーン

  1. 01既存のビルドチェーンへのターゲット追加
  2. 02SDK ターゲット前後への処理の挿入
  3. 03プロジェクト間でのクエリ結果の返却
  4. 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 を忘れると、ビルドエラー時にファイル追跡が失敗し、その後のインクリメンタルビルドに支障をきたします。

コメント