1

Note: This is related to the well known VS2010/VS2012 problem of, under certain circumstances, having to specify /p:VisualStudioVersion=11.0 when using MSBuild to build C++/CLI applications.

Problem: When building my VS2012 C++/CLI application using the MSBuild task referring to a C++/CLI project file I need to add /p:VisualStudioVersion=11.0 to the MSBuild command line, otherwise I get this error:

error MSB8008: Specified platform toolset (v110) is not installed or invalid. Please make sure that a supported PlatformToolset value is selected.

This only shows up when building on machines with both VS2010 and VS2012 installed, and even from a Developer Command Prompt for VS2012 or after calling %VS110COMNTOOLS%\vsvars32.bat myself.

Obviously I know the workaround already, but I would like to get rid of the requirement of specifiying the same additional command-line argument all the time.

Some details: I have a .proj file that sets up the MSBuild task for building the C++/CLI application. Here's the meat of it (let's call it Foo.proj):

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <ItemGroup>

    <CxxProjects
      Include="$(MSBuildThisFileDirectory)src\**\*.vcxproj"
    />

  </ItemGroup>

  <Target Name="build">
    <MSBuild Projects="@(CxxProjects)
             Properties="VisualStudioVersion=11.0"/>
  </Target>

</Project>

The above is not complete, it's just for illustration. The problem is that setting the property VisualStudioVersion for the MSBuild task as above doesn't help. I still get the same MSB8008 error. Unless ... yeah, using MSBuild Foo.proj /p:VisualStudioVersion=11.0.

Is it possible to fix this somehow - am I missing something here? I could even go for editing the individual .vcxproj files themselves if I only knew how (I have tried already).

rjnilsson
  • 2,343
  • 15
  • 20
  • Are you aware of this: https://blogs.msdn.microsoft.com/webdev/2012/08/21/visual-studio-project-compatibility-and-visualstudioversion/ I suggest you use the AdditionalProperties tricks it links to here: http://sedodream.com/2009/04/29/MSBuildPropertiesAndAdditionalPropertiesKnownMetadata.aspx – Simon Mourier Jul 04 '16 at 20:52
  • I actually read that blog post but never got around to try AdditionalProperties. Need to give it a shot perhaps. – rjnilsson Jul 05 '16 at 05:32
  • @SimonMourier: Post that as a reply and I'll award you the bounty. Read my own answer to the question for a rationale. – rjnilsson Jul 07 '16 at 04:46

4 Answers4

1

Depends on which level you want to fix it.

In Microsoft.Cpp.Platform.targets there is an import statement you can use:

<Import Condition="'$(_ToolsetFound)' == 'true' and Exists('$(_PlatformFolder)ImportAfter')" Project="$(_PlatformFolder)ImportAfter\*.targets"/>

which imports all *.targets files from a specific Platform-dependent ImportAfter folder. You can define the simplest file which sets any Properties on a global level (for all .vcpproj files)

