Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wrong VisualStudioVersion set by Microsoft.Common.props #52

Closed
ctaggart opened this issue Mar 30, 2015 · 3 comments
Closed

wrong VisualStudioVersion set by Microsoft.Common.props #52

ctaggart opened this issue Mar 30, 2015 · 3 comments
Labels

Comments

@ctaggart
Copy link

The VisualStudioVersion property is correct without Microsoft.Common.props, but with that props file, the property ends up being 10.0 for ToolsVersion 12.0 and 14.0.

I am using Microsoft.Build.Evaluation.Project to load the project files with the constructor to pass in the global properties. Loaded from assembly: C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\Microsoft.Build\v4.0_4.0.0.0__b03f5f7f11d50a3a\Microsoft.Build.dll

The VisualStudioVersion appears to depend on two things:

  1. the ToolsVersion in the project file

  2. the Microsoft.Common.props if it exists

  3. no ToolsVersion and no common.props has no VisualStudioVersion

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
</Project>
PS C:\Projects\SourceLink1> Fsi.exe .\vsversion.fsx
MSBuildToolsVersion 2.0
  1. ToolsVersion 4.0 ends up with VisualStudioVersion 11.0
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
</Project>
MSBuildToolsVersion 4.0
VisualStudioVersion 11.0
  1. ToolsVersion 12.0 ends up with VisualStudioVersion 12.0
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
</Project>
MSBuildToolsVersion 12.0
VisualStudioVersion 12.0
  1. ToolsVersion 14 ends up with VisualStudio 14.0
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
</Project>
MSBuildToolsVersion 14.0
VisualStudioVersion 14.0
    1. no ToolsVersion and with common.props has no VisualStudioVersion
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="C:\Projects\msbuild\src\XMakeTasks\Microsoft.Common.props" />
</Project>
MSBuildToolsVersion 2.0
  1. ToolsVersion 4.0 ends up with VisualStudioVersion 11.0
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="C:\Projects\msbuild\src\XMakeTasks\Microsoft.Common.props" />
</Project>
MSBuildToolsVersion 11.0
  1. ToolsVersion 12.0 ends up with VisualStudioVersion 10.0
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="C:\Projects\msbuild\src\XMakeTasks\Microsoft.Common.props" />
</Project>
MSBuildToolsVersion 10.0
  1. ToolsVersion 14.0 ends up with VisualStudioVersion 10.0
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="C:\Projects\msbuild\src\XMakeTasks\Microsoft.Common.props" />
</Project>
MSBuildToolsVersion 10.0

I consider 7 & 8 to be bugs. I think this is the cause:
https://github.com/Microsoft/msbuild/blob/master/src/XMakeTasks/Microsoft.Common.props#L38

More info: ctaggart/SourceLink#50 (comment)

@sarajoiner
Copy link
Contributor

This is "by design" because you're using the .NET 4.X version of the MSBuild engine, which does not officially support VS 2013+ projects. Per the comment in Microsoft.Common.props above the line you flagged:

<PropertyGroup Condition="'$(MSBuildAssemblyVersion)' == '' and ('$(VisualStudioVersion)' != '' and '$(VisualStudioVersion)' &gt;= '12.0')"> 
    <!--
        Reset VisualStudioVersion if it's 12.0+: Should be 10.0 if VS 2010 is installed or 11.0 
        otherwise, but since we don't have a good way of telling whether VS 2010 is installed, 
        make it 11.0 if  VS 2012 is installed or 10.0 otherwise.  The reset should be safe 
        because if it was already set to something (e.g. 11.0 in a VS 2012 command prompt) 
        then MSBuild's internal VisualStudioVersion-defaulting code should never come into 
        the picture, so the only way it could  be 12.0+ when building a TV 12.0 project 
        (because we're in this file) using MSBuild 4.5 (because MSBuildAssemblyVersion 
        hasn't been set) is if it's a TV 12.0 project on an empty command prompt. 
    -->

If you update your tool to instead use the VS 2013 or VS 2015 (or OSS :) ) version of MSBuild, you should no longer see the behavior difference caused by the common props. (Although as explained below, you will also default to always using the "current" ToolsVersion instead of reading it from the project file.)

Historical background for the curious:

In VS 2013, we updated ToolsVersion for the first time since Visual Studio started making asset compatibility guarantees (VS 2010 SP1). At that point, we had to figure out what it meant for, e.g., MSBuild N to build a compatible project from VS N+1, and the above code is part of the answer we came to. Specifically, the answer to the question of "what happens when VS 2012 (MSBuild 4.X) attempts to build a VS 2013 (MSBuild 12) project?".

