2

In my build process, I'm always using a pattern, whereby somes tasks are designed to compute the list of items in an item group, and some other tasks create the physical corresponding items.

This allows me to minimize my build times by performing incremental build.

In one of our project, I need to manipulate the items in an ItemGroup. My first attempt, was to first, clear the contents of the ItemGroup and then, include only the ones I'm interested about back into the ItemGroup.

However, I stumbled upon a behavior of MSBuild that does not make sense to me. The issue, is trying to clear items from an ItemGroup only when a particular Target executes. That is, only if, after analysing its Inputs and Outputs attributes, MSBuild determines that the Target must be executed.

Here is a minimal code snippet that reproduce my problem:

  <Target Name="ComputeCustomItemGroup">
    <CreateItem Include="C:\Temp\fichier1.ext;C:\Temp\fichier2.ext;">
      <Output TaskParameter="Include" ItemName="CustomItemGroup" />
    </CreateItem>
  </Target>

  <Target Name="CreateCustomItemGroup" DependsOnTargets="ComputeCustomItemGroup"
          Inputs="C:\Temp\input"
          Outputs="C:\Temp\output">
    <Message Text="Creating custom item group..." />
    <!-- Would like the ability to clear item group *ONLY* when the target is executed -->
    <!-- But this clears the item group every time it appears in the dependency chain of a currently executing target ! -->
    <ItemGroup>
      <CustomItemGroup Remove="@(CustomItemGroup)" />
    </ItemGroup>
  </Target>

  <Target Name="CustomTarget" DependsOnTargets="CreateCustomItemGroup">
    <Message Text="Executing Custom Target..." />
    <!-- Here, @(CustomItemGroup) is always empty... -->
    <Message Text="CustomItemGroup: @(CustomItemGroup)" />
  </Target>

  <Target Name="Build" DependsOnTargets="CustomTarget" />

</Project>

In the code sample above, the @(CustomItemGroup) is initially set to a collection containing a couple of file paths. That's fine.

Now, if you create two files, at the following locations C:\Temp\input and C:\Temp\output (one after the other, obviously), then the result of the sample code above is that @(CustomItemGroup) comes back empty, even though the Target Name="CreateCustomItemGroup" is not executed.

I've tried using the legacy CreateItem way to manipulate ItemGroups but I could not find a safisfying answer.

Can anyone suggest a workaround?

Maxime Labelle
  • 3,609
  • 2
  • 27
  • 48
  • Something in your snippet logic doesn't add up. `CreateCustomItemGroup` _always_ gets executed because there's no conditions defined that will to tell it not to. – KMoraz Apr 18 '13 at 22:15
  • 1
    It is not *always* executed. If both files exist and the output file is more recent than the input file, the CreateCustomItemGroup target is definitely *not* executed. – Maxime Labelle Apr 19 '13 at 05:01

1 Answers1

1

You are facing "Output Inference" as described here http://msdn.microsoft.com/en-us/library/vstudio/ee264087%28v=vs.100%29.aspx

The target has no out-of-date outputs and is skipped. MSBuild evaluates the target and makes changes to items and properties as if the target had been run.

Consider re-designing your logic to use condition statements for assignments.

Lanorkin
  • 7,310
  • 2
  • 42
  • 60
  • Thanks that's exactly my issue here. This feature makes a lot of sense and it allows me to simplify a bit of my logic. In this particular instance, I ended up modifying the custom task run as part of the ComputeXXX target to get the same information that it would otherwise have gotten when running the CreateXXX target. If that makes sense... – Maxime Labelle Apr 19 '13 at 13:38