Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
MSBuild membagi daftar item menjadi berbagai kategori, atau batch, berdasarkan metadata item, dan menjalankan target atau tugas satu kali dengan setiap batch.
Pengelompokan tugas
Batching tugas memungkinkan Anda menyederhanakan file proyek dengan menyediakan cara untuk membagi daftar item menjadi batch yang berbeda dan meneruskan masing-masing batch tersebut ke dalam tugas secara terpisah. Batching berarti bahwa file proyek hanya perlu memiliki tugas dan atributnya dideklarasikan sekali, meskipun dapat dijalankan beberapa kali.
Anda menentukan bahwa Anda ingin MSBuild melakukan batching dengan tugas dengan menggunakan %(ItemMetaDataName) notasi di salah satu atribut tugas. Pada contoh berikut, daftar item Example dibagi menjadi batch berdasarkan nilai metadata item Color, dan secara terpisah meneruskan setiap batch ke proses MyTask.
Nota
Jika Anda tidak mereferensikan daftar item di tempat lain dalam atribut tugas, atau nama metadata mungkin ambigu, Anda dapat menggunakan notasi %(<ItemCollection.ItemMetaDataName>) untuk sepenuhnya memenuhi syarat nilai metadata item yang akan digunakan untuk batching.
<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>
Untuk contoh batching yang lebih spesifik, lihat Metadata item dalam batching tugas.
Penjadwalan Target
MSBuild memeriksa apakah input dan output target sudah diperbarui sebelum menjalankan target. Jika masukan dan keluaran sudah terkini, target akan dilewati. Jika tugas di dalam target menggunakan batching, MSBuild perlu menentukan apakah input dan output untuk setiap batch item sudah diperbarui. Jika tidak, target dieksekusi setiap kali terkena.
Contoh berikut menunjukkan sebuah elemen Target yang berisi atribut Outputs dengan notasi %(ItemMetadataName). MSBuild membagi Example daftar item menjadi batch berdasarkan Color metadata item, dan menganalisis tanda waktu file output untuk setiap batch. Jika keluaran dari kumpulan proses tidak diperbarui, maka target akan dijalankan. Jika tidak, target dilewati.
<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>
Untuk contoh lain dari batching target, lihat Metadata item dalam batching target.
Perubahan item dan properti
Bagian ini menjelaskan cara memahami efek mengubah properti dan/atau metadata item, saat menggunakan batching target atau batching tugas.
Karena batching target dan batching tugas adalah dua operasi MSBuild yang berbeda, penting untuk memahami dengan tepat bentuk batching yang digunakan MSBuild dalam setiap kasus. Saat sintaks batching %(ItemMetadataName) muncul dalam tugas pada sasaran, tetapi tidak dalam atribut pada Target, MSBuild menggunakan batching tugas. Satu-satunya cara untuk menentukan batching target adalah dengan menggunakan sintaks batching pada atribut Target, biasanya Outputs atribut .
Dengan batch target dan batch tugas, batch dapat dianggap berjalan secara independen. Semua batch dimulai dengan salinan status awal properti dan nilai metadata item yang sama. Setiap mutasi nilai properti selama eksekusi batch tidak terlihat oleh batch lain. Pertimbangkan contoh berikut:
<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>
Outputnya adalah:
Target DemoIndependentBatches:
Things: 2 is red; needed change=true;1 is red; needed change=
Dalam target ItemGroup secara implisit sebagai tugas, dan dengan atribut Condition%(Color), pengelompokan tugas dilakukan. Ada dua batch: satu untuk merah dan yang lainnya untuk biru. Properti %(NeededColorChange) hanya diatur jika %(Color) metadata berwarna biru, dan pengaturan hanya memengaruhi item individual yang cocok dengan kondisi saat batch biru dijalankan. Atribut Message dari tugas Text tidak memicu batching, meskipun menggunakan sintaks %(ItemMetadataName), karena digunakan di dalam transformasi elemen.
Batch berjalan secara independen, tetapi tidak secara paralel. Itu membuat perbedaan saat Anda mengakses nilai metadata yang berubah dalam eksekusi batch. Dalam kasus di mana Anda mengatur properti berdasarkan beberapa metadata dalam eksekusi batch, properti akan mengambil set nilai terakhir :
<PropertyGroup>
<SomeProperty>%(SomeItem.MetadataValue)</SomeProperty>
</PropertyGroup>
Setelah eksekusi batch, properti mempertahankan nilai akhir %(MetadataValue).
Meskipun batch berjalan secara independen, penting untuk mempertimbangkan perbedaan antara batching sasaran dan batching berdasarkan tugas, dan juga mengetahui jenis mana yang berlaku untuk situasi Anda. Pertimbangkan contoh berikut untuk memahami lebih baik pentingnya perbedaan ini.
Tugas bisa implisit, daripada eksplisit, yang dapat menimbulkan kebingungan ketika pembagian tugas dilakukan dengan tugas implisit.
PropertyGroup Ketika elemen PropertyGroup atau ItemGroup muncul dalam Target, setiap deklarasi properti dalam grup diperlakukan secara implisit seperti tugas CreateProperty atau CreateItem yang terpisah. Perilaku ini menunjukkan bahwa eksekusi build berbeda saat target diolah dalam batch, dibandingkan saat target diolah secara individu (yaitu, ketika tidak memiliki sintaks %(ItemMetadataName) dalam atribut Outputs). Ketika target di-batch, ItemGroup dijalankan sekali per target, tetapi ketika target tidak di-batch, yang setara implisit dari CreateItem tugas atau CreateProperty di-batch menggunakan batching tugas, sehingga target hanya dijalankan sekali, dan setiap item atau properti dalam grup di-batch secara terpisah menggunakan batching tugas.
Contoh berikut mengilustrasikan pengelompokan target vs. pengelompokan tugas ketika metadata diubah. Pertimbangkan situasi di mana Anda memiliki folder A dan B dengan beberapa file:
A\1.stub
B\2.stub
B\3.stub
Sekarang lihat output dari dua proyek serupa ini.
<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>
Outputnya adalah:
Test1:
>> A\ 'A\' 'A'
Test1:
>> B\ 'B\' 'B'
Sekarang hapus Outputs atribut yang menentukan batching target.
<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>
Outputnya adalah:
Test1:
>> A\ 'B\' 'B'
>> B\ 'B\' 'B'
Perhatikan bahwa judul Test1 hanya dicetak sekali, tetapi dalam contoh sebelumnya, judul dicetak dua kali. Itu berarti target tidak di-batch. Dan akibatnya, hasilnya berbeda secara membingungkan.
Alasannya adalah ketika menggunakan pengelompokan target, setiap batch target menjalankan semua yang ada dalam target tersebut dengan salinan mandirinya dari semua properti dan item, tetapi ketika Anda menghilangkan atribut Outputs, baris individual dalam grup properti diperlakukan sebagai tugas yang berbeda dan dapat dikelompokkan. Dalam kasus ini, tugas ComponentDir di-batch (menggunakan sintaks %(ItemMetadataName)), sehingga ketika baris ComponentName dieksekusi, kedua batch dari baris ComponentDir tersebut sudah selesai, dan batch kedua yang dijalankan menentukan nilai seperti yang terlihat di baris kedua.
Fungsi properti menggunakan metadata
Batching dapat dikontrol oleh fungsi properti yang menyertakan metadata. Contohnya,
$([System.IO.Path]::Combine($(RootPath),%(Compile.Identity)))
Menggunakan Combine untuk menggabungkan jalur folder root dengan jalur item Kompile.
Fungsi properti mungkin tidak muncul dalam nilai metadata. Contohnya,
%(Compile.FullPath.Substring(0,3))
tidak diperbolehkan.
Untuk informasi selengkapnya tentang fungsi properti, lihat Fungsi properti.
Pembuatan batch item pada metadata referensi mandiri
Pertimbangkan contoh metadata referensi berikut dari dalam definisi item:
<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>
Penting untuk dicatat bahwa perilaku berbeda ketika didefinisikan di luar target apa pun dan dalam target.
Metadata item yang merujuk pada dirinya sendiri dan berada di luar dari target apa pun
<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>
Referensi metadata ditentukan per instans item (tanpa dipengaruhi oleh instans item yang telah ditentukan atau dibuat sebelumnya) - menghasilkan output yang diharapkan:
i=[a/b.txt;c/d.txt;g/h.txt]
i->MyPath=[b.txt;d.txt;h.txt]
Metadata referensi mandiri item di dalam target
<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>
Perujukan metadata dalam kasus ini menyebabkan batching, yang menghasilkan kemungkinan output yang tidak terduga dan tidak diinginkan.
i=[a/b.txt;c/d.txt;g/h.txt;g/h.txt]
i->MyPath=[;b.txt;b.txt;d.txt]
Untuk setiap instans item, mesin menerapkan metadata semua instans item yang sudah ada sebelumnya (itulah sebabnya MyPath kosong untuk item pertama dan berisi b.txt untuk item kedua). Dalam kasus lebih banyak instans yang telah ada sebelumnya, perilaku ini menyebabkan penggandaan instans item saat ini (itulah sebabnya instans item g/h.txt terjadi dua kali dalam daftar yang dihasilkan).
Untuk secara eksplisit menginformasikan tentang perilaku yang mungkin tidak diinginkan ini, versi MSBuild yang lebih baru mengeluarkan pesan 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]
Jika referensi diri disengaja, Anda memiliki beberapa opsi tergantung pada skenario yang sebenarnya dan kebutuhan yang tepat:
- Pertahankan kode dan abaikan pesan
- Tentukan item di luar target
- Gunakan item pembantu dan operasi transformasi
Menggunakan elemen pembantu dan operasi transformasi
Jika Anda ingin mencegah perilaku batching yang diinduksi oleh referensi metadata, Anda dapat mencapainya dengan menentukan item terpisah lalu menggunakan operasi transformasi untuk membuat instans item dengan metadata yang diinginkan:
<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>