Until VS 2013, we'd simply read the "ToolsVersion" tag in the project and used it. That worked in the world pre-VS 2010 SP1, where Visual Studio forced an update to the ToolsVersion every release and only supported loading projects with that ToolsVersion -- if something was ToolsVersion 3.5, you could depend on the fact that it only worked with, and was only expected to work with, VS 2008. And if someone tried to build a ToolsVersion 3.5 project on a machine without VS 2008 / .NET 3.5 installed ... well, that was their problem.

(Side note: we're speaking specifically of build process components, not the core engine, here. All later versions should be capable of building projects from all earlier versions of MSBuild, with the appropriate build process, as long as that build process is installed.)

It also worked in the world of VS 2010 SP1 / VS 2012, because due to MSBuild being an in-place update from 4.0 -> 4.5, the ToolsVersion didn't change -- all tool differentiation was done at the sub-toolset level (as directed by VisualStudioVersion).

However, in VS 2013, with ToolsVersion 12.0, and with the expectation that the following release would update ToolsVersion yet again, we had to answer the question, "What is the appropriate behavior for a ToolsVersion 14.0 project loaded in VS 2013?"

We couldn't just say "Use the 14.0 build process", because (a) there's no guarantee that VS 2015 would even be on the machine, (b) since VS 2013 is built against MSBuild 12, if there was any new MSBuild syntax introduced in VS 2015, there was a non-trivial chance that MSBuild 12 wouldn't even be able load or build the project, and (c) even if MSBuild could, if there were sufficiently large functional differences in the build process for a particular project type between VS 2013 and 2015, all the VS support infrastructure (project systems, designers, etc.) might behave in strange/unexpected ways.

So the answer we came to was that we'd make MSBuild ignore the "ToolsVersion" tag in project file by default, and always use the "current" ToolsVersion. Thus, in the above example, even though the project file said 'ToolsVersion="14.0"', VS 2013 (MSBuild 12) would build the project as though it were a ToolsVersion="12.0" project. All tools would be known to exist, all behavior would be as expected.

Cool. That solved VS 2013 and all future versions of VS.

However, the asset compatibility guarantee wasn't just "VS 2013 and up", it included VS 2010 SP1 and VS 2012, which were based on MSBuild 4.0 and 4.5 respectively.

In MSBuild 4.0, we'd added some much simpler defaulting logic: If MSBuild didn't recognize the ToolsVersion in the project file, it would default to the current version ("4.0"). So as long as someone loaded a 12.0 or higher project on a machine with ONLY VS 2010 and/or VS 2012 installed, we were also fine.

But if someone, say, attempted to load a ToolsVersion 12.0 project in VS 2010 SP1 on a machine with both that and VS 2013 installed, MSBuild 4.X (probably technically 4.5.1 since that's what comes with 2013) would happily load the project up as a ToolsVersion 12.0 project ... right until the point where it ran into a construct it didn't recognize, at which point it would log some likely-unhelpful error and exit.

We couldn't do anything about the fact that MSBuild 4.X would attempt to load the project as a ToolsVersion 12.0 project. (At least not without changing MSBuild 4.X, which would have been ... logistically difficult.) What we could do, however, was make that ToolsVersion 12.0 project "look like" a ToolsVersion 4.X project as much as possible. To do this, we added a new built-in property, MSBuildAssemblyVersion, that we could then key off of in the targets: if it existed, we were 12+, business as usual. If it didn't exist, we were 4.X trying to build a 12+ project, and tweaking was required.

Thus the above code in Microsoft.Common.props, to reset VisualStudioVersion to one of the allowed 4.X values: 10.0 or 11.0.

Thus also the redirection code e.g. here: https://github.com/Microsoft/msbuild/blob/master/src/XMakeTasks/Microsoft.Common.targets#L32 to make sure that, when a project imported "$(MSBuildToolsPath)\Microsoft.Common.targets", it would get the 4.X one, instead of the 12+ one.

This wasn't a 100% complete solution:

  • ToolsVersion still reported the original value
  • If the project file itself made use of MSBuild 12+ constructs, there was nothing we could do to keep MSBuild 4.X from breaking. (Though in that case, the authors of that project type ought to have made sure their project templates set a MinimumVisualStudioVersion of 12+, so that the IDE's "this project is not compatible" logic would take over.)

But we found that in practice, most of the time it was "good enough".

briansmith added a commit to briansmith/ring that referenced this issue Aug 1, 2015
* Silence some warnings about things that MSVC 2015 warns about that
  MSVC 2013 didn't.

* Change the solution so that it opens in Visual Studio 2015 if Visual
  Studio 2015 is installed.

* Change ToolsVersion to 14.0 in the project files so that Visual
  Studio 2015 does not put a warning in the build log about the version
  being 12.0. This means that Visual Studio 2013 will have a warning,
  but the warning is harmless, and if we have to choose, it's better
  for VS 2013 to warn than VS 2015 to warn, in the long term. See
  dotnet/msbuild#52 (comment).

* Build with the VS 2013 XP-compatible toolchain if using Visual Studio
  2013 (including its msbuild); Otherwise build with the Visual Studio
  2015 XP-compatible toolchain. See
  https://social.msdn.microsoft.com/Forums/vstudio/en-US/ \
    d06c3741-c637-4627-9b1a-1e068803a067/ \
    setting-platformtoolset-value-based-on-vs-version.
briansmith added a commit to briansmith/ring that referenced this issue Aug 27, 2015
* Silence some warnings about things that MSVC 2015 warns about that
  MSVC 2013 didn't.

* Change the solution so that it opens in Visual Studio 2015 if Visual
  Studio 2015 is installed.

* Change ToolsVersion to 14.0 in the project files so that Visual
  Studio 2015 does not put a warning in the build log about the version
  being 12.0. This means that Visual Studio 2013 will have a warning,
  but the warning is harmless, and if we have to choose, it's better
  for VS 2013 to warn than VS 2015 to warn, in the long term. See
  dotnet/msbuild#52 (comment).

* Build with the VS 2013 XP-compatible toolchain if using Visual Studio
  2013 (including its msbuild); Otherwise build with the Visual Studio
  2015 XP-compatible toolchain. See
  https://social.msdn.microsoft.com/Forums/vstudio/en-US/ \
    d06c3741-c637-4627-9b1a-1e068803a067/ \
    setting-platformtoolset-value-based-on-vs-version.
kalypto-ashish added a commit to kalyptorisk/svnquery that referenced this issue Dec 26, 2015
remove the dependency on MSBuild from .NET 4 as it will give wrong results
for VS2013 onwards, as per dotnet/msbuild#52
@1TheMuffinMan
Copy link

Since the VisualStudioVersion resolves to 10 instead of 14 when I create an asp.net core project with the web api template the build is looking for VisualStudio\v10.0\DotNet\Microsoft.DotNet.Props, but that file lives under the v14.0 folder.

@soerennielsen
Copy link

oh man, my head hurts. What a mess, but thank you for the explanation.

kkm000 pushed a commit to kkm000/CodeContracts.MSBuild that referenced this issue Dec 9, 2017
1. MSBuild tools version is generally does not correlate with the Visual
   Studio or SDK version, and the changes between different versions of
   scripts under Contracts/MsBuild/ were inconsequential anyway. We now
   use a common set of build files for all MSBuild versions 4.0 and above.

   See dotnet/msbuild#52 (comment)
   for the elaboration on the versioning conventions.

2. Generated contract assemblies are included into the project's output
   group (BuiltProjectOutputGroupOutput), and therefore picked up by
   the Pack target to be included into the package.
kkm000 pushed a commit to kkm000/CodeContracts.MSBuild that referenced this issue Dec 21, 2017
MSBuild tools version is generally does not correlate with the Visual
Studio or SDK version, and the changes between different versions of
scripts under Contracts/MsBuild/ were inconsequential anyway. We now
use a common set of build files for all MSBuild versions 4.0 and above.

See dotnet/msbuild#52 (comment)
for the elaboration on the versioning conventions.
kkm000 pushed a commit to kkm000/CodeContracts.MSBuild that referenced this issue Dec 21, 2017
1. MSBuild tools version is generally does not correlate with the Visual
   Studio or SDK version, and the changes between different versions of
   scripts under Contracts/MsBuild/ were inconsequential anyway. We now
   use a common set of build files for all MSBuild versions 4.0 and above.

   See dotnet/msbuild#52 (comment)
   for the elaboration on the versioning conventions.

2. Generated contract assemblies are included into the project's output
   group (BuiltProjectOutputGroupOutput), and therefore picked up by
   the Pack target to be included into the package.
radical added a commit to radical/msbuild that referenced this issue May 1, 2018
Merge upstream master branch and update SDKs accordingly
@AR-May AR-May added the triaged label Feb 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants