MSBuild 项

MSBuild 项是生成系统中的输入,它们通常表示文件(文件是在属性中指定的 Include )。 项根据项的元素名称分组到项类型中。 项类型是可用作任务参数的项的命名列表。 任务使用项值来执行生成过程的步骤。

由于项按它们所属的项类型命名,因此可以互换使用术语“item”和“item value”。

在项目文件中创建项

将项目文件中的项声明为 ItemGroup 元素的子元素。 有效项名称以大写或小写字母或下划线开头(_);有效的后续字符包括字母数字字符(字母或数字)、下划线和连字符(-)。 子元素的名称是项的类型。 元素 Include 的属性指定要与该项类型一起包含的项(文件)。 例如,以下 XML 将创建一个命名 Compile的项类型,其中包括两个文件。

<ItemGroup>
    <Compile Include = "file1.cs"/>
    <Compile Include = "file2.cs"/>
</ItemGroup>

file2.cs 不会替换项 file1.cs;而是将文件名追加到项类型的值 Compile 列表中。

以下 XML 通过在一个属性中声明这两个 Include 文件来创建相同的项类型。 请注意,文件名用分号分隔。

<ItemGroup>
    <Compile Include = "file1.cs;file2.cs"/>
</ItemGroup>

Include 属性是相对于项目文件文件夹进行解释的路径, $(MSBuildProjectPath)即使该项位于导入的文件(如文件) .targets 中也是如此。

在执行期间创建项

目标元素外部的项在生成评估阶段分配值。 在后续执行阶段,可以通过以下方式创建或修改项:

  • 任何任务都可以发出项。 若要发出项,Task 元素必须具有具有属性的ItemName 元素。

  • CreateItem 任务可以发出项。 此用法已弃用。

  • Target 元素可能包含可能包含项元素的 ItemGroup 元素。

引用项目文件中的项

若要在整个项目文件中引用项类型,请使用语法 @(ItemType)。 例如,可以使用上一个示例中 @(Compile)的项类型。 通过使用此语法,可以通过将项类型指定为该任务的参数,将项传递给任务。 有关详细信息,请参阅 “如何:选择要生成的文件”。

默认情况下,项类型的项由分号分隔(;)展开时)。 可以使用语法 @(ItemType, 'separator') 指定除默认值以外的分隔符。 有关详细信息,请参阅 “如何:显示用逗号分隔的项列表”。

使用通配符指定项目

可以使用***?通配符将一组文件指定为生成输入,而不是单独列出每个文件。

  • ?通配符与单个字符匹配。
  • *通配符匹配零个或多个字符。
  • **通配符序列与部分路径匹配。

例如,可以使用项目文件中的以下元素指定目录中包含项目文件的所有 .cs 文件。

<CSFile Include="*.cs"/>

以下元素选择驱动器上.vb的所有D:文件:

<VBFile Include="D:/**/*.vb"/>

如果要在项中包含文本 *? 字符,而不进行通配符扩展,则必须 转义通配符

有关通配符的详细信息,请参阅 “如何:选择要生成的文件”。

使用 Exclude 属性

项元素可以包含属性 Exclude ,该属性从项类型中排除特定项(文件)。 特性 Exclude 通常与通配符一起使用。 例如,以下 XML 将目录中的每个 .cs 文件添加到 CSFile 项类型, DoNotBuild.cs 文件除外。

<ItemGroup>
    <CSFile  Include="*.cs"  Exclude="DoNotBuild.cs"/>
</ItemGroup>

Exclude 属性仅影响包含这两个属性的项元素中添加的项 Include 。 以下示例不会排除在上述项元素中添加的文件 Form1.cs

<Compile Include="*.cs" />
<Compile Include="*.res" Exclude="Form1.cs">

有关详细信息,请参阅 “如何:从生成中排除文件”。

条目元数据

除了属性中IncludeExclude的信息之外,项还可以包含元数据。 此元数据可由需要有关项的详细信息或批处理任务和目标的任务使用。 有关详细信息,请参阅批处理

元数据是在项目文件中声明为项元素的子元素的键值对的集合。 子元素的名称是元数据的名称,子元素的值是元数据的值。

元数据与包含它的项元素相关联。 例如,以下 XML 将具有值的Culture元数据添加到Fr类型的one.cs和two.cs项。CSFile

<ItemGroup>
    <CSFile Include="one.cs;two.cs">
        <Culture>Fr</Culture>
    </CSFile>
