roslyn 编绎工程

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.MSBuild;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace CShapScriptWorkLibrary2015
{
//需要下载BuildTools for Visual Studio 2015 https://www.microsoft.com/zh-CN/download/details.aspx?id=48159

//解决办法就是在引用了第三方组件的项目中, 引用第三方组件中引用了的.NET Framework 4.0 的 dll.这样批处理是可以成功执行完成编译的了.但 Visual Studio 2015 编译却报错了.

//于是折腾了一番, 敲定解决办法是:

// 1.拷贝System.Runtime.dll到解决方案目录(随意, 我的是Library目录)下.

// 2.直接打开需要引用的csproj文件,向其中添加:

//<Reference Include = "System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" >

//< HintPath > ..\..\Library\System.Runtime.dll</HintPath>
//    <Private>True</Private>
//</Reference>

//3.向 Web.Config 的 runtime --> assemblyBinding 节添加:

//<dependentAssembly>
//<assemblyIdentity name = "System.Runtime" publicKeyToken= "b03f5f7f11d50a3a" culture= "neutral" />
//< bindingRedirect oldVersion= "0.0.0.0-4.0.0.0" newVersion= "4.0.0.0" />
//</ dependentAssembly >


//Microsoft.Build.15.4.8
//Microsoft.Build.Framework.15.4.8
//Microsoft.Build.Tasks.Core.15.4.8
//Microsoft.Build.Utilities.Core.15.4.8
//Microsoft.CodeAnalysis.Common.2.6.0
//Microsoft.CodeAnalysis.CSharp.2.6.0
//Microsoft.CodeAnalysis.CSharp.Workspaces.2.6.0
//Microsoft.CodeAnalysis.Workspaces.Common.2.6.0 

//自己收集到的
//Microsoft.Net.Compilers
//Microsoft.CodeAnalysis.Compilers
//Microsoft.CodeAnalysis 

//<? xml version="1.0" encoding="utf-8"?>
//<packages>
//  <package id = "Microsoft.CodeAnalysis" version="1.1.1" targetFramework="net452" />
//  <package id = "Microsoft.CodeAnalysis.Analyzers" version="1.1.0" targetFramework="net452" />
//  <package id = "Microsoft.CodeAnalysis.Common" version="1.1.1" targetFramework="net452" />
//  <package id = "Microsoft.CodeAnalysis.CSharp" version="1.1.1" targetFramework="net452" />
//  <package id = "Microsoft.CodeAnalysis.CSharp.Workspaces" version="1.1.1" targetFramework="net452" />
//  <package id = "Microsoft.CodeAnalysis.VisualBasic" version="1.1.1" targetFramework="net452" />
//  <package id = "Microsoft.CodeAnalysis.VisualBasic.Workspaces" version="1.1.1" targetFramework="net452" />
//  <package id = "Microsoft.CodeAnalysis.Workspaces.Common" version="1.1.1" targetFramework="net452" />
//  <package id = "Microsoft.Composition" version="1.0.27" targetFramework="net452" />
//  <package id = "Microsoft.Net.Compilers" version="1.1.1" targetFramework="net452" developmentDependency="true" />
//  <package id = "System.Collections" version="4.0.0" targetFramework="net452" />
//  <package id = "System.Collections.Immutable" version="1.1.37" targetFramework="net452" />
//  <package id = "System.Diagnostics.Debug" version="4.0.0" targetFramework="net452" />
//  <package id = "System.Globalization" version="4.0.0" targetFramework="net452" />
//  <package id = "System.IO" version="4.0.0" targetFramework="net452" />
//  <package id = "System.Linq" version="4.0.0" targetFramework="net452" />
//  <package id = "System.Reflection" version="4.0.0" targetFramework="net452" />
//  <package id = "System.Reflection.Extensions" version="4.0.0" targetFramework="net452" />
//  <package id = "System.Reflection.Metadata" version="1.1.0" targetFramework="net452" />
//  <package id = "System.Reflection.Primitives" version="4.0.0" targetFramework="net452" />
//  <package id = "System.Resources.ResourceManager" version="4.0.0" targetFramework="net452" />
//  <package id = "System.Runtime" version="4.0.0" targetFramework="net452" />
//  <package id = "System.Runtime.Extensions" version="4.0.0" targetFramework="net452" />
//  <package id = "System.Runtime.InteropServices" version="4.0.0" targetFramework="net452" />
//  <package id = "System.Text.Encoding" version="4.0.0" targetFramework="net452" />
//  <package id = "System.Text.Encoding.Extensions" version="4.0.0" targetFramework="net452" />
//  <package id = "System.Threading" version="4.0.0" targetFramework="net452" />
//</packages>


//Can you please add the following NuGet package references to your project and try again?
//NuGet.Frameworks
//NuGet.Packaging
//NuGet.ProjectModel
//NuGet.Versioning
//MsBuild is trying to do a restore (ResolvePackageAssets task) and it needs these packages.


//最重要的一步
//由于roslyn 使用反射调用 Microsoft.CodeAnalysis.CSharp.Workspaces.dll Microsoft.CodeAnalysis.CSharp.dll  因此需要手动将这两个dll 放到exe 目录

//
//
// netcoreapp2.1
//
//

public class CShapScriptWork
{
    /// <summary>
    /// 待写入文件的log列表
    /// </summary>
    static List<string> Logs = new List<string>();

    /// <summary>
    /// 输出文件,成功与否
    /// </summary>
    static Dictionary<string, bool> OutputFiles = new Dictionary<string, bool>();

    public void CompileSolution(string[] args)
    {
        //命令行参数解析器
        CommandLineArgumentParser arguments = CommandLineArgumentParser.Parse(args);

        if (arguments.Has(ConfigInfo.Help) || arguments.Has(ConfigInfo.Question))
        {
            string helpFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "help.txt");
            string[] contents = File.ReadAllLines(helpFile);
            foreach (string content in contents)
            {
                Console.WriteLine(content);
            }

            return;
        }

        //解决方案路径
        string solutionUrl;
        if (arguments.Has(ConfigInfo.SolutionUrl))
        {
            solutionUrl = arguments.Get(ConfigInfo.SolutionUrl).Next;
        }
        else
        {
            solutionUrl = GetAppSetting(ConfigInfo.SolutionUrl);
        }

        //输出目录
        string outputDir;
        if (arguments.Has(ConfigInfo.OutputDir))
        {
            outputDir = arguments.Get(ConfigInfo.OutputDir).Next;
        }
        else
        {
            outputDir = GetAppSetting(ConfigInfo.OutputDir);
        }

        //编译属性
        string properties;
        if (arguments.Has(ConfigInfo.Properties))
        {
            properties = arguments.Get(ConfigInfo.Properties).Next;
        }
        else
        {
            properties = GetAppSetting(ConfigInfo.Properties);
        }

        Dictionary<string, string> keyValues;
        if (!string.IsNullOrEmpty(properties))
        {
            keyValues = new Dictionary<string, string>();
            IEnumerable<string> props = properties.Split(';').Where(t => !string.IsNullOrWhiteSpace(t));
            foreach (var item in props)
            {
                string[] prop = item.Split('=');
                keyValues.Add(prop[0], prop[1]);
            }
        }
        else
        {
            keyValues = null;
        }

        string logFile;
        if (arguments.Has(ConfigInfo.LogFile))
        {
            logFile = arguments.Get(ConfigInfo.LogFile).Next;
        }
        else
        {
            logFile = GetAppSetting(ConfigInfo.LogFile);
        }

        if (!File.Exists(solutionUrl))
        {
            AddFormatPrint("The file specified does not exist.");
            AddFormatPrint("FileName:" + solutionUrl);
        }
        else
        {
            AddFormatPrint("Start building solutions");
            AddFormatPrint();

            AddFormatPrint("Check output directory exists");
            if (!Directory.Exists(outputDir))
            {
                AddFormatPrint("Create output directory:");
                AddFormatPrint(outputDir);
                Directory.CreateDirectory(outputDir);
                AddFormatPrint("Output directory has been created successfully");
            }
            else
            {
                AddFormatPrint("Output directory already exists");
            }
            AddFormatPrint();

            AddFormatPrint("Start compilation solution");
            AddFormatPrint();
            try
            {
                bool success = CompileSolution1(solutionUrl, outputDir, keyValues);
                AddFormatPrint();

                if (success)
                {
                    AddFormatPrint("Compilation completed successfully.");
                }
                else
                {
                    AddFormatPrint("Compilation failed.");
                }
            }
            catch (Exception ex)
            {
                AddFormatPrint(ex.Message);
            }
        }

        foreach (string fullPathName in OutputFiles.Where(t => t.Value == false).Select(t => t.Key))
        {
            try
            {
                File.Delete(fullPathName);
            }
            catch
            {
            }
        }
        File.WriteAllLines(logFile, Logs);

#if DEBUG
AddFormatPrint(“Press the any key to exit.”);
Console.ReadKey();
#endif
}

    private void MSBuildWorkspaceFailed(object sender, WorkspaceDiagnosticEventArgs e)
    {
        Console.WriteLine(e.Diagnostic.Message);
        //Console.WriteLine(e.Diagnostic.LoaderExceptions);
    }



    //private static void Compile(ISolution solution)
    //{
    //    var workspaceServices = (IHaveWorkspaceServices)solution;
    //    var projectDependencyService = workspaceServices.WorkspaceServices.GetService<IProjectDependencyService>();

    //    foreach (var projectId in projectDependencyService.GetDependencyGraph(solution).GetTopologicallySortedProjects())
    //    {
    //        var currentDomain = AppDomain.CurrentDomain;
    //        var assemblyName = new AssemblyName();
    //        assemblyName.Name = "Most." + solution.GetProject(projectId).AssemblyName;

    //        var assemblyBuilder = currentDomain.DefineDynamicAssembly
    //                       (assemblyName, AssemblyBuilderAccess.RunAndSave);

    //        var moduleBuilder = assemblyBuilder.
    //                                        DefineDynamicModule(assemblyName.Name);
    //        var types = moduleBuilder.GetTypes();
    //        types.Aggregate((ts, t) =>
    //        {
    //            var tb = t as TypeBuilder;
    //            return tb.CreateType();
    //        });
    //        solution.GetProject(projectId).GetCompilation().Emit(moduleBuilder);
    //        assemblyBuilder.Save(assemblyName.Name);
    //    }
    //}

    /// <summary>
    /// 编译解决方案和输出项目bin文件
    /// </summary>
    /// <param name="solutionUrl"></param>
    /// <param name="outputDir"></param>
    /// <param name="keyValues"></param>
    /// <returns></returns>
    private bool CompileSolution1(string solutionUrl, string outputDir, Dictionary<string, string> keyValues = null)
    {
        bool success = true;

        MSBuildWorkspace workspace;
        if (keyValues == null)
            keyValues = new Dictionary<string, string>();
        //if (keyValues.ContainsKey("CheckForSystemRuntimeDependency") == false)
        //    keyValues.Add("CheckForSystemRuntimeDependency","true");
        Solution solution = null;
        try
        {
            workspace = MSBuildWorkspace.Create(keyValues);

            workspace.WorkspaceFailed += MSBuildWorkspaceFailed;
            workspace.LoadMetadataForReferencedProjects = true;

            

            //solution = workspace.OpenSolutionAsync(solutionUrl).Result;

            solution = workspace.OpenSolutionAsync(solutionUrl).Result;
            var aaa = solution.Projects;
            //Property MSBuildInstance As VisualStudioInstance
             Get all instances of MSBuild
            //Private ReadOnly visualStudioInstances() As VisualStudioInstance = MSBuildLocator.QueryVisualStudioInstances().ToArray()
            Pick the instance of MSBuild you want
            //MSBuildInstance = visualStudioInstances(???)
            //MSBuildLocator.RegisterInstance(MSBuildInstance)
            //Using Workspace As MSBuildWorkspace = MSBuildWorkspace.Create()
            //    AddHandler Workspace.WorkspaceFailed, AddressOf MSBuildWorkspaceFailed
            //    Dim currentProject As Project = Workspace.OpenProjectAsync(FileName).Result
             Do something with the project
            //End Using

            Print message for WorkspaceFailed event to help diagnosing project load failures.
            // Private Sub MSBuildWorkspaceFailed(_1 As Object, e1 As WorkspaceDiagnosticEventArgs)
            //    If MsgBox(e1.Diagnostic.Message, MsgBoxStyle.AbortRetryIgnore, "MSBuild Failed") = MsgBoxResult.Abort Then
            //        End
            //    End If
            //End Sub


            //var proj = sln.Projects.First(x => x.Name == "CodeAnalysis.Desktop");
            foreach (var p in solution.Projects)
            {
                Console.WriteLine(p.FilePath);
                var facadesDir = @"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.2\Facades\";
                string libDir = @"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.2\";
                var proj = p.AddMetadataReference(MetadataReference.CreateFromFile(typeof(object).Assembly.Location));
                proj = proj.AddMetadataReference(MetadataReference.CreateFromFile(facadesDir + "System.Runtime.dll"));
                proj = proj.AddMetadataReference(MetadataReference.CreateFromFile(facadesDir + "System.Runtime.Extensions.dll"));
                proj = proj.AddMetadataReference(MetadataReference.CreateFromFile(facadesDir + "System.IO.dll"));
                proj = proj.AddMetadataReference(MetadataReference.CreateFromFile(facadesDir + "System.Threading.Tasks.dll"));
                proj = proj.AddMetadataReference(MetadataReference.CreateFromFile(facadesDir + "System.Text.Encoding.dll"));
                proj = proj.AddMetadataReference(MetadataReference.CreateFromFile(facadesDir + "System.Reflection.dll"));

                proj = proj.AddMetadataReference(MetadataReference.CreateFromFile(Assembly.GetExecutingAssembly().Location));
                proj = proj.AddMetadataReference(MetadataReference.CreateFromFile(libDir + "mscorlib.dll"));
                //proj = proj.AddMetadataReference(MetadataReference.CreateFromFile(libDir + "System.Collections.dll"));
                //proj = proj.AddMetadataReference(MetadataReference.CreateFromFile(libDir + "System.IO.FileSystem.dll"));
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("编绎失败!");
            Console.WriteLine(ex.Message);
            return false;
        }

        ProjectDependencyGraph projectGraph = solution.GetProjectDependencyGraph();

        IEnumerable<ProjectId> projectIds = projectGraph.GetTopologicallySortedProjects();
        foreach (ProjectId projectId in projectIds)
        {
            Project project = solution.GetProject(projectId);
            AddFormatPrint("Building: {0}", project.FilePath);
            try
            {
                Compilation projectCompilation = project.GetCompilationAsync().Result;
                if (null != projectCompilation && !string.IsNullOrEmpty(projectCompilation.AssemblyName))
                {
                    string fileName = string.Format("{0}.dll", projectCompilation.AssemblyName);
                    string fullPathName = string.Format("{0}\\{1}", outputDir, fileName);
                    if (!OutputFiles.ContainsKey(fullPathName))
                    {
                        OutputFiles.Add(fullPathName, true);
                    }

                    var diagnostics = projectCompilation.GetDiagnostics();
                    var warnDiagnostics = diagnostics.Where(x => x.Severity == DiagnosticSeverity.Warning).ToArray();
                    var errorDiagnostics = diagnostics.Where(x => x.Severity == DiagnosticSeverity.Error).ToArray();

                    foreach (var e in errorDiagnostics.Concat(warnDiagnostics).ToArray())
                    {
                        AddFormatPrint("{0}: {1}", e.Severity.ToString(), e.ToString());
                    }

                    if (errorDiagnostics.Any())
                    {
                        OutputFiles[fullPathName] = false;
                        AddFormatPrint("Build failed.");
                        success = false;
                    }
                    else
                    {
                        AddFormatPrint("Build successfully.");

                        using (var stream = new MemoryStream())
                        {
                            EmitResult result = projectCompilation.Emit(stream);
                            AddFormatPrint("{0}  -->  {1}", project.Name, fullPathName);
                            if (result.Success)
                            {
                                using (FileStream file = File.Create(fullPathName))
                                {
                                    stream.Seek(0, SeekOrigin.Begin);
                                    stream.CopyTo(file);
                                }
                                AddFormatPrint("Output successfully.");
                            }
                            else
                            {
                                OutputFiles[fullPathName] = false;
                                AddFormatPrint("Output failed.");
                                success = false;
                            }
                        }
                    }
                    AddFormatPrint();
                }
                else
                {
                    AddFormatPrint("Build failed. {0}", project.FilePath);
                    success = false;
                }
            }
            catch (AggregateException ex)
            {
                foreach (var ie in ex.InnerExceptions)
                {
                    AddFormatPrint(ie.Message);
                }
                success = false;
            }
            catch (Exception ex)
            {
                AddFormatPrint(ex.Message);
                success = false;
            }
            AddFormatPrint();
        }

        return success;
    }

    /// <summary>
    /// 添加消息记录和打印消息
    /// </summary>
    /// <param name="format"></param>
    /// <param name="args"></param>
    private void AddFormatPrint(string format = "", params object[] args)
    {
        if (format == string.Empty)
        {
            Logs.Add(string.Empty);
            Console.WriteLine();
        }
        else
        {
            string log = string.Format(format, args);
            Logs.Add(log);
            Console.WriteLine(log);
        }
    }

    /// <summary>
    /// 获取配置值
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    private string GetAppSetting(string key)
    {
        return ConfigurationManager.AppSettings[key] ?? ConfigurationManager.AppSettings[ConfigInfo.KeyValues[key]];
    }
}

public struct ConfigInfo
{
    /// <summary>
    /// 解决方案路径
    /// </summary>
    public const string SolutionUrl = "-s";

    /// <summary>
    /// 输出目录
    /// </summary>
    public const string OutputDir = "-o";

    /// <summary>
    /// 编译属性
    /// </summary>
    public const string Properties = "-p";

    /// <summary>
    /// 日志文件名称
    /// </summary>
    public const string LogFile = "-l";

    /// <summary>
    /// 帮助
    /// </summary>
    public const string Help = "-h";

    /// <summary>
    /// 提问
    /// </summary>
    public const string Question = "-?";

    /// <summary>
    /// 全称键值对
    /// </summary>
    public static readonly Dictionary<string, string> KeyValues = new Dictionary<string, string> { { SolutionUrl, "solutionUrl" }, { OutputDir, "outputDir" }, { Properties, "properties" }, { LogFile, "logFile" } };
}



//参数解析******************************************************************************************
//在项目中引入这两个类就可以在Main函数里对args做相应的解析和操作了。
//例如有控制台应用Example,在命令行中输入:
//Example.exe -u MrJson -p admin123
//在Example的Main函数里处理args:

//static void Main(string[] args)
//{
//    var arguments = CommandLineArgumentParser.Parse(args);

//    if (arguments.Has("-u"))
//    {
//        Console.WriteLine("用户名:{0}", arguments.Get("-u").Next);
//    }

//    if (arguments.Has("-p"))
//    {
//        Console.WriteLine("密码:{0}", arguments.Get("-p").Next);
//    }
//}

//如果参数后面要传多个值,例如下面这个例子,-chpwd参数需要两个参数:  Example.exe -chpwd admin888 admin999   那么,就可以这样处理:
//        if(arguments.Has("-chpwd"))
//{
//    var arg = arguments.Get("-chpwd");
//        var oldPwd = arg.Take();
//        var newPwd = arg.Take().Take();
//        // 或者
//        var pwds = arg.Take(2);
//        oldPwd = pwds.First();
//    newPwd = pwds.Last();

//    Console.WriteLine("原密码:{0} 新密码:{1}", oldPwd, newPwd);

public class CommandLineArgument
{
    List<CommandLineArgument> _arguments;

    int _index;

    string _argumentText;

    public CommandLineArgument Next
    {
        get
        {
            if (_index < _arguments.Count - 1)
            {
                return _arguments[_index + 1];
            }

            return null;
        }
    }
    public CommandLineArgument Previous
    {
        get
        {
            if (_index > 0)
            {
                return _arguments[_index - 1];
            }

            return null;
        }
    }
    internal CommandLineArgument(List<CommandLineArgument> args, int index, string argument)
    {
        _arguments = args;
        _index = index;
        _argumentText = argument;
    }

    public CommandLineArgument Take()
    {
        return Next;
    }

    public IEnumerable<CommandLineArgument> Take(int count)
    {
        var list = new List<CommandLineArgument>();
        var parent = this;
        for (int i = 0; i < count; i++)
        {
            var next = parent.Next;
            if (next == null)
                break;

            list.Add(next);

            parent = next;
        }

        return list;
    }

    public static implicit operator string(CommandLineArgument argument)
    {
        return argument._argumentText;
    }

    public override string ToString()
    {
        return _argumentText;
    }
}

public class CommandLineArgumentParser
{

    List<CommandLineArgument> _arguments;
    public static CommandLineArgumentParser Parse(string[] args)
    {
        return new CommandLineArgumentParser(args);
    }

    public CommandLineArgumentParser(string[] args)
    {
        _arguments = new List<CommandLineArgument>();

        for (int i = 0; i < args.Length; i++)
        {
            _arguments.Add(new CommandLineArgument(_arguments, i, args[i]));
        }

    }

    public CommandLineArgument Get(string argumentName)
    {
        return _arguments.FirstOrDefault(p => p == argumentName);
    }

    public bool Has(string argumentName)
    {
        return _arguments.Count(p => p == argumentName) > 0;
    }
}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值