Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<h1>Problem</h1> <p>The documentation <a href="http://msdn.microsoft.com/en-us/library/bb629392" rel="nofollow noreferrer">ItemDefinitionGroup Element (MSBuild)</a> refers to <a href="http://msdn.microsoft.com/en-us/library/bb651788" rel="nofollow noreferrer">Item Definitions</a> which has a note which states:</p> <blockquote> <p>Item metadata from an ItemGroup is not useful in an ItemDefinitionGroup metadata declaration because ItemDefinitionGroup elements are processed before ItemGroup elements.</p> </blockquote> <p>This means that your <code>%(Filename)</code> metadata reference in the <code>&lt;ItemDefinitionGroup/&gt;</code> cannot be expanded. You can see this yourself with this following snippet. In the snippet, the <code>.ToString()</code> call converts the result to a string object, preventing MSBuild from further expanding it. (If I had left <code>.ToString()</code> out, MSBuild would have been left with a <code>System.RegularExpressions.Match</code> object. Leaving the metadata definition as a <code>Match</code> object seems to delay expansion to string until the <code>&lt;Message/&gt;</code>’s <code>Text</code> is evaluated, causing MSBuild to do a string expansion pass over it, resulting in <code>%(Identity)</code> being expanded when you might not expect it to be. This delayed expansion is also demonstrated in the following snippet.)</p> <pre><code>&lt;?xml version="1.0" encoding="utf-8"?&gt; &lt;Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"&gt; &lt;ItemGroup&gt; &lt;MyItem Include="MyItem’s value" /&gt; &lt;MyItem Include="MyItem’s second value" /&gt; &lt;/ItemGroup&gt; &lt;ItemDefinitionGroup&gt; &lt;MyItem&gt; &lt;ItemDefinitionMatchedText&gt;$([System.Text.RegularExpressions.Regex]::Match(%(Identity), ".*").get_Groups().get_Item(0).ToString())&lt;/ItemDefinitionMatchedText&gt; &lt;ItemDefinitionMatchedTextDelayed&gt;$([System.Text.RegularExpressions.Regex]::Match(%(Identity), ".*").get_Groups().get_Item(0))&lt;/ItemDefinitionMatchedTextDelayed&gt; &lt;/MyItem&gt; &lt;/ItemDefinitionGroup&gt; &lt;Target Name="Build" Outputs="%(MyItem.Identity)"&gt; &lt;Message Text="Data being matched against for item “%(MyItem.Identity)” is “%(ItemDefinitionMatchedText)”"/&gt; &lt;Message Text="Delayed string conversion causes delayed expansion: “%(MyItem.ItemDefinitionMatchedTextDelayed)”"/&gt; &lt;/Target&gt; &lt;/Project&gt; </code></pre> <p>Output:</p> <pre><code>Build: Data being matched against for item “MyItem’s value” is “%(Identity)” Delayed string conversion causes delayed expansion: “MyItem’s value” Build: Data being matched against for item “MyItem’s second value” is “%(Identity)” Delayed string conversion causes delayed expansion: “MyItem’s second value” </code></pre> <p>The note from MSBuild’s documentation indicates that Item metadata is not available in <code>&lt;ItemDefinitionGroup/&gt;</code>. It appears, from using <code>Regex.Match()</code>, that the <a href="http://msdn.microsoft.com/en-us/library/dd633440" rel="nofollow noreferrer">property function expansion</a> is treating <code>%(Identity)</code> or, in your case, <code>%(Filename)</code> as an unquoted free-form string. Thus, since you invoke <code>Regex.IsMatch()</code> with the same syntax as I invoke <code>Regex.Match()</code> in the above example, it follows that your <code>Regex.IsMatch()</code> is trying to check if the literal string <code>%(Filename)</code> contains <code>x8</code> (optionally followed by any number of 6s whose presence or absence will not affect the match).</p> <h1>Solution</h1> <p>The only way I know of to dynamically calculate an Item’s metadata based on existing metadata is to create a new Item derived from the original item. For example, to create a list of <code>&lt;ProjectReference/&gt;</code>s with the metadata you need, you could use the following item definition to produce <code>ProjectReferenceWithArch</code> Items. I chose to use <a href="http://msdn.microsoft.com/en-us/library/dd633440#BKMK_String" rel="nofollow noreferrer">property function syntax</a> after using <a href="http://msdn.microsoft.com/en-us/library/dd633440#BKMK_ValueOrDefault" rel="nofollow noreferrer"><code>[MSBuild]::ValueOrDefault()</code></a> to turn it into a string in property expansion context so that I could use <code>String.Contains()</code> (Regex is a bit overkill for your case, but you could easily modify this to match against a regular expression if needed). I updated your <code>&lt;Message/&gt;</code> to print out the <code>Project</code> metadata to demonstrate that this metadata survives into the new Item’s definition.</p> <pre><code>&lt;ItemGroup&gt; &lt;ProjectReferenceWithArch Include="@(ProjectReference)"&gt; &lt;Isx86&gt;$([MSBuild]::ValueOrDefault('%(Filename)', '').Contains('x86'))&lt;/Isx86&gt; &lt;/ProjectReferenceWithArch&gt; &lt;/ItemGroup&gt; &lt;Target Name="AdditionalTasks"&gt; &lt;Message Text="%(ProjectReferenceWithArch.Filename) Isx86 '%(Isx86)' Inline '$([System.Text.RegularExpressions.Regex]::IsMatch(%(Filename), '.*x86*'))' Project '%(Project)'" Importance="high" /&gt; &lt;/Target&gt; </code></pre> <p>Output:</p> <pre><code>AdditionalTasks: Example.UnitTests-x86 Isx86 'True' Inline 'True' Project '{7e854803-007c-4800-80f9-be908655229d}' Example.UnitTests Isx86 'False' Inline 'False' Project '{eaac5f22-bfb8-4df7-a711-126907831a0f}' </code></pre> <h1>Alternative Solution (EDIT)</h1> <p>I just noticed <a href="https://stackoverflow.com/a/857195/429091">that you can dynamically update an Item’s metadata if you do so in a <code>&lt;Target/&gt;</code></a>. The syntax looks like this:</p> <pre><code>&lt;Target Name="AdditionalTasks"&gt; &lt;ItemGroup&gt; &lt;ProjectReference&gt; &lt;Isx86&gt;$([MSBuild]::ValueOrDefault('%(Filename)', '').Contains('x86'))&lt;/Isx86&gt; &lt;/ProjectReference&gt; &lt;/ItemGroup&gt; &lt;/Target&gt; </code></pre> <p>Just ensure that this target runs before the target in which you need to check the <code>Isx86</code> metadata or that the <code>&lt;ItemGroup/&gt;</code> appears before the metadata is needed in your <code>&lt;Target/&gt;</code>.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload