dotnet / msbuild

The Microsoft Build Engine (MSBuild) is the build platform for .NET and Visual Studio.
https://docs.microsoft.com/visualstudio/msbuild/msbuild
MIT License
5.23k stars 1.35k forks source link

Microsoft.Build dependency on System.Runtime.Loader #3510

Closed daveaglick closed 6 years ago

daveaglick commented 6 years ago

It looks like Microsoft.Build references System.Runtime.Loader which isn't supported on .NET Framework (see https://github.com/dotnet/cli/issues/6019#issuecomment-286161210):

2018-07-12_16h45_17

When attempting to trigger SDK resolver resolution on a .NET Framework host, I get assembly loading exceptions in Microsoft.Build.BackEnd.SdkResolution.SdkResolverService.ResolveSdk(). I haven't seen this issue before, so I suspect the System.Runtime.Loader usage may be limited to the new(ish) SDK resolution stuff.

My initial reading of the situation is that performing SDK resolver resolution using the MSBuild API from a .NET Framework host is currently impossible - is that correct? If so, that seems like kind of a big problem to me given that custom SDKs are gradually becoming more popular.

rainersigwald commented 6 years ago

It works from VS and msbuild.exe so it should definitely not be a general problem with .NET Framework hosts. What are the exact errors you're seeing?

daveaglick commented 6 years ago

That is a really good point...

Here's the build warning I'm seeing:

E:\Code\Buildalyzer\tests\repos\Rx.NET\AsyncRx.NET\System.Reactive.Async\System.Reactive.Async.csproj :
warning MSB4243: The NuGet-based SDK resolver failed to run because NuGet assemblies could not be
 located.  Check your installation of MSBuild or set the environment variable "MSBUILD_NUGET_PATH" to
 the folder that contains the required NuGet assemblies. Could not load file or assembly
 'System.Runtime.Loader, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one
 of its dependencies. The system cannot find the file specified.

Digging deeper, if I set up a custom assembly resolver (by handling AppDomain.CurrentDomain.AssemblyResolve) I can see the assembly resolution request:

2018-07-12_18h14_16

Obviously that's never going to complete successfully because there is no System.Runtime.Loader assembly for .NET Framework. Here's the call stack when the System.Runtime.Loader assembly is first requested:

2018-07-12_18h14_44

And here's the code that triggers the System.Runtime.Loader assembly load:

2018-07-12_18h21_19

Which, looking closer now, I'm starting wonder if the failure is being caused by NuGet.MSBuildSdkResolver...and sure enough:

2018-07-12_18h25_02

So now I think I know what's going on: I set the MSBuild environment to use tools, etc. from the .NET Core SDK when the project type uses the SDK, even when the host is .NET Framework. That's to minimize the need for Visual Studio or the Build Tools when building an SDK-based project. That's worked well so far - all the .NET Core SDK stuff targets variations of netstandard so the .NET Framework host has no trouble consuming it (except for very specific .NET Core-only targets, but that's to be expected). So in this case, the SDK resolver was coming from NuGet.MSBuildSdkResolver.dll in the .NET Core SDK, which targets netstandard but apparently has a dependency on System.Runtime.Loader.

That's unfortunate because it means I can't fully commit to the SDK tools on a .NET Framework host, but at least I know what's going on. The NuGet.MSBuildSdkResolver.dll in the Visual Studio directory targets .NET Framework and doesn't have a dependency on System.Runtime.Loader so that's probably the one I want to use, even when building a SDK project using the SDK tools. I'll either have to set MSBUILD_NUGET_PATH based on the host platform instead of the project type, or special case this somehow during assembly resolution.

Sorry for the long-winded comment here - was using it to record everything for future reference. I guess there might be a follow-up issue here somewhere, or maybe I'm just holding it wrong. Let me know if it's worth opening a new issue with NuGet for the different NuGet.MSBuildSdkResolver.dll dependencies.

TL;DR: The NuGet.MSBuildSdkResolver.dll specific to the host platform and not the project type needs to be loaded.

rainersigwald commented 6 years ago

That's super interesting, thanks for the details!

@jeffkl is probably also interested (but on vacation)