mcpField
T
target-authoring

target-authoring

github.com/dotnet开发5.8k3.1k 次安装1 天前更新
代码仓库

关于 target-authoring

面向编写自定义 MSBuild 目标的开发者技能,介绍依赖链、扩展钩子、目标输出、命名和失败清理模式。

主要功能

  1. 01三级目标链模式
  2. 02安全扩展 DependsOn
  3. 03选择目标排序机制
  4. 04Returns 与 Outputs 指引
  5. 05目标命名约定
  6. 06使用 OnError 清理失败

适用场景

  1. 01向现有构建链添加目标
  2. 02在 SDK 目标前后插入操作
  3. 03在项目间返回查询结果
  4. 04避免增量构建数据过期

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/dotnet/skills --skill target-authoring

安装后在 Claude Code 中输入/target-authoring确认已加载。

详细介绍

自定义目标编写模式

来自 MSBuild 仓库中 Microsoft.Common.CurrentVersion.targets 的规范模式。

三级目标链

每个主要入口点(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。
  • 当你无法控制目标文件时,优先使用 BeforeTargets="CoreCompile",而不是修改 $(CompileDependsOn)。

Returns 与 Outputs


<Target Name="Build"
    DependsOnTargets="$(BuildDependsOn)"
    Returns="@(TargetPathWithTargetPlatformMoniker)" />


<Target Name="GetTargetPath" Returns="@(TargetPathWithTargetPlatformMoniker)" />
  • Returns 指定调用此项目时 MSBuild 任务接收的内容。用于项目间通信。
  • 内部目标上的 Outputs 用于增量构建(时间戳检查)。用于判断是否为最新状态。
  • 绝不要混用这两种用途。查询目标(GetTargetPath、GetTargetFrameworks)应使用 Returns,而不是 Outputs。

目标命名约定

模式含义示例
_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