Skip to content

Commit 32c9c2a

Browse files
author
Dave Thomas
committed
Move compiling API's to shared module
Add compiling API’s to SourceCodeServices
1 parent 4b256d1 commit 32c9c2a

File tree

1 file changed

+170
-0
lines changed

1 file changed

+170
-0
lines changed

src/fsharp/vs/service.fs

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ open Microsoft.FSharp.Compiler.AbstractIL.Internal.Library
2323
open Microsoft.FSharp.Compiler.AccessibilityLogic
2424
open Microsoft.FSharp.Compiler.Ast
2525
open Microsoft.FSharp.Compiler.CompileOps
26+
open Microsoft.FSharp.Compiler.Driver
2627
open Microsoft.FSharp.Compiler.ErrorLogger
2728
open Microsoft.FSharp.Compiler.Lib
2829
open Microsoft.FSharp.Compiler.MSBuildResolver
@@ -2123,6 +2124,115 @@ module Helpers =
21232124
let AreSubsumable3((fileName1:string,_,o1:FSharpProjectOptions),(fileName2:string,_,o2:FSharpProjectOptions)) =
21242125
(fileName1 = fileName2)
21252126
&& FSharpProjectOptions.AreSubsumable(o1,o2)
2127+
2128+
module CompileHelpers =
2129+
let mkCompilationErorHandlers() =
2130+
let errors = ResizeArray<_>()
2131+
2132+
let errorSink warn exn =
2133+
let mainError,relatedErrors = SplitRelatedErrors exn
2134+
let oneError trim e = errors.Add(ErrorInfo.CreateFromException (e, warn, trim, Range.range0))
2135+
oneError false mainError
2136+
List.iter (oneError true) relatedErrors
2137+
2138+
let errorLogger =
2139+
{ new ErrorLogger("CompileAPI") with
2140+
member x.WarnSinkImpl(exn) = errorSink true exn
2141+
member x.ErrorSinkImpl(exn) = errorSink false exn
2142+
member x.ErrorCount = errors |> Seq.filter (fun e -> e.Severity = FSharpErrorSeverity.Error) |> Seq.length }
2143+
2144+
let loggerProvider =
2145+
{ new ErrorLoggerProvider() with
2146+
member x.CreateErrorLoggerThatQuitsAfterMaxErrors(_tcConfigBuilder, _exiter) = errorLogger }
2147+
errors, errorLogger, loggerProvider
2148+
2149+
let tryCompile errorLogger f =
2150+
use unwindParsePhase = PushThreadBuildPhaseUntilUnwind (BuildPhase.Parse)
2151+
use unwindEL_2 = PushErrorLoggerPhaseUntilUnwind (fun _ -> errorLogger)
2152+
let exiter = { new Exiter with member x.Exit n = raise StopProcessing }
2153+
try
2154+
f exiter
2155+
0
2156+
with e ->
2157+
stopProcessingRecovery e Range.range0
2158+
1
2159+
2160+
/// Compile using the given flags. Source files names are resolved via the FileSystem API. The output file must be given by a -o flag.
2161+
let compileFromArgs (argv: string[], tcImportsCapture, dynamicAssemblyCreator) =
2162+
2163+
let errors, errorLogger, loggerProvider = mkCompilationErorHandlers()
2164+
let result =
2165+
tryCompile errorLogger (fun exiter ->
2166+
mainCompile (argv, (*bannerAlreadyPrinted*)true, (*openBinariesInMemory*)true, exiter, loggerProvider, tcImportsCapture, dynamicAssemblyCreator) )
2167+
2168+
errors.ToArray(), result
2169+
2170+
let compileFromAsts (asts, assemblyName, outFile, dependencies, noframework, pdbFile, executable, tcImportsCapture, dynamicAssemblyCreator) =
2171+
2172+
let errors, errorLogger, loggerProvider = mkCompilationErorHandlers()
2173+
2174+
let executable = defaultArg executable true
2175+
let target = if executable then CompilerTarget.ConsoleExe else CompilerTarget.Dll
2176+
2177+
let result =
2178+
tryCompile errorLogger (fun exiter ->
2179+
compileOfAst ((*openBinariesInMemory=*)true, assemblyName, target, outFile, pdbFile, dependencies, noframework, exiter, loggerProvider, asts, tcImportsCapture, dynamicAssemblyCreator))
2180+
2181+
errors.ToArray(), result
2182+
2183+
let dynamicAssemblyCreator (debugInfo: bool, tcImportsRef: TcImports option ref, execute: _ option, assemblyBuilderRef: _ option ref) (_tcConfig,ilGlobals,_errorLogger,outfile,_pdbfile,ilxMainModule,_signingInfo) =
2184+
2185+
// Create an assembly builder
2186+
let assemblyName = System.Reflection.AssemblyName(System.IO.Path.GetFileNameWithoutExtension outfile)
2187+
let flags = System.Reflection.Emit.AssemblyBuilderAccess.Run
2188+
#if FX_NO_APP_DOMAINS
2189+
let assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, flags)
2190+
let moduleBuilder = assemblyBuilder.DefineDynamicModule("IncrementalModule")
2191+
#else
2192+
let assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, flags)
2193+
let moduleBuilder = assemblyBuilder.DefineDynamicModule("IncrementalModule", debugInfo)
2194+
#endif
2195+
// Omit resources in dynamic assemblies, because the module builder is constructed without a filename the module
2196+
// is tagged as transient and as such DefineManifestResource will throw an invalid operation if resources are present.
2197+
//
2198+
// Also, the dynamic assembly creator can't currently handle types called "<Module>" from statically linked assemblies.
2199+
let ilxMainModule =
2200+
{ ilxMainModule with
2201+
TypeDefs = ilxMainModule.TypeDefs.AsList |> List.filter (fun td -> not (isTypeNameForGlobalFunctions td.Name)) |> mkILTypeDefs
2202+
Resources=mkILResources [] }
2203+
2204+
// The function used to resolve typees while emitting the code
2205+
let assemblyResolver s =
2206+
match tcImportsRef.Value.Value.TryFindExistingFullyQualifiedPathFromAssemblyRef s with
2207+
| Some res -> Some (Choice1Of2 res)
2208+
| None -> None
2209+
2210+
// Emit the code
2211+
let _emEnv,execs = ILRuntimeWriter.emitModuleFragment(ilGlobals, ILRuntimeWriter.emEnv0, assemblyBuilder, moduleBuilder, ilxMainModule, debugInfo, assemblyResolver)
2212+
2213+
// Execute the top-level initialization, if requested
2214+
if execute.IsSome then
2215+
for exec in execs do
2216+
match exec() with
2217+
| None -> ()
2218+
| Some exn -> raise exn
2219+
2220+
// Register the reflected definitions for the dynamically generated assembly
2221+
for resource in ilxMainModule.Resources.AsList do
2222+
if IsReflectedDefinitionsResource resource then
2223+
Quotations.Expr.RegisterReflectedDefinitions(assemblyBuilder, moduleBuilder.Name, resource.Bytes)
2224+
2225+
// Save the result
2226+
assemblyBuilderRef := Some assemblyBuilder
2227+
2228+
let setOutputStreams execute =
2229+
// Set the output streams, if requested
2230+
match execute with
2231+
| Some (writer,error) ->
2232+
System.Console.SetOut writer
2233+
System.Console.SetError error
2234+
| None -> ()
2235+
21262236

