Filtering metadata elements in msbuild

I would like to create a new collection of elements with modified metadata. For example, change the separators of ClCompile.AdditionalIncludeDirectories. To do this, I first create a collection of elements from the metadata AdditionalIncludeDirectories, and then convert it:

<ItemGroup> <IncludeDirs0 Include="%(ClCompile.AdditionalIncludeDirectories)"> <key>@(ClCompile)</key> </IncludeDirs0> </ItemGroup> <ItemGroup> <IncludeDirs Include="@(IncludeDirs0 -> '-I %(Identity)', ' ')"> <key>%(IncludeDirs0.key)</key> </IncludeDirs> </ItemGroup> <ItemGroup> <Compile Include="@(ClCompile)"> <IncludeDirs>@(IncludeDirs)</IncludeDirs> </Compile> </ItemGroup> 

The problem is how to filter IncludeDirs in the group of compilation elements, so that each compilation element will have the right to include a directory. (so the ClCompile identity is equal to the IncludeDirs key). I tried to add a condition such as: Condition="'%(IncludeDirs.key)'=='%(ClCompile.Identity)'" , but without any success.
I could use IncludeDirs directly: <Message Text="%(IncludeDirs.key) : @(IncludeDirs)"/> , but I feel this is not the point, since the Compile collection should contain all the metadata.

What am I missing here?

+4
source share
2 answers

You can do this with one additional goal, which collects the necessary items. See MSBuild Batching .

 <?xml version="1.0" encoding="utf-8"?> <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup> <ClCompile Include="1" /> <ClCompile Include="2"> <AdditionalIncludeDirectories>2.1;2.2;2.3</AdditionalIncludeDirectories> </ClCompile> </ItemGroup> <Target Name="TransformClCompile" Inputs="%(ClCompile.Identity)" Outputs="_Non_Existent_Item_To_Batch_"> <PropertyGroup> <IncludeDirs>%(ClCompile.AdditionalIncludeDirectories)</IncludeDirs> </PropertyGroup> <ItemGroup> <IncludeDirs Include="$(IncludeDirs)" /> <Compile Include="@(ClCompile)"> <IncludeDirs>@(IncludeDirs ->'-I %(Identity)', ' ')</IncludeDirs> </Compile> </ItemGroup> </Target> <Target Name="Build" DependsOnTargets="TransformClCompile"> <Message Text="compile %(Compile.Identity) %(Compile.IncludeDirs)" /> </Target> </Project> 

Output:

  compile 1 compile 2 -I 2.1 -I 2.2 -I 2.3 
+4
source

There are ways to do this more succinctly in 4.0+ using property functions.

 <?xml version="1.0" encoding="utf-8"?> <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup> <ClCompile Include="1" /> <ClCompile Include="2"> <AdditionalIncludeDirectories>2.1;2.2;2.3</AdditionalIncludeDirectories> </ClCompile> </ItemGroup> <Target Name="Build" > <Message Text="compile %(ClCompile.Identity)" Condition="'%(ClCompile.AdditionalIncludeDirectories)' ==''"/> <Message Text="compile %(ClCompile.Identity) /I $([System.String]::Join(' /I ', $([System.Text.RegularExpressions.Regex]::Split('%(ClCompile.AdditionalIncludeDirectories)', ';'))))" Condition="'%(ClCompile.AdditionalIncludeDirectories)' !=''"/> </Target> </Project> 

Output

 compile 1 compile 2 /I 2.1 /I 2.2 /I 2.3 

It's not very cute, but it's a little better, I think. Instead of String.Split, you should use Regex.Split, because the latter needs an array of splitters, and it's a little difficult to do.

MSBuild middleware needs some improvements, I think.

Dan (msbuild)

+3
source

Source: https://habr.com/ru/post/1339986/


All Articles