private IAssemblyLoadContextFactory GetRuntimeFactory() { var cacheKey = Tuple.Create("RuntimeLoadContextFactory", _project.Name, _appEnv.Configuration, _appEnv.RuntimeFramework); return(_cache.Get <IAssemblyLoadContextFactory>(cacheKey, ctx => { var applicationHostContext = new ApplicationHostContext(_hostServices, _project.ProjectDirectory, packagesDirectory: null, configuration: _appEnv.Configuration, targetFramework: _appEnv.RuntimeFramework, cache: _cache, cacheContextAccessor: _cacheContextAccessor, namedCacheDependencyProvider: _namedDependencyProvider); applicationHostContext.DependencyWalker.Walk(_project.Name, _project.Version, _appEnv.RuntimeFramework); // Watch all projects for project.json changes foreach (var library in applicationHostContext.DependencyWalker.Libraries) { if (string.Equals(library.Type, "Project")) { ctx.Monitor(new FileWriteTimeCacheDependency(library.Path)); } } // Add a cache dependency on restore complete to reevaluate dependencies ctx.Monitor(_namedDependencyProvider.GetNamedDependency(_project.Name + "_RestoreComplete")); return new AssemblyLoadContextFactory(applicationHostContext.ServiceProvider); })); }
public CompilationContext CompileProject( CompilationProjectContext projectContext, IEnumerable <IMetadataReference> incomingReferences, IEnumerable <ISourceReference> incomingSourceReferences, Func <IList <ResourceDescriptor> > resourcesResolver) { var path = projectContext.ProjectDirectory; var name = projectContext.Target.Name; var projectInfo = GetProjectInfo(projectContext.ProjectFilePath); if (_cacheContextAccessor.Current != null) { _cacheContextAccessor.Current.Monitor(new FileWriteTimeCacheDependency(projectContext.ProjectFilePath)); // Monitor the trigger {projectName}_BuildOutputs var buildOutputsName = name + "_BuildOutputs"; _cacheContextAccessor.Current.Monitor(_namedDependencyProvider.GetNamedDependency(buildOutputsName)); _cacheContextAccessor.Current.Monitor(_namedDependencyProvider.GetNamedDependency(name + "_Dependencies")); } Logger.TraceInformation("[{0}]: Compiling '{1}'", GetType().Name, name); var sw = Stopwatch.StartNew(); CompilationContext context; using (new ResolveHooker()) using (var files = new TempFiles()) { var outFileName = $"{name}.dll"; var outDir = files.CreateDir(); var outFile = Path.Combine(outDir, outFileName); var args = new List <string>(); args.Add("fsc.exe"); args.Add($"--out:{outFile}"); args.Add("--target:library"); args.Add("--noframework"); args.Add("--optimize-"); args.Add("--debug"); if (SupportsPdbGeneration) { args.Add($"--pdb:{Path.ChangeExtension(outFile, ".pdb")}"); } args.Add($"--doc:{Path.ChangeExtension(outFile, ".xml")}"); args.AddRange(projectInfo.Files); // These are the metadata references being used by your project. // Everything in your project.json is resolved and normailzed here: // - Project references // - Package references are turned into the appropriate assemblies // Each IMetadaReference maps to an assembly foreach (var reference in incomingReferences) { string fileName = null; var projectRef = reference as IMetadataProjectReference; if (projectRef != null) { var dir = files.CreateDir(); projectRef.EmitAssembly(dir); fileName = Path.Combine(dir, $"{projectRef.Name}.dll"); } var fileRef = reference as IMetadataFileReference; if (fileRef != null) { fileName = fileRef.Path; } else if (fileName == null) { throw new Exception($"Unknown reference type {reference.GetType()}"); } args.Add($"-r:{fileName}"); } //Console.WriteLine(string.Join(Environment.NewLine, args)); var scs = new SimpleSourceCodeServices(); var result = scs.Compile(args.ToArray()); var errors = result.Item1.Select(FSharpDiagnosticMessage.CompilationMessage); var resultCode = result.Item2; //System.Diagnostics.Debugger.Launch(); MemoryStream assembly = null; MemoryStream pdb = null; MemoryStream xml = null; if (resultCode == 0) { assembly = new MemoryStream(); xml = new MemoryStream(); using (var fs = File.OpenRead(outFile)) fs.CopyTo(assembly); var pdbFile = Path.ChangeExtension(outFile, ".pdb"); if (File.Exists(pdbFile)) { pdb = new MemoryStream(); using (var fs = File.OpenRead(pdbFile)) fs.CopyTo(pdb); } var xmlFile = Path.ChangeExtension(outFile, ".xml"); if (File.Exists(xmlFile)) { xml = new MemoryStream(); using (var fs = File.OpenRead(xmlFile)) fs.CopyTo(xml); } } context = new CompilationContext( projectContext, projectInfo, resultCode == 0, errors, assembly?.ToArray(), pdb?.ToArray(), xml?.ToArray()); assembly?.Dispose(); pdb?.Dispose(); xml?.Dispose(); } sw.Stop(); Logger.TraceInformation("[{0}]: Compiled '{1}' in {2}ms", GetType().Name, name, sw.ElapsedMilliseconds); return(context); }
public CompilationContext CompileProject( Project project, ILibraryKey target, IEnumerable <IMetadataReference> incomingReferences, IEnumerable <ISourceReference> incomingSourceReferences, IList <IMetadataReference> outgoingReferences) { var path = project.ProjectDirectory; var name = project.Name; var isMainAspect = string.IsNullOrEmpty(target.Aspect); var isPreprocessAspect = string.Equals(target.Aspect, "preprocess", StringComparison.OrdinalIgnoreCase); if (!string.IsNullOrEmpty(target.Aspect)) { name += "!" + target.Aspect; } _watcher.WatchProject(path); _watcher.WatchFile(project.ProjectFilePath); if (_cacheContextAccessor.Current != null) { _cacheContextAccessor.Current.Monitor(new FileWriteTimeCacheDependency(project.ProjectFilePath)); // Monitor the trigger {projectName}_BuildOutputs var buildOutputsName = project.Name + "_BuildOutputs"; _cacheContextAccessor.Current.Monitor(_namedDependencyProvider.GetNamedDependency(buildOutputsName)); } var exportedReferences = incomingReferences.Select(ConvertMetadataReference); Trace.TraceInformation("[{0}]: Compiling '{1}'", GetType().Name, name); var sw = Stopwatch.StartNew(); var compilationSettings = project.GetCompilationSettings( target.TargetFramework, target.Configuration); var sourceFiles = Enumerable.Empty <String>(); if (isMainAspect) { sourceFiles = project.SourceFiles; } else if (isPreprocessAspect) { sourceFiles = project.PreprocessSourceFiles; } var parseOptions = new CSharpParseOptions(languageVersion: compilationSettings.LanguageVersion, preprocessorSymbols: compilationSettings.Defines.AsImmutable()); IList <SyntaxTree> trees = GetSyntaxTrees( project, sourceFiles, incomingSourceReferences, parseOptions); var embeddedReferences = incomingReferences.OfType <IMetadataEmbeddedReference>() .ToDictionary(a => a.Name, ConvertMetadataReference); var references = new List <MetadataReference>(); references.AddRange(exportedReferences); var compilation = CSharpCompilation.Create( name, trees, references, compilationSettings.CompilationOptions); var aniSw = Stopwatch.StartNew(); Trace.TraceInformation("[{0}]: Scanning '{1}' for assembly neutral interfaces", GetType().Name, name); var assemblyNeutralWorker = new AssemblyNeutralWorker(compilation, embeddedReferences); assemblyNeutralWorker.FindTypeCompilations(compilation.Assembly.GlobalNamespace); assemblyNeutralWorker.OrderTypeCompilations(); var assemblyNeutralTypeDiagnostics = assemblyNeutralWorker.GenerateTypeCompilations(); assemblyNeutralWorker.Generate(); aniSw.Stop(); Trace.TraceInformation("[{0}]: Found {1} assembly neutral interfaces for '{2}' in {3}ms", GetType().Name, assemblyNeutralWorker.TypeCompilations.Count(), name, aniSw.ElapsedMilliseconds); foreach (var t in assemblyNeutralWorker.TypeCompilations) { outgoingReferences.Add(new EmbeddedMetadataReference(t)); } var newCompilation = assemblyNeutralWorker.Compilation; newCompilation = ApplyVersionInfo(newCompilation, project, parseOptions); var compilationContext = new CompilationContext(newCompilation, incomingReferences.Concat(outgoingReferences).ToList(), assemblyNeutralTypeDiagnostics, project); var modules = new List <ICompileModule>(); using (var childContext = _loadContextFactory.Create()) { if (isMainAspect && project.PreprocessSourceFiles.Any()) { try { var preprocessAssembly = childContext.Load(project.Name + "!preprocess"); foreach (var preprocessType in preprocessAssembly.ExportedTypes) { if (preprocessType.GetTypeInfo().ImplementedInterfaces.Contains(typeof(ICompileModule))) { var module = (ICompileModule)ActivatorUtilities.CreateInstance(_services, preprocessType); modules.Add(module); } } } catch (Exception ex) { var compilationException = ex.InnerException as RoslynCompilationException; if (compilationException != null) { // Add diagnostics from the precompile step foreach (var diag in compilationException.Diagnostics) { compilationContext.Diagnostics.Add(diag); } Trace.TraceError("[{0}]: Failed loading meta assembly '{1}'", GetType().Name, name); } else { Trace.TraceError("[{0}]: Failed loading meta assembly '{1}':\n {2}", GetType().Name, name, ex); } } } foreach (var module in modules) { module.BeforeCompile(compilationContext); } } sw.Stop(); Trace.TraceInformation("[{0}]: Compiled '{1}' in {2}ms", GetType().Name, name, sw.ElapsedMilliseconds); return(compilationContext); }