如何在使用其他规则的属性时设置自定义构建规则的输出属性? [英] How do I set the Outputs Property of a Custom Build Rule when it uses an other rule's Property ?
问题描述
我设法用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
Condition="'@(TestRule)' != '' and '%(TestRule.ExcludedFromBuild)' != 'true'"
CommandLineTemplate="%(TestRule.CommandLineTemplate)"
OutputSubDir="%(TestRule.OutputSubDir)"
AdditionalOptions="%(TestRule.AdditionalOptions)"
Inputs="%(TestRule.Identity)" />
</Target>
<PropertyGroup>
<ComputeLinkInputsTargets>
$(ComputeLinkInputsTargets);
ComputeTestRuleOutput;
</ComputeLinkInputsTargets>
<ComputeLibInputsTargets>
$(ComputeLibInputsTargets);
ComputeTestRuleOutput;
</ComputeLibInputsTargets>
</PropertyGroup>
<Target
Name="ComputeTestRuleOutput"
Condition="'@(TestRule)' != ''">
<ItemGroup>
<TestRuleDirsToMake
Condition="'@(TestRule)' != '' and '%(TestRule.ExcludedFromBuild)' != 'true'"
Include="%(TestRule.Outputs)" />
<Link
Include="%(TestRuleDirsToMake.Identity)"
Condition="'%(Extension)'=='.obj' or '%(Extension)'=='.res' or '%(Extension)'=='.rsc' or '%(Extension)'=='.lib'" />
<Lib
Include="%(TestRuleDirsToMake.Identity)"
Condition="'%(Extension)'=='.obj' or '%(Extension)'=='.res' or '%(Extension)'=='.rsc' or '%(Extension)'=='.lib'" />
<ImpLib
Include="%(TestRuleDirsToMake.Identity)"
Condition="'%(Extension)'=='.obj' or '%(Extension)'=='.res' or '%(Extension)'=='.rsc' or '%(Extension)'=='.lib'" />
</ItemGroup>
<MakeDir
Directories="@(TestRuleDirsToMake->'%(RootDir)%(Directory)')" />
</Target>
</Project>
and the Extract of .VCXPROJ :
and the Extract of .VCXPROJ :
<ItemGroup>
<TestRule Include="test.ext">
<OutputSubDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">info\</OutputSubDir>
<FileType>Document</FileType>
</TestRule>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="TestRule.targets" />
</ImportGroup>
I discovered something else:
I discovered something else:
<ItemGroup>
<TestRule Include="test.ext">
<OutputSubDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">info\</OutputSubDir>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(TargetDir)%(OutputSubDir).dll\</Outputs>
<FileType>Document</FileType>
</TestRule>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="TestRule.targets" />
</ImportGroup>
is not the same as:
is not the same as:
<ItemGroup>
<TestRule Include="test.ext">
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(TargetDir)%(OutputSubDir).dll\</Outputs>
<OutputSubDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">info\</OutputSubDir>
<FileType>Document</FileType>
</TestRule>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="TestRule.targets" />
</ImportGroup>
In the first case, the Outputs will use the value of OutputSubDir but not in the second case where it will use the value defined in the props file.
MSBuild looks to be sequential
推荐答案
(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\"
< span class=\"code-attribute\"> 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\"
< span class=\"code-attribute\"> DisplayName=\"Outputs\"
\t 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>
(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 '
这篇关于如何在使用其他规则的属性时设置自定义构建规则的输出属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!