如何为批处理任务的每次执行获取 MSBuild 输出参数?

How to get MSBuild output parameter for each execution of a batched task?

我有一个 MSBuild 目标,它 运行 是针对多个项目的 Exec 任务。我如何获得它们每个的退出代码?

只有当输入文件自上次 运行(即增量构建)后发生更改时,我才能使用它来获取所有退出代码和 运行:

<ItemGroup>
    <TestItem Include="MyFile1" />
    <TestItem Include="MyFile2" />
    <TestItem Include="MyFile10" />
</ItemGroup>

<Target Name="PrepareItemTest">
    <ItemGroup>
        <TestItem>
            <!-- The timestamp of the "done file" is used below to detect if this target has been run since the inputs have been modified. -->
            <DoneFilePath>%(TestItem.RelativeDir)%(TestItem.Filename).done/DoneFilePath>
        </TestItem>
    </ItemGroup>
</Target>

<Target Name="ItemTest"
      DependsOnTargets="PrepareItemTest"
      Inputs="@(TestItem);@(OtherInputs)"
      Outputs="%(TestItem.DoneFilePath)">

    <Exec Command="ECHO Running on %(TestItem.Identity) |findstr 1" IgnoreExitCode="true">
        <Output TaskParameter="ExitCode" PropertyName="TestExitCode"/>
    </Exec>

    <Error Condition=" '$(TestExitCode)' != '0' " Text="Error $TestExitCode" />
    <WriteLinesToFile Condition=" '$(TestExitCode)' == '0' " File="%(TestItem.DoneFilePath)" Lines="Ran successfully on %(TestItem.Filename)%(TestItem.Extension)" />
</Target>

输出:

Ran ItemTest. Exit code=0
Ran ItemTest. Exit code=1

所以这会打印返回的所有不同退出代码,但不会将它们与输入项相关联,所以我不知道哪些输入已成功处理,哪些未成功处理。

完成此任务的最简单方法是 batch 完成 目标 而不是任务本身。那实际上 "moves the loop up a level",来自(伪代码):

target PrepareItemTest {
    foreach item in TestItem {
        TestExitCode.append(exec().result))
    }
    warn("exit codes: " + TestExitCode)
}

target PrepareItemTest {
    foreach item in TestItem {
        TestExitCode.append(exec().result))
        warn("exit code: " item + " " + TestExitCode)
    }
}

如果项目代表产生输出的文件,这很简单,您应该在 Inputs 属性中进行批处理(并定义 Outputs 以获得正确的增量行为)。

对于您给出的示例,它有点令人困惑,因为目标没有生成一组输出文件。这意味着您必须滥用目标的 Outputs 属性才能获得批处理行为。你可以这样做:

<Target Name="ItemTest" Outputs="%(TestItem.Identity)">
    <Exec Command="ECHO Running on @(TestItem->'%(Identity)') |findstr 1" IgnoreExitCode="true">
        <Output TaskParameter="ExitCode" PropertyName="TestExitCode"/>
    </Exec>

    <Warning Text="Ran ItemTest for @(TestItem). Exit code=$(TestExitCode)" />
</Target>

产生

Project "D:\work\batch-over-target.proj" on node 1 (default targets).
ItemTest:
  ECHO Running on MyItem1 |findstr 1
  Running on MyItem1
D:\work\batch-over-target.proj(14,5): warning : Ran ItemTest for MyItem1. Exit code=0
ItemTest:
  ECHO Running on MyItem2 |findstr 1
  The command "ECHO Running on MyItem2 |findstr 1" exited with code 1.
D:\work\batch-over-target.proj(14,5): warning : Ran ItemTest for MyItem2. Exit code=1
ItemTest:
  ECHO Running on MyItem10 |findstr 1
  Running on MyItem10
D:\work\batch-over-target.proj(14,5): warning : Ran ItemTest for MyItem10. Exit code=0
Done Building Project "D:\work\batch-over-target.proj" (default targets).

这样做的原因是,在一个批次中,使用 @(ItemName) 访问的项目包括 仅适合该批次 的结果。如果您仔细确保每个批次只有一个项目,您可以将输出与输入相关联。