如何在使用其他规则的属性时设置自定义构建规则的输出属性?

问题描述:





我设法用VS2008构建自定义构建规则并在VS2010中升级它。

但我有一个问题在VS2010中使用规则的输出属性。



基本上,我添加了一个自定义属性名称OutputSubDir(String),我想在Outputs属性中使用它,就像这样:$(Target)%(OutputSubDir)%(Filename).txt



当我为OutputSubDir设置默认值(在props文件中)时,我的自定义构建规则即使我为项目中的选定项目设置了一个新值,也使用了这个值。

唯一的方法,我让MSBuild使用新的一个是覆盖Outputs属性(使用相同的值)作为默认值!)



看起来像:

- 项目项有输出属性,然后使用项目项的OutputSubDir属性

- Project Item没有Outputs属性,使用Project的Outputs属性然后在同一位置使用OutputSubDir属性输出属性(即:在项目级别=默认值)



看起来MSBuild不允许对其项目进行多态性。



您是否知道我如何配置属性,规则和/或目标以使用良好的值来生成输出?



你知道VS2013问题是否仍然存在吗?



我可以提供样本文件(.props,.xml& .targets)但是很长时间才将它们直接放在问题中。 (我不知道是否可以在这里上传它们)



以下是文件:

TestRule.xml

Hi,

I manage to build a custom build rule with VS2008 and upgrade it in VS2010.
But I have a problem with the Outputs Property of the Rule in VS2010.

Basically, I add a custom property name OutputSubDir (String) and I want to use it in the Outputs property like this : $(Target)%(OutputSubDir)%(Filename).txt

When I put a default value (in the props file) for OutputSubDir, my Custom Build Rule used this value even if I set a new one for the selected item in the project.
The only way, I made MSBuild use the new one is to override the Outputs property as well (using the same value as the default one !)

It looks like :
- Project Item has Outputs property, then use the OutputSubDir Property of the Project Item
- Project Item does not have Outputs property, use the Outputs property of the Project then use the OutputSubDir property at the same location of the Outputs property (i.e.: at the Project level = default value)

It looks like MSBuild does not allow Polymorphism on its Items.

Do you have any idea how can I configure the properties, the rule, and/or the target to make the Outputs using the good value ?

Do you know if the problem still exists with VS2013 ?

