Esempio n. 1
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));

                if (isMainAspect)
                {
                    // 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.GetCompilerOptions(target.TargetFramework, target.Configuration)
                                             .ToCompilationSettings(target.TargetFramework);

            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);

            IList<SyntaxTree> trees = GetSyntaxTrees(
                project,
                sourceFiles,
                incomingSourceReferences,
                parseOptions,
                isMainAspect);

            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>();

            if (isMainAspect && project.PreprocessSourceFiles.Any())
            {
                try
                {
                    modules = GetCompileModules(target).Modules;
                }
                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);
                    }
                }
            }

            if (modules.Count > 0)
            {
                var precompSw = Stopwatch.StartNew();
                foreach (var module in modules)
                {
                    module.BeforeCompile(compilationContext);
                }

                precompSw.Stop();
                Trace.TraceInformation("[{0}]: Compile modules ran in in {1}ms", GetType().Name, precompSw.ElapsedMilliseconds);
            }

            sw.Stop();
            Trace.TraceInformation("[{0}]: Compiled '{1}' in {2}ms", GetType().Name, name, sw.ElapsedMilliseconds);

            return compilationContext;
        }