</ItemGroup>

项可以具有零个或多个元数据值。 可以随时更改元数据值。 如果将元数据设置为空值,则可以有效地将其从生成中删除。

引用项目文件中的项元数据

可以使用语法 %(ItemMetadataName)在整个项目文件中引用项元数据。 如果存在歧义,可以使用项类型的名称限定引用。 例如,你可以指定 %(ItemType.ItemMetaDataName)。 以下示例使用 Display 元数据对任务进行批处理 Message 。 有关如何使用项元数据进行批处理的详细信息,请参阅 任务批处理中的项元数据

<Project>
    <ItemGroup>
        <Stuff Include="One.cs" >
            <Display>false</Display>
        </Stuff>
        <Stuff Include="Two.cs">
            <Display>true</Display>
        </Stuff>
    </ItemGroup>
    <Target Name="Batching">
        <Message Text="@(Stuff)" Condition=" '%(Display)' == 'true' "/>
    </Target>
</Project>

已知项元数据

将项添加到项类型时,将为该项分配一些已知元数据。 例如,所有项都具有已知的元数据 %(Filename),其值为项的文件名(没有扩展名)。 有关详细信息,请参阅 已知项元数据

使用元数据转换项类型

可以使用元数据将项列表转换为新项列表。 例如,可以使用表达式CppFiles将包含表示.cpp文件的项的项转换为相应的文件列表.obj的项类型@(CppFiles -> '%(Filename).obj')

以下代码创建一个CultureResource项类型,其中包含具有EmbeddedResource元数据的所有Culture项的副本。 元数据 Culture 值将成为新元数据 CultureResource.TargetDirectory的值。

<Target Name="ProcessCultureResources">
    <ItemGroup>
        <CultureResource Include="@(EmbeddedResource)"
            Condition="'%(EmbeddedResource.Culture)' != ''">
            <TargetDirectory>%(EmbeddedResource.Culture) </TargetDirectory>
        </CultureResource>
    </ItemGroup>
</Target>

有关项的更多作,请参阅 MSBuild 项函数转换

项定义

可以使用 ItemDefinitionGroup 元素将默认元数据添加到任何项类型。 与已知的元数据一样,默认元数据与指定的项类型的所有项相关联。 可以在项定义中显式替代默认元数据。 例如,以下 XML 提供Compile项one.cs,并three.cs值为“Monday”的元数据BuildDay。 代码为项提供 two.cs 值为“Tuesday”的元数据 BuildDay

<ItemDefinitionGroup>
    <Compile>
        <BuildDay>Monday</BuildDay>
    </Compile>
</ItemDefinitionGroup>
<ItemGroup>
    <Compile Include="one.cs;three.cs" />
    <Compile Include="two.cs">
        <BuildDay>Tuesday</BuildDay>
    </Compile>
</ItemGroup>

有关详细信息,请参阅 项定义

Target 的 ItemGroup 中项的属性

Target 元素可能包含可能包含项元素的 ItemGroup 元素。 当为属于某一ItemGroupTarget项的项指定属性时,本节中的属性有效。

删除属性

Remove 属性从项类型中删除特定项(文件)。 此属性是在 .NET Framework 3.5(仅限目标内部)中引入的。 从 MSBuild 15.0 开始,支持内部和外部目标。

以下示例从.config项类型中删除每个Compile文件。

<Target>
    <ItemGroup>
        <Compile Remove="*.config"/>
    </ItemGroup>
</Target>

MatchOnMetadata 属性

MatchOnMetadata 属性仅适用于 Remove 引用其他项(例如 Remove="@(Compile);@(Content)")的属性,并指示 Remove 作根据指定元数据名称的值匹配项,而不是基于项值进行匹配。

匹配规则:从B Remove="@(A)" MatchOnMetadata="M"具有元数据B的所有项中删除,其元数据值MV值元数据MA匹配的任何项MV

<Project>
  <ItemGroup>
    <A Include='a1' M1='1' M2='a' M3="e"/>
    <A Include='b1' M1='2' M2='x' M3="f"/>
    <A Include='c1' M1='3' M2='y' M3="g"/>
    <A Include='d1' M1='4' M2='b' M3="h"/>

    <B Include='a2' M1='x' m2='c' M3="m"/>
    <B Include='b2' M1='2' m2='x' M3="n"/>
    <B Include='c2' M1='2' m2='x' M3="o"/>
    <B Include='d2' M1='3' m2='y' M3="p"/>
    <B Include='e2' M1='3' m2='Y' M3="p"/>
    <B Include='f2' M1='4'        M3="r"/>
    <B Include='g2'               M3="s"/>

    <B Remove='@(A)' MatchOnMetadata='M1;M2'/>
  </ItemGroup>

  <Target Name="PrintEvaluation">
    <Message Text="%(B.Identity) M1='%(B.M1)' M2='%(B.M2)' M3='%(B.M3)'" />
  </Target>
