F# Compiler Services


コンパイラの組み込み

このチュートリアルではF#コンパイラをホストする方法を紹介します。

注意: 以下で使用しているAPIは実験的なもので、 新しいnugetパッケージの公開に伴って変更される可能性があります。 注意: F#コンパイラをホストする方法はいくつかあります。 一番簡単な方法は fsc.exe のプロセスを使って引数を渡す方法です。


まず、F# Interactiveサービスを含むライブラリへの参照を追加します:

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

let scs = SimpleSourceCodeServices()

次に、一時ファイルへコンテンツを書き込みます:

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

そしてコンパイラを呼び出します:

1: 
let errors1, exitCode1 = scs.Compile([| "fsc.exe"; "-o"; fn3; "-a"; fn2 |])

エラーが発生した場合は「終了コード」とエラーの配列から原因を特定できます:

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

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

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

if exitCode1b <> 0 then
    errors1b
    |> Array.iter (printfn "%A")

動的アセンブリへのコンパイル

コードを動的アセンブリとしてコンパイルすることもできます。 動的アセンブリはF# Interactiveコードジェネレータでも使用されています。

この機能はたとえばファイルシステムが必ずしも利用できないような状況で役に立ちます。

出力ファイルの名前を指定する "-o" オプションを指定することは可能ですが、 実際には出力ファイルがディスク上に書き込まれることはありません。

'execute' 引数に 'None' を指定するとアセンブリ用の初期化コードが実行されません。

1: 
2: 
let errors2, exitCode2, dynAssembly2 = 
    scs.CompileToDynamicAssembly([| "-o"; fn3; "-a"; fn2 |], execute=None)

'Some' を指定するとアセンブリ用の初期化コードが実行されます。

1: 
2: 
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
module Array

from Microsoft.FSharp.Collections
val iter : action:('T -> unit) -> array:'T [] -> unit

Full name: Microsoft.FSharp.Collections.Array.iter
val printfn : format:Printf.TextWriterFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
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