F# Compiler Services


Hosted Compiler

This tutorial demonstrates how to host the F# compiler.

NOTE: The FSharp.Compiler.Service API is subject to change when later versions of the nuget package are published

NOTE: There are several options for hosting the F# compiler. The easiest one is to use the fsc.exe process and pass arguments.

NOTE: By default compilations using FSharp.Compiler.Service reference FSharp.Core 4.3.0.0 (matching F# 3.0). You can override this choice by passing a reference to FSharp.Core for 4.3.1.0 or later explicitly in your command-line arguments.


First, we need to reference the libraries that contain F# interactive service:

1: 
2: 
3: 
4: 
5: 
6: 
#r "FSharp.Compiler.Service.dll"
open System.IO
open FSharp.Compiler.SourceCodeServices

// Create an interactive checker instance 
let checker = FSharpChecker.Create()

Now write content to a temporary file:

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
let fn = Path.GetTempFileName()
let fn2 = Path.ChangeExtension(fn, ".fsx")
let fn3 = Path.ChangeExtension(fn, ".dll")

File.WriteAllText(fn2, """
module M

type C() = 
   member x.P = 1

let x = 3 + 4
""")

Now invoke the compiler:

1: 
2: 
3: 
let errors1, exitCode1 = 
    checker.Compile([| "fsc.exe"; "-o"; fn3; "-a"; fn2 |]) 
    |> Async.RunSynchronously

If errors occur you can see this in the 'exitCode' and the returned array of errors:

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
9: 
File.WriteAllText(fn2, """
module M

let x = 1.0 + "" // a type error
""")

let errors1b, exitCode1b = 
    checker.Compile([| "fsc.exe"; "-o"; fn3; "-a"; fn2 |])
    |> Async.RunSynchronously

Compiling to a dynamic assembly

You can also compile to a dynamic assembly, which uses the F# Interactive code generator. This can be useful if you are, for example, in a situation where writing to the file system is not really an option.

You still have to pass the "-o" option to name the output file, but the output file is not actually written to disk.

The 'None' option indicates that the initiatlization code for the assembly is not executed.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
let errors2, exitCode2, dynAssembly2 = 
    checker.CompileToDynamicAssembly([| "-o"; fn3; "-a"; fn2 |], execute=None)
     |> Async.RunSynchronously

(*
Passing 'Some' for the 'execute' parameter executes  the initiatlization code for the assembly.
*)
let errors3, exitCode3, dynAssembly3 = 
    checker.CompileToDynamicAssembly([| "-o"; fn3; "-a"; fn2 |], Some(stdout,stderr))
     |> Async.RunSynchronously
namespace System
namespace System.IO
Multiple items
namespace FSharp

--------------------
namespace Microsoft.FSharp
namespace FSharp.Compiler
namespace FSharp.Compiler.SourceCodeServices
val checker : FSharpChecker

Full name: Compiler.checker
type FSharpChecker
member CheckFileInProject : parsed:FSharpParseFileResults * filename:string * fileversion:int * source:string * options:FSharpProjectOptions * ?textSnapshotInfo:obj * ?userOpName:string -> Async<FSharpCheckFileAnswer>
member CheckProjectInBackground : options:FSharpProjectOptions * ?userOpName:string -> unit
member ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients : unit -> unit
member Compile : argv:string [] * ?userOpName:string -> Async<FSharpErrorInfo [] * int>
member Compile : ast:ParsedInput list * assemblyName:string * outFile:string * dependencies:string list * ?pdbFile:string * ?executable:bool * ?noframework:bool * ?userOpName:string -> Async<FSharpErrorInfo [] * int>
member CompileToDynamicAssembly : otherFlags:string [] * execute:(TextWriter * TextWriter) option * ?userOpName:string -> Async<FSharpErrorInfo [] * int * Assembly option>
member CompileToDynamicAssembly : ast:ParsedInput list * assemblyName:string * dependencies:string list * execute:(TextWriter * TextWriter) option * ?debug:bool * ?noframework:bool * ?userOpName:string -> Async<FSharpErrorInfo [] * int * Assembly option>
member GetBackgroundCheckResultsForFileInProject : filename:string * options:FSharpProjectOptions * ?userOpName:string -> Async<FSharpParseFileResults * FSharpCheckFileResults>
member GetBackgroundParseResultsForFileInProject : filename:string * options:FSharpProjectOptions * ?userOpName:string -> Async<FSharpParseFileResults>
member GetParsingOptionsFromCommandLineArgs : argv:string list * ?isInteractive:bool -> FSharpParsingOptions * FSharpErrorInfo list
member GetParsingOptionsFromCommandLineArgs : sourceFiles:string list * argv:string list * ?isInteractive:bool -> FSharpParsingOptions * FSharpErrorInfo list
member GetParsingOptionsFromProjectOptions : FSharpProjectOptions -> FSharpParsingOptions * FSharpErrorInfo list
member GetProjectOptionsFromCommandLineArgs : projectFileName:string * argv:string [] * ?loadedTimeStamp:DateTime * ?extraProjectInfo:obj -> FSharpProjectOptions
member GetProjectOptionsFromScript : filename:string * source:string * ?loadedTimeStamp:DateTime * ?otherFlags:string [] * ?useFsiAuxLib:bool * ?assumeDotNetFramework:bool * ?extraProjectInfo:obj * ?optionsStamp:int64 * ?userOpName:string -> Async<FSharpProjectOptions * FSharpErrorInfo list>
member InvalidateAll : unit -> unit
member InvalidateConfiguration : options:FSharpProjectOptions * ?startBackgroundCompileIfAlreadySeen:bool * ?userOpName:string -> unit
member KeepProjectAlive : options:FSharpProjectOptions * ?userOpName:string -> Async<IDisposable>
member MatchBraces : filename:string * source:string * options:FSharpParsingOptions * ?userOpName:string -> Async<(range * range) []>
member NotifyProjectCleaned : options:FSharpProjectOptions * ?userOpName:string -> Async<unit>
member ParseAndCheckFileInProject : filename:string * fileversion:int * source:string * options:FSharpProjectOptions * ?textSnapshotInfo:obj * ?userOpName:string -> Async<FSharpParseFileResults * FSharpCheckFileAnswer>
member ParseAndCheckProject : options:FSharpProjectOptions * ?userOpName:string -> Async<FSharpCheckProjectResults>
member ParseFile : filename:string * source:string * options:FSharpParsingOptions * ?userOpName:string -> Async<FSharpParseFileResults>
member StopBackgroundCompile : unit -> unit
member TokenizeFile : source:string -> FSharpTokenInfo [] []
member TokenizeLine : line:string * state:FSharpTokenizerLexState -> FSharpTokenInfo [] * FSharpTokenizerLexState
member TryGetRecentCheckResultsForFile : filename:string * options:FSharpProjectOptions * ?source:string * ?userOpName:string -> (FSharpParseFileResults * FSharpCheckFileResults * int) option
member WaitForBackgroundCompile : unit -> unit
member BeforeBackgroundFileCheck : IEvent<string * obj option>
member CurrentQueueLength : int
member FileChecked : IEvent<string * obj option>
member FileParsed : IEvent<string * obj option>
member private FrameworkImportsCache : FrameworkImportsCache
member ImplicitlyStartBackgroundWork : bool
member MaxMemory : int
member MaxMemoryReached : IEvent<unit>
member PauseBeforeBackgroundWork : int
member ProjectChecked : IEvent<string * obj option>
member private ReactorOps : IReactorOperations
member private ReferenceResolver : Resolver
member ImplicitlyStartBackgroundWork : bool with set
member MaxMemory : int with set
member PauseBeforeBackgroundWork : int with set
static member Create : ?projectCacheSize:int * ?keepAssemblyContents:bool * ?keepAllBackgroundResolutions:bool * ?legacyReferenceResolver:Resolver * ?tryGetMetadataSnapshot:ILReaderTryGetMetadataSnapshot -> FSharpChecker
static member GlobalForegroundParseCountStatistic : int
static member GlobalForegroundTypeCheckCountStatistic : int

Full name: FSharp.Compiler.SourceCodeServices.FSharpChecker
static member FSharpChecker.Create : ?projectCacheSize:int * ?keepAssemblyContents:bool * ?keepAllBackgroundResolutions:bool * ?legacyReferenceResolver:FSharp.Compiler.ReferenceResolver.Resolver * ?tryGetMetadataSnapshot:FSharp.Compiler.AbstractIL.ILBinaryReader.ILReaderTryGetMetadataSnapshot -> FSharpChecker
val fn : string

Full name: Compiler.fn
type Path =
  static val DirectorySeparatorChar : char
  static val AltDirectorySeparatorChar : char
  static val VolumeSeparatorChar : char
  static val InvalidPathChars : char[]
  static val PathSeparator : char
  static member ChangeExtension : path:string * extension:string -> string
  static member Combine : [<ParamArray>] paths:string[] -> string + 3 overloads
  static member GetDirectoryName : path:string -> string
  static member GetExtension : path:string -> string
  static member GetFileName : path:string -> string
  ...

Full name: System.IO.Path
Path.GetTempFileName() : string
val fn2 : string

Full name: Compiler.fn2
Path.ChangeExtension(path: string, extension: string) : string
val fn3 : string

Full name: Compiler.fn3
type File =
  static member AppendAllLines : path:string * contents:IEnumerable<string> -> unit + 1 overload
  static member AppendAllText : path:string * contents:string -> unit + 1 overload
  static member AppendText : path:string -> StreamWriter
  static member Copy : sourceFileName:string * destFileName:string -> unit + 1 overload
  static member Create : path:string -> FileStream + 3 overloads
  static member CreateText : path:string -> StreamWriter
  static member Decrypt : path:string -> unit
  static member Delete : path:string -> unit
  static member Encrypt : path:string -> unit
  static member Exists : path:string -> bool
  ...

Full name: System.IO.File
File.WriteAllText(path: string, contents: string) : unit
File.WriteAllText(path: string, contents: string, encoding: System.Text.Encoding) : unit
val errors1 : obj

Full name: Compiler.errors1
val exitCode1 : obj

Full name: Compiler.exitCode1
member FSharpChecker.Compile : argv:string [] * ?userOpName:string -> Async<FSharpErrorInfo [] * int>
member FSharpChecker.Compile : ast:FSharp.Compiler.Ast.ParsedInput list * assemblyName:string * outFile:string * dependencies:string list * ?pdbFile:string * ?executable:bool * ?noframework:bool * ?userOpName:string -> Async<FSharpErrorInfo [] * int>
Multiple items

--------------------
type Async<'T>

Full name: Microsoft.FSharp.Control.Async<_>
val errors1b : obj

Full name: Compiler.errors1b
val exitCode1b : obj

Full name: Compiler.exitCode1b
val errors2 : obj

Full name: Compiler.errors2
val exitCode2 : obj

Full name: Compiler.exitCode2
val dynAssembly2 : obj

Full name: Compiler.dynAssembly2
member FSharpChecker.CompileToDynamicAssembly : otherFlags:string [] * execute:(TextWriter * TextWriter) option * ?userOpName:string -> Async<FSharpErrorInfo [] * int * System.Reflection.Assembly option>
member FSharpChecker.CompileToDynamicAssembly : ast:FSharp.Compiler.Ast.ParsedInput list * assemblyName:string * dependencies:string list * execute:(TextWriter * TextWriter) option * ?debug:bool * ?noframework:bool * ?userOpName:string -> Async<FSharpErrorInfo [] * int * System.Reflection.Assembly option>
union case Option.None: Option<'T>
val errors3 : obj

Full name: Compiler.errors3
val exitCode3 : obj

Full name: Compiler.exitCode3
val dynAssembly3 : obj

Full name: Compiler.dynAssembly3
union case Option.Some: Value: 'T -> Option<'T>
val stdout<'T> : TextWriter

Full name: Microsoft.FSharp.Core.Operators.stdout
val stderr<'T> : TextWriter

Full name: Microsoft.FSharp.Core.Operators.stderr
Fork me on GitHub