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);
            }));
        }
Exemplo n.º 2
0
        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);
        }
Exemplo n.º 3
0
        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);
        }