Использование FsLex/Yacc в Vs2013
Я пытаюсь воскресить старый проект F# parser, с которым я работал в vs 2008 для работы с vs 2013. Он использует FsLexYacc.
Я получил это нормально, используя шаг предварительной сборки, как показано ниже:
fslex --unicode "$(ProjectDir)XpathLexer.fsl"
fsyacc --module XpathParser "$(ProjectDir)XpathParser.fsy"
Но это не идеально, так как всегда выполняется независимо от того, изменились ли входы.
Затем я попытался просто использовать старые действия MsBuild:
<FsYacc Include="XpathParser.fsy">
<FsLex Include="XpathLexer.fsl">
но они, похоже, полностью игнорировались в процессе сборки. Это правильно? Были ли эти задачи сборки удалены?
Затем я обнаружил некоторые вещи, документированные под vs C++, которые, как я думал, могли бы работать:
<CustomBuild Include="XpathParser.fsy">
<Message>Calling FsYacc</Message>
<Command>fsyacc --module XpathParser "$(ProjectDir)XpathParser.fsy"</Command>
<Outputs>$(ProjectDir)XpathParser.fs</Outputs>
</CustomBuild>
а также
<PropertyGroup>
<CustomBuildBeforeTargets>CoreCompile</CustomBuildBeforeTargets>
</PropertyGroup>
(Я проверил файл Microsoft.Fsharp.Targets для определения цели "CoreCompile".)
Увы, до сих пор нет сигар.
Кто-нибудь может пролить свет на то, действительно ли возможно правильно интегрировать fslex/yacc в решение vs 2013, и если да, то как?
3 ответа
Я не думаю, что эти инструменты включены по умолчанию в компилятор F#, который устанавливается вместе с Visual Studio, и поэтому задачи не существуют. Я сделал следующее с проектом Visual Studio 2012, но я ожидаю, что он будет похож на VS 2013. Вот шаги, которые я должен был выполнить:
- Установите FSharp.Powerpack от nuget. Здесь есть инструменты fslex и fsyacc, а также задачи и цели сборки.
- Выгрузите проект и отредактируйте файл.fsproj.
Добавьте оператор импорта для файла FSharp.Powerpack.target. Это добавит
CallFsLex
а такжеCallFsYacc
строить цели. Я добавил это после импорта дляMicrosoft.FSharp.targets
:<Import Project="$(ProjectDir)\..\packages\FSPowerPack.Community.3.0.0.0\Tools\FSharp.PowerPack.targets" />
Добавьте эти три свойства в основную группу PropertyGroup в верхней части файла:
<FsYaccToolPath>..\packages\FSPowerPack.Community.3.0.0.0\Tools</FsYaccToolPath> <FsLexToolPath>..\packages\FSPowerPack.Community.3.0.0.0\Tools</FsLexToolPath> <FsLexUnicode>true</FsLexUnicode>
Это сообщает задачам сборки, где найти необходимые инструменты, и устанавливает опцию Unicode для fslex.- Чтобы использовать цели, которые мы импортировали, вам нужно определить группы элементов FsLex и FsYacc с используемыми входными файлами. Вам также необходимо добавить элементы Compile для выходных файлов.fs. В итоге вы получите что-то вроде этого в разделе ItemGroup:
<Compile Include="Sql.fs" />
<FsYacc Include="SqlParser.fsp">
<Module>SqlParser</Module>
</FsYacc>
<Compile Include="SqlParser.fsi" />
<Compile Include="SqlParser.fs" />
<FsLex Include="SqlLexer.fsl" />
<Compile Include="SqlLexer.fs" />
Вы можете использовать задачи сборки FsLex и FsYacc напрямую, ссылаясь на файл FSharp.Powerpack.Build.Tasks.dll, но для меня это было проще.
Вот что у меня работает (Windows 7 x64, Visual Studio 2013 Ultimate RTM):
Загрузите и установите "PowerPack для FSharp 3.0 + .NET 4.x + VS2012" из CodePlex ( https://fsharppowerpack.codeplex.com/downloads/get/625449).
Создайте следующий ключ реестра:
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\AssemblyFolders\FSharp.PowerPack-1.9.9.9
(для 64-разрядных версий Windows опуститеWow6432Node
для 32-битных версий) и установите его(Default)
значение для установочного каталога F# PowerPack (например, "C:\Program Files (x86)\FSharpPowerPack-4.0.0.0\bin"). [Это связано с давней / регрессионной ошибкой вsrc/FSharp.PowerPack/CompilerLocationUtils.fs
что в основном нарушает обнаружение инструмента.]Импортируйте цели PowerPack (ПОСЛЕ импорта целей F#) в ваш файл *.fsproj:
<Import Project="$(MSBuildExtensionsPath32)\FSharp\1.0\FSharp.PowerPack.targets" />
Обновите свой
ItemGroup
Узел что-то вроде этого (используйте FsYacc соответственно):<ItemGroup> <None Include="App.config" /> <FsLex Include="Lexer.fsl" /> <Compile Include="Lexer.fs"> <Visible>False</Visible> </Compile> <Compile Include="Program.fs" /> </ItemGroup>
Включить ссылку на
FSharp.PowerPack.dll
и построить.
Вы должны получить файл *.fsproj, подобный следующему:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>8c565f99-d6bc-43a9-ace9-eadfe429c0f7</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>FsYaccTest</RootNamespace>
<AssemblyName>FsYaccTest</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<TargetFSharpCoreVersion>4.3.1.0</TargetFSharpCoreVersion>
<Name>FsYaccTest</Name>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<!-- Snip -->
</PropertyGroup>
<ItemGroup>
<Reference Include="FSharp.PowerPack">
<HintPath>C:\Program Files (x86)\FSharpPowerPack-4.0.0.0\bin\FSharp.PowerPack.dll</HintPath>
</Reference>
<Reference Include="mscorlib" />
<Reference Include="FSharp.Core, Version=$(TargetFSharpCoreVersion), Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Numerics" />
</ItemGroup>
<PropertyGroup>
<MinimumVisualStudioVersion Condition="'$(MinimumVisualStudioVersion)' == ''">11</MinimumVisualStudioVersion>
</PropertyGroup>
<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)" />
<Import Project="$(MSBuildExtensionsPath32)\FSharp\1.0\FSharp.PowerPack.targets" />
<PropertyGroup>
<FsLexUnicode>true</FsLexUnicode>
</PropertyGroup>
<ItemGroup>
<None Include="App.config" />
<FsLex Include="Lexer.fsl" />
<Compile Include="Lexer.fs">
<Visible>False</Visible>
</Compile>
<Compile Include="Program.fs" />
</ItemGroup>
</Project>
Примечание: вы, вероятно, можете опустить создание ключа реестра, если вы предоставите FsYaccToolPath
как описано в ответе Майка З.
Похоже, что это работает - по крайней мере, по моему опыту, если вы используете отдельный пакет nuget FsLexYacc, как описано здесь, а затем добавляете следующее в файл fsproj (извлеченный из примера github):
Рядом со всем другим импортом:
<Import Project="..\packages\FsLexYacc.6.0.4\bin\FsLexYacc.targets" />
и т. д.
а затем для исходных файлов:
<FsYacc Include="Parser.fsp">
<OtherFlags>--module SqlParser</OtherFlags>
</FsYacc>
<FsLex Include="Lexer.fsl">
<OtherFlags>--unicode</OtherFlags>
</FsLex>
Не нужно ничего делать, кроме как отредактировать файл fsproj и установить пакеты nuget.