Skip to content

Commit 7fce299

Browse files
committed
main
1 parent 8d3b1c6 commit 7fce299

File tree

1 file changed

+138
-14
lines changed

1 file changed

+138
-14
lines changed

docs/document/Modern CSharp/docs/Understanding MSBuild.md

Lines changed: 138 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -52,22 +52,76 @@
5252
5353
## Item Section
5454

55-
`<ItemGroup>` section is for specifying files to be included on build, one could use builtin.
55+
`<ItemGroup>` section is generally for specifying files to be included on build.
56+
Children under `<ItemGroup>` are not necessarily files, **they can be any list with a name(the tag name) that has items represented as string**.
5657
Attributes for child items are similar to parameters of item-cmdlet in PowerShell.
5758

58-
- `Include`: include items on declaration
59-
- `Exclude`: exclude items on declaration
60-
6159
```xml
6260
<ItemGroup>
63-
<Compile Include="one.cs;three.cs" />
64-
<Compile Exclude="*.fs" />
61+
<!-- represents a normal list -->
62+
<!-- child tag with same name are included within same list -->
63+
<FooList Include="foo;bar" />
64+
<FooList Include="baz;qux" />
65+
66+
<MyFile Include="*.cs"/>
6567
</ItemGroup>
6668
```
6769

