Mikayla Hutchinson
Mikayla Hutchinson

Reputation: 16153

MSBuild batching multiple inputs into each output

Is it possible to dependency-check multiple inputs for each output when using MSBuild batching?

I thought I'd found a solution to this by constructing my inputs list in the metadata of the output file, as follows:

<ItemGroup>
  <Foo Include="output1">
    <Inputs>input1a;input1b</Inputs>
  </Foo>
  <Foo Include="output2">
    <Inputs>input2a;input2b</Inputs>
  </Foo>
</ItemGroup>

<Target Name="_CompileFoo" Outputs="@(Foo)" Inputs="%(Foo.Inputs)">
    <FooCompiler Src="%(Foo.Inputs)" Out="@(Foo)" />
</Target>

However, MSBuild complains that the file "input1a;input1b" does not exist. It seems that the string->items conversion takes place before the expression evaluation.

Is there any solution to this other than writing my own dependency checking?

Upvotes: 9

Views: 4817

Answers (1)

Checking multiple dependencies works if the item group is set up the other way round with the compilation result as metadata.

<ItemGroup>
  <Foo Include="input1a">
    <Result>output1</Result>
  </Foo>
  <Foo Include="input1b">
    <Result>output1</Result>
  </Foo>
  <Foo Include="input2a">
    <Result>output2</Result>
  </Foo>
  <Foo Include="input2b">
    <Result>output2</Result>
  </Foo>
</ItemGroup>

<Target Name="_CompileFoo" Inputs="@(Foo)" Outputs="%(Result)">
  <FooCompiler Overwrite="true" Src="@(Foo)" Out="%(Foo.Result)"/>
</Target>

And instead of manually converting the Foo item group, you can transform this in a prerequisite target building a new item group _Foo as follows.

<ItemGroup>
  <Foo Include="output1">
    <Inputs>input1a;input1b</Inputs>
  </Foo>
  <Foo Include="output2">
    <Inputs>input2a;input2b</Inputs>
  </Foo>
</ItemGroup>

<Target Name="_PrepareItemsForCompileFoo">
  <ItemGroup>
    <_Foo Include="%(Foo.Inputs)">
      <Result>%(Foo.Identity)</Result>
    </_Foo>
  </ItemGroup>
</Target>

<Target Name="_CompileFoo" DependsOnTargets="_PrepareItemsForCompileFoo" Inputs="@(_Foo)" Outputs="%(Result)">
  <FooCompiler Overwrite="true" Src="@(_Foo)" Out="%(_Foo.Result)"/>
</Target>

Upvotes: 18

Related Questions