Элементы SBuild

Элементы MSBuild — это входные данные для системы сборки. Они, как правило, представляют файлы (файлы указаны в атрибуте Include). Элементы группируются в типы, определяемые их именами. Типы элементов — это именованные списки элементов, которые можно использовать в качестве параметров для задач. Задачи используют значения элементов для выполнения этапов процесса сборки.

Так как имена элементов образуются от имен типов, которым они принадлежат, термины "элемент" и "значение элемента" могут использоваться один вместо другого.

Создание элементов в файле проекта

Элементы в файле проекта объявляются как дочерние элементы элемента 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 например в файле.

Создание элементов во время выполнения

Значения элементам, находящимся за пределами элементов Target, присваиваются на этапе оценки сборки. На следующем этапе выполнения элементы могут быть созданы и их значения могут быть изменены следующим образом.

  • Любая задача может создать элемент. Для создания элемента элемент Задача должен иметь дочерний элемент Выходные данные с атрибутом ItemName.

  • Задача CreateItem также может создать элемент. Этот способ не рекомендуется использовать.

  • Targetэлементы могут содержать элементы ItemGroup, которые могут содержать элементы элемента.

Ссылки на элементы в файле проекта

Чтобы ссылаться на типы элементов в файле проекта, используйте синтаксис @(ItemType). Например, для обращения к типу элементов из предыдущего примера следует использовать конструкцию @(Compile). Используя этот синтаксис, можно передавать элементы в задачи, указывая тип элементов в качестве параметра этой задачи. Дополнительные сведения см. в разделе Практическое руководство. Выбор файлов для сборки.

По умолчанию при развертывании элементы типа разделяются знаком "точка с запятой" (;). Синтаксис @(ItemType, 'separator') можно использовать для указания разделителя, отличного от значения по умолчанию. Дополнительные сведения см. в разделе Практическое руководство. Отображение списка элементов, разделенных запятыми.

Использование подстановочных знаков для указания элементов

С помощью подстановочных знаков **, * и ? в качестве входных данных для сборки можно указать сразу группу файлов, не перечисляя эти файлы по отдельности.

  • Подстановочный знак ? заменяет один символ.
  • Знак * заменяет несколько символов (или ни одного).
  • Последовательность подстановочных знаков ** заменяет частичный путь.

Например, можно указать все файлы с расширением .cs в каталоге с файлом проекта, используя следующий элемент в файле проекта.

<CSFile Include="*.cs"/>

Следующий элемент выбирает все файлы с расширением .vb на диске D:.

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

Чтобы включить в элемент сами символы * или? без выполнения подстановки, необходимо экранировать подстановочные знаки.

Дополнительные сведения о подстановочных знаках см. в разделе Практическое руководство. Выбор файлов для сборки.

Использование атрибута Exclude

Элементы Item могут содержать атрибут Exclude, исключающий определенные элементы (файлы) из типа элементов. Атрибут Exclude обычно используется вместе с подстановочными знаками. Например, следующий XML-файл добавляет каждый .cs файл в каталоге к типу CSFileэлемента, кроме файла DoNotBuild.cs.

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

Атрибут Exclude применяется только к элементам, добавляемым с помощью атрибута Include в элемент Item, содержащий их оба. В следующем примере файл Form1.cs, добавленный в предыдущий элемент Item, не исключается.

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

Дополнительные сведения см. в разделе Практическое руководство. Исключение файлов из сборки.

Метаданные элементов

Помимо сведений в атрибутах Include и Exclude элементы могут содержать метаданные. Эти метаданные могут использоваться задачами, требующими дополнительных сведений об элементах, или для пакетной обработки задач и целевых объектов. Дополнительные сведения см. в статье Пакетная обработка.

Метаданные — это коллекция пар "ключ-значение", которые объявляются в файле проекта как дочерние элементы элемента Item. Имя дочернего элемента совпадает с именем метаданных, а значение дочернего элемента совпадает со значением метаданных.

Метаданные связаны с элементом Item, который их содержит. Например, следующий 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 xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <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 элемента с элементами.obj, представляющими .cpp файлы в соответствующий список файлов с помощью выражения@(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-кода элементам Compileone.cs и three.cs назначаются метаданные BuildDay со значением "Понедельник". В этом коде элементу two.cs назначаются метаданные BuildDay со значением "Вторник".

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

Дополнительные сведения см. в разделе Определения элементов.

Атрибуты элементов в элементе ItemGroup целевого объекта

Targetэлементы могут содержать элементы ItemGroup, которые могут содержать элементы элемента. Атрибуты в этом разделе допустимы, если они указаны для элемента в ItemGroup объекте, который находится в объекте Target.

Удалить атрибут

Атрибут 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 с метаданными M, значение которых V для M соответствует любым элементам из A с метаданными M значения V.

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

В примере значения b2c2элементов и d2 удаляются из элементаB, так как:

  • b2 и c2 из B соответствуют b1 из A в M1=2 и M2=x;
  • d2 из B соответствуют c1 из A в M1=3 и M2=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 из MSBuild:

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

Эта строка удаляет элементы из _TransitiveItemsToCopyToOutputDirectory элементов с одинаковыми TargetPath значениями метаданных из элементов _ThisProjectItemsToCopyToOutputDirectory

Атрибут MatchOnMetadataOptions

Указывает стратегию сопоставления строк, используемую MatchOnMetadata для сопоставления значений метаданных разных элементов (при сопоставлении имен метаданных регистр не учитывается). Возможные значения: CaseSensitive, CaseInsensitiveили PathLike. Значение по умолчанию — CaseSensitive.

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

Атрибут KeepMetadata

Если элемент создается в целевом объекте, элемент Item может содержать атрибут KeepMetadata. Если этот атрибут задан, из исходного элемента в целевой передаются только те метаданные, имена которых содержатся в списке имен, разделенных точкой с запятой. Пустое значение этого атрибута эквивалентно тому, что атрибут не задан. Атрибут KeepMetadata появился в .NET Framework версии 4.5.

В следующем примере показано использование атрибута KeepMetadata.

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
ToolsVersion="4.0">

    <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 ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

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

Если исходный и целевой элементы имеют одинаковое значение Include, но различные метаданные, элемент добавляется в целевую группу, даже если KeepDuplicates имеет значение false. Пустое значение этого атрибута эквивалентно тому, что атрибут не задан. Атрибут KeepDuplicates появился в .NET Framework версии 4.5.

В следующем примере показано использование атрибута KeepDuplicates.

<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

    <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 Так как атрибут рассматривает метаданные элементов в дополнение к значениям элементов, важно знать, что происходит с метаданными. Например, см. сведения об обнаружении дубликатов при использовании функции элемента метаданных.

Обновление метаданных элементов в 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.
  • Если элемент совпадает несколько раз в пределах и между несколькими ссылочными элементами:
    • Получается последнее вхождение для каждого типа элемента, на который задана ссылка (то есть для каждого типа элемента получается один элемент).
    • Это соответствует поведению пакетной обработки элементов задачи в целевых объектах.
  • Где можно поместить ссылки %():
    • Метаданные
    • Условия метаданных
  • Сопоставление имен метаданных не учитывает регистр.

Обновление метаданных элементов в 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:
-->