70+
### Item Attributes
71+
72+
Item attributes are for controlling how items could be initialized, added and removed to a list
73+
74+
- `Include`: include items on declaration
75+
- use `KeepMetadata` or `RemoveMetadata` to optionally include or exclude metadata from when **creating items by transforming** from another **within a `<Target>`**
76+
```xml
77+
<ItemGroup>
78+
<Old Include="*"> <!-- [!code highlight] -->
79+
<Foo>foo</Foo> <!-- [!code highlight] -->
80+
<Bar>bar</Bar> <!-- [!code highlight] -->
81+
</Old> <!-- [!code highlight] -->
82+
</ItemGroup>
83+
84+
<Target>
85+
<ItemGroup>
86+
<New Include="@(Old)" RemoveMetadata="Foo"/> <!-- transform from Old --> <!-- [!code highlight] -->
87+
</ItemGroup>
88+
<!-- Old.Foo was removed after transformation -->
89+
<Message Text="Old.Foo was removed after transformation" <!-- [!code highlight] -->
90+
Condition="%(New.Foo) == ''" <!-- [!code highlight] -->
91+
Importance="high"/> <!-- [!code highlight] -->
92+
</Target>
93+
```
94+
- use `KeepDuplicates` when adding new item within a `<Target>` that you expect the new would be added when deplicates exist.
95+
> [!WARNING]
96+
> The idendity of a item depends on all metadata within it, so as long as one metadata differ, it would not be considered as a duplicate.
97+
```xml
98+
<ItemGroup>
99+
<FooList Include="foo;bar" />
100+
<FooList Include="foo;qux" />
101+
</ItemGroup>
102+
103+
<Target Name="Hello">
104+
<ItemGroup>
105+
<!-- bar would not be added since it already exists in FooList -->
106+
<FooList Include="bar" KeepDuplicates="false" /> <!-- [!code highlight] -->
107+
</ItemGroup>
108+
<!-- foo;bar;foo;qux -->
109+
<Message Text="@(FooList)" Importance="high"></Message> <!-- [!code highlight] -->
110+
</Target>
111+
```
112+
- `Exclude`: exclude items on declaration
113+
```xml
114+
<ItemGroup>
115+
<Compile Include="one.cs;three.cs" />
116+
<Compile Exclude="*.fs" />
117+
</ItemGroup>
118+
```
68119
- `Remove`: remove items after declaration, typically inside a `<Target>` section
69120
- optionally use `MatchOnMetadata` together to delete base on another type of items
70-
- optionally use ``
121+
- optionally use `MatchOnMetadataOptions` to specify the comparing strategy on match
122+
- `CaseInsensitive`: the default when unspecified
123+
- `CaseSensitive`
124+
- `PathLike`: match paths ignoring separator and trailing slash
71125
```xml
72126
<ItemGroup>
73127
<CSFile Include="Programs.cs"/>
@@ -88,6 +142,47 @@ Attributes for child items are similar to parameters of item-cmdlet in PowerShel
88142
<Message Text="Remained cs items: %(CSFile.Identity)" Importance="high"></Message>
89143
</Target>
90144
```
145+
- `Update`: update metadata **outside a `<Target>`**
146+
```xml
147+
<ItemGroup>
148+
<FooList Include="foo;bar;baz">
149+
<!-- assign FooMetaData to all items in Include -->
150+
<FooMetaData>this is a foo metadata</FooMetaData>
151+
</FooList>
152+
<!-- update FooMetaData for foo and bar -->
153+
<FooList Update="foo;bar" FooMetaData="this is a bar metadata now!"/> <!-- [!code highlight] -->
154+
</ItemGroup>
155+
156+
<Target Name="Hello">
157+
<Message Text="%(FooList.Identity): %(FooList.FooMetaData)" Importance="high"/>
158+
<!-- foo: this is a bar metadata now!
159+
bar: this is a bar metadata now!
160+
baz: this is a foo metadata -->
161+
</Target>
162+
```
163+
164+
### Item Functions
165+
166+
There's some intrinsic functions to be used to **transform** a item list to another or **get properties** like `Count` of a item list.
167+
168+
> [!NOTE]
169+
> [Item Functions](https://learn.microsoft.com/en-us/visualstudio/msbuild/item-functions?view=vs-2022)
170+
171+
> [!NOTE]
172+
> If a expression includes item enumeration `%(itemType)`, item functions that returns a statistics of list would return result for each **distinct item**
173+
>```xml
174+
><ItemGroup>
175+
> <FooList Include="foo;bar" />
176+
> <FooList Include="foo;qux" />
177+
></ItemGroup>
178+
>
179+
><Target Name="Hello">
180+
> <Message Text="%(FooList.Identity) @(FooList->Count())" Importance="high" /> <!-- [!code highlight] -->
181+
> <!-- foo 2
182+
> bar 1
183+
> qux 1 -->
184+
></Target>
185+
>```
91186

92187
### Default Filters
93188

@@ -103,6 +198,11 @@ Each item has pre-defined metadata can be accessed.
103198
> [!NOTE]
104199
> [Well-Known Item Metadata](https://learn.microsoft.com/en-us/visualstudio/msbuild/msbuild-well-known-item-metadata?view=vs-2022)
105200

201+
> [!NOTE]
202+
> If a item does not represent a file, the most of intrinsic metadata would be empty.
203+
204+
205+
106206
## Expression Syntax
107207

108208
Expression syntax in msbuild has some flavor of Command Prompt and PowerShell.
@@ -115,7 +215,7 @@ Expression syntax in msbuild has some flavor of Command Prompt and PowerShell.
115215
- access [registry item](https://learn.microsoft.com/en-us/visualstudio/msbuild/msbuild-properties?view=vs-2022#registry-properties) with its path
116216
- **item accessor** `@(itemType)`
117217
- use `@(itemType, '<sep>')` to concat items using separator
118-
- use `@(itemType->'<metadata_expr>')` to collected transformed values to a list
218+
- use `@(itemType->expr)` to collected transformed values generated by `expr` to a list, `expr` can be a string interpolation or [*item function*](https://learn.microsoft.com/en-us/visualstudio/msbuild/item-functions?view=vs-2022)
119219
```xml
120220
<ItemGroup>
121221
<MyFile Include="Programs.cs"/>
@@ -126,6 +226,8 @@ Expression syntax in msbuild has some flavor of Command Prompt and PowerShell.
126226
<!-- Collected metadata: Program.cs; ConsoleApp.csproj -->
127227
<Message Text="Collected metadata: @(MyFile->'%(FileName)%(Extension)')" <!-- [!code highlight] -->
128228
Importance="high" /> <!-- [!code highlight] -->
229+
<Message Text="Exists: @(MyFile->Count())" <!-- 5 --> <!-- [!code highlight] -->
230+
Importance="high" /> <!-- [!code highlight] -->
129231
</Target>
130232
```
131233

@@ -137,10 +239,6 @@ For [special characters](https://learn.microsoft.com/en-us/visualstudio/msbuild/
137239
[System.Uri]::EscapeDataString('"') # %22
138240
```
139241

140-
```lua
141-
foo
142-
```
143-
144242
> [!TIP]
145243
> Notation like `&quot;` is also viable
146244
@@ -167,9 +265,9 @@ So one could include dedicated part of the config for different build scenarios.
167265

168266
## Builtin Variables
169267

170-
## MSBuild Task
268+
## Target Section
171269

172-
A task is a pre-defined procedure to be executed in `Target` section in their declared order.
270+
A task is a pre-defined procedure to be executed in `<Target>` section in their declared order.
173271
The containing `Target` is like a function which must have a name while a task is just named as its tag.
174272
MSBuild ships with some builtin task to be used out of box.
175273

@@ -197,6 +295,32 @@ Or you can implement one using [inline task](https://learn.microsoft.com/en-us/v
197295
> [!NOTE]
198296
> See: [Task Writing](https://learn.microsoft.com/en-us/visualstudio/msbuild/task-writing?view=vs-2022)
199297
298+
### Update Metadata in Target
299+
300+
Such approach seems to only allow updating on all existing items since `Include` could try to add new items and new metadata would result them to be duplicates.
301+
302+
```xml
303+
<ItemGroup>
304+
<FooList Include="foo;bar;baz">
305+
<FooMetaData>this is a foo metadata</FooMetaData>
306+
</FooList>
307+
</ItemGroup>
308+
309+
<Target Name="Hello">
310+
<ItemGroup>
311+
<FooList> <!-- no Include here --> <!-- [!code highlight] -->
312+
<!-- update all existing items from FooList -->
313+
<FooMetaData>this is a bar metadata now!</FooMetaData> <!-- [!code highlight] -->
314+
</FooList>
315+
</ItemGroup>
316+
317+
<Message Text="%(FooList.Identity): %(FooList.FooMetaData)" Importance="high"/> <!-- [!code highlight] -->
318+
<!-- foo: this is a bar metadata now!
319+
bar: this is a bar metadata now!
320+
baz: this is a bar metadata now! -->
321+
</Target>
322+
```
323+
200324
### Generating Items from Tasks
201325

202326
## Importing

0 commit comments

Comments
 (0)