使用 MSBuild 时强制项目始终使用 VS2012/VC11 构建

Force project to always build using VS2012/VC11 when using MSBuild

注意:这与众所周知的 VS2010/VS2012问题有关,在某些情况下,必须指定/p:VisualStudioVersion=11.0 使用 MSBuild 构建 C++/CLI 应用程序时。

问题:当使用引用 C++/CLI 项目文件的 MSBuild 任务构建我的 VS2012 C++/CLI 应用程序时,我需要将 /p:VisualStudioVersion=11.0 添加到 MSBuild 命令行,否则我会收到此错误:

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

只有在同时安装了 VS2010 和 VS2012 的机器上构建时,甚至从 Developer Command Prompt for VS2012 或我自己调用 %VS110COMNTOOLS%\vsvars32.bat 之后才会出现。

显然我已经知道解决方法,但我想摆脱指定始终使用相同的附加命令行参数的要求

一些细节:我有一个 .proj 文件,它设置了用于构建 C++/CLI 应用程序的 MSBuild 任务。这是它的核心(我们称之为 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>

以上内容并不完整,仅供参考。问题是如上所述为 MSBuild 任务设置 属性 VisualStudioVersion 没有帮助。我仍然收到相同的 MSB8008 错误。除非......是的,使用 MSBuild Foo.proj /p:VisualStudioVersion=11.0.

是否有可能以某种方式解决这个问题 - 我在这里遗漏了什么吗?如果我知道怎么做(我已经尝试过),我什至可以自己编辑单个 .vcxproj 文件。

取决于您要修复它的级别。

在 Microsoft.Cpp.Platform.targets 中有一个您可以使用的导入语句:

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

从特定平台相关的 ImportAfter 文件夹导入所有 *.targets 文件。您可以定义最简单的文件,在全局级别设置任何属性(对于所有 .vcpproj 文件)

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

或者您可以使用从 Microsoft.Cpp.Current.targets

导入

<Import Condition=" '$(ForceImportAfterCppTargets)' != '' and exists('$(ForceImportAfterCppTargets)')" Project="$(ForceImportAfterCppTargets)"/> 只需声明 $(ForceImportAfterCppTargets) 属性 指向一个特定文件,该文件将为每个平台覆盖它。

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

或者你可以创建相应的环境变量 - MSBuild emits Properties from Environment variables

希望这对您有所帮助。

PS:如果您可以使用 /verbosity:diag 生成 msbuild 日志,这可能对您和我们有很大帮助 - 更容易查看完整且非常详细的日志。两组日志 - 一组成功构建结果,一组失败将提供更多帮助

您可以通过将以下标记添加到 属性 组来在项目文件中指定特定的工具集:

<PlatformToolset>v110</PlatformToolset>

你根本不需要任何外部参数。

那么,开始吧。下面是 actual 最小复制案例 - 我的问题中的那个确实有效。我想我是在这么多不同的小改动之间来回切换,以至于我最终没有真正测试确切的代码就发布了。抱歉。

罪魁祸首假设 VisualStudioVersion 最初没有设置,除非我自己设置 - 至少在构建过程的早期没有设置。对我来说,MSBuild 依赖于 Visual Studio 是非常不直观的,而不仅仅是相反。

<?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>

但对我没有用的是直接在 .vcxproj 文件中设置 VisualStudioVersionPlatformToolset(是的,这次是无条件的)——这在构建过程中似乎为时已晚,至少在以这种特殊方式构建时。

另一件让我感到困惑的事情是,即使 明确地 为 VS2012 设置构建环境,VisualStudioVersion 属性 默认为 VS2010。

感谢那些回复的人。真正促使我找出问题的是对我最初关于使用 <AdditionalProperties> 的问题的评论。我试过了 'accidentally' 硬编码 11.0 而不是使用 $(VisualStudioVersion) - 这导致我通过无条件设置 VisualStudioVersion:[=20= 使其适用于我的其他情况]

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

因此,如果评论者将他的建议作为回复而不是评论发布,我将奖励他。否则我只会让自动奖励发生。

VS2012 与 VS2010 组合的问题,这里有详细描述: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.

post 在此处有一个 link 到另一个 post:MSBuild: Properties and AdditionalProperties Known Metadata。本文对此进行了解释:

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.

因此,一种解决方案是使用 AdditionalProperties 元数据,允许在 msbuild 过程后期定义属性,如下所示:

<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>