5

I've got a custom build rule in VS2010 for my VC++ project. In this rule, I'd like to allow the users to add complex conditions on whether the file is processed.

This also needs to be evaluated at the time of the target execution rather than in the 'Condition' of the 'Item' itself (due to the fact that only the 'application' project can process it and needs to process it with the settings of the 'application' project and not the dependent projects).

I've tried adding a custom field to the object and then just removing the items from the group at execution time. e.g.

<ItemGroup>
    <MyItemType Remove="@(MyItemType)" Condition="!(%(MyItemType.IncludeCondition))" />
</ItemGroup>

Unfortunately, this gives me the error:

error MSB4113: Specified condition "!(%(MyItemType.IncludeCondition))" evaluates to "!'testfilename1' == 'testfilename2' or false" instead of a boolean.

(The original condition expression in '%(MyItemType.IncludeCondition)' was '%(Filename)' == 'testfilename2' or $(TestBooleanFalse))

It seems as though MSBuild won't evaluate the contents of the item metadata to a boolean (which seems like good practice in most circumstances, just not this one).

Is there anyway I can get MSbuild to actually evaluate the metadata down to a boolean value, or is there some other method I could use to get the same result?


P.S. I've had a brief look through the MSBuild Property Functions, but couldn't see anything that would run the MSBuild boolean evaluation code over the function input)


A very trimmed down example of an MSBuild project showing the issue, courtesy of Lanrokin:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
    <ItemGroup>
        <MyItemType Include="item1.ext1" />
        <MyItemType Include="item1.ext2" />
    </ItemGroup>

    <Target Name="SpecifyConditions">
        <ItemGroup>
            <MyItemType>
                <IncludeCondition>'%(Filename)%(Extension)' == 'item1.ext1'</IncludeCondition>
            </MyItemType>
        </ItemGroup>
    </Target>

    <Target Name="Build" DependsOnTargets="SpecifyConditions">
        <Message Importance="high" Text="@(MyItemType)" Condition="%(MyItemType.IncludeCondition)" />
    </Target>
</Project>
Grant Peters
  • 7,691
  • 3
  • 45
  • 57
  • Tried to edit post but it was rejected. Please review if it si something you want to make work http://pastebin.com/nkdz80y5 and consider including sample into question – Lanorkin Apr 04 '13 at 13:30
  • @Lanorkin - Thanks, there was a slight bug in the example you gave, but it shows the issue I'm having. (Hopefully people won't just respond and say to turn the `ItemGroup` in 'SpecifyConditions' into a 'Remove' with the condition specified as a condition of the `MyItemType` declaration) – Grant Peters Apr 05 '13 at 02:58

3 Answers3

1

This has to do with the way in which MSBuild evaluates. See Sayed's book for more information: Inside the Microsoft® Build Engine: Using MSBuild and Team Foundation Build

By moving the location of the condition in the sample, you can accomplish what I think you were trying to achieve.

<Target Name="SpecifyConditions">
    <ItemGroup>
        <MyItemType Condition="'%(Filename)%(Extension)' == 'item1.ext1'">
            <IncludeCondition>true</IncludeCondition>
        </MyItemType>
    </ItemGroup>
</Target>

<Target Name="Build" DependsOnTargets="SpecifyConditions">
    <Message Importance="high" Text="@(MyItemType)" Condition="%(MyItemType.IncludeCondition) == 'true'" />
</Target>

MSBuildPM
  • 11
  • 1
  • In such solution we still make msbuild to calculate condition in `SpecifyConditions` task, while idea is to "pass" condition as a parameter, so that it will be calculated in `Build` task. – Lanorkin Apr 09 '13 at 07:40
0

Try to declare the conditions inline instead of the item metadata:

 <ItemGroup>
    <MyItemType Remove="@(MyItemType)" Condition="('%(MyItemType.Filename)' == 'testfilename2')" />
  </ItemGroup>

Or use Property Functions in the metadata condition:

<Target Name="SpecifyConditions">
    <ItemGroup>
        <MyItemType>
            <IncludeCondition>$([System.String]::Equals('%(Filename)%(Extension)', 'item1.ext1'))</IncludeCondition>
        </MyItemType>
    </ItemGroup>
</Target>

<Target Name="Build" DependsOnTargets="SpecifyConditions">
    <Message Importance="high" Text="@(MyItemType)" Condition="%(MyItemType.IncludeCondition)" />
</Target>
KMoraz
  • 14,004
  • 3
  • 49
  • 82
  • I can't do this as the conditions are user defined per file (as noted in my second sentence in the original question). – Grant Peters Apr 01 '13 at 23:46
  • Does this work: `Condition="'(%(MyItemType.IncludeCondition))' == 'False'"` – KMoraz Apr 02 '13 at 17:11
  • no, idea is that `%(MyItemType.IncludeCondition)` expanded as `string` rather than boolean, though it is not evaluated – Lanorkin Apr 04 '13 at 13:47
0

I think a small tweak of your conditional statement from:

'%(Filename)' == 'testfilename2' or $(TestBooleanFalse)

to

('%(Filename)' == 'testfilename2') or $(TestBooleanFalse)

by wrapping the first condition inside a bracket will fix the problem.

RinoTom
  • 2,278
  • 2
  • 26
  • 40