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[]

  • mokeefe

    No problem.

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


  • SalamELIAS

    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)');"


  • Carolyn Chau

    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


  • Tycotrix

    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.


  • qwerty51015

    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!


  • loosie

    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


  • dom_tiger_99

    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.


  • kmax

    FDBK45170 seems related to this, just slightly different failure

  • Rob Cannon

    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



  • Random behaviour with ITaskItem[]