I'm packing a nuget, and need to determine which PackagePath
to use depending on which .NET version the assembly is built with. Currently, our build output has all .NET Framework binaries (almost everything) in the output root and the .NET Core binary (very few) in a net7.0/
subfolder.
I'm currently checking the binary path for "net7.0" to determine whether to use the net472 or net7.0 package path for the nuget via this condition:
'$([System.String]::Copy(%(NugetResourceContent.RecursiveDir)).Contains(`$(DotNetVersion)`))' == 'true'
but some parts of the toolchain (which I don't have control over) throw the following error:
Directory.Build.targets(201,136): Error MSB4186: Invalid static method invocation syntax: "[System.String]::Copy().Contains(`$(DotNetVersion)`)". Method 'System.String.Copy' not found. Static method invocation should be of the form: $([FullTypeName]::Method()), e.g. $([System.IO.Path]::Combine(`a`,`b`)). Check that all parameters are defined, are of the correct type, and are specified in the right order.
It builds locally on up-to-date tools, so I suspect the ability to use instance functions in this way is newer. Is there another way to do this?
The comments above asked some basic questions that had me reevaluate my assumptions, and I found the solution.
When there are multiple <TargetFrameworks>
values defined - e.g. <TargetFrameworks>net472;net7.0</TargetFrameworks>
- then the targets get evaluated once per framwork plus once at the end with a blank $(TargetFramework)
value.
You can see this for yourself if you drop this target into your project file:
<Target Name="ThisIsAfterBuild" AfterTargets="Build" BeforeTargets="SomeOtherTarget">
<Message Importance="High" Text="ThisIsAfterBuild TF is $(TargetFramework)" />
</Target>
So the source of the error was that last pass where it wasn't being set, resulting in $(NugetResourceContent)
not having been set earlier. To preempt that, the fix was to add a condition to the target so it'd only add the DLL when $(TargetFramework)
was set:
<Target Name="CreateLocalizationDllPackageContent"
AfterTargets="Build"
BeforeTargets="AddLocalizationDllsToNugetContent"
Condition="'$(TargetFramework)' != ''">
<ItemGroup>
<NugetResourceContent Include="$(OutputPath)\**\$(AssemblyName).resources.dll" />
</ItemGroup>
</Target>
<Target Name="AddLocalizationDllsToNugetContent"
AfterTargets="CreateLocalizationDllPackageContent"
BeforeTargets="_GetPackageFiles" >
<ItemGroup>
<Content Include="%(NugetResourceContent.FullPath)" PackagePath="lib\$(TargetFramework)\%(NugetResourceContent.RecursiveDir)" Condition="'$(TargetFramework)' != ''" />
</ItemGroup>
</Target>
To answer the original question, [System.String]::Copy()
should have still worked, but that final pass that didn't have TargetFramework set also caused %(NugetResourceContent.RecursiveDir)
to not be set. Had I enclosed it in parentheses, it probably would've continued quietly because it'd be an empty string instead of no argument.