21272237
// There is only one instance of this type, held in FSharpChecker
21282238
type BackgroundCompiler(projectCacheSize, keepAssemblyContents, keepAllBackgroundResolutions) as self =
@@ -2697,6 +2807,66 @@ type FSharpChecker(projectCacheSize, keepAssemblyContents, keepAllBackgroundReso
26972807

26982808
member ic.TryGetRecentTypeCheckResultsForFile(filename, options, ?source) = ic.TryGetRecentCheckResultsForFile(filename,options,?source=source)
26992809

2810+
member ic.Compile(argv: string[]) =
2811+
CompileHelpers.compileFromArgs (argv, None, None)
2812+
2813+
member ic.Compile (ast:ParsedInput list, assemblyName:string, outFile:string, dependencies:string list, ?pdbFile:string, ?executable:bool, ?noframework:bool) =
2814+
let noframework = defaultArg noframework false
2815+
CompileHelpers.compileFromAsts (ast, assemblyName, outFile, dependencies, noframework, pdbFile, executable, None, None)
2816+
2817+
member ic.CompileToDynamicAssembly (otherFlags: string[], execute: (TextWriter * TextWriter) option) =
2818+
CompileHelpers.setOutputStreams execute
2819+
2820+
// References used to capture the results of compilation
2821+
let tcImportsRef = ref (None: TcImports option)
2822+
let assemblyBuilderRef = ref None
2823+
let tcImportsCapture = Some (fun tcImports -> tcImportsRef := Some tcImports)
2824+
2825+
// Function to generate and store the results of compilation
2826+
let debugInfo = otherFlags |> Array.exists (fun arg -> arg = "-g" || arg = "--debug:+" || arg = "/debug:+")
2827+
let dynamicAssemblyCreator = Some (CompileHelpers.dynamicAssemblyCreator (debugInfo, tcImportsRef, execute, assemblyBuilderRef))
2828+
2829+
// Perform the compilation, given the above capturing function.
2830+
let errorsAndWarnings, result = CompileHelpers.compileFromArgs (otherFlags, tcImportsCapture, dynamicAssemblyCreator)
2831+
2832+
// Retrieve and return the results
2833+
let assemblyOpt =
2834+
match assemblyBuilderRef.Value with
2835+
| None -> None
2836+
| Some a -> Some (a :> System.Reflection.Assembly)
2837+
2838+
errorsAndWarnings, result, assemblyOpt
2839+
2840+
member ic.CompileToDynamicAssembly (asts:ParsedInput list, assemblyName:string, dependencies:string list, execute: (TextWriter * TextWriter) option, ?debug:bool, ?noframework:bool) =
2841+
CompileHelpers.setOutputStreams execute
2842+
2843+
// References used to capture the results of compilation
2844+
let tcImportsRef = ref (None: TcImports option)
2845+
let assemblyBuilderRef = ref None
2846+
let tcImportsCapture = Some (fun tcImports -> tcImportsRef := Some tcImports)
2847+
2848+
let debugInfo = defaultArg debug false
2849+
let noframework = defaultArg noframework false
2850+
let location = Path.Combine(Path.GetTempPath(),"test"+string(hash assemblyName))
2851+
try Directory.CreateDirectory(location) |> ignore with _ -> ()
2852+
2853+
let outFile = Path.Combine(location, assemblyName + ".dll")
2854+
2855+
// Function to generate and store the results of compilation
2856+
let dynamicAssemblyCreator = Some (CompileHelpers.dynamicAssemblyCreator (debugInfo, tcImportsRef, execute, assemblyBuilderRef))
2857+
2858+
// Perform the compilation, given the above capturing function.
2859+
let errorsAndWarnings, result =
2860+
CompileHelpers.compileFromAsts (asts, assemblyName, outFile, dependencies, noframework, None, Some execute.IsSome, tcImportsCapture, dynamicAssemblyCreator)
2861+
2862+
// Retrieve and return the results
2863+
let assemblyOpt =
2864+
match assemblyBuilderRef.Value with
2865+
| None -> None
2866+
| Some a -> Some (a :> System.Reflection.Assembly)
2867+
2868+
errorsAndWarnings, result, assemblyOpt
2869+
27002870
/// This function is called when the entire environment is known to have changed for reasons not encoded in the ProjectOptions of any project/compilation.
27012871
/// For example, the type provider approvals file may have changed.
27022872
member ic.InvalidateAll() =

0 commit comments

Comments
 (0)