Random behaviour with ITaskItem[]

I have a target that I pass an ItemGroup to. I then call a task that takes this ItemGroup as a parameter and a ITaskItem as another parameter.

Sometimes, if I pass an ITaskItem[] to the ITaskItem parameter, MSBuild is clever enough to realise that I want the task called once for each item in the ItemGroup.

Most of the time, however, I get this error: Multiple items cannot be passed into a parameter of type "Microsoft.Build.Framework.ITaskItem"

Anyone any ideas why this behaviour would be so random



Answer this question

Random behaviour with ITaskItem[]

  • Derek Knudsen

    Thanks, Sumedh

    Interestingly, I fixed the problem by actually reading the documentation on batching and removing the transform from the OutputFile attribute.

    <Target Name="Compile" Inputs="@(Compile);"
    Outputs="@(Compile -> '%(Filename)$(OutputExtension)')"
    DependsOnTargets="$(CompileDependsOn)">

    <Task
    SourceFiles="@(Compile)"
    OutputFile="$(IntermediateOutputPath)%(Filename)$(IntermediateExt)"/>
    </Target>

    I am convinced, however that the malformed Outputs parameter shouldn't have caused that behaviour, and is probably a bug!


  • tropics43

    Can you tell me what items are in the @(Compile) list. Just one item or multiple items

    Can you also tell me what the values are of the properties $(xxx) in the snippet above. I want to try and reproduce/debug this.


  • Steve010010101111101010011111111

    FDBK45170 seems related to this, just slightly different failure

  • Nagendra Rao S.V

    Michael,

    Can you please log this issue along with the details of your investigation through the MSDN Product Feedback Center (http://lab.msdn.microsoft.com/productfeedback/default.aspx) This will get it into our bug database and we can investigate a fix for our next release.

    Neil



  • Deathra

    Hi Michael,

    This is hard to believe, but this behaviour is actually "by design". Of course, we intend to fix this "design". Thanks for logging a bug via MSDN.

    The issue, of course, is the incorrectly formatted transform in the Outputs attribute. Because the Outputs transform is incorrectly formatted for the "Bug" target, we ignore the transform and pick up just the correctly formatted %(Filename) instead. This causes target batching, and the one-by-one behaviour, which is what the task expects.

    The fix would be to detect the incorrect transform and error out so you know what's going on. And then the right action for the user would be to move the batching onto the task (which is what you've done).

    Thanks!

    --Sumedh


  • Siang

    No problem.

    This has been filed as bug number FDBK46603 - "Improperly formed Outputs parameter causes strange batching behaviour"


  • LoneStar

    Sumedh, it doesn't matter what the values of the properties are. I can reproduce the error with the following:

    < xml version="1.0" encoding="utf-8" >
    <
    Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build"
    >
    <
    ItemGroup
    >
    <
    Test Include="c:\windows\*.dll"
    />
    </
    ItemGroup
    >

    <UsingTask TaskName="MyTask" AssemblyFile="MyTask.dll" />

    <Target Name="Build" Inputs="@(Test)" Outputs="@(Test->'c:\test\%(FileName).txt')">
    <
    MyTask Files ="@(Test)" FileToCreate="@(Test->'c:\test\%(FileName).txt')"
    />
    </
    Target
    >

    <Target Name="Bug" Inputs="@(Test)" Outputs="@(Test->'c:\test\%(FileName).txt'">
    <
    MyTask Files ="@(Test)" FileToCreate="@(Test->'c:\test\%(FileName).txt')"
    />
    </Target
    >

    </Project>

    Where MyTask looks like this:

    public class MyTask:Task
    {
    private ITaskItem[] files;

    public ITaskItem[] Files
    {
    get { return files; }
    set { files = value; }
    }

    private ITaskItem fileToCreate;

    public ITaskItem FileToCreate
    {
    get { return fileToCreate; }
    set { fileToCreate = value; }
    }

    public override bool Execute()
    {
    Log.LogCommandLine(fileToCreate.ItemSpec);
    return true;
    }
    }

    Running the Build target will throw an error, whereas the Bug target will use batching and pass the test. The only difference between the two targets is the improperly terminated Outputs parameter.

    Hope that helps you track down the problem.


  • aniscartujo

    Okay, it appears to be related to transforms and the Outputs parameter.

    If I specify the target like this:

    <Target Name="Compile" Inputs="@(Compile);"
    Outputs="@(Compile -> '%(Filename)$(OutputExtension)
    "
    DependsOnTargets="$(CompileDependsOn)"
    >

    <Task
    SourceFiles="@(Compile)
    "
    OutputFile="@(Compile -> '$(IntermediateOutputPath)%(Filename)$(IntermediateExt)');
    "/>
    </
    Target>

    It works, but I lose the Outputs checking because the transform is incorrectly terminated.

    <Target Name="Compile" Inputs="@(Compile);"
    Outputs="@(Compile -> '%(Filename)$(OutputExtension)')
    "
    DependsOnTargets="$(CompileDependsOn)"
    >

    <Task
    SourceFiles="@(Compile)
    "
    OutputFile="@(Compile -> '$(IntermediateOutputPath)%(Filename)$(IntermediateExt)');
    "/>
    </
    Target>

    When I terminate the Outputs correctly, the task fails with the error in my first post.

    Interestingly, having no inputs and outputs also causes the error.

    Is this a bug


  • Fernandob

    Michael,

    Why do you have a semi-colon at the end of this I think presence of the semi-colon is causing the error. (I need to look into why having a malformed Outputs on the target doesn't cause the error... I'll reply again later...)

    OutputFile="@(Compile -> '$(IntermediateOutputPath)%(Filename)$(IntermediateExt)');"


  • Random behaviour with ITaskItem[]