public void Test(string input, bool isValid) { var temp1 = Path.GetTempFileName(); var fn1 = Path.ChangeExtension(temp1, ".fsx"); File.WriteAllText(fn1, input); var fn2 = Path.ChangeExtension(temp1, ".dll"); FSharpChecker checker = FSharpChecker.Create(FSharpOption <int> .None, FSharpOption <bool> .None, FSharpOption <bool> .None, FSharpOption <ReferenceResolver.Resolver> .None, FSharpOption <FSharpFunc <Tuple <string, DateTime>, FSharpOption <Tuple <object, IntPtr, int> > > > .None, FSharpOption <bool> .None); var result = checker.CompileToDynamicAssembly(new[] { "-o", fn2, "-a", fn1 }, FSharpOption <Tuple <TextWriter, TextWriter> > .None, FSharpOption <string> .None); var t = Microsoft.FSharp.Control.FSharpAsync.RunSynchronously(result, FSharpOption <int> .None, FSharpOption <CancellationToken> .None); if (isValid) { t.Item1.Should().BeNullOrEmpty(); } else { t.Item1.Should().NotBeNullOrEmpty(); } }
public FSharpSession(string text, MirrorSharpFSharpOptions options) { _text = text; Checker = FSharpChecker.Create( null, keepAssemblyContents: true, keepAllBackgroundResolutions: true, legacyReferenceResolver: null ); AssemblyReferencePaths = options.AssemblyReferencePaths; AssemblyReferencePathsAsFSharpList = ToFSharpList(options.AssemblyReferencePaths); ProjectOptions = new FSharpProjectOptions( "_", sourceFiles: new[] { "_.fs" }, otherOptions: ConvertToOtherOptions(options), referencedProjects: Array.Empty <Tuple <string, FSharpProjectOptions> >(), isIncompleteTypeCheckEnvironment: true, useScriptResolutionRules: false, loadTime: DateTime.Now, unresolvedReferences: null, originalLoadReferences: FSharpList <Tuple <Range.range, string> > .Empty, extraProjectInfo: null, stamp: null ); }
private FsharpFolderComposite FindProjectFilesUsingBuildalyzer(IAnalyzerResult analyzerResult) { var inputFiles = new FsharpFolderComposite(); var projectUnderTestDir = Path.GetDirectoryName(analyzerResult.ProjectFilePath); var projectRoot = Path.GetDirectoryName(projectUnderTestDir); var rootFolderComposite = new FsharpFolderComposite() { FullPath = projectRoot, RelativePath = string.Empty }; var cache = new Dictionary <string, FsharpFolderComposite> { [string.Empty] = rootFolderComposite }; // Save cache in a singleton so we can use it in other parts of the project FolderCompositeCache <FsharpFolderComposite> .Instance.Cache = cache; inputFiles.Add(rootFolderComposite); var fSharpChecker = FSharpChecker.Create(projectCacheSize: null, keepAssemblyContents: null, keepAllBackgroundResolutions: null, legacyReferenceResolver: null, tryGetMetadataSnapshot: null, suggestNamesForErrors: null, keepAllBackgroundSymbolUses: null, enableBackgroundItemKeyStoreAndSemanticClassification: null); foreach (var sourceFile in analyzerResult.SourceFiles) { // Skip xamarin UI generated files if (sourceFile.EndsWith(".xaml.cs")) { continue; } var relativePath = Path.GetRelativePath(projectUnderTestDir, sourceFile); var folderComposite = GetOrBuildFolderComposite(cache, Path.GetDirectoryName(relativePath), projectUnderTestDir, projectRoot, inputFiles); var fileName = Path.GetFileName(sourceFile); var file = new FsharpFileLeaf() { SourceCode = FileSystem.File.ReadAllText(sourceFile), RelativePath = FileSystem.Path.Combine(folderComposite.RelativePath, fileName), FullPath = sourceFile }; // Get the syntax tree for the source file Tuple <FSharpProjectOptions, FSharpList <FSharpErrorInfo> > fSharpOptions = FSharpAsync.RunSynchronously(fSharpChecker.GetProjectOptionsFromScript(filename: file.FullPath, sourceText: SourceText.ofString(file.SourceCode), previewEnabled: null, loadedTimeStamp: null, otherFlags: null, useFsiAuxLib: null, useSdkRefs: null, assumeDotNetFramework: null, extraProjectInfo: null, optionsStamp: null, userOpName: null), timeout: null, cancellationToken: null); FSharpParseFileResults result = FSharpAsync.RunSynchronously(fSharpChecker.ParseFile(fileName, SourceText.ofString(file.SourceCode), fSharpChecker.GetParsingOptionsFromProjectOptions(fSharpOptions.Item1).Item1, userOpName: null), timeout: null, cancellationToken: null); if (result.ParseTree.Value.IsImplFile) { var syntaxTree = (ImplFile)result.ParseTree.Value; file.SyntaxTree = syntaxTree; folderComposite.Add(file); } else { var message = $"Cannot make Fsharp SyntaxTree from .fsi filetype (SyntaxTree.ParsedImplFileInput class wanted)"; throw new InputException(message); } } return(inputFiles); }
private (bool, FSharpErrorInfo[]) TryCompilation(FSharpChecker checker, FSharpList <ParsedInput> trees, List <string> pathlist, FSharpList <string> dependencies) { Tuple <FSharpErrorInfo[], int> result = FSharpAsync.RunSynchronously( checker.Compile( trees, AssemblyName, pathlist.First(), dependencies, pdbFile: null, executable: false, noframework: true, userOpName: null), timeout: null, cancellationToken: null); return(result.Item2 == 0, result.Item1); }
internal FSharpAssembly(FSharpCompilerOptionsBuilder builder, FSharpChecker checker) { var args = builder.ToArray(); var task = checker.CompileToDynamicAssembly( args, FSharpOption <Tuple <TextWriter, TextWriter> > .None, FSharpOption <string> .None); var result = FSharpAsync.RunSynchronously(task, default, default);
public CompilingProcessResult Compile(IEnumerable <ParsedInput> syntaxTrees, bool devMode) { var analyzerResult = _input.ProjectInfo.ProjectUnderTestAnalyzerResult; FSharpList <ParsedInput> trees = ListModule.OfSeq(syntaxTrees.Reverse()); FSharpList <string> dependencies = ListModule.OfSeq(analyzerResult.References); //we need a checker if we want to compile var checker = FSharpChecker.Create(projectCacheSize: null, keepAssemblyContents: null, keepAllBackgroundResolutions: null, legacyReferenceResolver: null, tryGetMetadataSnapshot: null, suggestNamesForErrors: null, keepAllBackgroundSymbolUses: null, enableBackgroundItemKeyStoreAndSemanticClassification: null); var pathlist = new List <string>(); var pdblist = new List <string>(); foreach (var testProject in _input.ProjectInfo.TestProjectAnalyzerResults) { var injectionPath = _input.ProjectInfo.GetInjectionFilePath(testProject); if (!_fileSystem.Directory.Exists(injectionPath.Substring(0, injectionPath.LastIndexOf('\\')))) { _fileSystem.Directory.CreateDirectory(injectionPath); } pathlist.Add(Path.Combine(injectionPath, _input.ProjectInfo.GetInjectionFilePath(testProject))); pdblist.Add(Path.Combine(injectionPath, _input.ProjectInfo.ProjectUnderTestAnalyzerResult.GetSymbolFileName())); _logger.LogDebug("Injected the mutated assembly file into {0}", injectionPath); } if (!pathlist.Any()) { throw new GeneralStrykerException("Could not find project under test."); } //rollback still needs to be implemented RollbackProcessResult rollbackProcessResult = null; (var compilationSucces, FSharpErrorInfo[] errorinfo) = TryCompilation(checker, trees, pathlist, dependencies); if (compilationSucces) { //we return if compiled succesfully //it is however not used as this is the end of the current F# implementation return(new CompilingProcessResult() { Success = compilationSucces, RollbackResult = rollbackProcessResult }); } // compiling failed _logger.LogError("Failed to restore the project to a buildable state. Please report the issue. Stryker can not proceed further"); throw new CompilationException("Failed to restore build able state."); }
/// <summary> /// Recursively scans the given directory for files to mutate /// </summary> private FsharpFolderComposite FindInputFiles(string path, string projectUnderTestDir, string parentFolder) { var lastPathComponent = Path.GetFileName(path); var folderComposite = new FsharpFolderComposite { FullPath = Path.GetFullPath(path), RelativePath = Path.Combine(parentFolder, lastPathComponent), }; foreach (var folder in FileSystem.Directory.EnumerateDirectories(folderComposite.FullPath).Where(x => !_foldersToExclude.Contains(Path.GetFileName(x)))) { folderComposite.Add(FindInputFiles(folder, projectUnderTestDir, folderComposite.RelativePath)); } var fSharpChecker = FSharpChecker.Create(projectCacheSize: null, keepAssemblyContents: null, keepAllBackgroundResolutions: null, legacyReferenceResolver: null, tryGetMetadataSnapshot: null, suggestNamesForErrors: null, keepAllBackgroundSymbolUses: null, enableBackgroundItemKeyStoreAndSemanticClassification: null); foreach (var file in FileSystem.Directory.GetFiles(folderComposite.FullPath, "*.fs", SearchOption.TopDirectoryOnly)) { var fileName = Path.GetFileName(file); var fileLeaf = new FsharpFileLeaf() { SourceCode = FileSystem.File.ReadAllText(file), RelativePath = Path.Combine(folderComposite.RelativePath, fileName), FullPath = file, }; // Get the syntax tree for the source file Tuple <FSharpProjectOptions, FSharpList <FSharpErrorInfo> > fsharpoptions = FSharpAsync.RunSynchronously(fSharpChecker.GetProjectOptionsFromScript(fileLeaf.FullPath, SourceText.ofString(fileLeaf.SourceCode), previewEnabled: null, loadedTimeStamp: null, otherFlags: null, useFsiAuxLib: null, useSdkRefs: null, assumeDotNetFramework: null, extraProjectInfo: null, optionsStamp: null, userOpName: null), timeout: null, cancellationToken: null); FSharpParseFileResults result = FSharpAsync.RunSynchronously(fSharpChecker.ParseFile(fileLeaf.FullPath, SourceText.ofString(fileLeaf.SourceCode), fSharpChecker.GetParsingOptionsFromProjectOptions(fsharpoptions.Item1).Item1, userOpName: null), timeout: null, cancellationToken: null); if (result.ParseTree.Value.IsImplFile) { var syntaxTree = (ImplFile)result.ParseTree.Value; fileLeaf.SyntaxTree = syntaxTree; folderComposite.Add(fileLeaf); } else { var message = $"Cannot make Fsharp SyntaxTree from .fsi filetype (SyntaxTree.ParsedImplFileInput class wanted)"; throw new InputException(message); } } return(folderComposite); }
protected override async Task Compile( string code, string[] references) { var sourcePath = Path.GetTempFileName() + ".fs"; File.WriteAllText(sourcePath, code); var compilerArgs = new[] { "fsc", sourcePath, $"--out:{FileName}", $"--pdb:{PdbName}", $"--lib:\"{BasePath}\"", "--debug", "--target:library" } .Concat(GetStandardReferences().Concat(references).Select(r => $"--reference:{r}")) .ToArray(); var checker = FSharpChecker.Create( FSharpOption <int> .None, FSharpOption <bool> .None, FSharpOption <bool> .None, #pragma warning disable CS0618 FSharpOption <LegacyReferenceResolver> .None, #pragma warning restore CS0618 FSharpOption <FSharpFunc <Tuple <string, DateTime>, FSharpOption <Tuple <object, IntPtr, int> > > > .None, FSharpOption <bool> .None, FSharpOption <bool> .None, FSharpOption <bool> .None, FSharpOption <bool> .None ); var resultFSharpAsync = checker.Compile(compilerArgs, FSharpOption <string> .None); var result = await FSharpAsync.StartAsTask(resultFSharpAsync, FSharpOption <TaskCreationOptions> .None, FSharpOption <CancellationToken> .None); if (result.Item2 != 0) { var errors = result .Item1 .Select(e => $"{e.FileName}({e.StartLine},{e.StartColumn}): {(e.Severity.IsError ? "error" : "warning")} {e.ErrorNumber}: {e.Message}"); throw new InvalidOperationException($"Compilation Failed:{Environment.NewLine}{string.Join(Environment.NewLine, errors)}"); } }
public static Assembly Compile(string source) { var fileHelpersAssembly = typeof(EngineBase).Assembly; var checker = FSharpChecker.Create( FSharpOption <int> .None, FSharpOption <bool> .None, FSharpOption <bool> .None, FSharpOption <LegacyReferenceResolver> .None, FSharpOption <FSharpFunc <Tuple <string, DateTime>, FSharpOption <Tuple <object, IntPtr, int> > > > .None, FSharpOption <bool> .None, FSharpOption <bool> .None, FSharpOption <bool> .None, FSharpOption <bool> .None); var file = Path.GetTempFileName(); File.WriteAllText(file + ".fs", source); var action = checker.CompileToDynamicAssembly( new[] { "-o", file + ".dll", "-a", file + ".fs", "--reference:" + fileHelpersAssembly.Location }, FSharpOption <Tuple <TextWriter, TextWriter> > .None, FSharpOption <string> .None); var compileResult = FSharpAsync .StartAsTask(action, FSharpOption <TaskCreationOptions> .None, FSharpOption <CancellationToken> .None) .Result; var exitCode = compileResult.Item2; var compilationErrors = compileResult.Item1; if (compilationErrors.Any() && exitCode != 0) { var errors = new StringBuilder(); foreach (var error in compilationErrors) { errors.AppendLine(error.ToString()); } throw new InvalidOperationException($"Cannot compile fsharp: {errors}"); } return(compileResult.Item3.Value); }
static void Main(string[] args) { FSharpChecker fSharpChecker = FSharpChecker.Create(null, null, null, null, null, null, null, null); var fullPath = Path.GetFullPath("..\\..\\..\\..\\..\\boolMutateTestApp\\boolMutateTestApp\\Program.fs"); var sourceCode = File.ReadAllText(fullPath); Tuple <FSharpProjectOptions, FSharpList <FSharpErrorInfo> > fsharpoptions = FSharpAsync.RunSynchronously(fSharpChecker.GetProjectOptionsFromScript(fullPath, SourceText.ofString(sourceCode), null, null, null, null, null, null, null, null, null), null, null); FSharpParseFileResults result = FSharpAsync.RunSynchronously(fSharpChecker.ParseFile(fullPath, SourceText.ofString(sourceCode), fSharpChecker.GetParsingOptionsFromProjectOptions(fsharpoptions.Item1).Item1, null), null, null); var syntaxTree = result.ParseTree; if (syntaxTree.Value.IsImplFile) { var test = ((ImplFile)syntaxTree.Value).Item; VisitModulesAndNamespaces(test.modules); } else { Console.WriteLine("F# Interface file (*.fsi) not supported."); } //fSharpChecker.CompileToDynamicAssembly() // FSharpAsync<Tuple<FSharpErrorInfo[], int>> Compile(FSharpList<SyntaxTree.ParsedInput> ast, string assemblyName, string outFile, FSharpList<string> dependencies, [OptionalArgument] FSharpOption<string> pdbFile, [OptionalArgument] FSharpOption<bool> executable, [OptionalArgument] FSharpOption<bool> noframework, [OptionalArgument] FSharpOption<string> userOpName); }
public Task <IDotNetCompilation> GetFunctionCompilationAsync(FunctionMetadata functionMetadata) { // First use the C# compiler to resolve references, to get consistency with the C# Azure Functions programming model // Add the #r statements from the .fsx file to the resolver source string scriptSource = GetFunctionSource(functionMetadata); var resolverSourceBuilder = new StringBuilder(); using (StringReader sr = new StringReader(scriptSource)) { string line; while ((line = sr.ReadLine()) != null) { if (_hashRRegex.IsMatch(line)) { resolverSourceBuilder.AppendLine(line); } } } resolverSourceBuilder.AppendLine("using System;"); var resolverSource = resolverSourceBuilder.ToString(); Script <object> script = CodeAnalysis.CSharp.Scripting.CSharpScript.Create(resolverSource, options: _metadataResolver.CreateScriptOptions(), assemblyLoader: AssemblyLoader.Value); var compiler = new SimpleSourceCodeServices(msbuildEnabled: FSharpOption <bool> .Some(false)); FSharpErrorInfo[] errors = null; byte[] assemblyBytes = null; byte[] pdbBytes = null; string scriptPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); Directory.CreateDirectory(scriptPath); string scriptFilePath = Path.Combine(scriptPath, Path.GetFileName(functionMetadata.ScriptFile)); var assemblyName = Utility.GetAssemblyNameFromMetadata(functionMetadata, Guid.NewGuid().ToString()); var assemblyFileName = Path.Combine(scriptPath, assemblyName + ".dll"); var pdbName = Path.ChangeExtension(assemblyFileName, PlatformHelper.IsWindows ? "pdb" : "dll.mdb"); try { var scriptFileBuilder = new StringBuilder(); // Write an adjusted version of the script file, prefixing some 'open' declarations foreach (string import in script.Options.Imports) { scriptFileBuilder.AppendLine("open " + import); } // Suppress undesirable warnings scriptFileBuilder.AppendLine("#nowarn \"988\""); // Set the line to match the original script scriptFileBuilder.AppendLine("# 0 @\"" + functionMetadata.ScriptFile + "\""); // Add our original script scriptFileBuilder.AppendLine(scriptSource); File.WriteAllText(scriptFilePath, scriptFileBuilder.ToString()); var otherFlags = new List <string>(); otherFlags.Add("fsc.exe"); // The --noframework option is used because we will shortly add references to mscorlib and FSharp.Core // as dictated by the C# reference resolver, and F# doesn't like getting multiple references to those. otherFlags.Add("--noframework"); var references = script.GetCompilation().References .Where(m => !(m is UnresolvedMetadataReference)) .Select(m => "-r:" + m.Display) .Distinct(new FileNameEqualityComparer()); // Add the references as reported by the metadata resolver. otherFlags.AddRange(references); if (_optimizationLevel == OptimizationLevel.Debug) { otherFlags.Add("--optimize-"); otherFlags.Add("--debug+"); otherFlags.Add("--tailcalls-"); } // TODO: FACAVAL verify if this still applies to core if (!PlatformHelper.IsWindows) { var monoDir = Path.GetDirectoryName(typeof(string).Assembly.Location); var facadesDir = Path.Combine(monoDir, "Facades"); otherFlags.Add("--lib:" + facadesDir); } // If we have a private assembly folder, make sure the compiler uses it to resolve dependencies string privateAssembliesFolder = Path.Combine(Path.GetDirectoryName(functionMetadata.ScriptFile), DotNetConstants.PrivateAssembliesFolderName); if (Directory.Exists(privateAssembliesFolder)) { otherFlags.Add("--lib:" + Path.Combine(Path.GetDirectoryName(functionMetadata.ScriptFile), DotNetConstants.PrivateAssembliesFolderName)); } otherFlags.Add("--out:" + assemblyFileName); // Get the #load closure FSharpChecker checker = FSharpChecker.Create(null, null, null, msbuildEnabled: FSharpOption <bool> .Some(false)); var loadFileOptionsAsync = checker.GetProjectOptionsFromScript( filename: functionMetadata.ScriptFile, source: scriptSource, loadedTimeStamp: null, otherFlags: null, useFsiAuxLib: null, assumeDotNetFramework: null, extraProjectInfo: null); var loadFileOptions = FSharp.Control.FSharpAsync.RunSynchronously(loadFileOptionsAsync, null, null); foreach (var loadedFileName in loadFileOptions.Item1.ProjectFileNames) { if (Path.GetFileName(loadedFileName) != Path.GetFileName(functionMetadata.ScriptFile)) { otherFlags.Add(loadedFileName); } } // Add the (adjusted) script file itself otherFlags.Add(scriptFilePath); // Compile the script to a static assembly var result = compiler.Compile(otherFlags.ToArray()); errors = result.Item1; var code = result.Item2; if (code == 0) { assemblyBytes = File.ReadAllBytes(assemblyFileName); pdbBytes = null; if (File.Exists(pdbName)) { pdbBytes = File.ReadAllBytes(pdbName); } } else { string message = $"F# compilation failed with arguments: {string.Join(" ", otherFlags)}"; _logger.LogDebug(message); } } finally { DeleteDirectoryAsync(scriptPath, recursive: true) .ContinueWith( t => t.Exception.Handle(e => { string message = $"Unable to delete F# compilation file: {e.ToString()}"; _logger.LogWarning(message); return(true); }), TaskContinuationOptions.OnlyOnFaulted); } return(Task.FromResult <IDotNetCompilation>(new FSharpCompilation(errors, assemblyBytes, pdbBytes))); }
public ICompilation GetFunctionCompilation(FunctionMetadata functionMetadata) { // TODO: Get debug flag from context. Set to true for now. bool debug = true; // First use the C# compiler to resolve references, to get consistenct with the C# Azure Functions programming model Script <object> script = CodeAnalysis.CSharp.Scripting.CSharpScript.Create("using System;", options: _metadataResolver.CreateScriptOptions(), assemblyLoader: AssemblyLoader.Value); Compilation compilation = script.GetCompilation(); var compiler = new SimpleSourceCodeServices(); FSharpErrorInfo[] errors = null; FSharpOption <Assembly> assemblyOption = null; string scriptFilePath = Path.Combine(Path.GetTempPath(), Path.GetFileName(functionMetadata.ScriptFile)); try { var scriptFileBuilder = new StringBuilder(); // Write an adjusted version of the script file, prefixing some 'open' decarations foreach (string import in script.Options.Imports) { scriptFileBuilder.AppendLine("open " + import); } // Suppress undesirable warnings scriptFileBuilder.AppendLine("#nowarn \"988\""); // Set the line to match the original script scriptFileBuilder.AppendLine("# 0 @\"" + functionMetadata.ScriptFile + "\""); // Add our original script string scriptSource = GetFunctionSource(functionMetadata); scriptFileBuilder.AppendLine(scriptSource); File.WriteAllText(scriptFilePath, scriptFileBuilder.ToString()); var otherFlags = new List <string>(); // For some reason CompileToDynamicAssembly wants "fsc.exe" as the first arg, it is ignored. otherFlags.Add("fsc.exe"); // The --noframework option is used because we will shortly add references to mscorlib and FSharp.Core // as dictated by the C# reference resolver, and F# doesn't like getting multiple references to those. otherFlags.Add("--noframework"); // Add the references as reported by the C# reference resolver. foreach (var mdr in compilation.References) { if (!mdr.Display.Contains("Unresolved ")) { otherFlags.Add("-r:" + mdr.Display); } } // Above we have used the C# reference resolver to get the basic set of DLL references for the compilation. // // However F# has its own view on default options. For scripts these should include the // following framework facade references. otherFlags.Add("-r:System.Linq.dll"); // System.Linq.Expressions.Expression<T> otherFlags.Add("-r:System.Reflection.dll"); // System.Reflection.ParameterInfo otherFlags.Add("-r:System.Linq.Expressions.dll"); // System.Linq.IQueryable<T> otherFlags.Add("-r:System.Threading.Tasks.dll"); // valuetype [System.Threading.Tasks]System.Threading.CancellationToken otherFlags.Add("-r:System.IO.dll"); // System.IO.TextWriter otherFlags.Add("-r:System.Net.Requests.dll"); // System.Net.WebResponse etc. otherFlags.Add("-r:System.Collections.dll"); // System.Collections.Generic.List<T> otherFlags.Add("-r:System.Runtime.Numerics.dll"); // BigInteger otherFlags.Add("-r:System.Threading.dll"); // OperationCanceledException otherFlags.Add("-r:System.Runtime.dll"); otherFlags.Add("-r:System.Numerics.dll"); if (debug) { otherFlags.Add("--optimize-"); otherFlags.Add("--debug+"); otherFlags.Add("--tailcalls-"); } // This output DLL isn't actually written by FSharp.Compiler.Service when CompileToDynamicAssembly is called otherFlags.Add("--out:" + Path.ChangeExtension(Path.GetTempFileName(), "dll")); // Get the #load closure var loadFileOptionsAsync = FSharpChecker.Create().GetProjectOptionsFromScript(functionMetadata.ScriptFile, scriptSource, null, null, null); var loadFileOptions = FSharp.Control.FSharpAsync.RunSynchronously(loadFileOptionsAsync, null, null); foreach (var loadedFileName in loadFileOptions.ProjectFileNames) { if (Path.GetFileName(loadedFileName) != Path.GetFileName(functionMetadata.ScriptFile)) { otherFlags.Add(loadedFileName); } } // Add the (adjusted) script file itself otherFlags.Add(scriptFilePath); // Make the output streams (unused) var outStreams = FSharpOption <Tuple <TextWriter, TextWriter> > .Some(new Tuple <TextWriter, TextWriter>(Console.Out, Console.Error)); // Compile the script to a dynamic assembly var result = compiler.CompileToDynamicAssembly(otherFlags: otherFlags.ToArray(), execute: outStreams); errors = result.Item1; assemblyOption = result.Item3; } finally { File.Delete(scriptFilePath); } return(new FSharpCompilation(errors, assemblyOption)); }
void CompileToExe(string outputExe, string src, bool optimize = false, string target = "exe") { var checker = FSharpChecker.Create( FSharpOption <int> .None, FSharpOption <bool> .None, FSharpOption <bool> .None, FSharpOption <FSharp.Compiler.ReferenceResolver.Resolver> .None, FSharpOption <FSharpFunc <Tuple <string, DateTime>, FSharpOption <Tuple <object, IntPtr, int> > > > .None, FSharpOption <bool> .None, FSharpOption <bool> .None, FSharpOption <bool> .None); var tempSource = Environment.GetEnvironmentVariable("TEMP") + "/temp.fs"; var args = new List <string> { "fsc.exe", "--nologo", "--crossoptimize" + (optimize ? "+" : "-"), "--optimize" + (optimize ? "+" : "-"), "-o", outputExe, "--target:" + target }; if (optimize) { args.Add("--standalone"); } var lines = new List <string>(); var loads = new List <string>(); var libDirs = new List <string>(); // 提取#r、#I和#load using (var reader = new StringReader(src)) { var references = new List <string>(); while (reader.Peek() > 0) { var line = reader.ReadLine(); var lineTrimed = line.Trim(); if (lineTrimed.StartsWith("#r ")) { references.Add(lineTrimed.Substring(2).Trim().Trim('\"').Trim()); lines.Add(""); } else if (lineTrimed.StartsWith("#I ")) { libDirs.Add("\"" + lineTrimed.Substring(2).Trim().Trim('\"').Trim() + "\""); lines.Add(""); } else if (lineTrimed.StartsWith("#load ")) { loads.Add(lineTrimed.Substring(5).Trim().Trim('\"').Trim()); lines.Add(""); } else { lines.Add(line); } } if (libDirs.Count > 0) { args.Add("-I:" + libDirs.Aggregate((a, b) => { return(a + "," + b); })); } if (references.Count > 0) { if (!optimize) // 因为在选定Optimized选项时已经具有了standalone选项,所以在此处需要补一个standalone选项 { args.Add("--standalone"); } foreach (var r in references) { args.Add("-r:" + r); // 搜索dll并复制 var path = r.Trim().Trim('\"').Trim(); var n = new FileInfo(path).Name; if (!File.Exists(tempDir + n)) { if (!File.Exists(path)) { foreach (var dir in libDirs) { var s = dir.Trim().Trim('\"').Trim() + "/" + path; if (File.Exists(s)) { path = s; break; } } } if (File.Exists(path)) { File.Copy(path, tempDir + n); waitForClean.Add(n); } } } } } foreach (var load in loads) { var fileName = load; if (!File.Exists(fileName)) { foreach (var i in libDirs) { var s = i.Trim().Trim('\"').Trim() + "/" + fileName; if (File.Exists(s)) { fileName = s; break; } } } var warpedFileName = "\"" + fileName + "\""; args.Add(warpedFileName); } File.WriteAllLines(tempSource, lines); args.Add("\"" + tempSource + "\""); var async = checker.Compile( args.ToArray(), FSharpOption <string> .None); var result = Microsoft.FSharp.Control.FSharpAsync.RunSynchronously( async, FSharpOption <int> .None, FSharpOption <System.Threading.CancellationToken> .None); File.Delete(tempSource); if (result.Item1.Length > 0) { Dispatcher.Invoke(() => { var sb = new StringBuilder(); foreach (var i in result.Item1) { sb .Append('(') .Append(i.Range.StartLine) .Append(") ") .Append("FS") .Append(string.Format("{0:D4}", i.ErrorNumber)) .Append(':') .AppendLine(i.Message); } Output.Text = sb.ToString(); }); } }
public static async Task WarmUpAsync() { try { var fsasync = CodeFormatter.FormatDocumentAsync("tmp.fs", SourceOrigin.SourceOrigin.NewSourceString(SampleCode), FormatConfig.FormatConfig.Default, FSharpParsingOptions.Default, FSharpChecker.Create(null, null, null, null, null, null, null, null, null)); var _ = await FSharpAsync.StartAsTask(fsasync, null, null); } catch (Exception ex) { Trace.TraceError(ex.ToString()); } }
public ICompilation GetFunctionCompilation(FunctionMetadata functionMetadata) { // First use the C# compiler to resolve references, to get consistency with the C# Azure Functions programming model // Add the #r statements from the .fsx file to the resolver source string scriptSource = GetFunctionSource(functionMetadata); var resolverSourceBuilder = new StringBuilder(); using (StringReader sr = new StringReader(scriptSource)) { string line; while ((line = sr.ReadLine()) != null) { if (_hashRRegex.IsMatch(line)) { resolverSourceBuilder.AppendLine(line); } } } resolverSourceBuilder.AppendLine("using System;"); var resolverSource = resolverSourceBuilder.ToString(); Script <object> script = CodeAnalysis.CSharp.Scripting.CSharpScript.Create(resolverSource, options: _metadataResolver.CreateScriptOptions(), assemblyLoader: AssemblyLoader.Value); Compilation compilation = script.GetCompilation(); var compiler = new SimpleSourceCodeServices(msbuildEnabled: FSharpOption <bool> .Some(false)); FSharpErrorInfo[] errors = null; FSharpOption <Assembly> assemblyOption = null; string scriptFilePath = Path.Combine(Path.GetTempPath(), Path.GetFileName(functionMetadata.ScriptFile)); var asmName = FunctionAssemblyLoader.GetAssemblyNameFromMetadata(functionMetadata, compilation.AssemblyName); var dllName = Path.GetTempPath() + asmName + ".dll"; var pdbName = Path.ChangeExtension(dllName, "pdb"); try { var scriptFileBuilder = new StringBuilder(); // Write an adjusted version of the script file, prefixing some 'open' decarations foreach (string import in script.Options.Imports) { scriptFileBuilder.AppendLine("open " + import); } // Suppress undesirable warnings scriptFileBuilder.AppendLine("#nowarn \"988\""); // Set the line to match the original script scriptFileBuilder.AppendLine("# 0 @\"" + functionMetadata.ScriptFile + "\""); // Add our original script scriptFileBuilder.AppendLine(scriptSource); File.WriteAllText(scriptFilePath, scriptFileBuilder.ToString()); var otherFlags = new List <string>(); // For some reason CompileToDynamicAssembly wants "fsc.exe" as the first arg, it is ignored. otherFlags.Add("fsc.exe"); // The --noframework option is used because we will shortly add references to mscorlib and FSharp.Core // as dictated by the C# reference resolver, and F# doesn't like getting multiple references to those. otherFlags.Add("--noframework"); // Add the references as reported by the C# reference resolver. foreach (var mdr in compilation.References) { if (!mdr.Display.Contains("Unresolved ")) { otherFlags.Add("-r:" + mdr.Display); } } // Above we have used the C# reference resolver to get the basic set of DLL references for the compilation. // // However F# has its own view on default options. For scripts these should include the // following framework facade references. otherFlags.Add("-r:System.Linq.dll"); // System.Linq.Expressions.Expression<T> otherFlags.Add("-r:System.Reflection.dll"); // System.Reflection.ParameterInfo otherFlags.Add("-r:System.Linq.Expressions.dll"); // System.Linq.IQueryable<T> otherFlags.Add("-r:System.Threading.Tasks.dll"); // valuetype [System.Threading.Tasks]System.Threading.CancellationToken otherFlags.Add("-r:System.IO.dll"); // System.IO.TextWriter otherFlags.Add("-r:System.Net.Requests.dll"); // System.Net.WebResponse etc. otherFlags.Add("-r:System.Collections.dll"); // System.Collections.Generic.List<T> otherFlags.Add("-r:System.Runtime.Numerics.dll"); // BigInteger otherFlags.Add("-r:System.Threading.dll"); // OperationCanceledException otherFlags.Add("-r:System.Runtime.dll"); otherFlags.Add("-r:System.Numerics.dll"); if (_optimizationLevel == OptimizationLevel.Debug) { otherFlags.Add("--optimize-"); otherFlags.Add("--debug+"); otherFlags.Add("--tailcalls-"); } // If we have a private assembly folder, make sure the compiler uses it to resolve dependencies string privateAssembliesFolder = Path.Combine(Path.GetDirectoryName(functionMetadata.ScriptFile), DotNetConstants.PrivateAssembliesFolderName); if (Directory.Exists(privateAssembliesFolder)) { otherFlags.Add("--lib:" + Path.Combine(Path.GetDirectoryName(functionMetadata.ScriptFile), DotNetConstants.PrivateAssembliesFolderName)); } otherFlags.Add("--out:" + dllName); // Get the #load closure FSharpChecker checker = FSharpChecker.Create(null, null, null, msbuildEnabled: FSharpOption <bool> .Some(false)); var loadFileOptionsAsync = checker.GetProjectOptionsFromScript(functionMetadata.ScriptFile, scriptSource, null, null, null); var loadFileOptions = FSharp.Control.FSharpAsync.RunSynchronously(loadFileOptionsAsync, null, null); foreach (var loadedFileName in loadFileOptions.ProjectFileNames) { if (Path.GetFileName(loadedFileName) != Path.GetFileName(functionMetadata.ScriptFile)) { otherFlags.Add(loadedFileName); } } // Add the (adjusted) script file itself otherFlags.Add(scriptFilePath); // Compile the script to a static assembly var result = compiler.Compile(otherFlags.ToArray()); errors = result.Item1; var code = result.Item2; if (code == 0) { var assemblyBytes = File.ReadAllBytes(dllName); byte[] pdbBytes = null; if (File.Exists(pdbName)) { pdbBytes = File.ReadAllBytes(pdbName); } var assembly = Assembly.Load(assemblyBytes, pdbBytes); assemblyOption = FSharpOption <Assembly> .Some(assembly); } } finally { Task.WhenAll(DeleteIfExistsAsync(scriptFilePath), DeleteIfExistsAsync(dllName), DeleteIfExistsAsync(pdbName)) .ContinueWith(t => t.Exception.Handle(e => { // TODO: Trace return(true); }), TaskContinuationOptions.OnlyOnFaulted); } return(new FSharpCompilation(errors, assemblyOption)); }