Edit1 This is the content of such file, you can name it any way you want, just ensure it matches the above wildcard *.targets. You has to figure out the correct path for file (find what's the path in $(_PlatformFolder) property

<?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="4.0" DefaultTargets="build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup><VisualStudioVersion>11.0</VisualStudioVersion></PropertyGroup> </Project>

/Edit1

Or you can use this Import from Microsoft.Cpp.Current.targets

<Import Condition=" '$(ForceImportAfterCppTargets)' != '' and exists('$(ForceImportAfterCppTargets)')" Project="$(ForceImportAfterCppTargets)"/> just declare $(ForceImportAfterCppTargets) property which points to a single specific file which will override it for every platform.

Edit2 This approach is better if you want to affect only your build script - you have to do the same (put a file like in edit1) and pass the path to the file via $(ForceImportAfterCppTargets) property. Your build script will have something like this:

<MSBuild Projects="@(CxxProjects) Properties="ForceImportAfterCppTargets=path_to_my_targets"/>

/Edit2

Or you can create corresponding environment variable - MSBuild emits Properties from Environment variables

Hope this helps.

PS: if you can produce a msbuild log with /verbosity:diag that may help you and us a lot - mush easier to see the full and very detailed log. Two sets of logs - one with successful build results and one with failed will help even more

Alexey Shcherbak
  • 3,394
  • 2
  • 27
  • 44
  • Where should I put the above statements, exactly? As for the environment variable I was aware of that, but unfortunately that wasn't was I was looking for. – rjnilsson Jul 04 '16 at 15:54
  • Umm, I need to make a working example to play a bit with the set up. I'm not a VC++ dev so not sure about exact changes. Regarding 1st part - you can make a file let's say MyImportAfter.targets with a specific override (see edit1). Put it in the folder on your machine\build server and it will affect all your builds. literally every one on that machine. – Alexey Shcherbak Jul 06 '16 at 11:59
  • Thanks for your suggestion, however I've found the problem already and will post the solution ASAP. – rjnilsson Jul 06 '16 at 12:17
1

The problem, specific to the VS2012 with VS2010 combination, is described with details here: Visual Studio project compatibility and VisualStudioVersion

If you build a web project from the command line (not the developer prompt) then the value for VisualStudioVersion used will be 10.0. That is an artifact of the properties which I showed above. In this case you should pass this in as an MSBuild property. For example

msbuild.exe MyAwesomeWeb.csproj /p:VisualStudioVersion=11.0

In this case I’m passing in the property explicitly. This will always override any other mechanism to determine the value for VisualStudioVersion. If you are using the MSBuild task in a build script, then you can specify the property either in the Properties attribute or the AdditionalProperties attribute.

The post has a link to another post here: MSBuild: Properties and AdditionalProperties Known Metadata. This article explains this:

The difference is that if you specify properties using the Properties metadata then any properties defined using the Properties attribute on the MSBuild Task will be ignored. In contrast to that if you use the AdditionalProperties metadata then both values will be used, with a preference going to the AdditionalProperties values.

So one solution is to use the AdditionalProperties metadata that allow to define Properties late in the msbuild process, something like this:

<Project ToolsVersion="4.0" DefaultTargets="build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <ItemGroup>
    <CxxProjects Include="$(MSBuildThisFileDirectory)src\**\*.vcxproj">
        <AdditionalProperties>VisualStudioVersion=11.0</AdditionalProperties>
    </CxxProjects>
  </ItemGroup>

  <Target Name="build">
    <MSBuild Projects="@(CxxProjects) />
  </Target>

</Project>
Simon Mourier
  • 132,049
  • 21
  • 248
  • 298
  • As I say in [my own reply](http://stackoverflow.com/a/38237660/81588) my problem was slightly different but your comment triggered me finding the solution. Thanks. – rjnilsson Jul 07 '16 at 07:21
0

You can specify a particular toolset within the project file by adding the following tag to a property group:

<PlatformToolset>v110</PlatformToolset>

You shouldn't need any external parameters at all with this.

eh9
  • 7,340
  • 20
  • 43
  • Sorry, doesn't work. Still the same MSB8008 error. Already tried something similar. – rjnilsson Jul 04 '16 at 15:52
  • Unfortunate. I've got a similar situation with three versions of Visual Studio installed (at the moment) and it's been working fine for me. – eh9 Jul 04 '16 at 15:59
  • Incidentally, I've also got these environment variables defined: VS110COMNTOOLS, VS120COMNTOOLS, VS140COMNTOOLS – eh9 Jul 04 '16 at 16:01
  • Me too, as well as VS100COMNTOOLS. Do you actually have VS2010 installed (I believe that's where the problem is)? – rjnilsson Jul 05 '16 at 09:21
  • Don't have VS2010 installed, sorry. It's conceivable that you've got an old version of MSBuild that's somehow unable to pick up other toolset versions – eh9 Jul 05 '16 at 13:15
  • The problem is specific to VS2010+VS2012 in combination – rjnilsson Jul 07 '16 at 07:22
0

So, here goes. The below is the actual minimal reproduction case - the one in my question actually worked. I guess I was switching back and forth between so many different minor changes that I ended up posting without actually testing that exact code. Sorry for that.

The culprit was assuming that VisualStudioVersion was not set initially unless I did it myself - at least not that early in the build process. For me it's pretty unintuitive that MSBuild depends on Visual Studio, and not only the other way around.

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <PropertyGroup>
    <!--
      The below causes the problem - VisualStudioVersion already
      have a 'default' value of 10.0 at this point and therefore
      is never set to 11.0
    -->
    <VisualStudioVersion Condition="'$(VisualStudioVersion)' != ''">11.0</VisualStudioVersion>
  </PropertyGroup>

  <ItemGroup>

    <CxxProjects
      Include="$(MSBuildThisFileDirectory)src\**\*.vcxproj"
    />

  </ItemGroup>

  <Target Name="build">
    <MSBuild Projects="@(CxxProjects)
             Properties="VisualStudioVersion=$(VisualStudioVersion)"/>
  </Target>

</Project>

What never worked for me though was to set either VisualStudioVersion or PlatformToolset (yes, unconditionally this time) directly in the .vcxproj files - that seems to be too late in the build process, at least when building in this particular way.

Another thing that confused me was that even when explicitly setting up the build environment for VS2012 the VisualStudioVersion property defaults to VS2010.

Thanks to those that replied. What actually triggered me to find out the problems was the comment on my original question about using <AdditionalProperties>. I tried that and 'accidentally' hardcoded 11.0 instead of using $(VisualStudioVersion) - which lead me to get it working for my other cases as well by unconditionally setting VisualStudioVersion:

<PropertyGroup>
  <VisualStudioVersion>11.0</VisualStudioVersion>
</PropertyGroup>

Because of this I'll award the bounty to that commenter if he posts his suggestion as a reply instead of a comment. Otherwise I'll just let automatic awarding take place.

rjnilsson
  • 2,343
  • 15
  • 20