Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Az MSBuild az elemlistákat különböző kategóriákra vagy kötegekre osztja az elem metaadatai alapján, és minden köteggel egyszer futtat egy célt vagy feladatot.
Feladatok csoportosítása
A tevékenységek kötegelése egyszerűsíti a projektfájlokat azáltal, hogy az elemlistákat különböző kötegekre osztja fel, és ezeket a kötegeket külön-külön adja át feladatként. A kötegelés azt jelenti, hogy egy projektfájlnak csak egyszer kell deklarálnia a feladatot és annak attribútumait, annak ellenére, hogy többször is futtatható.
Megadhatja, hogy az MSBuild kötegelést végezzen egy feladattal az egyik feladat attribútumában az %(ItemMetaDataName) jelölés használatával. Az alábbi példa az Example elemlistát kötegekre osztja az Color elem metaadatainak értéke alapján, és külön továbbítja az egyes kötegeket a MyTask feladatnak.
Megjegyzés:
Ha nem hivatkozik az elemlistára a tevékenységattribútumok más részein, vagy a metaadatok neve nem egyértelmű, a %(<ItemCollection.ItemMetaDataName>) jelöléssel teljes mértékben minősítheti a kötegeléshez használandó elem metaadat-értékét.
<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>
Konkrétabb kötegelési példákért tekintse meg a tétel metadatáit a feladatok kötegelésében.
Célbeli kötegelés
Az MSBuild ellenőrzi, hogy a cél bemenetei és kimenetei naprakészek-e a cél futtatása előtt. Ha a bemenetek és a kimenetek is naprakészek, a cél ki lesz hagyva. Ha egy célon belüli tevékenység kötegelést használ, az MSBuildnek meg kell állapítania, hogy az egyes elemek kötegének bemenetei és kimenetei naprakészek-e. Ellenkező esetben a cél minden találatkor végrehajtódik.
Az alábbi példa egy Target olyan elemet mutat be, amely egy Outputs attribútumot tartalmaz a %(ItemMetadataName) jelöléssel. Az MSBuild az Example elemlistát kötegekre osztja az Color elem metaadatai alapján, és elemzi az egyes kötegekhez tartozó kimeneti fájlok időbélyegeit. Ha egy köteg kimenetei nem naprakészek, a cél végrehajtásra kerül. Ellenkező esetben a cél ki lesz hagyva.
<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>
A célkötegelés egy másik példáját az Elem metaadatai a cél kötegelésben című témakörben talál.
Elem- és tulajdonságmutációk
Ez a szakasz bemutatja, hogyan érthetjük meg a tulajdonságok és/vagy az elemek metaadatainak módosításának hatásait a cél- vagy feladatkötegelés során.
Mivel a cél kötegelés és a tevékenység kötegelése két különböző MSBuild művelet, fontos tisztában lenni azzal, hogy az MSBuild melyik kötegelési formáját használja mindegyik esetben. Ha a kötegelés szintaxisa %(ItemMetadataName) egy cél egy tevékenységében jelenik meg, de nem a Cél attribútumában, akkor az MSBuild tevékenység kötegelést használ. A célkötegezés megadásának egyetlen módja az, ha a célattribútum kötegelési szintaxisát használja, általában az Outputs attribútumot.
A cél kötegelés és a tevékenység kötegelése mellett a kötegek egymástól függetlenül futtathatók. Minden köteg azonos kezdeti állapotú tulajdonság- és elem metaadatértékek másolatával kezdődik. A tulajdonságértékek bármely mutációja a köteg végrehajtása során nem látható más kötegek számára. Vegye figyelembe a következő példát:
<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>
A kimenet a következő:
Target DemoIndependentBatches:
Things: 2 is red; needed change=true;1 is red; needed change=
A ItemGroup a célban implicit módon tevékenységként értelmezendő, és az %(Color) attribútumban a Condition feladatok csoportosítása és kezelése történik. Két tétel van: az egyik piros, a másik kék. A tulajdonság %(NeededColorChange) csak akkor van beállítva, ha a %(Color) metaadatok kékek, és a beállítás csak azokat az elemeket érinti, amelyek megfeleltek a kék köteg futtatásának feltételének. A Message tevékenység attribútuma Text a szintaxis ellenére nem aktiválja a %(ItemMetadataName) kötegelést, mert egy elemátalakításon belül használják.
A kötegek egymástól függetlenül futnak, de nem egyszerre. Ez különbséget tesz a kötegelt végrehajtás során változó metaadat-értékek elérésekor. Abban az esetben, ha a kötegelt végrehajtás bizonyos metaadatai alapján állít be egy tulajdonságot, a tulajdonság az utolsó értékhalmazt veszi fel:
<PropertyGroup>
<SomeProperty>%(SomeItem.MetadataValue)</SomeProperty>
</PropertyGroup>
A tömeges végrehajtás után a tulajdonság megtartja a %(MetadataValue) végső értékét.
Bár a kötegek egymástól függetlenül futnak, fontos figyelembe venni a célzott kötegelés és a feladatok kötegelése közötti különbséget, és tudni, hogy melyik típus vonatkozik az Ön helyzetére. Az alábbi példában jobban megértheti ennek a különbségnek a fontosságát.
A feladatok lehetnek implicit módon megadottak ahelyett, hogy explicitek lennének, ami zavaró lehet, amikor a feladatok csoportosítása implicit módon történik. Amikor egy vagy PropertyGroup több ItemGroup elem megjelenik egy Targetcsoportban, a csoport minden tulajdonságdeklarációja implicit módon egy különálló CreateProperty vagy CreateItem feladatként lesz kezelve. Ez a viselkedés azt jelenti, hogy a build végrehajtása eltérő akkor, ha a célpont kötegelve van, szemben azzal, amikor a célpont nincs kötegelve (vagyis ha hiányzik az %(ItemMetadataName) szintaxis az Outputs attribútumban). Amikor a cél kötegelve van, a ItemGroup végrehajtódik célonként egyszer, de ha a cél nincs kötegelve, az CreateItem vagy CreateProperty feladatok implicit megfelelőit feladatok kötegelésével hajtja végre, így a cél csak egyszer hajtódik végre, és a csoport minden egyes elemét vagy tulajdonságát külön kötegeli feladatok kötegelésével.
Az alábbi példa a célzott kötegelést és a feladatok kötegelését mutatja be abban az esetben, ha a metaadatok módosulnak. Fontolja meg azt a helyzetet, amikor az A és a B mappában van néhány fájl:
A\1.stub
B\2.stub
B\3.stub
Most tekintse meg a két hasonló projekt kimenetét.
<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>
A kimenet a következő:
Test1:
>> A\ 'A\' 'A'
Test1:
>> B\ 'B\' 'B'
Most távolítsa el a Outputs attribútumot, amely a cél kötegelést meghatározta.
<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>
A kimenet a következő:
Test1:
>> A\ 'B\' 'B'
>> B\ 'B\' 'B'
Figyelje meg, hogy a címsor Test1 csak egyszer van kinyomtatva, de az előző példában kétszer nyomtatták ki. Ez azt jelenti, hogy a cél nincs kötegelve. Ennek eredményeképpen a kimenet zavaróan eltérő.
Ennek az az oka, hogy a cél kötegelés használatakor minden célköteg a célban lévő összes tulajdonságot és elemet saját, független másolattal hajtja végre, de ha kihagyja az Outputs attribútumot, a tulajdonságcsoport egyes sorai különálló, esetleg kötegelt tevékenységekként lesznek kezelve. Ebben az esetben a ComponentDir feladat kötegelve van (a %(ItemMetadataName) szintaxist használja), így mire a ComponentName sor végrehajtásra kerül, a ComponentDir sor mindkét kötege befejeződött, és a másodikként lefutott határozta meg az értéket, amit a második sorban láthatunk.
Tulajdonságfüggvények metaadatok használatával
A kötegelés metaadatokat tartalmazó tulajdonságfüggvényekkel szabályozható. Például
$([System.IO.Path]::Combine($(RootPath),%(Compile.Identity)))
Combine arra szolgál, hogy egy gyökérmappa elérési útját kombinálja egy fordítási elem elérési útjával.
Előfordulhat, hogy a tulajdonságfüggvények nem jelennek meg a metaadatértékek között. Például
%(Compile.FullPath.Substring(0,3))
nem engedélyezett.
A tulajdonságfüggvényekről további információt a Tulajdonságfüggvények című témakörben talál.
Elem kötegelése önhivatkozási metaadatokon
Fontolja meg a metaadatok elemdefiníción belüli hivatkozását az alábbi példában:
<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>
Fontos megjegyezni, hogy a viselkedés akkor különbözik, ha a célon kívül és a célon belül van meghatározva.
Elem önhivatkozási metaadatai bármely célterületen kívül
<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>
A metaadatokra való hivatkozás elempéldányonként oldódik fel (a korábban definiált vagy létrehozott elempéldányok nem befolyásolják) – ami a várt kimenethez vezet:
i=[a/b.txt;c/d.txt;g/h.txt]
i->MyPath=[b.txt;d.txt;h.txt]
Elem önhivatkozási metaadatai egy célobjektumon belül
<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>
A metaadatokra való hivatkozás ebben az esetben kötegeléshez vezet, amely esetleg váratlan és nem várt kimenetet eredményez:
i=[a/b.txt;c/d.txt;g/h.txt;g/h.txt]
i->MyPath=[;b.txt;b.txt;d.txt]
Minden egyes elempéldány esetében a motor az összes már meglévő elempéldány metaadatait alkalmazza (emiatt az első elemnél üres MyPath, és a második elemhez tartozik b.txt). Több már meglévő példány esetén ez a viselkedés az aktuális elempéldány szorzásához vezet (ezért fordul elő kétszer az g/h.txt elempéldány az eredményül kapott listában).
Ha explicit módon szeretne tájékoztatást adni erről a valószínűleg nem szándékos viselkedésről, az MSBuild hibaüzenet MSB4120későbbi verziói:
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]
Ha az önhivatkozás szándékos, a tényleges forgatókönyvtől és a pontos igényektől függően néhány lehetőség közül választhat:
- Tartsa meg a kódot, és hagyja figyelmen kívül az üzenetet
- Az elem meghatározása a célterületen kívül
- Segédelem és az átalakítási művelet használata
Segédelem és az átalakítási művelet használata
Ha meg szeretné akadályozni a metaadat-hivatkozás által kiváltott kötegelési viselkedést, ezt egy külön elem definiálásával, majd az átalakítási művelettel a kívánt metaadatokkal rendelkező elempéldányok létrehozásához teheti meg:
<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>