public IMetadataProjectReference CompileProject(
      CompilationProjectContext projectContext,
      Func<LibraryExport> referenceResolver,
      Func<IList<ResourceDescriptor>> resourcesResolver,
      string configuration)
    {
      var export = referenceResolver();
      if (export == null)
      {
          return null;
      }

      var incomingReferences = export.MetadataReferences;
      var incomingSourceReferences = export.SourceReferences;

      var compilationContext = _compiler.CompileProject(
        projectContext,
        incomingReferences,
        incomingSourceReferences,
        resourcesResolver);

      if (compilationContext == null)
      {
        return null;
      }

      // Project reference
      return new FSharpProjectReference(compilationContext);
    }
Example #2
0
        public CompilationContext(CSharpCompilation compilation,
                                  CompilationProjectContext compilationContext,
                                  IEnumerable<IMetadataReference> incomingReferences,
                                  Func<IList<ResourceDescriptor>> resourcesResolver)
        {
            Project = compilationContext;
            Modules = new List<ICompileModule>();

            _resourcesResolver = resourcesResolver;

            var projectContext = new ProjectContext
            {
                Name = compilationContext.Target.Name,
                ProjectDirectory = compilationContext.ProjectDirectory,
                ProjectFilePath = compilationContext.ProjectFilePath,
                TargetFramework = compilationContext.Target.TargetFramework,
                Version = compilationContext.Version?.ToString(),
                Configuration = compilationContext.Target.Configuration
            };

            _beforeCompileContext = new BeforeCompileContext(
                compilation,
                projectContext,
                ResolveResources,
                () => new List<Diagnostic>(),
                () => new List<IMetadataReference>(incomingReferences)
             );
        }
        public CompiledProjectMetadataReference(CompilationProjectContext project, string assemblyPath, string pdbPath)
        {
            Name = project.Target.Name;
            ProjectPath = project.ProjectFilePath;
            Path = assemblyPath;

            _project = project;
            _assemblyPath = assemblyPath;
            _pdbPath = pdbPath;
        }
        public CompiledProjectMetadataReference(CompilationProjectContext project, string assemblyPath, string pdbPath)
        {
            Name        = project.Target.Name;
            ProjectPath = project.ProjectFilePath;
            Path        = assemblyPath;

            _project      = project;
            _assemblyPath = assemblyPath;
            _pdbPath      = pdbPath;
        }
Example #5
0
 internal CompilationContext(
   CompilationProjectContext project,
   FSharpProjectInfo projectInfo,
   bool success,
   IEnumerable<FSharpDiagnosticMessage> messages,
   byte[] assembly,
   byte[] pdb,
   byte[] xml)
 {
   _project = project;
   ProjectInfo = projectInfo;
   Success = success;
   Diagnostics = messages.ToList();
   Assembly = assembly;
   Pdb = pdb;
   Xml = xml;
 }
Example #6
0
        public CompilationContext CompileProject(
            CompilationProjectContext projectContext,
            IEnumerable<IMetadataReference> incomingReferences,
            IEnumerable<ISourceReference> incomingSourceReferences,
            Func<IList<ResourceDescriptor>> resourcesResolver,
            string configuration)
        {
            var path = projectContext.ProjectDirectory;
            var name = projectContext.Target.Name;

            var isMainAspect = string.IsNullOrEmpty(projectContext.Target.Aspect);
            var isPreprocessAspect = string.Equals(projectContext.Target.Aspect, "preprocess", StringComparison.OrdinalIgnoreCase);

            if (!string.IsNullOrEmpty(projectContext.Target.Aspect))
            {
                name += "!" + projectContext.Target.Aspect;
            }

            if (_cacheContextAccessor.Current != null)
            {
                _cacheContextAccessor.Current.Monitor(new FileWriteTimeCacheDependency(projectContext.ProjectFilePath));

                if (isMainAspect)
                {
                    // Monitor the trigger {projectName}_BuildOutputs
                    var buildOutputsName = projectContext.Target.Name + "_BuildOutputs";

                    _cacheContextAccessor.Current.Monitor(_namedDependencyProvider.GetNamedDependency(buildOutputsName));
                }

                _cacheContextAccessor.Current.Monitor(_namedDependencyProvider.GetNamedDependency(projectContext.Target.Name + "_Dependencies"));
            }

            var exportedReferences = incomingReferences
                .Select(reference => reference.ConvertMetadataReference(_assemblyMetadataFactory));

            Logger.TraceInformation("[{0}]: Compiling '{1}'", GetType().Name, name);
            var sw = Stopwatch.StartNew();

            var compilationSettings = projectContext.CompilerOptions.ToCompilationSettings(
                projectContext.Target.TargetFramework, projectContext.ProjectDirectory);

            var sourceFiles = Enumerable.Empty<string>();
            if (isMainAspect)
            {
                sourceFiles = projectContext.Files.SourceFiles;
            }
            else if (isPreprocessAspect)
            {
                sourceFiles = projectContext.Files.PreprocessSourceFiles;
            }

            var parseOptions = new CSharpParseOptions(languageVersion: compilationSettings.LanguageVersion,
                                                      preprocessorSymbols: compilationSettings.Defines);

            var trees = GetSyntaxTrees(
                projectContext,
                sourceFiles,
                incomingSourceReferences,
                parseOptions,
                isMainAspect);

            var references = new List<MetadataReference>();
            references.AddRange(exportedReferences);

            if (isPreprocessAspect)
            {
                compilationSettings.CompilationOptions =
                    compilationSettings.CompilationOptions
                        .WithOutputKind(OutputKind.DynamicallyLinkedLibrary)
                        .WithCryptoKeyFile(null)
                        .WithCryptoPublicKey(ImmutableArray<byte>.Empty)
                        .WithDelaySign(false);
            }

            var compilation = CSharpCompilation.Create(
                name,
                trees,
                references,
                compilationSettings.CompilationOptions);

            compilation = ApplyProjectInfo(compilation, projectContext, parseOptions);

            var compilationContext = new CompilationContext(
                compilation,
                projectContext,
                incomingReferences,
                resourcesResolver);

            ValidateSigningOptions(compilationContext);
            AddStrongNameProvider(compilationContext);

            if (isMainAspect && projectContext.Files.PreprocessSourceFiles.Any())
            {
                try
                {
                    var modules = GetCompileModules(projectContext.Target, configuration).Modules;

                    foreach (var m in modules)
                    {
                        compilationContext.Modules.Add(m);
                    }
                }
                catch (Exception ex) when (ex.InnerException is RoslynCompilationException)
                {
                    var compilationException = ex.InnerException as RoslynCompilationException;

                    // Add diagnostics from the precompile step
                    foreach (var diag in compilationException.Diagnostics)
                    {
                        compilationContext.Diagnostics.Add(diag);
                    }
                }
            }

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

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

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

            return compilationContext;
        }