I can provide sample files (.props, .xml & .targets) but there are quite long to put them directly in the question. (and I don't know if it is possible to upload them here)

Here are the files :
TestRule.xml

<?xml version="1.0" encoding="utf-8"?>
<ProjectSchemaDefinitions xmlns="clr-namespace:Microsoft.Build.Framework.XamlTypes;assembly=Microsoft.Build.Framework" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:sys="clr-namespace:System;assembly=mscorlib" xmlns:transformCallback="Microsoft.Cpp.Dev10.ConvertPropertyCallback">
  <Rule

    Name="TestRule"

    PageTemplate="tool"

    DisplayName="Test Rule"

    Order="200">
    <Rule.DataSource>
      <DataSource

        Persistence="ProjectFile"

        ItemType="TestRule" />
    </Rule.DataSource>
    <Rule.Categories>
      <Category

        Name="General">
        <Category.DisplayName>
          <sys:String>General</sys:String>
        </Category.DisplayName>
      </Category>
      <Category

        Name="Command Line"

        Subtype="CommandLine">
        <Category.DisplayName>
          <sys:String>Command Line</sys:String>
        </Category.DisplayName>
      </Category>
    </Rule.Categories>
    <StringListProperty

      Name="Inputs"

      Category="Command Line"

      IsRequired="true"

      Switch=" ">
      <StringListProperty.DataSource>
        <DataSource

          Persistence="ProjectFile"

          ItemType="TestRule"

          SourceType="Item" />
      </StringListProperty.DataSource>
    </StringListProperty>
    <StringProperty

      Name="OutputSubDir"

      Category="General"

      HelpContext="0"

      DisplayName="Output SubDir"

      Description="Sub Folder of $(Target) where output file should be"

      Switch="[value]" />
    <StringProperty

      Name="CommandLineTemplate"

      DisplayName="Command Line"

      Visible="False"

      IncludeInCommandLine="False" />
    <DynamicEnumProperty

      Name="TestRuleBeforeTargets"

      Category="General"

      EnumProvider="Targets"

      IncludeInCommandLine="False">
      <DynamicEnumProperty.DisplayName>
        <sys:String>Execute Before</sys:String>
      </DynamicEnumProperty.DisplayName>
      <DynamicEnumProperty.Description>
        <sys:String>Specifies the targets for the build customization to run before.</sys:String>
      </DynamicEnumProperty.Description>
      <DynamicEnumProperty.ProviderSettings>
        <NameValuePair

          Name="Exclude"

          Value="^TestRuleBeforeTargets|^Compute" />
      </DynamicEnumProperty.ProviderSettings>
      <DynamicEnumProperty.DataSource>
        <DataSource

          Persistence="ProjectFile"

          HasConfigurationCondition="true" />
      </DynamicEnumProperty.DataSource>
    </DynamicEnumProperty>
    <DynamicEnumProperty

      Name="TestRuleAfterTargets"

      Category="General"

      EnumProvider="Targets"

      IncludeInCommandLine="False">
      <DynamicEnumProperty.DisplayName>
        <sys:String>Execute After</sys:String>
      </DynamicEnumProperty.DisplayName>
      <DynamicEnumProperty.Description>
        <sys:String>Specifies the targets for the build customization to run after.</sys:String>
      </DynamicEnumProperty.Description>
      <DynamicEnumProperty.ProviderSettings>
        <NameValuePair

          Name="Exclude"

          Value="^TestRuleAfterTargets|^Compute" />
      </DynamicEnumProperty.ProviderSettings>
      <DynamicEnumProperty.DataSource>
        <DataSource

          Persistence="ProjectFile"

          ItemType=""

          HasConfigurationCondition="true" />
      </DynamicEnumProperty.DataSource>
    </DynamicEnumProperty>
    <StringListProperty

      Name="Outputs"

      DisplayName="Outputs"

	    Visible="True"

      IncludeInCommandLine="False"/>
    <StringProperty

      Name="ExecutionDescription"

      DisplayName="Execution Description"

      IncludeInCommandLine="False" />
    <StringListProperty

      Name="AdditionalDependencies"

      DisplayName="Additional Dependencies"

      Visible="False"

      IncludeInCommandLine="False" />
    <StringProperty

      Subtype="AdditionalOptions"

      Name="AdditionalOptions"

      Category="Command Line"

      Visible="False">
      <StringProperty.DisplayName>
        <sys:String>Additional Options</sys:String>
      </StringProperty.DisplayName>
      <StringProperty.Description>
        <sys:String>Additional Options</sys:String>
      </StringProperty.Description>
    </StringProperty>
  </Rule>
  <ItemType

    Name="TestRule"

    DisplayName="Test Rule" />
  <FileExtension

    Name="*.ext"

    ContentType="TestRule" />
  <ContentType

    Name="TestRule"

    DisplayName="Test Rule"

    ItemType="TestRule" />
</ProjectSchemaDefinitions>





TestRule.props



TestRule.props

<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup

    Condition="'$(TestRuleBeforeTargets)' == '' and '$(TestRuleAfterTargets)' == '' and '$(ConfigurationType)' != 'Makefile'">
    <TestRuleBeforeTargets>Midl</TestRuleBeforeTargets>
    <TestRuleAfterTargets>CustomBuild</TestRuleAfterTargets>
  </PropertyGroup>
  <PropertyGroup>
    <TestRuleDependsOn

      Condition="'$(ConfigurationType)' != 'Makefile'">_SelectedFiles;$(TestRuleDependsOn)</TestRuleDependsOn>
  </PropertyGroup>
  <ItemDefinitionGroup>
    <TestRule>
      <CommandLineTemplate>
        ECHO OutputDir should be $(TargetDir)[OutputSubDir]%(Filename).txt
      </CommandLineTemplate>
      <Outputs>$(TargetDir)%(OutputSubDir)%(Filename).txt</Outputs>
      <ExecutionDescription>Test Rule</ExecutionDescription>
    </TestRule>
  </ItemDefinitionGroup>
</Project>





TestRule.targets



TestRule.targets

<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <PropertyPageSchema

      Include="$(MSBuildThisFileDirectory)$(MSBuildThisFileName).xml" />
    <AvailableItemName

      Include="TestRule">
      <Targets>_TestRule</Targets>
    </AvailableItemName>
  </ItemGroup>
  <UsingTask

    TaskName="TestRule"

    TaskFactory="XamlTaskFactory"

    AssemblyName="Microsoft.Build.Tasks.v4.0">
    <Task>$(MSBuildThisFileDirectory)$(MSBuildThisFileName).xml</Task>
  </UsingTask>
  <Target

    Name="_TestRule"

    BeforeTargets="$(TestRuleBeforeTargets)"

    AfterTargets="$(TestRuleAfterTargets)"

    Condition="'@(TestRule)' != ''"

    DependsOnTargets="$(TestRuleDependsOn);ComputeTestRuleOutput"

    Outputs="%(TestRule.Outputs)"

    Inputs="%(TestRule.Identity);%(TestRule.AdditionalDependencies);$(MSBuildProjectFile)">
    <ItemGroup

      Condition="'@(SelectedFiles)' != ''">
      <TestRule

        Remove="@(TestRule)"

        Condition="'%(Identity)' != '@(SelectedFiles)'" />
    </ItemGroup>
    <ItemGroup>
      <TestRule_tlog

        Include="%(TestRule.Outputs)"

        Condition="'%(TestRule.Outputs)' != '' and '%(TestRule.ExcludedFromBuild)' != 'true'">
        <Source>@(TestRule, '|')</Source>
      </TestRule_tlog>
    </ItemGroup>
    <Message

      Importance="High"

      Text="%(TestRule.ExecutionDescription)" />
	<Message

		Importance="High"

		Text="OutputSubDir = %(TestRule.OutputSubDir)" />
	<Message

		Importance="High"

		Text="Outputs = %(TestRule.Outputs)" />
    <WriteLinesToFile

      Condition="'@(TestRule_tlog)' != '' and '%(TestRule_tlog.ExcludedFromBuild)' != 'true'"

      File="$(IntDir)$(ProjectName).write.1.tlog"

      Lines="^%(TestRule_tlog.Source);@(TestRule_tlog->'%(Fullpath)')" />
    <TestRule

      
									

(Target)%(OutputSubDir)%(Filename).txt



When I put a default value (in the props file) for OutputSubDir, my Custom Build Rule used this value even if I set a new one for the selected item in the project.

The only way, I made MSBuild use the new one is to override the Outputs property as well (using the same value as the default one !)



It looks like :

- Project Item has Outputs property, then use the OutputSubDir Property of the Project Item

- Project Item does not have Outputs property, use the Outputs property of the Project then use the OutputSubDir property at the same location of the Outputs property (i.e.: at the Project level = default value)



It looks like MSBuild does not allow Polymorphism on its Items.



Do you have any idea how can I configure the properties, the rule, and/or the target to make the Outputs using the good value ?
$b $b

Do you know if the problem still exists with VS2013 ?



I can provide sample files (.props, .xml & .targets) but there are quite long to put them directly in the question. (and I don’t know if it is possible to upload them here)



Here are the files :

TestRule.xml

(Target)%(OutputSubDir)%(Filename).txt

When I put a default value (in the props file) for OutputSubDir, my Custom Build Rule used this value even if I set a new one for the selected item in the project.
The only way, I made MSBuild use the new one is to override the Outputs property as well (using the same value as the default one !)

It looks like :
- Project Item has Outputs property, then use the OutputSubDir Property of the Project Item
- Project Item does not have Outputs property, use the Outputs property of the Project then use the OutputSubDir property at the same location of the Outputs property (i.e.: at the Project level = default value)

It looks like MSBuild does not allow Polymorphism on its Items.

Do you have any idea how can I configure the properties, the rule, and/or the target to make the Outputs using the good value ?

Do you know if the problem still exists with VS2013 ?

I can provide sample files (.props, .xml & .targets) but there are quite long to put them directly in the question. (and I don't know if it is possible to upload them here)

Here are the files :
TestRule.xml
<?xml version="1.0" encoding="utf-8"?>
<ProjectSchemaDefinitions xmlns="clr-namespace:Microsoft.Build.Framework.XamlTypes;assembly=Microsoft.Build.Framework" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:sys="clr-namespace:System;assembly=mscorlib" xmlns:transformCallback="Microsoft.Cpp.Dev10.ConvertPropertyCallback">
  <Rule

    Name="TestRule"

    PageTemplate="tool"

    DisplayName="Test Rule"

    Order="200">
    <Rule.DataSource>
      <DataSource

        Persistence="ProjectFile"

        ItemType="TestRule" />
    </Rule.DataSource>
    <Rule.Categories>
      <Category

        Name="General">
        <Category.DisplayName>
          <sys:String>General</sys:String>
        </Category.DisplayName>
      </Category>
      <Category

        Name="Command Line"

        Subtype="CommandLine">
        <Category.DisplayName>
          <sys:String>Command Line</sys:String>
        </Category.DisplayName>
      </Category>
    </Rule.Categories>
    <StringListProperty

      Name="Inputs"

      Category="Command Line"

      IsRequired="true"

      Switch=" ">
      <StringListProperty.DataSource>
        <DataSource

          Persistence="ProjectFile"

          ItemType="TestRule"

          SourceType="Item" />
      </StringListProperty.DataSource>
    </StringListProperty>
    <StringProperty

      Name="OutputSubDir"

      Category="General"

      HelpContext="0"

      DisplayName="Output SubDir"

      Description="Sub Folder of


(Target) where output file should be\"

Switch=\"[value]\" />
<StringProperty

Name=\"CommandLineTemplate\"

DisplayName=\"Command Line\"

Visible=\"False\"

IncludeInCommandLine=\"False\" />
<DynamicEnumProperty

Name=\"TestRuleBeforeTargets\"

Category=\"General\"

EnumProvider=\"Targets\"

IncludeIn CommandLine=\"False\">
<DynamicEnumProperty.DisplayName>
<sys:String>Execute Before</sys:String>
</DynamicEnumProperty.DisplayName>
<DynamicEnumProperty.Description>
<sys:String>Specifies the targets for the build customization to run before.</sys:String>
</DynamicEnumProperty.Description>
<DynamicEnumProperty.ProviderSettings>
<NameValuePair

Name=\"Exclude\"

Value=\"^TestRuleBeforeTargets|^Compute\" />
</DynamicEnumProperty.ProviderSettings>
<DynamicEnumProperty.DataSource>
<DataSource

Persistence=\"ProjectFile\"

HasConfigurationCondition=\"true\" />
</DynamicEnumProperty.DataSource>
</DynamicEnumProperty>
<DynamicEnumProperty

Name=\"TestRuleAfterTargets\"

Category=\"General\"

EnumProvider=\"Targets\"

IncludeInCommandLine=\"False\">
<DynamicEnumProperty.DisplayName>
<sys:String>Execute After</sys:String>
</DynamicEnumProperty.DisplayName>
<DynamicEnumProperty.Description>
<sys:String>Specifies the targets for the build customization to run after.</sys:String>
</Dynam icEnumProperty.Description>
<DynamicEnumProperty.ProviderSettings>
<NameValuePair

Name=\"Exclude\"

Value=\"^TestRuleAfterTargets|^Compute\" />
</DynamicEnumProperty.ProviderSettings>
<DynamicEnumProperty.DataSource>
<DataSource

Persistence=\"ProjectFile\"

ItemType=\"\"

HasConfigurationCondition=\"true\" />
</DynamicEnumProperty.D ataSource>
</DynamicEnumProperty>
<StringListProperty

Name=\"Outputs\"

DisplayName=\"Outputs\"

\t Visible=\"True\"

IncludeInCommandLine=\"False\"/>
<StringProperty

Name=\"ExecutionDescription\"

DisplayName=\"Execution Description\"

IncludeInCommandLine=\"False\" />
<StringListProperty

an>Name=\"AdditionalDependencies\"

DisplayName=\"Additional Dependencies\"

Visible=\"False \"

IncludeInCommandLine=\"False\" />
<StringProperty

Subtype =\"AdditionalOptions\"

Name=\"AdditionalOptions\"

Category=\"Command Line\"
pan>
Visible=\"False\">
<StringProperty.DisplayName>
<sys:String>Additional Options</sys:String>
</StringProperty.DisplayName>
<StringProperty.Description>
<sys:String>Additional Options</sys:String>
</StringProperty.Description>
</StringProperty>
</Rule>
<ItemType

Name=\"TestRule\"

DisplayName=\"Test Rule\" />
<FileExtension

Name=\"*.ext\"

ContentType=\"TestRule\" />
<ContentType

pan> Name=\"TestRule\"

DisplayName=\"Test Rule\"

ItemType=\"TestRule\" />
</ProjectSchemaDefinitions>
(Target) where output file should be" Switch="[value]" /> <StringProperty Name="CommandLineTemplate" DisplayName="Command Line" Visible="False" IncludeInCommandLine="False" /> <DynamicEnumProperty Name="TestRuleBeforeTargets" Category="General" EnumProvider="Targets" IncludeInCommandLine="False"> <DynamicEnumProperty.DisplayName> <sys:String>Execute Before</sys:String> </DynamicEnumProperty.DisplayName> <DynamicEnumProperty.Description> <sys:String>Specifies the targets for the build customization to run before.</sys:String> </DynamicEnumProperty.Description> <DynamicEnumProperty.ProviderSettings> <NameValuePair Name="Exclude" Value="^TestRuleBeforeTargets|^Compute" /> </DynamicEnumProperty.ProviderSettings> <DynamicEnumProperty.DataSource> <DataSource Persistence="ProjectFile" HasConfigurationCondition="true" /> </DynamicEnumProperty.DataSource> </DynamicEnumProperty> <DynamicEnumProperty Name="TestRuleAfterTargets" Category="General" EnumProvider="Targets" IncludeInCommandLine="False"> <DynamicEnumProperty.DisplayName> <sys:String>Execute After</sys:String> </DynamicEnumProperty.DisplayName> <DynamicEnumProperty.Description> <sys:String>Specifies the targets for the build customization to run after.</sys:String> </DynamicEnumProperty.Description> <DynamicEnumProperty.ProviderSettings> <NameValuePair Name="Exclude" Value="^TestRuleAfterTargets|^Compute" /> </DynamicEnumProperty.ProviderSettings> <DynamicEnumProperty.DataSource> <DataSource Persistence="ProjectFile" ItemType="" HasConfigurationCondition="true" /> </DynamicEnumProperty.DataSource> </DynamicEnumProperty> <StringListProperty Name="Outputs" DisplayName="Outputs" Visible="True" IncludeInCommandLine="False"/> <StringProperty Name="ExecutionDescription" DisplayName="Execution Description" IncludeInCommandLine="False" /> <StringListProperty Name="AdditionalDependencies" DisplayName="Additional Dependencies" Visible="False" IncludeInCommandLine="False" /> <StringProperty Subtype="AdditionalOptions" Name="AdditionalOptions" Category="Command Line" Visible="False"> <StringProperty.DisplayName> <sys:String>Additional Options</sys:String> </StringProperty.DisplayName> <StringProperty.Description> <sys:String>Additional Options</sys:String> </StringProperty.Description> </StringProperty> </Rule> <ItemType Name="TestRule" DisplayName="Test Rule" /> <FileExtension Name="*.ext" ContentType="TestRule" /> <ContentType Name="TestRule" DisplayName="Test Rule" ItemType="TestRule" /> </ProjectSchemaDefinitions>





TestRule.props



TestRule.props

<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup

    Condition="'


(TestRuleBeforeTargets)' == '' and '
(TestRuleBeforeTargets)' == '' and '