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: 
#r "FSharp.Compiler.Service.dll"
open Microsoft.FSharp.Compiler.SimpleSourceCodeServices
open System.IO

let scs = SimpleSourceCodeServices()

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, ".fs")
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: 
let errors1, exitCode1 = scs.Compile([| "fsc.exe"; "-o"; fn3; "-a"; fn2 |])

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

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

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

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

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: 
let errors2, exitCode2, dynAssembly2 = 
    scs.CompileToDynamicAssembly([| "-o"; fn3; "-a"; fn2 |], execute=None)

(*
Passing 'Some' for the 'execute' parameter executes  the initiatlization code for the assembly.
*)
let errors3, exitCode3, dynAssembly3 = 
    scs.CompileToDynamicAssembly([| "-o"; fn3; "-a"; fn2 |], Some(stdout,stderr))
namespace Microsoft
namespace Microsoft.FSharp
namespace Microsoft.FSharp.Compiler
namespace Microsoft.FSharp.Compiler.SimpleSourceCodeServices
namespace System
namespace System.IO
val scs : SimpleSourceCodeServices

Full name: Compiler.scs
Multiple items
type SimpleSourceCodeServices =
  new : ?msbuildEnabled:bool -> SimpleSourceCodeServices
  member Compile : argv:string [] -> FSharpErrorInfo [] * int
  member Compile : ast:ParsedInput list * assemblyName:string * outFile:string * dependencies:string list * ?pdbFile:string * ?executable:bool * ?noframework:bool -> FSharpErrorInfo [] * int
  member CompileToDynamicAssembly : otherFlags:string [] * execute:(TextWriter * TextWriter) option -> FSharpErrorInfo [] * int * Assembly option
  member CompileToDynamicAssembly : ast:ParsedInput list * assemblyName:string * dependencies:string list * execute:(TextWriter * TextWriter) option * ?debug:bool * ?noframework:bool -> FSharpErrorInfo [] * int * Assembly option
  member TokenizeFile : source:string -> FSharpTokenInfo [] []
  member TokenizeLine : line:string * state:int64 -> FSharpTokenInfo [] * int64

Full name: Microsoft.FSharp.Compiler.SimpleSourceCodeServices.SimpleSourceCodeServices

--------------------
new : ?msbuildEnabled:bool -> SimpleSourceCodeServices
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 : Compiler.FSharpErrorInfo []

Full name: Compiler.errors1
val exitCode1 : int

Full name: Compiler.exitCode1
member SimpleSourceCodeServices.Compile : argv:string [] -> Compiler.FSharpErrorInfo [] * int
member SimpleSourceCodeServices.Compile : ast:Compiler.Ast.ParsedInput list * assemblyName:string * outFile:string * dependencies:string list * ?pdbFile:string * ?executable:bool * ?noframework:bool -> Compiler.FSharpErrorInfo [] * int
val errors1b : Compiler.FSharpErrorInfo []

Full name: Compiler.errors1b
val exitCode1b : int

Full name: Compiler.exitCode1b
val errors2 : Compiler.FSharpErrorInfo []

Full name: Compiler.errors2
val exitCode2 : int

Full name: Compiler.exitCode2
val dynAssembly2 : System.Reflection.Assembly option

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

Full name: Compiler.errors3
val exitCode3 : int

Full name: Compiler.exitCode3
val dynAssembly3 : System.Reflection.Assembly option

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