</Project>

在此示例中,项值b2c2d2从项B中删除,因为:

  • b2 c2B on 和 on b1AM1=2匹配项M2=x
  • d2from B matches on c1AM1=3 andM2=y

Message 任务输出以下内容:

  a2 M1='x' M2='c' M3='m'
  e2 M1='3' M2='Y' M3='p'
  f2 M1='4' M2='' M3='r'
  g2 M1='' M2='' M3='s'

MatchOnMetadata 的示例用法

      <_TransitiveItemsToCopyToOutputDirectory Remove="@(_ThisProjectItemsToCopyToOutputDirectory)" MatchOnMetadata="TargetPath" MatchOnMetadataOptions="PathLike" />

此行从项中删除具有相同_TransitiveItemsToCopyToOutputDirectory元数据值的项TargetPath_ThisProjectItemsToCopyToOutputDirectory

MatchOnMetadataOptions 属性

指定用于 MatchOnMetadata 匹配项之间的元数据值的字符串匹配策略(元数据名称始终不区分大小写)。 可能的值为 CaseSensitiveCaseInsensitivePathLike。 默认值是 CaseSensitive

PathLike 将路径感知规范化应用于规范化斜杠方向、忽略尾部斜杠、消除 ...使所有相对路径绝对针对当前目录的值。

KeepMetadata 属性

如果在目标中生成项,则 item 元素可以包含该 KeepMetadata 属性。 如果指定此属性,则只有以分号分隔的名称列表中的元数据才会从源项传输到目标项。 此属性的空值等效于不指定它。 特性 KeepMetadata 是在 .NET Framework 4.5 中引入的。

下面的示例演示如何使用该 KeepMetadata 属性。

<Project>
    <ItemGroup>
        <FirstItem Include="rhinoceros">
            <Class>mammal</Class>
            <Size>large</Size>
        </FirstItem>

    </ItemGroup>
    <Target Name="MyTarget">
        <ItemGroup>
            <SecondItem Include="@(FirstItem)" KeepMetadata="Class" />
        </ItemGroup>

        <Message Text="FirstItem: %(FirstItem.Identity)" />
        <Message Text="  Class: %(FirstItem.Class)" />
        <Message Text="  Size:  %(FirstItem.Size)"  />

        <Message Text="SecondItem: %(SecondItem.Identity)" />
        <Message Text="  Class: %(SecondItem.Class)" />
        <Message Text="  Size:  %(SecondItem.Size)"  />
    </Target>
</Project>

<!--
Output:
  FirstItem: rhinoceros
    Class: mammal
    Size:  large
  SecondItem: rhinoceros
    Class: mammal
    Size:
-->

RemoveMetadata 属性

如果在目标中生成项,则 item 元素可以包含该 RemoveMetadata 属性。 如果指定此属性,则所有元数据将从源项传输到目标项,但名称包含在以分号分隔的名称列表中的元数据除外。 此属性的空值等效于不指定它。 特性 RemoveMetadata 是在 .NET Framework 4.5 中引入的。

下面的示例演示如何使用该 RemoveMetadata 属性。

<Project>

    <PropertyGroup>
        <MetadataToRemove>Size;Material</MetadataToRemove>
    </PropertyGroup>

    <ItemGroup>
        <Item1 Include="stapler">
            <Size>medium</Size>
            <Color>black</Color>
            <Material>plastic</Material>
        </Item1>
    </ItemGroup>

    <Target Name="MyTarget">
        <ItemGroup>
            <Item2 Include="@(Item1)" RemoveMetadata="$(MetadataToRemove)" />
        </ItemGroup>

        <Message Text="Item1: %(Item1.Identity)" />
        <Message Text="  Size:     %(Item1.Size)" />
        <Message Text="  Color:    %(Item1.Color)" />
        <Message Text="  Material: %(Item1.Material)" />
        <Message Text="Item2: %(Item2.Identity)" />
        <Message Text="  Size:     %(Item2.Size)" />
        <Message Text="  Color:    %(Item2.Color)" />
        <Message Text="  Material: %(Item2.Material)" />
    </Target>
