Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
MSBuild verdeelt itemlijsten in verschillende categorieën of batches, op basis van metagegevens van items en voert één keer een doel of taak uit met elke batch.
Batchverwerking van taken
Met taakbatches kunt u uw projectbestanden vereenvoudigen door itemlijsten in verschillende batches te verdelen en elk van deze batches afzonderlijk door te geven aan een taak. Batchverwerking betekent dat een projectbestand slechts één keer de taak en de bijbehorende kenmerken hoeft te hebben gedeclareerd, ook al kan het meerdere keren worden uitgevoerd.
U geeft op dat MSBuild batchverwerking met een taak moet uitvoeren met behulp van de %(ItemMetaDataName) notatie in een van de taakkenmerken. In het volgende voorbeeld wordt de Example itemlijst gesplitst in batches op basis van de metagegevenswaarde van het Color item en worden alle batches afzonderlijk doorgegeven aan de MyTask taak.
Opmerking
Als u niet naar de itemlijst elders in de taakkenmerken verwijst of als de naam van de metagegevens niet eenduidig is, kunt u de notatie %(<ItemCollection.ItemMetaDataName>) gebruiken om de metagegevenswaarde van het item volledig in aanmerking te nemen voor batchverwerking.
<Project>
<ItemGroup>
<Example Include="Item1">
<Color>Blue</Color>
</Example>
<Example Include="Item2">
<Color>Red</Color>
</Example>
</ItemGroup>
<Target Name="RunMyTask">
<MyTask
Sources = "@(Example)"
Output = "%(Color)\MyFile.txt"/>
</Target>
</Project>
Zie Itemmetagegevens in batchverwerking voor specifiekere batchverwerkingsvoorbeelden.
Doelbatchverwerking
MSBuild controleert of de invoer en uitvoer van een doel up-to-date zijn voordat het doel wordt uitgevoerd. Als zowel invoer als uitvoer up-to-date zijn, wordt het doel overgeslagen. Als een taak in een doel batchverwerking gebruikt, moet MSBuild bepalen of de invoer en uitvoer voor elke batch items up-to-date zijn. Anders wordt het doel telkens uitgevoerd wanneer het wordt bereikt.
In het volgende voorbeeld ziet u een Target element dat een Outputs kenmerk met de %(ItemMetadataName) notatie bevat. MSBuild verdeelt de Example itemlijst in batches op basis van de metagegevens van het Color item en analyseert de tijdstempels van de uitvoerbestanden voor elke batch. Als de uitvoer van een batch niet up-to-date is, wordt het doel uitgevoerd. Anders wordt het doel overgeslagen.
<Project>
<ItemGroup>
<Example Include="Item1">
<Color>Blue</Color>
</Example>
<Example Include="Item2">
<Color>Red</Color>
</Example>
</ItemGroup>
<Target Name="RunMyTask"
Inputs="@(Example)"
Outputs="%(Color)\MyFile.txt">
<MyTask
Sources = "@(Example)"
Output = "%(Color)\MyFile.txt"/>
</Target>
</Project>
Zie Itemmetagegevens in doelbatches voor een ander voorbeeld van doelbatches.
Item- en eigenschapsmutaties
In deze sectie wordt beschreven hoe u de effecten van het wijzigen van eigenschappen en/of itemmetagegevens begrijpt wanneer u doelbatches of taakbatches gebruikt.
Omdat doelbatches en taakbatches twee verschillende MSBuild-bewerkingen zijn, is het belangrijk om precies te begrijpen welke vorm van batchverwerking MSBuild in elk geval gebruikt. Wanneer de batchsyntaxis %(ItemMetadataName) wordt weergegeven in een taak in een doel, maar niet in een kenmerk op het doel, gebruikt MSBuild taakbatches. De enige manier om doelbatches op te geven, is door de batchsyntaxis op een doelkenmerk te gebruiken, meestal het Outputs kenmerk.
Met zowel doelbatches als taakbatches kunnen batches onafhankelijk worden uitgevoerd. Alle batches beginnen met een kopie van dezelfde beginstatus van de eigenschap en metagegevenswaarden van items. Eventuele mutaties van eigenschapswaarden tijdens batchuitvoering zijn niet zichtbaar voor andere batches. Bekijk het volgende voorbeeld:
<ItemGroup>
<Thing Include="2" Color="blue" />
<Thing Include="1" Color="red" />
</ItemGroup>
<Target Name="DemoIndependentBatches">
<ItemGroup>
<Thing Condition=" '%(Color)' == 'blue' ">
<Color>red</Color>
<NeededColorChange>true</NeededColorChange>
</Thing>
</ItemGroup>
<Message Importance="high"
Text="Things: @(Thing->'%(Identity) is %(Color); needed change=%(NeededColorChange)')"/>
</Target>
De uitvoer is:
Target DemoIndependentBatches:
Things: 2 is red; needed change=true;1 is red; needed change=
De ItemGroup binnen het doel is impliciet een taak, en met de %(Color) en Condition attributen wordt batchverwerking van taken uitgevoerd. Er zijn twee batches: één voor rood en de andere voor blauw. De eigenschap %(NeededColorChange) wordt alleen ingesteld als de %(Color) metagegevens blauw zijn en de instelling alleen van invloed is op het afzonderlijke item dat overeenkomt met de voorwaarde toen de blauwe batch werd uitgevoerd. Het Message kenmerk van de Text taak veroorzaakt geen batchverwerking, ondanks de %(ItemMetadataName) syntaxis, omdat het wordt gebruikt binnen een itemtransformatie.
Batches worden onafhankelijk uitgevoerd, maar niet parallel. Dit is van invloed wanneer u metagegevenswaarden raadpleegt die in de batchverwerking worden veranderd. In het geval dat u een eigenschap instelt op basis van sommige metagegevens in de batchuitvoering, neemt de eigenschap de laatste waardeset:
<PropertyGroup>
<SomeProperty>%(SomeItem.MetadataValue)</SomeProperty>
</PropertyGroup>
Na de batchuitvoering behoudt de eigenschap de uiteindelijke waarde van %(MetadataValue).
Hoewel batches onafhankelijk worden uitgevoerd, is het belangrijk om rekening te houden met het verschil tussen doelbatches en taakbatchverwerking en om te weten welk type van toepassing is op uw situatie. Bekijk het volgende voorbeeld om beter inzicht te krijgen in het belang van dit onderscheid.
Taken kunnen impliciet zijn, in plaats van expliciet, wat verwarrend kan zijn wanneer er takenbatches worden uitgevoerd met impliciete taken. Wanneer een PropertyGroup- of ItemGroup-element in een Target voorkomt, wordt elke eigenschapsverklaring in de groep impliciet behandeld als een afzonderlijke CreateProperty- of CreateItem-taak. Dit gedrag betekent dat de uitvoering van de build anders is wanneer het doel wordt gebatcheerd, versus wanneer het doel niet in batch is gebatcheerd (dat wil zeggen, wanneer de syntaxis in het %(ItemMetadataName) kenmerk ontbreektOutputs). Wanneer het doel wordt gebatcheerd, wordt het ItemGroup één keer per doel uitgevoerd, maar wanneer het doel niet in batch wordt gebatcheerd, worden de impliciete equivalenten van de CreateItem of CreateProperty taken gebatcheerd met behulp van taakbatchverwerking, zodat het doel slechts eenmaal wordt uitgevoerd en elk item of elke eigenschap in de groep afzonderlijk wordt gebatcheerd met behulp van taakbatch.
In het volgende voorbeeld ziet u doelbatches versus taakbatches in het geval dat metagegevens worden gemuteerd. Overweeg een situatie waarin u mappen A en B met een aantal bestanden hebt:
A\1.stub
B\2.stub
B\3.stub
Bekijk nu de uitvoer van deze twee vergelijkbare projecten.
<ItemGroup>
<StubFiles Include="$(MSBuildThisFileDirectory)**\*.stub"/>
<StubDirs Include="@(StubFiles->'%(RecursiveDir)')"/>
</ItemGroup>
<Target Name="Test1" AfterTargets="Build" Outputs="%(StubDirs.Identity)">
<PropertyGroup>
<ComponentDir>%(StubDirs.Identity)</ComponentDir>
<ComponentName>$(ComponentDir.TrimEnd('\'))</ComponentName>
</PropertyGroup>
<Message Text=">> %(StubDirs.Identity) '$(ComponentDir)' '$(ComponentName)'"/>
</Target>
De uitvoer is:
Test1:
>> A\ 'A\' 'A'
Test1:
>> B\ 'B\' 'B'
Verwijder nu het Outputs kenmerk dat de doelbatch specificeert.
<ItemGroup>
<StubFiles Include="$(MSBuildThisFileDirectory)**\*.stub"/>
<StubDirs Include="@(StubFiles->'%(RecursiveDir)')"/>
</ItemGroup>
<Target Name="Test1" AfterTargets="Build">
<PropertyGroup>
<ComponentDir>%(StubDirs.Identity)</ComponentDir>
<ComponentName>$(ComponentDir.TrimEnd('\'))</ComponentName>
</PropertyGroup>
<Message Text=">> %(StubDirs.Identity) '$(ComponentDir)' '$(ComponentName)'"/>
</Target>
De uitvoer is:
Test1:
>> A\ 'B\' 'B'
>> B\ 'B\' 'B'
U ziet dat de kop Test1 slechts eenmaal wordt afgedrukt, maar in het vorige voorbeeld is deze twee keer afgedrukt. Dat betekent dat het doel niet in een batch is verwerkt. En als gevolg hiervan is de uitvoer verwarrend anders.
De reden hiervoor is dat bij het gebruik van doelbatch elke doelbatch alles in het doel uitvoert met een eigen onafhankelijke kopie van alle eigenschappen en items, maar wanneer u het Outputs kenmerk weglaat, worden de afzonderlijke regels in de eigenschapsgroep behandeld als afzonderlijke, mogelijk gebatcheerde taken. In dit geval wordt de ComponentDir taak gebundeld (het gebruikt de %(ItemMetadataName) syntaxis), zodat wanneer de ComponentName regel wordt uitgevoerd, beide batches van de ComponentDir regel zijn voltooid, en de tweede die draaide, bepaalde de waarde zoals te zien op de tweede regel.
Eigenschappenfuncties met behulp van metagegevens
Batchverwerking kan worden beheerd door eigenschapsfuncties die metagegevens bevatten. Bijvoorbeeld
$([System.IO.Path]::Combine($(RootPath),%(Compile.Identity)))
gebruikt Combine om een pad naar de hoofdmap te combineren met een pad naar een compileeritem.
Eigenschapsfuncties worden mogelijk niet weergegeven in metagegevenswaarden. Bijvoorbeeld
%(Compile.FullPath.Substring(0,3))
is niet toegestaan.
Zie Eigenschapsfuncties voor meer informatie over eigenschapsfuncties.
Batchverwerking van items met betrekking tot zelfreferentiële metagegevens
Bekijk het volgende voorbeeld van het verwijzen naar metagegevens vanuit een itemdefinitie:
<ItemGroup>
<i Include='a/b.txt' MyPath='%(Filename)%(Extension)' />
<i Include='c/d.txt' MyPath='%(Filename)%(Extension)' />
<i Include='g/h.txt' MyPath='%(Filename)%(Extension)' />
</ItemGroup>
Het is belangrijk om te weten dat het gedrag verschilt wanneer het buiten een doel en binnen het doel is gedefinieerd.
Item zelfverwijzende metagegevens buiten een doel
<Project>
<ItemGroup>
<i Include='a/b.txt' MyPath='%(Filename)%(Extension)' />
<i Include='c/d.txt' MyPath='%(Filename)%(Extension)' />
<i Include='g/h.txt' MyPath='%(Filename)%(Extension)' />
</ItemGroup>
<Target Name='ItemOutside'>
<Message Text="i=[@(i)]" Importance='High' />
<Message Text="i->MyPath=[@(i->'%(MyPath)')]" Importance='High' />
</Target>
</Project>
Metagegevens waarnaar wordt verwezen, worden opgelost per itemexemplaar (niet beïnvloed door eerder gedefinieerde of gemaakte itemexemplaren) - Wat leidt tot verwachte uitvoer.
i=[a/b.txt;c/d.txt;g/h.txt]
i->MyPath=[b.txt;d.txt;h.txt]
Item zelfverwijzend naar metagegevens binnen een doel
<Project>
<Target Name='ItemInside'>
<ItemGroup>
<i Include='a/b.txt' MyPath='%(Filename)%(Extension)' />
<i Include='c/d.txt' MyPath='%(Filename)%(Extension)' />
<i Include='g/h.txt' MyPath='%(Filename)%(Extension)' />
</ItemGroup>
<Message Text="i=[@(i)]" Importance='High' />
<Message Text="i->MyPath=[@(i->'%(MyPath)')]" Importance='High' />
</Target>
</Project>
Metagegevens die in dit geval verwijzen, leiden tot batchverwerking, wat mogelijk onverwachte en onbedoelde uitvoer oplevert:
i=[a/b.txt;c/d.txt;g/h.txt;g/h.txt]
i->MyPath=[;b.txt;b.txt;d.txt]
Voor elk itemexemplaar past de engine de metagegevens van alle bestaande itemexemplaren toe (dat is waarom het MyPath leeg is voor het eerste item en b.txt bevat voor het tweede item). In het geval van meer bestaande exemplaren leidt dit gedrag tot vermenigvuldiging van het huidige itemexemplaar (daarom vindt het g/h.txt itemexemplaar twee keer plaats in de resulterende lijst).
Om expliciet te informeren over dit mogelijk onbedoelde gedrag, geven latere versies van MSBuild het bericht MSB4120:
proj.proj(4,11): message : MSB4120: Item 'i' definition within target is referencing self via metadata 'Filename' (qualified or unqualified). This can lead to unintended expansion and cross-applying of pre-existing items. More info: https://aka.ms/msbuild/metadata-self-ref
proj.proj(4,11): message : MSB4120: Item 'i' definition within target is referencing self via metadata 'Extension' (qualified or unqualified). This can lead to unintended expansion and cross-applying of pre-existing items. More info: https://aka.ms/msbuild/metadata-self-ref
proj.proj(5,11): message : MSB4120: Item 'i' definition within target is referencing self via metadata 'Filename' (qualified or unqualified). This can lead to unintended expansion and cross-applying of pre-existing items. More info: https://aka.ms/msbuild/metadata-self-ref
proj.proj(5,11): message : MSB4120: Item 'i' definition within target is referencing self via metadata 'Extension' (qualified or unqualified). This can lead to unintended expansion and cross-applying of pre-existing items. More info: https://aka.ms/msbuild/metadata-self-ref
proj.proj(6,11): message : MSB4120: Item 'i' definition within target is referencing self via metadata 'Filename' (qualified or unqualified). This can lead to unintended expansion and cross-applying of pre-existing items. More info: https://aka.ms/msbuild/metadata-self-ref
proj.proj(6,11): message : MSB4120: Item 'i' definition within target is referencing self via metadata 'Extension' (qualified or unqualified). This can lead to unintended expansion and cross-applying of pre-existing items. More info: https://aka.ms/msbuild/metadata-self-ref
i=[a/b.txt;c/d.txt;g/h.txt;g/h.txt]
i->MyPath=[;b.txt;b.txt;d.txt]
Als de zelfverwijzing opzettelijk is, hebt u enkele opties, afhankelijk van het werkelijke scenario en de exacte behoeften:
- De code behouden en het bericht negeren
- Het item buiten het doel definiëren
- Een helper-item en de transformatiebewerking gebruiken
Een helper-item en de transformatiebewerking gebruiken
Als u wilt voorkomen dat het batchgedrag wordt veroorzaakt door de metagegevensverwijzing, kunt u dit bereiken door een afzonderlijk item te definiëren en vervolgens de transformatiebewerking te gebruiken om itemexemplaren te maken met de gewenste metagegevens:
<Project>
<Target Name='ItemOutside'>
<ItemGroup>
<j Include='a/b.txt' />
<j Include='c/*' />
<i Include='@(j)' MyPath="%(Filename)%(Extension)" />
</ItemGroup>
<Message Text="i=[@(i)]" Importance='High' />
<Message Text="i->MyPath=[@(i->'%(MyPath)')]" Importance='High' />
</Target>
</Project>