Msbuild: Version Update for Visual Studio "16"

Created on 20 Sep 2018  Â·  18Comments  Â·  Source: dotnet/msbuild

We need to address versioning concerns with the next major Visual Studio version ("16", currently our master branch). This proposal outlines our current thinking on what to do to minimize impact to customers and partner teams. Unfortunetely since VisualStudioVersion is revving, even doing nothing will be breaking.

Proposal

  • File Version: 16.0.32.32432… 16.1.56.3455... etc. [Completed. Not breaking]

    • This has already been updated. Should be no negative impact to customers.

  • Assembly Version: 15.1.0.0 [Completed. No change from Dev15]

    • This will not rev to avoid customer binding redirect impact.

    • Updating this would have very little positive impact other than to look better.

  • VisualStudioVersion: 15.0 -> 16.0 [Potential Impact]

    • Potential impact, but needs to change to keep in sync with the environment variable set by VS.

  • ToolsVersion: 15.0 -> Current [Potential Impact]

    • Changing to 16.0 is a potential break for customer content, so we will have to add "fallback" logic (see below).
    • Leaving at 15.0 breaks some user imports that may use ToolsVersion where VisualStudioVersion would have been a better choice.
    • Changing to Current breaks the cycle of having to change on every release.
  • Install Location: <VSRoot>\MSBuild\Current\Bin\MSBuild.exe [Definite Impact]

    • Remaining at 15.0 is already impacting teams internally and will break assumptions.
    • Changing to 16.0 will impact partner teams (i.e. NuGet).
    • Changing to Current is better than hard coding a new numeric value that will change next release.
    • Adding Current to the install path retains relative paths used by MSBuild and others.

Required Actions:

  • [x] Update MSBuild to use Current
  • [ ] Update MSBuild fallback logic to reduce breaking change impact.
  • [ ] Update vswhere example (from 15.0 hard coded to Current).
  • [x] Update MSBuildLocator
  • [x] Inform partner teams of the change

Fallback Logic

Customer may be importing $(MSBuildExtensionsPath)\$(ToolsVersion). To not cause a breaking change, we will add fallback so that ToolsVerison will resolve to $(MSBuildExtensionsPath)Current or $(MSBuildExtensionsPath)15.0. We have an existing mechanism to support this.

Customer Changes

Finding MSBuild (Install Location Change)
Anyone who wants to find MSBuild will need to update. For example:
https://github.com/Microsoft/vswhere#example

Most examples hard code 15.0. This proposal would require them to update to Current to continue to work.

Known examples that hard-code the path:

  • NuGet
  • MSBuildLocator (owned by MSBuild team and recommended to find MSBuild)

Installing Targets / Extensions
Anyone who is dropping files into \ … \ $(VS_Major_Version) and importing them as $(ToolsVersion) will continue to work (see fallback), but they should update to use either VisualStudioVersion, Current, or drop the versioning entirely for instanced components (preferred).

Most helpful comment

Hopefully this is the right thread.
I just installed Visual Studio 2019 preview, and I'm now facing issues with my build scripts (using cake build). I get the following error:

MSBUILD : error MSB1040: ToolsVersion is not valid. The tools version "15.0" is unrecognized. Available tools versions are "Current".
Switch: 15.0

And this is how I configure the MSBuildSettings in the script:

new DotNetCoreMSBuildSettings
    {
        ToolVersion = MSBuildVersion.MSBuild15
    }

I would like to report the error and, if possible, get indications to fix it (I already tried uninstalling the preview, without success).
The only workaround at the moment is to remove the fixed ToolVersion (leaving it null), but that's not an ideal solution (I always prefer to "pin" versions to be sure that builds run in a predictable way).

All 18 comments

