Reputation: 2343
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).
Upvotes: 1
Views: 662
Reputation: 138776
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>
Upvotes: 1
Reputation: 2343
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.
Upvotes: 0
Reputation: 3454
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
Upvotes: 1
Reputation: 7430
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.
Upvotes: 0