Dynamic Compilation and Execution using F#
Celso Axelrud
Feb/17/2011
The following example shows how to compile a module from a string inside an executable and make it available to be used by the same executable.
For better understanding of the steps, the example uses F# interactive.
Here is the code:
#r "FSharp.Compiler.dll"
#r "FSharp.Compiler.CodeDom.dll"
#I @"C:\Users\caxelrud\Documents\Visual Studio 2010\Projects\NLMPC"
open System
open System.IO
open System.CodeDom.Compiler
open Microsoft.FSharp.Compiler.CodeDom
(* For this example, copy Fsharp.Core.* from C:\Program Files (x86)\Reference Assemblies\Microsoft\FSharp\2.0\Runtime\v4.0 and FSharp.Powerpack.dll to the local directory*)
let CompileFSharpString(str, assemblies, output) =
use pro = new FSharpCodeProvider()
let opt = CompilerParameters(assemblies, output)
let res = pro.CompileAssemblyFromSource( opt, [|str|] )
printfn "%A" res.Errors
if res.Errors.Count = 0 then
Some(FileInfo(res.PathToAssembly))
else None ;;
let (++) v1 v2 = Path.Combine(v1, v2)
let path= @"C:\Users\caxelrud\My Documents\Visual Studio 2010\Projects\NLMPC"
let defaultAsms = [|path++"System.dll"; path++"FSharp.Core.dll"; path++"FSharp.Powerpack.dll"|]
let randomFile() = path ++ Path.GetRandomFileName() + ".dll";;
//let randomFile() = __SOURCE_DIRECTORY__ ++ Path.GetRandomFileName() + ".dll"
type System.CodeDom.Compiler.CodeCompiler with
static member CompileFSharpString (str, ?assemblies, ?output) =
let assemblies = defaultArg assemblies defaultAsms
let output = defaultArg output (randomFile())
printfn "%A %s" assemblies output
CompileFSharpString(str, assemblies, output);;
// Module definition
let library = "
module Temp.Main
let f(x,y) = sin x + cos y
" ;;
// Create the assembly
let fileinfo = CodeCompiler.CompileFSharpString(library);;
// Just testing in the interactive env.
#r "zmm30vu5.eqq.dll"
let a = Temp.Main.f(0.5 * Math.PI, 0.0);; // val a : float = 2.0
// Purely reflective invocation of the function.
let asm = Reflection.Assembly.LoadFrom(fileinfo.Value.FullName)
let mth = asm.GetType("Temp.Main").GetMethod("f")
// Wrap weakly typed function with strong typing.
let f(x,y) = mth.Invoke(null, [|box (x:float); box (y:float)|]) :?> float;;
// Call the function
let b = f (0.5 * Math.PI, 0.0);; // val b : float = 2.0
No comments:
Post a Comment