2012-11-07 25 views
19

私は、ユーザーの操作に基づいてC#プロジェクトのコードを生成するソフトウェアを持っています。私はソリューションを自動的にコンパイルするためのGUIを作成したいので、再コンパイルをトリガーするためにVisual Studioをロードする必要はありません。RoslynでC#ソリューションをコンパイルするにはどうすればよいですか?

私はRoslynと遊ぶチャンスを探していて、これを行うにはmsbuildではなくRoslynを試してみることにしました。残念ながら、私はこのような方法でRoslynを使用する上で良いリソースを見つけることはできないようです。

誰でも正しい方向に向けることができますか?

答えて

22

Roslyn.Services.Workspace.LoadSolutionを使用してソリューションを読み込むことができます。プロジェクトを完了したら、それぞれのプロジェクトを依存関係順に調べ、プロジェクトのためにCompilationを取得し、Emitを呼び出してください。

コンパイルを以下のようなコードで依存関係の順序で得ることができます。 (はい、私はIHaveWorkspaceServicesにキャストしなければならないことを知っています。それは次の公開リリースでうまくいくでしょう、と私は約束します)。

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

注1:LoadSolutionはまだ.csprojファイルを解析し、ファイル/参照/コンパイラオプションを決定するためにカバーの下に使用MSBuildのを行います。

注2:Roslynはまだ完全な言語ではないため、これを試みると正常にコンパイルされないプロジェクトが存在する可能性があります。

+0

(sln.ProjectsInDependencyOrder' 'のように)依存順序を決定する便利な方法はありますか、これは私が自分で実装する必要があります何かありますか? (例えば、プロジェクト参照を経由して依存関係ツリーを構築する) – NobodysNightmare

+1

GetTopologicallySortedProjects()を持つIProjectDependencyServiceがあります。私はそれを得る方法を正確に調べるのに便利なコンピュータを持っていませんが、後で更新します。 –

+0

いくつかのコードを追加する答えを編集しました。 –

8

また、オンザフライで完全なソリューションをコンパイルしたいと考えました。 Kevin Pilch-Bisson's answerJosh E's commentからビルドすると、自分自身をコンパイルしてファイルに書き込むコードを書いています。

ソフトウェア使用し

Visual Studioのコミュニティ2015 Update 1の

Microsoft.CodeAnalysisのv1.1.0.0(コマンドInstall-Package Microsoft.CodeAnalysisとパッケージマネージャコンソールを使用してインストールされます)。

コード

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

RuntimeMetadataVersionの値が見つかりません。 System.Objectを含むアセンブリが見つかりませんでした。また、オプションによって指定されたRuntimeMetadataVersionの値もありませんでした。 – Aflred

+0

FYIこの例を使用するには、Microsoft.Build.Tasks.CoreとMicrosoft.Build Packagesもインストールする必要があります –

+0

これは、roslyn.services名前空間が廃止されているので、はるかに良い答えと思われます。 –

関連する問題