Background: I manage a fairly large solution. Every so often, people add a DLL reference to a project in the solution where they should've added a project reference. I want to issue a warning in such case. I want to do it by finding all reference with 'bin\debug' in their HintPath*. I know that references are Items in ItemGroup, with metadata "HintPath".
I expected something like this to work:
<Warning Text="Reference %(Reference.Identity) should be a project reference. HintPath: %(Reference.HintPath)"
Condition="%(Reference.HintPath).IndexOf('bin\debug') != -1"/>
However, Seems like I can't use string function IndexOf like that. I tried many permutations of the above, without success.
An item metadata dataset contains categorical data that provides valuable context for the items in a target time-series dataset. Unlike related time-series datasets, item metadata datasets provide information that is static.
%(Directory) Contains the directory of the item, without the root directory. For example: MyProject\Source\ %(RecursiveDir)
Using MSBuild 4.0 Property Functions it is possible to do string comparisons:
<Target Name="AfterBuild">
<Message Text="Checking reference... '%(Reference.HintPath)'" Importance="high" />
<Warning Text="Reference %(Reference.Identity) should be a project reference. HintPath: %(Reference.HintPath)"
Condition="$([System.String]::new('%(Reference.HintPath)').Contains('\bin\$(Configuration)'))" />
</Target>
First not that your syntax is not correct for invoking functions, it would need to be:
%(Reference.HintPath.IndexOf(...)) # Note: not supported by MSBuild
However, property functions in MSBuild are not allowed on item metadata, so that is not going to help you either.
What you could work around this, by invoking a separate target which is basically called for every item.
<Target Name="CheckProjectReferences">
<MSBuild
Projects="$(MSBuildProjectFullPath)"
Properties="Identity=%(Reference.Identity);HintPath=%(Reference.HintPath)"
Targets="_Warn"/>
</Target>
<Target Name="_Warn">
<Warning Text="Reference $(Identity) should be a project reference. HintPath: $(HintPath)"
Condition="$(HintPath.IndexOf('bin\debug')) != -1"/>
</Target>
Frankly, I'm not sure if that is enough to catch all "violations". For example, the above will only work for bin\debug
, but not for bin\Debug
or other mixed-cased variations, which are functionally equivalent. To look for them as well, you'd need to call the IndexOf(string, StringComparison)
overload, however just doing:
$(HintPath.IndexOf('bin\debug', System.StringComparison.OrdinalIgnoreCase))
Will not work, because the MSBuild overload resolution will pick IndexOf(char, Int32)
and give you this error:
MSB4184: The expression ""bin\debug".IndexOf(bin\debug, System.StringComparison.OrdinalIgnoreCase)" cannot be evaluated. String must be exactly one character long.
So, you'll need to convince it by using the IndexOf(String, Int32, Int32, StringComparison)
overload directly:
$(HintPath.IndexOf('bin\debug', 0, 9, System.StringComparison.OrdinalIgnoreCase))
You may need to also check for bin\Release
or other variations. I'm not sure if that is the best way to figure out a reference should be a project reference, but if you know (and to a certain extend control) your environment it might be feasible.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With