在msbuild中使用目标批处理时如何处理错误?

在msbuild中使用目标批处理时如何处理错误?,msbuild,Msbuild,我正在对一个目标使用批处理,我希望能够执行特定于发生错误的迭代的错误清理。下面是一个完全通用的示例: <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0" DefaultTargets="Build"> <ItemGroup> <Example Include="Item1"> <Color>Blue&

我正在对一个目标使用批处理,我希望能够执行特定于发生错误的迭代的错误清理。下面是一个完全通用的示例:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0" DefaultTargets="Build">

<ItemGroup>
    <Example Include="Item1">
        <Color>Blue</Color>
    </Example>
    <Example Include="Item2">
        <Color>Red</Color>
    </Example>
</ItemGroup>

<Target Name="Build"
    Inputs="@(Example)"
    Outputs="%(Example.Color).txt">
    <Error Text="An error occurred during %(Example.Color)" />
    <OnError ExecuteTargets="HandleErrors" />
</Target>

<Target Name="HandleErrors">
    <Message Text="Do some cleanup about %(Example.Color)" Importance="high" />
</Target>

</Project>

蓝色
红色

当颜色为蓝色时,生成目标失败。但是HandleErrors目标运行两次,每种颜色运行一次。是否有办法使其仅针对故障期间处于活动状态的颜色运行?

IIUC,您的HandleErrors将单独批处理

您将有条件或无条件地使用错误任务。无论哪种情况,您都应该能够使用task调用HandleErrors并将%(Example.Color)作为属性传递。比如:

<MSBuild Targets="HandleErrors" Properties="ErrorColor=%(Example.Color)" />


另一种方法是,在发生错误时创建一个属性,并在HandleErrors目标中使用该属性。尽管上述方法会更干净。

我认为不清楚这里到底发生了什么。在我们进入你的问题之前,让我们来看看发生了什么,通过修改你的PRJ文件。

下面是一个修改过的文件sample-no-error.proj,我在其中删除了错误部分,并在其中添加了一个消息任务

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0" DefaultTargets="Build">
  <ItemGroup>
      <Example Include="Item1">
          <Color>Blue</Color>
      </Example>
      <Example Include="Item2">
          <Color>Red</Color>
      </Example>
  </ItemGroup>

  <Target Name="Build"
      Inputs="@(Example)"
      Outputs="%(Example.Color).txt">

    <Message Text="Inside of Build, color: %(Example.Color)" />
  </Target>  
</Project>

蓝色
红色
当我从命令行构建它时,结果是。 从这里我们可以看到目标本身被执行了两次。这是因为在目标上,您已使用Outputs=%(Example.Color).txt装饰它。使用%(…)时,将启动MSBuild批处理。有两种配料方式;目标批处理,任务批处理。目标批处理是指每批执行一个完整的目标(这就是您在这里要做的)。任务批处理是指每批执行一个任务

我有另一个示例,它与您的示例完全相同,只是我在构建目标中添加了一个额外的消息语句

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0" DefaultTargets="Build">
  <ItemGroup>
      <Example Include="Item1">
          <Color>Blue</Color>
      </Example>
      <Example Include="Item2">
          <Color>Red</Color>
      </Example>
  </ItemGroup>

  <Target Name="Build"
      Inputs="@(Example)"
      Outputs="%(Example.Color).txt">

    <Message Text="Inside of Build, color: %(Example.Color)" />

    <Error Text="An error occurred during %(Example.Color)" />
    <OnError ExecuteTargets="HandleErrors" />
  </Target>

  <Target Name="HandleErrors">
    <Message Text="Inside of the HandleErrors target" />
    <Message Text="Do some cleanup about %(Example.Color)" Importance="high" />
  </Target>
</Project>

蓝色
红色
当我构建这个时,结果是。 基于此,我们可以看到构建目标执行了一次,并且发生了一个错误,因此第二次没有执行,就像在上一个没有错误的示例中一样。在那之后,手误目标踢了进来。在那里面它遇到了元素

<Message Text="Inside of the HandleErrors target" />

消息被发送到记录器(注意,这只被调用了一次)。在那之后,事情变得复杂起来

<Message Text="Do some cleanup about %(Example.Color)" Importance="high" />

现在,这产生了两个消息语句。这是因为任务批处理已经开始在这里发挥作用。该任务在红色和蓝色的%(Example.Color)的每个唯一批中调用一次。因此,我们知道该目标只被调用了一次(在原始错误发生的地方),但您正在将整个示例项集传递给它

如果您想知道哪个值产生了错误,您必须在构建目标中跟踪该值。您可以将当前颜色放置在属性中,然后在HandleErrors目标中引用该颜色。例如,请看下面的sample-id-errors.proj

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0" DefaultTargets="Build">
  <ItemGroup>
      <Example Include="Item1">
          <Color>Blue</Color>
      </Example>
      <Example Include="Item2">
          <Color>Red</Color>
      </Example>
  </ItemGroup>

  <Target Name="Build"
      Inputs="@(Example)"
      Outputs="%(Example.Color).txt">
    <PropertyGroup>
      <_LastUsedColor>%(Example.Color)</_LastUsedColor>
    </PropertyGroup>

    <Message Text="Inside of Build, color: %(Example.Color)" />

    <Error Text="An error occurred during %(Example.Color)" />
    <OnError ExecuteTargets="HandleErrors" />
  </Target>

  <Target Name="HandleErrors">
    <Message Text="Inside of the HandleErrors target" />
    <Message Text="The color which caused the error was: $(_LastUsedColor)"/>
  </Target>
</Project>

蓝色
红色
%(例如:颜色)
在这里您可以看到,在构建中,我只是设置了_LastUsedColor属性的值,然后如果发生错误,我就在该目标中使用相同的属性。当我构建这个文件时,结果是


我想这就是你想要实现的。如果您不知道批处理是如何工作的,那么批处理是相当混乱的。我在网上找到了一大堆关于批处理的资源

Aha!我没有注意到我在HandleErrors目标中通过引用那里的%(Example.Color)进行任务批处理。当然,设置属性正是我所需要的。感谢您快速而详细的回复(以及您不可或缺的书籍:-)。