问题 在为F#3.1.1使用新的独立安装程序时,如何在CI服务器上使用F#


当我在Visual Studio中创建一个新项目时,它在fsproj文件中包含以下行:

  <Choose>
    <When Condition="'$(VisualStudioVersion)' == '11.0'">
      <PropertyGroup Condition="Exists('$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets')">
        <FSharpTargetsPath>$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets</FSharpTargetsPath>
      </PropertyGroup>
    </When>
    <Otherwise>
      <PropertyGroup Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets')">
        <FSharpTargetsPath>$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets</FSharpTargetsPath>
      </PropertyGroup>
    </Otherwise>
  </Choose>
  <Import Project="$(FSharpTargetsPath)" />

在CI服务器上,由于FSharpTargetsPath仍为空,因此无法构建。 我们使用新的 F#3.1.1的独立安装程序 在CI服务器上并没有安装Visual Studio。 我需要添加什么才能使其工作?


11988
2018-01-23 13:35


起源



答案:


在我看来,choose子句可能实际上是不正确的。我会认为 $(VisualStudioVersion) 如果没有Visual Studio安装,那将是空的。但是,那 $(FSharpTargetPath) 这指向我希望独立目标文件驻留的位置。很明显,将3.1换成3.0。见下文。

  <Choose>
    <When Condition="'$(VisualStudioVersion)' == '11.0'">
      <PropertyGroup Condition="Exists('$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets')">
        <FSharpTargetsPath>$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets</FSharpTargetsPath>
      </PropertyGroup>
    </When>
    <Otherwise>
      <PropertyGroup Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets')">
        <FSharpTargetsPath>$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets</FSharpTargetsPath>
      </PropertyGroup>
      <PropertyGroup Condition="Exists('$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.1\Framework\v4.0\Microsoft.FSharp.Targets')">
        <FSharpTargetsPath>$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.1\Framework\v4.0\Microsoft.FSharp.Targets</FSharpTargetsPath>
      </PropertyGroup>          
    </Otherwise>
  </Choose>

免责声明:


8
2018-01-23 14:07



谢谢!这对我来说是一个很大的帮助。我想在使用FAKE时使用3.0,使用VS 2012使用3.0,使用VS 2013使用3.1,我想我已经使用这些指令进行了整理。 - lefthandedgoat
使用锚定路径 $(MSBuildExtensionsPath32)\.. 到达,得到 C:\ Program Files(x86) 已成为构建的定时炸弹,因为该变量是 C:\ Program Files(x86)\ Microsoft Visual Studio \ 2017 \ BuildTools \ MSBuild 在VS2017中,类似于MSBuild 15 Microsoft.FSharp.targets 文件似乎也在不停地移动。 - brianary


答案:


在我看来,choose子句可能实际上是不正确的。我会认为 $(VisualStudioVersion) 如果没有Visual Studio安装,那将是空的。但是,那 $(FSharpTargetPath) 这指向我希望独立目标文件驻留的位置。很明显,将3.1换成3.0。见下文。

  <Choose>
    <When Condition="'$(VisualStudioVersion)' == '11.0'">
      <PropertyGroup Condition="Exists('$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets')">
        <FSharpTargetsPath>$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets</FSharpTargetsPath>
      </PropertyGroup>
    </When>
    <Otherwise>
      <PropertyGroup Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets')">
        <FSharpTargetsPath>$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets</FSharpTargetsPath>
      </PropertyGroup>
      <PropertyGroup Condition="Exists('$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.1\Framework\v4.0\Microsoft.FSharp.Targets')">
        <FSharpTargetsPath>$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.1\Framework\v4.0\Microsoft.FSharp.Targets</FSharpTargetsPath>
      </PropertyGroup>          
    </Otherwise>
  </Choose>

免责声明:


8
2018-01-23 14:07



谢谢!这对我来说是一个很大的帮助。我想在使用FAKE时使用3.0,使用VS 2012使用3.0,使用VS 2013使用3.1,我想我已经使用这些指令进行了整理。 - lefthandedgoat
使用锚定路径 $(MSBuildExtensionsPath32)\.. 到达,得到 C:\ Program Files(x86) 已成为构建的定时炸弹,因为该变量是 C:\ Program Files(x86)\ Microsoft Visual Studio \ 2017 \ BuildTools \ MSBuild 在VS2017中,类似于MSBuild 15 Microsoft.FSharp.targets 文件似乎也在不停地移动。 - brianary


这是3.1.1安装程序中的错误。

概要

这仅影响清洁机器安装。在底部运行脚本,事情将开始工作,不需要对项目进行任何更改。

细节

从VS 2013开始,F#项目模板包含 Choose 你在问题中提供的片段。设计如下:

  • 初步检查 VisualStudioVersion = 11.0 对于VS 2012的反击支持:不管你信不信,一个新的VS 2013 F#项目将在VS 2012和2013中正常开放,前提是你的目标是F#3.0。在VS 2012(aka版本11.0)中打开项目时,将使用F#3.0构建目标文件。

  • 展望未来,我们不希望在项目文件中进行硬编码版本号和路径的业务,因此第二种情况代表了消费构建目标的未来机制。此案例指向每个VS版本的填充程序文件,该文件只包含“真实”构建目标文件的导入。对于VS 2013(又名版本12.0), $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets 是3行,只需导入真实目标 $(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.1\Framework\v4.0\Microsoft.FSharp.Targets。使用这种方法,当新的VS版本出现时,不需要使用新版本和路径更新项目文件。您的项目将自动找到与您正在使用的任何VS版本匹配的填充文件,该填充文件将指向该版本的VS支持的相应“真实”目标。

这是超级neato,除了3.1.1安装程序错误地将填充文件放入“检测到VS时仅部署”桶中。所以在一个干净的构建服务器上,虽然是“真正的”目标文件  安装(它在“总是部署”桶中),垫片不是,并且您使用默认模板获得了破坏的构建。 :-(

解决方法

编辑项目文件以便直接消耗真实目标是完全有效的。这会奏效。但我会说首选的解决方法是自己创建填充文件。

要自己创建丢失的填充文件(实际上是2个文件,也有一个可移植文件),只需从admin powershell提示符下面运行:

$shimDir = "${env:ProgramFiles(x86)}\MSBuild\Microsoft\VisualStudio\v12.0\FSharp"
mkdir $shimDir | out-null

$shimFormat = @'
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.1\Framework\v4.0\Microsoft{0}.FSharp.targets" />
</Project>
'@

'','.Portable' |%{ ($shimFormat -f $_ -split '\n') | out-file "$shimDir\Microsoft$_.FSharp.targets" -encoding ascii }

6
2018-01-23 20:20



谢谢你的详细解答。 “首选解决方法”的问题是我实际上无法访问CI服务器。我所能做的就是希望管理员安装安装程序。 - forki23
即使有了这个修复,我在mono上也有同样的问题 travis-ci.org/fsharp/FAKE/builds/17504786 - forki23


我在我的项目中要求3.1,所以我删除了选择块,只需在顶部附近添加一个FSharpTargetsPath属性,请参阅 SourceLink.fsproj。这是我们为FAKE项目所做的更简单的版本 FakeLib.fsproj

<FSharpTargetsPath>$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.1\Framework\v4.0\Microsoft.FSharp.Targets</FSharpTargetsPath>

1
2018-01-25 00:04