Как использовать F # на сервере CI при использовании нового автономного установщика для F # 3.1.1

Когда я создаю новый проект в 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. Что я должен добавить, чтобы сделать эту работу?

Ответ 1

Мне кажется, что предложение select может быть неверным. Я бы подумал, что $(VisualStudioVersion) будет пустым ", если не было установки визуальной студии. Однако $(FSharpTargetPath), который указывает на то, где я ожидаю, что файл автономных целей будет находиться. Очевидно, замена 3,0 для 3,1. Смотри ниже.

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

Отказ от ответственности: это чистая работа, поскольку я не на ПК, где я могу попробовать это.

Ответ 2

Это ошибка в установщике для 3.1.1.

Резюме

Это влияет только на установку чистой машины. Запустите script внизу, и все начнет работать, никаких изменений, необходимых для вашего проекта.

Подробнее

Начиная с VS 2013, шаблоны проектов F # содержат фрагмент Choose, как вы указали в своем вопросе. Конструкция выглядит следующим образом:

  • Первоначальная проверка для VisualStudioVersion = 11.0 предназначена для поддержки back-compat с VS 2012: верьте или нет, новый проект VS 2013 F # откроется отлично как в VS 2012, так и в 2013 году, если вы настроите F # 3.0. Файл целей построения F # 3.0 используется, когда проект открыт в VS 2012 (aka version 11.0).

  • Идем дальше, мы не хотим быть в числе номеров и путей версии hardcoding в вашем файле проекта, поэтому второй случай представляет собой будущий механизм для потребления целей сборки. Этот случай указывает на файл shim для VS-версии, который не содержит ничего, кроме импорта файла "real" build target. Для 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

Мне требуется 3.1 в моих проектах, поэтому я удаляю этот блок выбора и просто добавляю свойство FSharpTargetsPath в верхней части страницы, см. SourceLink.fsproj. Это более простая версия того, что мы сделали для проектов FAKE, таких как FakeLib.fsproj.

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