MSBuild:如何更新项目中的默认元数据?

时间:2013-07-30 15:31:56

标签: msbuild metadata

我在使用MSBuild编写脚本时遇到以下问题: 我使用两个元数据“metadata1”和“metadata2”创建一个默认项“itemA”,其中metadata2指的是metadata1。

当我稍后定义itemA并覆盖metadata1时,metadata2仍然包含metadata1的默认值。如何让metadata2引用“new”metadata1?

代码中的插图如下:

  <ItemDefinitionGroup>
    <itemA>
      <Metadata1>default</Metadata1>
      <Metadata2>%(itemA.Metadata1)</Metadata2>
    </itemA>
  </ItemDefinitionGroup>    
  <ItemGroup>
    <itemA Include="first" >
      <Metadata1>m_data1</Metadata1>
    </itemA>
  </ItemGroup>

但请看打印

<Message Text="itemA.Metadata1 = %(itemA.Metadata1)" />
<Message Text="itemA.Metadata2 = %(itemA.Metadata2)" />

提供了:

itemA.Metadata1 = m_data1       ***<-- correctly updated***

itemA.Metadata2 = default       ***<-- why showing the default value, not* m_data1??**

如何使itemA.Metadata2在更新后与itemA.Metadata1具有相同的值?

2 个答案:

答案 0 :(得分:1)

我认为这是不可能的,因为评估顺序为Item Definitions - Value Sources - Note

  

ItemGroup中的项元数据在ItemDefinitionGroup元数据声明中没有用,因为ItemDefinitionGroup元素在ItemGroup元素之前处理。

您必须覆盖ItemGroup

中itemA的Metadata2值
  <ItemDefinitionGroup>
    <itemA>
      <Metadata1>default</Metadata1>
      <Metadata2>%(Metadata1)</Metadata2>
    </itemA>
  </ItemDefinitionGroup>    
  <ItemGroup>
    <itemA Include="first" >
      <Metadata1>m_data1</Metadata1>
      <Metadata2>%(Metadata1)</Metadata2>
    </itemA>
  </ItemGroup>

答案 1 :(得分:1)

作为palo states,由于Metadata2已经过评估,因此您必须明确覆盖该值。您对Metadata1的更改不会自动传播到初始化期间引用它的其他位置。

但是,您可以通过启动MSBuild的新实例并将更新的元数据作为属性传递来“重新评估”项目的元数据。从命令行对此项目运行msbuild /t:Wrapper将导致Metadata1和Metadata2打印相同的值:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <DefaultMetadata1 Condition="DefaultMetadata1==''">default</DefaultMetadata1>
  </PropertyGroup>

  <ItemDefinitionGroup>
    <itemA>
      <Metadata1>$(DefaultMetadata1)</Metadata1>
      <Metadata2>%(itemA.Metadata1)</Metadata2>
    </itemA>
  </ItemDefinitionGroup>    
  <ItemGroup>
    <itemA Include="first" >
      <Metadata1>m_data1</Metadata1>
    </itemA>
  </ItemGroup>

  <Target Name="Wrapper">       
    <MSBuild 
      Projects="$(MSBuildProjectFile)"
      Targets="Worker"
      Properties="DefaultMetadata1=%(itemA.Metadata1)"
    />
  </Target>

  <Target Name="Worker">
    <Message Text="itemA.Metadata1 = %(itemA.Metadata1)" />
    <Message Text="itemA.Metadata2 = %(itemA.Metadata2)" />
  </Target>
</Project>

这种方法的有用性取决于你想要完成的事情。毫无疑问,您可以使用属性而不是项元数据来查找备用解决方案。

虽然上述解决方案适用于您描述的案例,但它很快就会失控。可能有一个更简单的解决方案,可能涉及一些冗余代码。

我的建议是使用简单的解决方案,尽可能地消除尽可能多的冗余,而无需发明新方法来绕过MSBuild的小功能集。这里聪明的技巧可能不会在一天结束时为你节省很多LOC,并且可能导致代码不太可读,这使得新手更难理解正在发生的事情。