msbuild: GAC Resolution fallback introduces unexpected bugs - should be an error instead of a warning
So this one could be fun, because I immediately realize it’s going to break some people if implemented. I’m here to argue that’s a good thing. This was brought up by an issue we hit while upgrading to .Net 4.6. But, it’s far from the first time I’ve been bitten by it.
MSBuild currently falls back to the framework assemblies in the GAC if the targeted framework reference assemblies are not on the machine. You get a warning like this:
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.Common.targets(983, 5): warning MSB3644: The reference assemblies for framework “.NETFramework,Version=v4.5.2” were not found. To resolve this, install the SDK or Targeting Pack for this framework version or retarget your application to a version of the framework for which you have the SDK or Targeting Pack installed. Note that assemblies will be resolved from the Global Assembly Cache (GAC) and will be used in place of reference assemblies. Therefore your assembly may not be correctly targeted for the framework you intend.
That’s a warning, not an error - the build continues. I’m arguing this should break the build, not produce downstream unexpected results.
Here’s the relevant code where the MSBuild decision of “can’t find the target? let’s use the GAC instead”, in GetPaths() is made. The GAC fallback seems explicitly intentional, as described here - but I think that’s bad behavior, especially with the framework core libraries.
The comment in code notes this:
// No reference assembly paths could be found, log a warning as there could be future errors which may be confusing because of this.
An example is the one we hit, there Array.Empty<T> was used in a Roslyn compiler optimization. Roslyn acted correctly here because it was passed a set of .Net 4.6 assemblies (via the GAC path) on our build server - even though MSBuild was told we were targeting Net 4.5.2. The “helpful” fallback really wasn’t - it led to downstream runtime breaks.
Semi-related: .Net 4.5.2 is curiously absent from MSBuild altogether: it doesn’t have the paths for .Net 4.5.2 cached, and I noticed 4.5.2 isn’t in the TargetDotNetFrameworkVersion enum either. I assume that’s because it has no compile-time relevance between 4.5.1 and 4.6, but I thought I would note it here for completeness sake.
In my experience (granted, I may have a slanted view), this fallback behavior usually results in a forward fallback, to a newer version of the framework than reference assemblies are installed for and targeting specified. This brings in assumptions of framework features for compilers and tools to make use of that won’t be present at runtime.
If anything, assumptions should be made to older versions of the framework than targeted, since those would be far more likely to be successful. But, I don’t think MSBuild should do that either. I think it should break the build, with a helpful error message saying where to get and install the reference assemblies. MSBuild already knows where it tried to find the assembly path for that framework moniker, it should relay this information to the user. Note: the existing error message doesn’t provide this info either.
What happens today is a range of not loading to slightly different behavior to runtime errors to just crashing the application. That’s much worse (in my opinion) than breaking the build and telling the user how to fix it.
From another view: MSBuild isn’t compiling what I asked it to. It’s subbing in assemblies and causing problems down the line, possibly in the hands of customers.
So here it is: How about we make failure to find the targeted framework reference assemblies break the build instead of just a warning and silently not compiling what was asked for?
About this issue
- Original URL
- State: closed
- Created 9 years ago
- Reactions: 5
- Comments: 20 (10 by maintainers)
Commits related to this issue
- Promote Framework not found (MSB3644) warning to error When the targeted .NET framework reference assembly folder is not found, an error (rather than warning) will be generated. This will prevent prod... — committed to AndyGerlicher/msbuild by AndyGerlicher 8 years ago
- Promote Framework not found (MSB3644) warning to error When the targeted .NET framework reference assembly folder is not found, an error (rather than warning) will be generated. This will prevent prod... — committed to AndyGerlicher/msbuild by AndyGerlicher 8 years ago
- Promote Framework not found (MSB3644) warning to error When the targeted .NET framework reference assembly folder is not found, an error (rather than warning) will be generated. This will prevent prod... — committed to AndyGerlicher/msbuild by AndyGerlicher 8 years ago
- Promote Framework not found (MSB3644) warning to error When the targeted .NET framework reference assembly folder is not found, an error (rather than warning) will be generated. This will prevent prod... — committed to AndyGerlicher/msbuild by AndyGerlicher 8 years ago
- Remove escape-hatch for NoReferenceAssemblyDirectoryFound When this message was converted to a warning (for #173), we added an escape-hatch environment variable to revert to the previous warning-only... — committed to rainersigwald/msbuild by rainersigwald 8 years ago
- Remove escape-hatch for NoReferenceAssemblyDirectoryFound When this message was converted to a warning (for #173), we added an escape-hatch environment variable to revert to the previous warning-only... — committed to rainersigwald/msbuild by rainersigwald 8 years ago
- Remove escape-hatch for NoReferenceAssemblyDirectoryFound (#1367) When this message was converted to a warning (for #173), we added an escape-hatch environment variable to revert to the previous warn... — committed to dotnet/msbuild by rainersigwald 8 years ago
- Update dependencies from https://github.com/dotnet/toolset build 20191206.5 (#173) - Microsoft.Dotnet.Toolset.Internal - 3.1.200-preview.19606.5 — committed to radical/msbuild by dotnet-maestro[bot] 5 years ago
We got this mentioned in the release notes for Update 2 RC: https://blogs.msdn.microsoft.com/visualstudio/2016/03/03/visual-studio-2015-update-2-rc/ (good call, @akoeplinger)
People following this bug might also be interested to know that there is now a standalone Build Tools Update 2 RC package (#480) that can be downloaded from http://go.microsoft.com/fwlink/?LinkId=518023. After Update 2 officially releases, you’ll be able to install the equivalent package on build servers to pick up this change.
I have a PR out for this now and we’re testing internally. Unless there’s an unforeseen consequence this will most likely ship in Update 2. Thank you everyone for the input on this, it definitely helped us make this decision.
@rainersigwald there’s no mention of it in the release notes: https://blogs.msdn.microsoft.com/visualstudio/2016/02/10/visual-studio-2015-update-2-ctp/
I think the change deserves a special call out given the impact it’ll likely have.
+1, this is spot on and is going to hit a lot of people on their build servers. Nonetheless this is the right thing to do, the current behavior is horrible and should result in an error. Having it in Update 2 would be best if at all possible.
The error should print a clear explanation of what is going on and how to fix it, preferably with a link to the reference assemblies package that needs to be installed so developers don’t need to hunt for the right package (and maybe add a
MSBUILD_I_KNOW_THIS_IS_TERRIBLE_BUT_PLEASE_IGNORE_THE_ERROR=1env variable to temporarily revert to the old behavior if you’re too concerned about blocking people).I completely agree with @NickCraver, this needs to ship ASAP (maybe even out of band hotfix) and be in Update 2 and it should BREAK people. If it breaks as part of the build its 1000000 times better than it breaking at runtime on a customers machine…
When you say the next Visual Studio release, does that correspond to a build tools release? A developer with Visual Studio is far more likely to have the reference assemblies than a build server does, so I’d say a great number of people affected by option 3 may not see anything until it hits a build server.
When the Roslyn optimizations are hit by building on a 4.6+ server without the 4.5 reference assemblies, the affected users are every consumer on 4.5 that tries to run a method missing the type the optimization thinks is there (
Array.Empty<T>). This happens in things likemyStringBuilder.AppendFormat("test"), which has an emptyparamson the end.I think this should definitely be in Update 2 and it should break people. I wish we broke instead of hitting this and I’d be a very appreciative developer if the break was there. By not fixing this as soon as possible the message is that releasing new framework releases and compilers that break people is fine out of band, but fixes aren’t. I know that’s not the intent and we want to see the best solution, but that is the reality of a delay. This fix should go out ASAP, it’s biting more and more people upgrading to .Net 4.6 every day.