Computer Science Experimentation

Thursday, February 17, 2011

Dynamic Compilation and Execution using F#


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