Example #7
0
        private IList<SyntaxTree> GetSyntaxTrees(CompilationProjectContext project,
                                                 IEnumerable<string> sourceFiles,
                                                 IEnumerable<ISourceReference> sourceReferences,
                                                 CSharpParseOptions parseOptions,
                                                 bool isMainAspect)
        {
            var trees = new List<SyntaxTree>();

            var dirs = new HashSet<string>();

            if (isMainAspect)
            {
                dirs.Add(project.ProjectDirectory);
            }

            foreach (var sourcePath in sourceFiles)
            {
                var syntaxTree = CreateSyntaxTree(sourcePath, parseOptions);

                trees.Add(syntaxTree);
            }

            foreach (var sourceFileReference in sourceReferences.OfType<ISourceFileReference>())
            {
                var sourcePath = sourceFileReference.Path;

                var syntaxTree = CreateSyntaxTree(sourcePath, parseOptions);

                trees.Add(syntaxTree);
            }

            // Watch all directories
            var ctx = _cacheContextAccessor.Current;

            foreach (var d in dirs)
            {
                ctx?.Monitor(new FileWriteTimeCacheDependency(d));
            }

            return trees;
        }
Example #8
0
        private static CSharpCompilation ApplyProjectInfo(CSharpCompilation compilation, CompilationProjectContext project,
            CSharpParseOptions parseOptions)
        {
            var projectAttributes = new Dictionary<string, string>(StringComparer.Ordinal)
            {
                [typeof(AssemblyTitleAttribute).FullName] = EscapeCharacters(project.Title),
                [typeof(AssemblyDescriptionAttribute).FullName] = EscapeCharacters(project.Description),
                [typeof(AssemblyCopyrightAttribute).FullName] = EscapeCharacters(project.Copyright),
                [typeof(AssemblyFileVersionAttribute).FullName] = EscapeCharacters(project.AssemblyFileVersion.ToString()),
                [typeof(AssemblyVersionAttribute).FullName] = EscapeCharacters(RemovePrereleaseTag(project.Version)),
                [typeof(AssemblyInformationalVersionAttribute).FullName] = EscapeCharacters(project.Version)
            };

            var assemblyAttributes = compilation.Assembly.GetAttributes()
                .Select(assemblyAttribute => assemblyAttribute.AttributeClass.ToString());
            var newAttributes = string.Join(Environment.NewLine, projectAttributes
                .Where(projectAttribute => projectAttribute.Value != null && !assemblyAttributes.Contains(projectAttribute.Key))
                .Select(projectAttribute => $"[assembly:{projectAttribute.Key}(\"{projectAttribute.Value}\")]"));

            if (!string.IsNullOrWhiteSpace(newAttributes))
            {
                compilation = compilation.AddSyntaxTrees(new[]
                {
                    CSharpSyntaxTree.ParseText(newAttributes, parseOptions,
                        path: $"{nameof(ApplyProjectInfo)}.cs",
                        encoding: Encoding.UTF8)
                });
            }

            return compilation;
        }
Example #9
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);

        var resourcesDir = files.CreateDir();
        foreach (var r in resourcesResolver())
        {
            Logger.TraceInformation("[{0}]: Resource: '{1}' ( filename: '{2}' )", GetType().Name, r.Name, r.FileName);
            string resourcePath = Path.Combine(resourcesDir, r.FileName);
            using (var fs = File.Create(resourcePath))
            {
                r.StreamFactory().CopyTo(fs);
            }
            args.Add($"--resource:{resourcePath},{r.Name}");
        }

        // 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}");
        }

#if DEBUG
        Logger.TraceInformation("[{0}]: Arguments '{1}'", GetType().Name, string.Join(Environment.NewLine, args));
#endif

        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 DesignTimeProjectReference(CompilationProjectContext project, CompileResponse response)
 {
     _project = project;
     _response = response;
 }