web-dev-qa-db-ja.com

RoslynでC#ソリューションをコンパイルするにはどうすればよいですか?

ユーザーの操作に基づいてC#プロジェクトのコードを生成するソフトウェアがあります。ソリューションを自動的にコンパイルするGUIを作成したいので、再コンパイルをトリガーするためだけにVisualStudioをロードする必要はありません。

Roslynで遊ぶ機会を少し探していたので、msbuildの代わりにRoslynを使用してこれを行うことにしました。残念ながら、Roslynをこのように使用するための優れたリソースを見つけることができないようです。

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

24
KallDrexx

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はまだ言語が完成していないため、これを試みたときに正常にコンパイルされないプロジェクトが存在する可能性があります。

26
Kevin Pilch

また、その場で完全なソリューションをコンパイルしたかったのです。 Kevin Pilch-Bissonの答えJosh Eのコメント から構築して、自分自身をコンパイルしてファイルに書き込むコードを書きました。

使用するソフトウェア

Visual Studio Community 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;
        }
    }
}
18
Ryan Kyle