2012-11-07 21 views
19

Mam program, który generuje kod dla projektu C# na podstawie działań użytkownika. Chciałbym stworzyć graficzny interfejs użytkownika, aby automatycznie skompilować rozwiązanie, więc nie muszę ładować Visual Studio tylko po to, aby wywołać rekompilację.Jak mogę skompilować rozwiązanie C# z Roslyn?

Szukałem okazji, by zagrać z Roslyn i postanowiłem spróbować użyć Roslyn zamiast msbuild. Niestety, nie mogę znaleźć żadnych dobrych zasobów na temat korzystania z Roslyn w ten sposób.

Czy ktoś może wskazać mi właściwy kierunek?

Odpowiedz

22

Możesz załadować rozwiązanie za pomocą Roslyn.Services.Workspace.LoadSolution. Gdy to zrobisz, musisz przejść przez każdy z projektów w kolejności zależności, uzyskać Compilation dla projektu i zadzwonić pod numer Emit.

Możesz pobrać kompilacje w kolejności zależności z kodem jak poniżej. (Tak, wiem, że trzeba rzucić na IHaveWorkspaceServices, to będzie lepiej w następnym wydaniu publicznym, obiecuję).

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

Note1: LoadSolution nadal używa msbuild pod kołdrą do analizowania plików .csproj i determinują pliki/Referencje/opcje kompilatora.

Uwaga2: ponieważ Roslyn nie jest jeszcze językiem kompletnym, najprawdopodobniej będą projekty, które nie będą się skutecznie kompilować podczas próby.

+0

Czy jest to wygodny sposób ustalania kolejności zależność (jak 'sln.ProjectsInDependencyOrder') czy jest to coś, co muszę wdrożyć na własną rękę? (Na przykład Przechodzenie przez referencje do projektu i budowanie drzewa zależności) – NobodysNightmare

+1

Istnieje usługa IProjectDependencyService, która ma funkcję GetTopologicallySortedProjects(). Nie mam pod ręką komputera, aby dokładnie sprawdzić, jak go zdobyć, ale zaktualizuję go później. –

+0

Edytowano odpowiedź, aby dodać kod. –

8

Chciałem również skompilować pełne rozwiązanie w locie. Budując z Kevin Pilch-Bisson's answer i Josh E's comment, napisałem kod, aby skompilować się i zapisać go do plików.

Software Używane

Visual Studio 2015 Community Aktualizacja 1

Microsoft.CodeAnalysis v1.1.0.0 (zainstalowany przy użyciu pakietu konsoli Menedżer z poleceniem Install-Package Microsoft.CodeAnalysis).

Kod

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

Nie znaleziono wartości dla RuntimeMetadataVersion. Nie znaleziono żadnego zestawu zawierającego obiekt System.Object ani nie podano wartości dla opcji RuntimeMetadataVersion określonej przez opcje. – Aflred

+0

Do użycia tego przykładu będziesz musiał zainstalować Microsoft.Build.Tasks.Core i Microsoft.Build Packages –

+0

To wydaje się być znacznie lepszą odpowiedzią, ponieważ przestrzeń nazw roslyn.services jest przestarzała. –

Powiązane problemy