I have a PR out now for the first round of changes (#3779).

@jaredpar the Roslyn setup will need to be updated at the same time since it installs to 15.0\... and needs to be changed to Current\....

@rrelyea I assume this will also impact NuGet locating MSBuild?

@rohit21agrawal - can you please dig into our dev branch for the issue Andy raises?

The NuGet side work is tracked here.
https://github.com/NuGet/Home/issues/7325

It should only be NuGet.exe that's impacted.

//cc @rainersigwald

Not that it is up to me, but can somebody please explain why the assembly version is not updated to Version 16?

ToolsVersion: 15.0 -> Current [Potential Impact]

  • Changing to Current breaks the cycle of having to change on every release.

This is going to break folks who expect MSBuildToolsVersion to be numerical version. I don't believe we've ever publicly shipped a value for this that wasn't a numerical version. Are you sure you want to do this?

Have a look at this github search to get an idea of how many people you're likely to break:
https://github.com/search?l=XML&q=MSBuildToolsVersion&type=Code

@MeikTranel because every time that VS version revs, we end up having to make a non-trivial amount of changes in order to react to that. With the move to current, this then becomes a noop for us.

@ericstj at this point, the change is in and lots of teams have actually spent time reacting to it already. It would not be easy to pull out at this point.

at this point, the change is in and lots of teams have actually spent time reacting to it already. It would not be easy to pull out at this point.

Seems like the sunk cost fallacy. I'm probably missing the benefit of this breaking change. It seems to me that we're just trying to hack something that was originally designed to be side-by-side to no longer be side-by-side.

@livarcocc Oh i'm not specifically mad about about the ToolsVersion. I just think it's messed up that the AssemblyVersion is not being moved up to 16? 15->Current is fine in my books... but 15.1 to 15.1 while the FileVersion as the overall version of the release moves to 16 is gonna wreak havoc for everybody trying to wrap their head around MSBuild Versions.

Changing the AssemblyVersion has undesirable downstream effects:

  • All consumers must update their binding redirects to point to the new version.
  • It becomes difficult or impossible to write an application that uses the MSBuild API that is compatible with either Visual Studio 2017 and Visual Studio 2019, depending on which is installed on the users machine.

I agree that it's unfortunate to leave the version at 15.1.0.0 forever. Ideally it'd rev in a more-understandable way. But since we already have to leave it alone for a full VS release cycle (we can't break binary compatibility in for example the 16.2 update), users must already reason about versions using FileVersion (or, inside the MSBuild language, $(MSBuildVersion) and friends).

On balance, we think leaving the AssemblyVersion fixed has the best tradeoff.

@ericstj like I mentioned above, this prevents us from having to do a bunch of work across many different teams every time that Visual Studio revs their main version. In many cases, it is a re-discover what we missed in the form of bug reports and things that are not working. With this change, we will have to do it only one.

@livarcocc could you have gotten folks to stop using this property to mean "side-by-side" since you now have VS controlling that for you? It seems to me an equally good fix that would be less breaking would be to ask teams to stop using MSBuildToolsVersion rather than to replace it with a meaningless value.

No, because many of the uses of the property have been baked into user projects via templates.

It's a hard requirement that this (from a template class library) continue to work:

  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />

I see, that's a bummer. I still think you need to evaluate the scope of the break of changing this from a numeric version to a string value. If I look above it looks to me like you only considered the break that results from changing from 15.0 -> something else. Perhaps you could special case the comparsion that uses MSBuildToolsVersion so that it could still be treated as a version, but keep the property expansion to treat it as the string "current".

Hopefully this is the right thread.
I just installed Visual Studio 2019 preview, and I'm now facing issues with my build scripts (using cake build). I get the following error:

MSBUILD : error MSB1040: ToolsVersion is not valid. The tools version "15.0" is unrecognized. Available tools versions are "Current".
Switch: 15.0

And this is how I configure the MSBuildSettings in the script:

new DotNetCoreMSBuildSettings
    {
        ToolVersion = MSBuildVersion.MSBuild15
    }

I would like to report the error and, if possible, get indications to fix it (I already tried uninstalling the preview, without success).
The only workaround at the moment is to remove the fixed ToolVersion (leaving it null), but that's not an ideal solution (I always prefer to "pin" versions to be sure that builds run in a predictable way).

Can we get a response to @ericstj's comment -

Perhaps you could special case the comparsion that uses MSBuildToolsVersion so that it could still be treated as a version, but keep the property expansion to treat it as the string "current".

Currently you guys only seem to be considering adding fallback logic when using MSBuildToolsVersion in a path, but there is also the breaking change when making version comparisons. The current stable version of WiX (v3.11.1) compares MSBuildToolsVersion to 4.0 to figure out which targets file to use. In VS2019 Preview 2, when you open a project created with that version of WiX it fails to load with

A numeric comparison was attempted on "$(MSBuildToolsVersion)" that evaluates to "Current" instead of a number, in condition " '$(MSBuildToolsVersion)' == '' OR '$(MSBuildToolsVersion)' < '4.0' ".

It would also fail to build from the command line with the same error. I would be surprised if WiX is the only one that would be blocked by this issue.

To mitigate this breaking change, I would expect MSBuild not to throw an error when trying to make a version comparison using the MSBuildToolsVersion property. It would be annoying, but you could probably just use 15.0 in these comparisons if you don't want to make it return the current version.

The discussion above mentions MSBuildExtensionsPath but it doesn't mention MSBuildUserExtensionsPath. This change looks like it will break the per-user extension mechanism.

MSBuildUserExtensionsPath is in the form C:\Users\[user id]\appdata\local\Microsoft\msbuild so it is shared by all instances of MSBuild on the machine. Changing MSBuildToolsVersion to Current will break existing extensions, and it will also break the ability for per-user extension targets to be versioned by folder.

e.g. ImportUserLocationsByWildcardBeforeMicrosoftCommonTargets from Microsoft.Common.CurrentVersion.targets:

<Import Project="$(MSBuildUserExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.targets\ImportAfter\*" Condition="'$(ImportUserLocationsByWildcardAfterMicrosoftCommonTargets)' == 'true' and exists('$(MSBuildUserExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.targets\ImportAfter')"/>

Per-user extension targets are important to third-party extensions as they allow targets to be injected into the build without requiring elevation (e.g. the _Sonar Scanner for MSBuild_ that provides build integration with _SonarQube/SonarCloud_);

Could this breaking change be avoided by changing the per-user location to use a different build variable (e.g. either VisualStudioVersion or a new variable)?

Hopefully this is the right thread.
I just installed Visual Studio 2019 preview, and I'm now facing issues with my build scripts (using cake build). I get the following error:

MSBUILD : error MSB1040: ToolsVersion is not valid. The tools version "15.0" is unrecognized. Available tools versions are "Current".
Switch: 15.0

And this is how I configure the MSBuildSettings in the script:

new DotNetCoreMSBuildSettings
    {
        ToolVersion = MSBuildVersion.MSBuild15
    }

I would like to report the error and, if possible, get indications to fix it (I already tried uninstalling the preview, without success).
The only workaround at the moment is to remove the fixed ToolVersion (leaving it null), but that's not an ideal solution (I always prefer to "pin" versions to be sure that builds run in a predictable way).

You're kind of in the right place. But your issue is more with Cake-Build's way of defaulting in their base task library.
You should raise an issue over at https://github.com/cake-build/cake
As for immediate help. Cake offers property override methods for all dotnet/msbuild tasks, so you are definitely able to just pass /p:ToolsVersion="15.0" from outside which effectively does the same thing.
Use this API:https://cakebuild.net/api/Cake.Common.Tools.DotNetCore.MSBuild/DotNetCoreMSBuildSettingsExtensions/FE731751

I split out two bugs to consider before 16.0 RTM:

  • #4150 -- version/numeric comparisons around MSBuildToolsVersion
  • #4149 -- MSBuildUserExtensionsPath

If you're interested, please give feedback on those ASAP, as the bar for changes in 16.0 is getting higher and higher.

Closing this item (the big change) as completed.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ghost picture ghost  Â·  4Comments

hubuk picture hubuk  Â·  3Comments

ctolkien picture ctolkien  Â·  4Comments

eduardobr picture eduardobr  Â·  3Comments

rainersigwald picture rainersigwald  Â·  3Comments