</Project>

<!--
Output:
  Item1: stapler
    Size:     medium
    Color:    black
    Material: plastic
  Item2: stapler
    Size:
    Color:    black
    Material:
-->

有关项的更多作,请参阅 MSBuild 项函数

KeepDuplicates 属性

如果在目标中生成项,则 item 元素可以包含该 KeepDuplicates 属性。 KeepDuplicates 是一个 Boolean 特性,指定当项是现有项的精确重复项时,是否应将项添加到目标组。

如果源项和目标项具有相同 的值但元数据不同,则即使 设置为 ,也会添加该项。 此属性的空值等效于不指定它。 特性 KeepDuplicates 是在 .NET Framework 4.5 中引入的。

下面的示例演示如何使用该 KeepDuplicates 属性。

<Project>

    <ItemGroup>
        <Item1 Include="hourglass;boomerang" />
        <Item2 Include="hourglass;boomerang" />
    </ItemGroup>

    <Target Name="MyTarget">
        <ItemGroup>
            <Item1 Include="hourglass" KeepDuplicates="false" />
            <Item2 Include="hourglass" />
        </ItemGroup>

        <Message Text="Item1: @(Item1)" />
        <Message Text="  %(Item1.Identity)  Count: @(Item1->Count())" />
        <Message Text="Item2: @(Item2)" />
        <Message Text="  %(Item2.Identity)  Count: @(Item2->Count())" />
    </Target>
</Project>

<!--
Output:
  Item1: hourglass;boomerang
    hourglass  Count: 1
    boomerang  Count: 1
  Item2: hourglass;boomerang;hourglass
    hourglass  Count: 2
    boomerang  Count: 1
-->

由于该 KeepDuplicates 属性考虑项的元数据以及项值,因此了解元数据发生的情况非常重要。 例如,请参阅 使用元数据项函数时检测重复项

更新 Target 外部 ItemGroup 中项的元数据

目标外部的项可以通过属性更新 Update 其现有元数据。 此属性 不适用于 目标下的项。

<Project>
    <PropertyGroup>
        <MetadataToUpdate>pencil</MetadataToUpdate>
    </PropertyGroup>

    <ItemGroup>
        <Item1 Include="stapler">
            <Size>medium</Size>
            <Color>black</Color>
            <Material>plastic</Material>
        </Item1>
        <Item1 Include="pencil">
            <Size>small</Size>
            <Color>yellow</Color>
            <Material>wood</Material>
        </Item1>
        <Item1 Include="eraser">
            <Color>red</Color>
        </Item1>
        <Item1 Include="notebook">
            <Size>large</Size>
            <Color>white</Color>
            <Material>paper</Material>
        </Item1>

        <Item2 Include="notebook">
            <Size>SMALL</Size>
            <Color>YELLOW</Color>
        </Item2>

        <!-- Metadata can be expressed either as attributes or as elements -->
        <Item1 Update="$(MetadataToUpdate);stapler;er*r;@(Item2)" Price="10" Material="">
            <Color>RED</Color>
        </Item1>
    </ItemGroup>

    <Target Name="MyTarget">
        <Message Text="Item1: %(Item1.Identity)
    Size: %(Item1.Size)
    Color: %(Item1.Color)
    Material: %(Item1.Material)
    Price: %(Item1.Price)" />
    </Target>
</Project>

<!--  
Item1: stapler
    Size: medium
    Color: RED
    Material:
    Price: 10
Item1: pencil
    Size: small
    Color: RED
    Material:
    Price: 10
Item1: eraser
    Size:
    Color: RED
    Material:
    Price: 10
Item1: notebook
    Size: large
    Color: RED
    Material:
    Price: 10
-->

在 MSBuild 版本 16.6 及更高版本中,该 Update 属性支持限定的元数据引用,以方便从两个或多个项导入元数据。

