当我在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。
我需要添加什么才能使其工作?
在我看来,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>
免责声明:
在我看来,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>
免责声明:
这是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 }
我在我的项目中要求3.1,所以我删除了选择块,只需在顶部附近添加一个FSharpTargetsPath属性,请参阅 SourceLink.fsproj。这是我们为FAKE项目所做的更简单的版本 FakeLib.fsproj。
<FSharpTargetsPath>$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.1\Framework\v4.0\Microsoft.FSharp.Targets</FSharpTargetsPath>