2012-11-07 11 views
19

Ho un software che genera codice per un progetto C# basato su azioni dell'utente. Vorrei creare una GUI per compilare automaticamente la soluzione, quindi non devo caricare Visual Studio solo per attivare una ricompilazione.Come si compila una soluzione C# con Roslyn?

Ho cercato di giocare un po 'con Roslyn e ho deciso di provare a utilizzare Roslyn invece di msbuild per farlo. Sfortunatamente, non riesco a trovare alcuna buona risorsa nell'usare Roslyn in questo modo.

Qualcuno può indicarmi la giusta direzione?

risposta

22

È possibile caricare la soluzione utilizzando Roslyn.Services.Workspace.LoadSolution. Dopo averlo fatto, è necessario passare attraverso ciascuno dei progetti in ordine di dipendenza, ottenere il Compilation per il progetto e chiamare Emit su di esso.

È possibile ottenere le compilazioni in ordine di dipendenza con il codice come di seguito. (Sì, lo so che dover trasmettere a IHaveWorkspaceServices fa schifo, sarà meglio nella prossima versione pubblica, lo prometto).

using Roslyn.Services; 
using Roslyn.Services.Host; 
using System; 
using System.Collections.Generic; 
using System.IO; 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var solution = Solution.Create(SolutionId.CreateNewId()).AddCSharpProject("Foo", "Foo").Solution; 
     var workspaceServices = (IHaveWorkspaceServices)solution; 
     var projectDependencyService = workspaceServices.WorkspaceServices.GetService<IProjectDependencyService>(); 
     var assemblies = new List<Stream>(); 
     foreach (var projectId in projectDependencyService.GetDependencyGraph(solution).GetTopologicallySortedProjects()) 
     { 
      using (var stream = new MemoryStream()) 
      { 
       solution.GetProject(projectId).GetCompilation().Emit(stream); 
       assemblies.Add(stream); 
      } 
     } 
    } 
} 

Nota 1: LoadSolution fa ancora uso msbuild sotto le coperte per analizzare i file .csproj e determinare i file/riferimenti/opzioni del compilatore.

Nota2: poiché Roslyn non è ancora completo, probabilmente ci saranno progetti che non vengono compilati correttamente quando si tenta di farlo.

+0

C'è un modo conveniente di determinare l'ordine di dipendenza (come 'sln.ProjectsInDependencyOrder') o si tratta di qualcosa che avrei dovuto implementare per conto mio? (Ad esempio, passare a riferimenti di progetto e creare un albero di dipendenza) – NobodysNightmare

+1

Esiste un IProjectDependencyService con GetTopologicallySortedProjects(). Non ho un computer a portata di mano per controllare esattamente come ottenerlo, ma verrà aggiornato in seguito. –

+0

Modificata la risposta per aggiungere del codice. –

8

Volevo anche compilare una soluzione completa al volo. Costruendo da Kevin Pilch-Bisson's answer e Josh E's comment, ho scritto il codice per compilare se stesso e scriverlo su file.

Software utilizzato

Visual Studio comunitaria 2015 Aggiornamento 1

Microsoft.CodeAnalysis v1.1.0.0 (installato utilizzando Package Manager Console con il comando Install-Package Microsoft.CodeAnalysis).

Codice

using System; 
using System.Collections.Generic; 
using System.IO; 
using Microsoft.CodeAnalysis; 
using Microsoft.CodeAnalysis.Emit; 
using Microsoft.CodeAnalysis.MSBuild; 

namespace Roslyn.TryItOut 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      string solutionUrl = "C:\\Dev\\Roslyn.TryItOut\\Roslyn.TryItOut.sln"; 
      string outputDir = "C:\\Dev\\Roslyn.TryItOut\\output"; 

      if (!Directory.Exists(outputDir)) 
      { 
       Directory.CreateDirectory(outputDir); 
      } 

      bool success = CompileSolution(solutionUrl, outputDir); 

      if (success) 
      { 
       Console.WriteLine("Compilation completed successfully."); 
       Console.WriteLine("Output directory:"); 
       Console.WriteLine(outputDir); 
      } 
      else 
      { 
       Console.WriteLine("Compilation failed."); 
      } 

      Console.WriteLine("Press the any key to exit."); 
      Console.ReadKey(); 
     } 

     private static bool CompileSolution(string solutionUrl, string outputDir) 
     { 
      bool success = true; 

      MSBuildWorkspace workspace = MSBuildWorkspace.Create(); 
      Solution solution = workspace.OpenSolutionAsync(solutionUrl).Result; 
      ProjectDependencyGraph projectGraph = solution.GetProjectDependencyGraph(); 
      Dictionary<string, Stream> assemblies = new Dictionary<string, Stream>(); 

      foreach (ProjectId projectId in projectGraph.GetTopologicallySortedProjects()) 
      { 
       Compilation projectCompilation = solution.GetProject(projectId).GetCompilationAsync().Result; 
       if (null != projectCompilation && !string.IsNullOrEmpty(projectCompilation.AssemblyName)) 
       { 
        using (var stream = new MemoryStream()) 
        { 
         EmitResult result = projectCompilation.Emit(stream); 
         if (result.Success) 
         { 
          string fileName = string.Format("{0}.dll", projectCompilation.AssemblyName); 

          using (FileStream file = File.Create(outputDir + '\\' + fileName)) 
          { 
           stream.Seek(0, SeekOrigin.Begin); 
           stream.CopyTo(file); 
          } 
         } 
         else 
         { 
          success = false; 
         } 
        } 
       } 
       else 
       { 
        success = false; 
       } 
      } 

      return success; 
     } 
    } 
} 
+0

Nessun valore trovato per RuntimeMetadataVersion. Non è stato trovato alcun assembly contenente System.Object né un valore per RuntimeMetadataVersion specificato tramite opzioni. – Aflred

+0

Per utilizzare questo esempio sarà necessario installare anche Microsoft.Build.Tasks.Core e Microsoft.Build Packages –

+0

Questa sembra essere una risposta molto migliore in quanto lo spazio dei nomi roslyn.services è obsoleto. –

Problemi correlati