@@ -9,6 +9,7 @@ open System
9
9
open System.IO
10
10
open System.Text
11
11
open System.Threading
12
+ open System.Reflection .Emit
12
13
open System.Runtime
13
14
open System.Collections .Generic
14
15
@@ -23,6 +24,7 @@ open Microsoft.FSharp.Compiler.AbstractIL.Internal.Library
23
24
open Microsoft.FSharp .Compiler .AccessibilityLogic
24
25
open Microsoft.FSharp .Compiler .Ast
25
26
open Microsoft.FSharp .Compiler .CompileOps
27
+ open Microsoft.FSharp .Compiler .Driver
26
28
open Microsoft.FSharp .Compiler .ErrorLogger
27
29
open Microsoft.FSharp .Compiler .Lib
28
30
open Microsoft.FSharp .Compiler .MSBuildResolver
@@ -2123,6 +2125,115 @@ module Helpers =
2123
2125
let AreSubsumable3 (( fileName1 : string , _ , o1 : FSharpProjectOptions ),( fileName2 : string , _ , o2 : FSharpProjectOptions )) =
2124
2126
( fileName1 = fileName2)
2125
2127
&& FSharpProjectOptions.AreSubsumable( o1, o2)
2128
+
2129
+ module CompileHelpers =
2130
+ let mkCompilationErorHandlers () =
2131
+ let errors = ResizeArray<_>()
2132
+
2133
+ let errorSink warn exn =
2134
+ let mainError , relatedErrors = SplitRelatedErrors exn
2135
+ let oneError trim e = errors.Add( ErrorInfo.CreateFromException ( e, warn, trim, Range.range0))
2136
+ oneError false mainError
2137
+ List.iter ( oneError true ) relatedErrors
2138
+
2139
+ let errorLogger =
2140
+ { new ErrorLogger( " CompileAPI" ) with
2141
+ member x.WarnSinkImpl ( exn ) = errorSink true exn
2142
+ member x.ErrorSinkImpl ( exn ) = errorSink false exn
2143
+ member x.ErrorCount = errors |> Seq.filter ( fun e -> e.Severity = FSharpErrorSeverity.Error) |> Seq.length }
2144
+
2145
+ let loggerProvider =
2146
+ { new ErrorLoggerProvider() with
2147
+ member x.CreateErrorLoggerThatQuitsAfterMaxErrors ( _tcConfigBuilder , _exiter ) = errorLogger }
2148
+ errors, errorLogger, loggerProvider
2149
+
2150
+ let tryCompile errorLogger f =
2151
+ use unwindParsePhase = PushThreadBuildPhaseUntilUnwind ( BuildPhase.Parse)
2152
+ use unwindEL_2 = PushErrorLoggerPhaseUntilUnwind ( fun _ -> errorLogger)
2153
+ let exiter = { new Exiter with member x.Exit n = raise StopProcessing }
2154
+ try
2155
+ f exiter
2156
+ 0
2157
+ with e ->
2158
+ stopProcessingRecovery e Range.range0
2159
+ 1
2160
+
2161
+ /// Compile using the given flags. Source files names are resolved via the FileSystem API. The output file must be given by a -o flag.
2162
+ let compileFromArgs ( argv : string [], tcImportsCapture , dynamicAssemblyCreator ) =
2163
+
2164
+ let errors , errorLogger , loggerProvider = mkCompilationErorHandlers()
2165
+ let result =
2166
+ tryCompile errorLogger ( fun exiter ->
2167
+ mainCompile ( argv, (* bannerAlreadyPrinted*) true , (* openBinariesInMemory*) true , exiter, loggerProvider, tcImportsCapture, dynamicAssemblyCreator) )
2168
+
2169
+ errors.ToArray(), result
2170
+
2171
+ let compileFromAsts ( asts , assemblyName , outFile , dependencies , noframework , pdbFile , executable , tcImportsCapture , dynamicAssemblyCreator ) =
2172
+
2173
+ let errors , errorLogger , loggerProvider = mkCompilationErorHandlers()
2174
+
2175
+ let executable = defaultArg executable true
2176
+ let target = if executable then CompilerTarget.ConsoleExe else CompilerTarget.Dll
2177
+
2178
+ let result =
2179
+ tryCompile errorLogger ( fun exiter ->
2180
+ compileOfAst ( (* openBinariesInMemory=*) true , assemblyName, target, outFile, pdbFile, dependencies, noframework, exiter, loggerProvider, asts, tcImportsCapture, dynamicAssemblyCreator))
2181
+
2182
+ errors.ToArray(), result
2183
+
2184
+ let dynamicAssemblyCreator ( debugInfo : bool , tcImportsRef : TcImports option ref , execute : _ option , assemblyBuilderRef : _ option ref ) ( _tcConfig , ilGlobals , _errorLogger , outfile , _pdbfile , ilxMainModule , _signingInfo ) =
2185
+
2186
+ // Create an assembly builder
2187
+ let assemblyName = System.Reflection.AssemblyName( System.IO.Path.GetFileNameWithoutExtension outfile)
2188
+ let flags = System.Reflection.Emit.AssemblyBuilderAccess.Run
2189
+ #if FX_ NO_ APP_ DOMAINS
2190
+ let assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly( assemblyName, flags)
2191
+ let moduleBuilder = assemblyBuilder.DefineDynamicModule( " IncrementalModule" )
2192
+ #else
2193
+ let assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly( assemblyName, flags)
2194
+ let moduleBuilder = assemblyBuilder.DefineDynamicModule( " IncrementalModule" , debugInfo)
2195
+ #endif
2196
+ // Omit resources in dynamic assemblies, because the module builder is constructed without a filename the module
2197
+ // is tagged as transient and as such DefineManifestResource will throw an invalid operation if resources are present.
2198
+ //
2199
+ // Also, the dynamic assembly creator can't currently handle types called "<Module>" from statically linked assemblies.
2200
+ let ilxMainModule =
2201
+ { ilxMainModule with
2202
+ TypeDefs = ilxMainModule.TypeDefs.AsList |> List.filter ( fun td -> not ( isTypeNameForGlobalFunctions td.Name)) |> mkILTypeDefs
2203
+ Resources= mkILResources [] }
2204
+
2205
+ // The function used to resolve typees while emitting the code
2206
+ let assemblyResolver s =
2207
+ match tcImportsRef.Value.Value.TryFindExistingFullyQualifiedPathFromAssemblyRef s with
2208
+ | Some res -> Some ( Choice1Of2 res)
2209
+ | None -> None
2210
+
2211
+ // Emit the code
2212
+ let _emEnv , execs = ILRuntimeWriter.emitModuleFragment( ilGlobals, ILRuntimeWriter.emEnv0, assemblyBuilder, moduleBuilder, ilxMainModule, debugInfo, assemblyResolver)
2213
+
2214
+ // Execute the top-level initialization, if requested
2215
+ if execute.IsSome then
2216
+ for exec in execs do
2217
+ match exec() with
2218
+ | None -> ()
2219
+ | Some exn -> raise exn
2220
+
2221
+ // Register the reflected definitions for the dynamically generated assembly
2222
+ for resource in ilxMainModule.Resources.AsList do
2223
+ if IsReflectedDefinitionsResource resource then
2224
+ Quotations.Expr.RegisterReflectedDefinitions( assemblyBuilder, moduleBuilder.Name, resource.Bytes)
2225
+
2226
+ // Save the result
2227
+ assemblyBuilderRef := Some assemblyBuilder
2228
+
2229
+ let setOutputStreams execute =
2230
+ // Set the output streams, if requested
2231
+ match execute with
2232
+ | Some ( writer, error) ->
2233
+ System.Console.SetOut writer
2234
+ System.Console.SetError error
2235
+ | None -> ()
2236
+
2126
2237
2127
2238
// There is only one instance of this type, held in FSharpChecker
2128
2239
type BackgroundCompiler ( projectCacheSize , keepAssemblyContents , keepAllBackgroundResolutions ) as self =
@@ -2697,6 +2808,66 @@ type FSharpChecker(projectCacheSize, keepAssemblyContents, keepAllBackgroundReso
2697
2808
2698
2809
member ic.TryGetRecentTypeCheckResultsForFile ( filename , options , ? source ) = ic.TryGetRecentCheckResultsForFile( filename, options,? source= source)
2699
2810
2811
+ member ic.Compile ( argv : string []) =
2812
+ CompileHelpers.compileFromArgs ( argv, None, None)
2813
+
2814
+ member ic.Compile ( ast : ParsedInput list , assemblyName : string , outFile : string , dependencies : string list , ? pdbFile : string , ? executable : bool , ? noframework : bool ) =
2815
+ let noframework = defaultArg noframework false
2816
+ CompileHelpers.compileFromAsts ( ast, assemblyName, outFile, dependencies, noframework, pdbFile, executable, None, None)
2817
+
2818
+ member ic.CompileToDynamicAssembly ( otherFlags : string [], execute : ( TextWriter * TextWriter ) option ) =
2819
+ CompileHelpers.setOutputStreams execute
2820
+
2821
+ // References used to capture the results of compilation
2822
+ let tcImportsRef = ref ( None: TcImports option)
2823
+ let assemblyBuilderRef = ref None
2824
+ let tcImportsCapture = Some ( fun tcImports -> tcImportsRef := Some tcImports)
2825
+
2826
+ // Function to generate and store the results of compilation
2827
+ let debugInfo = otherFlags |> Array.exists ( fun arg -> arg = " -g" || arg = " --debug:+" || arg = " /debug:+" )
2828
+ let dynamicAssemblyCreator = Some ( CompileHelpers.dynamicAssemblyCreator ( debugInfo, tcImportsRef, execute, assemblyBuilderRef))
2829
+
2830
+ // Perform the compilation, given the above capturing function.
2831
+ let errorsAndWarnings , result = CompileHelpers.compileFromArgs ( otherFlags, tcImportsCapture, dynamicAssemblyCreator)
2832
+
2833
+ // Retrieve and return the results
2834
+ let assemblyOpt =
2835
+ match assemblyBuilderRef.Value with
2836
+ | None -> None
2837
+ | Some a -> Some ( a :> System.Reflection.Assembly)
2838
+
2839
+ errorsAndWarnings, result, assemblyOpt
2840
+
2841
+ member ic.CompileToDynamicAssembly ( asts : ParsedInput list , assemblyName : string , dependencies : string list , execute : ( TextWriter * TextWriter ) option , ? debug : bool , ? noframework : bool ) =
2842
+ CompileHelpers.setOutputStreams execute
2843
+
2844
+ // References used to capture the results of compilation
2845
+ let tcImportsRef = ref ( None: TcImports option)
2846
+ let assemblyBuilderRef = ref None
2847
+ let tcImportsCapture = Some ( fun tcImports -> tcImportsRef := Some tcImports)
2848
+
2849
+ let debugInfo = defaultArg debug false
2850
+ let noframework = defaultArg noframework false
2851
+ let location = Path.Combine( Path.GetTempPath(), " test" + string( hash assemblyName))
2852
+ try Directory.CreateDirectory( location) |> ignore with _ -> ()
2853
+
2854
+ let outFile = Path.Combine( location, assemblyName + " .dll" )
2855
+
2856
+ // Function to generate and store the results of compilation
2857
+ let dynamicAssemblyCreator = Some ( CompileHelpers.dynamicAssemblyCreator ( debugInfo, tcImportsRef, execute, assemblyBuilderRef))
2858
+
2859
+ // Perform the compilation, given the above capturing function.
2860
+ let errorsAndWarnings , result =
2861
+ CompileHelpers.compileFromAsts ( asts, assemblyName, outFile, dependencies, noframework, None, Some execute.IsSome, tcImportsCapture, dynamicAssemblyCreator)
2862
+
2863
+ // Retrieve and return the results
2864
+ let assemblyOpt =
2865
+ match assemblyBuilderRef.Value with
2866
+ | None -> None
2867
+ | Some a -> Some ( a :> System.Reflection.Assembly)
2868
+
2869
+ errorsAndWarnings, result, assemblyOpt
2870
+
2700
2871
/// This function is called when the entire environment is known to have changed for reasons not encoded in the ProjectOptions of any project/compilation.
2701
2872
/// For example, the type provider approvals file may have changed.
2702
2873
member ic.InvalidateAll () =
0 commit comments