Как я могу выставить «Условия» MSBuild в VS2010 (для vС++)

У меня есть пользовательское правило сборки в VS2010 для моего проекта VC++. В этом правиле я хотел бы разрешить пользователям добавлять сложные условия, определяющие, обрабатывается ли файл.

Это также необходимо оценивать во время целевого выполнения, а не в «Состоянии» самого «Элемент» (из-за того, что только проект «приложение» может его обработать и должен обрабатывать с настройками проект приложения, а не зависимые проекты).

Я попытался добавить настраиваемое поле к объекту, а затем просто удалить элементы из группы во время выполнения. например

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

К сожалению, это дает мне ошибку:

ошибка MSB4113: указанное условие "!(%(MyItemType.IncludeCondition))" оценивается как "!'testfilename1' == 'testfilename2' или false" вместо логического значения.

(Исходное выражение условия в «%(MyItemType.IncludeCondition)» было '%(Filename)' == 'testfilename2' or $(TestBooleanFalse))

Похоже, что MSBuild не будет оценивать содержимое метаданных элемента как логическое значение (что в большинстве случаев кажется хорошей практикой, но не в этом случае).

Могу ли я в любом случае заставить MSbuild фактически оценить метаданные до логического значения или есть какой-то другой метод, который я мог бы использовать для получения того же результата?


P.S. Я кратко ознакомился со свойством MSBuild . Functions, но не смог увидеть ничего, что могло бы запустить логический оценочный код MSBuild по входным данным функции)


Очень урезанный пример проекта MSBuild, показывающий проблему, любезно предоставлен 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>

person Grant Peters    schedule 28.03.2013    source источник
comment
Пытался отредактировать сообщение, но оно было отклонено. Проверьте, хотите ли вы, чтобы это работало pastebin.com/nkdz80y5, и рассмотрите возможность включения образца в вопрос.   -  person Lanorkin    schedule 04.04.2013
comment
@Lanorkin - Спасибо, в приведенном вами примере была небольшая ошибка, но она показывает мою проблему. (Надеюсь, люди не просто ответят и скажут, что нужно превратить ItemGroup в «SpecifyConditions» в «Remove» с условием, указанным как условие объявления MyItemType)   -  person Grant Peters    schedule 05.04.2013


Ответы (3)


Это связано со способом оценки MSBuild. Дополнительные сведения см. в книге Сайеда: Внутри Microsoft® Build Engine: Использование MSBuild и Team Foundation Build

Перемещая положение условия в образце, вы можете добиться того, чего, я думаю, вы пытались достичь.

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

person MSBuildPM    schedule 08.04.2013
comment
В таком решении мы по-прежнему заставляем msbuild вычислять условие в задаче SpecifyConditions, а идея состоит в том, чтобы передать условие в качестве параметра, чтобы оно вычислялось в задаче Build. - person Lanorkin; 09.04.2013

Я думаю, что небольшая настройка вашего условного оператора от:

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

to

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

заключение первого условия в скобку решит проблему.

person RinoTom    schedule 04.04.2013

Попробуйте объявить условия встроенными вместо метаданных элемента:

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

Или используйте Property Functions в условии метаданных:

<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>
person KMoraz    schedule 29.03.2013
comment
Я не могу этого сделать, так как условия определяются пользователем для каждого файла (как указано в моем втором предложении в исходном вопросе). - person Grant Peters; 02.04.2013
comment
Это работает: Condition="'(%(MyItemType.IncludeCondition))' == 'False'" - person KMoraz; 02.04.2013
comment
нет, идея в том, что %(MyItemType.IncludeCondition) расширяется как string, а не как логическое значение, хотя оно и не оценивается - person Lanorkin; 04.04.2013