When developing a .NET debugger capable of targeting .NET Core applications, a library called dbgshim is used to bootstrap the entire process. While dbgshim is included with the .NET Runtime, it is generally recommended to ship dbgshim with your application so that your debugger doesn't have to worry about locating dbgshim on the target system; simply load your dbgshim into your debugger, point it at a given process and ask "does this process host a CLR we can attach to?"
Microsoft has shipped a NuGet package for dbgshim that includes sub-packages with native dbgshim implementations for all of the various operating systems/architectures it supports.
If you attempt to reference this NuGet package however, neither dbgshim nor the runtimes directory inside the sub-packages are copied to your output folder, regardless of whether you are doing dotnet build or dotnet pack. For the purposes of developing an application, I expect these files should be copied to the output directory upon doing dotnet build (so that you can find and load them in your application)
After doing some debugging, I have identified that the reason dbgshim does not get copied to the output directory is that the version of dbgshim in the package is considered to conflict with the version of dbgshim included in the runtime, and thus the runtime always wins.
The sequence of events that lead up to the conflict being detected are as follows:
The ResolvePackageFileConflicts task is run
PlatformManifestReader reads a PlatformManifest.txt file for the current runtime
As dbgshim is listed in this file, a conflict item is added for it
ConflictResolver tries to resolve the platform dbgshim against the NuGet package dbgshim
PackageOverrideResolver is called upon to see if there are potentially any overrides that could be taken advantage of
As there are no overrides, the platform dbgshim wins by virtue of having a higher file version and you get the following error in the MSBuild log
Encountered conflict between 'Platform:dbgshim.dll' and 'CopyLocal:C:\Users\user.nuget\packages\microsoft.diagnostics.dbgshim.win-x64\7.0.430602\runtimes\win-x64\native\dbgshim.dll'. Choosing 'Platform:dbgshim.dll' because file version '8.0.23.36403' is greater than '7.0.8.30602'. (TaskId:82)
If DbgShim is removed from PlatformManifest.txt, dbgshim and/or the runtimes folder is copied to the output directory upon building, as expected
In dotnet/sdk#2221 an issue similar to this is described, and there is a workaround in the code to deal with this, however it seems this workaround is predicated on having a "reference" of some kind to the conflicting assembly, which isn't the case when we've got a native, unreferenced library.
As a creative workaround, I attempted to add a target to "enhance" the list of package overrides with the goal of telling the conflict resolver to use my package as per this line
<TargetName="Hack"BeforeTargets="_HandlePackageFileConflicts">
<ItemGroup>
<PackageConflictOverridesInclude="Microsoft.Diagnostics.DbgShim.win-x64">
<!-- Use an arbitrarily high number so we always win -->
<OverriddenPackages>
Microsoft.NETCore.App.Ref|99.0
</OverriddenPackages>
</PackageConflictOverrides>
</ItemGroup>
</Target>
Unfortunately, I found this does not work because the platform dbgshim has a nullPackageVersion, hence the check in this if statement fails
I'm not sure whether I would recommend having dbgshim simply be omitted from PlatformManifest.txt, as this file may be used for other purposes as well. Arguably, dbgshim is kind of a special case, so potentially there could just be special rules for how to handle conflicts against dbgshim.dll, libdbgshim.so and libdbgshim.dylib
When developing a .NET debugger capable of targeting .NET Core applications, a library called
dbgshimis used to bootstrap the entire process. Whiledbgshimis included with the .NET Runtime, it is generally recommended to shipdbgshimwith your application so that your debugger doesn't have to worry about locatingdbgshimon the target system; simply load yourdbgshiminto your debugger, point it at a given process and ask "does this process host a CLR we can attach to?"Microsoft has shipped a NuGet package for
dbgshimthat includes sub-packages with nativedbgshimimplementations for all of the various operating systems/architectures it supports.If you attempt to reference this NuGet package however, neither
dbgshimnor theruntimesdirectory inside the sub-packages are copied to your output folder, regardless of whether you are doingdotnet buildordotnet pack. For the purposes of developing an application, I expect these files should be copied to the output directory upon doingdotnet build(so that you can find and load them in your application)After doing some debugging, I have identified that the reason
dbgshimdoes not get copied to the output directory is that the version ofdbgshimin the package is considered to conflict with the version ofdbgshimincluded in the runtime, and thus the runtime always wins.The sequence of events that lead up to the conflict being detected are as follows:
The ResolvePackageFileConflicts task is run
PlatformManifestReader reads a
PlatformManifest.txtfile for the current runtimeAs
dbgshimis listed in this file, a conflict item is added for itConflictResolver tries to resolve the platform dbgshim against the NuGet package dbgshim
PackageOverrideResolver is called upon to see if there are potentially any overrides that could be taken advantage of
As there are no overrides, the platform dbgshim wins by virtue of having a higher file version and you get the following error in the MSBuild log
If DbgShim is removed from
PlatformManifest.txt,dbgshimand/or theruntimesfolder is copied to the output directory upon building, as expectedIn dotnet/sdk#2221 an issue similar to this is described, and there is a workaround in the code to deal with this, however it seems this workaround is predicated on having a "reference" of some kind to the conflicting assembly, which isn't the case when we've got a native, unreferenced library.
As a creative workaround, I attempted to add a target to "enhance" the list of package overrides with the goal of telling the conflict resolver to use my package as per this line
Unfortunately, I found this does not work because the platform
dbgshimhas anullPackageVersion, hence the check in thisifstatement failsI'm not sure whether I would recommend having
dbgshimsimply be omitted fromPlatformManifest.txt, as this file may be used for other purposes as well. Arguably,dbgshimis kind of a special case, so potentially there could just be special rules for how to handle conflicts againstdbgshim.dll,libdbgshim.soandlibdbgshim.dylib