<Project>
    <ItemGroup>
        <Item1 Include="stapler">
            <Size>medium</Size>
            <Color>black</Color>
            <Material>plastic</Material>
        </Item1>
        <Item1 Include="pencil">
            <Size>small</Size>
            <Color>yellow</Color>
            <Material>wood</Material>
        </Item1>
        <Item1 Include="eraser">
            <Size>small</Size>
            <Color>red</Color>
            <Material>gum</Material>
        </Item1>
        <Item1 Include="notebook">
            <Size>large</Size>
            <Color>white</Color>
            <Material>paper</Material>
        </Item1>

        <Item2 Include="pencil">
            <Size>MEDIUM</Size>
            <Color>RED</Color>
            <Material>PLASTIC</Material>
            <Price>10</Price>
        </Item2>

        <Item3 Include="notebook">
            <Size>SMALL</Size>
            <Color>BLUE</Color>
            <Price>20</Price>
        </Item3>

        <!-- Metadata can be expressed either as attributes or as elements -->
        <Item1 Update="@(Item2);er*r;@(Item3)" Size="%(Size)" Color="%(Item2.Color)" Price="%(Item3.Price)" Model="2020">
            <Material Condition="'%(Item2.Material)' != ''">Premium %(Item2.Material)</Material>
        </Item1>
    </ItemGroup>

    <Target Name="MyTarget">
        <Message Text="Item1: %(Item1.Identity)
    Size: %(Item1.Size)
    Color: %(Item1.Color)
    Material: %(Item1.Material)
    Price: %(Item1.Price)
    Model: %(Item1.Model)" />
    </Target>
</Project>

<!--  
Item1: stapler
    Size: medium
    Color: black
    Material: plastic
    Price:
    Model:
Item1: pencil
    Size: small
    Color: RED
    Material: Premium PLASTIC
    Price:
    Model: 2020
Item1: eraser
    Size: small
    Color:
    Material: gum
    Price:
    Model: 2020
Item1: notebook
    Size: large
    Color:
    Material: paper
    Price: 20
    Model: 2020
-->

备注:

  • 未限定的元数据 (%(MetadataName)) 绑定到正在更新的项类型(Item1 在上面的示例中)。 限定的元数据 (%(Item2.Color)) 绑定在 Update 表达式中捕获的匹配项类型的集合内。
  • 如果项在多个引用的项内和之间多次匹配:
    • 将捕获每个引用项类型中的最后一个匹配项(因此每个项类型有一个捕获的项)。
    • 这与目标下的任务项批处理的行为匹配。
  • 其中可以放置 %() 引用:
    • Metadata
    • 元数据条件
  • 元数据名称匹配不区分大小写。

更新 Target 的 ItemGroup 中项的元数据

元数据也可以在目标内修改,其表现力比 Update

<Project>
    <ItemGroup>
        <Item1 Include="stapler">
            <Size>medium</Size>
            <Color>black</Color>
            <Material>plastic</Material>
        </Item1>
        <Item1 Include="pencil">
            <Size>small</Size>
            <Color>yellow</Color>
            <Material>wood</Material>
        </Item1>
        <Item1 Include="eraser">
            <Size>small</Size>
            <Color>red</Color>
            <Material>gum</Material>
        </Item1>
        <Item1 Include="notebook">
            <Size>large</Size>
            <Color>white</Color>
            <Material>paper</Material>
        </Item1>

        <Item2 Include="pencil">
            <Size>MEDIUM</Size>
            <Color>RED</Color>
            <Material>PLASTIC</Material>
            <Price>10</Price>
        </Item2>

        <Item2 Include="ruler">
            <Color>GREEN</Color>
        </Item2>

    </ItemGroup>

    <Target Name="MyTarget">
        <ItemGroup>
            <!-- Metadata can be expressed either as attributes or as elements -->
            <Item1 Size="GIGANTIC" Color="%(Item2.Color)">
                <Material Condition="'%(Item2.Material)' != ''">Premium %(Item2.Material)</Material>
            </Item1>
        </ItemGroup>

        <Message Text="Item1: %(Item1.Identity)
    Size: %(Item1.Size)
    Color: %(Item1.Color)
    Material: %(Item1.Material)
    Price: %(Item1.Price)
    Model: %(Item1.Model)" />
    </Target>
</Project>

<!--  
Item1: stapler
    Size: GIGANTIC
    Color: GREEN
    Material: Premium PLASTIC
    Price:
    Model:
Item1: pencil
    Size: GIGANTIC
    Color: GREEN
    Material: Premium PLASTIC
    Price:
    Model:
Item1: eraser
    Size: GIGANTIC
    Color: GREEN
    Material: Premium PLASTIC
    Price:
    Model:
Item1: notebook
    Size: GIGANTIC
    Color: GREEN
    Material: Premium PLASTIC
    Price:
    Model:
-->