BITKit/Src/Core/Sharp/BITSharp.cs

229 lines
8.5 KiB
C#

using System;
using System.CodeDom.Compiler;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using BITKit.Mod;
#if UNITY_5_3_OR_NEWER
using System.Collections;
using BITKit.UX;
using UnityEngine;
using UnityEngine.Rendering;
using static BITKit.Mod.DotNetSdkRoslynService;
#endif
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace BITKit
{
public class BITSharp
{
#if UNITY_5_3_OR_NEWER
[RuntimeInitializeOnLoadMethod]
private static void Reload()
{
ReferencedAssemblies.Clear();
Dictionary.Clear();
assemblies = null;
}
#endif
public static readonly List<string> ReferencedAssemblies = new();
private static readonly ConcurrentDictionary<string, Type> Dictionary = new();
private static Assembly[] assemblies;
public static bool TryGetTypeFromFullName(string fullClassName, out Type type)
{
type = GetTypeFromFullName(fullClassName);
return type is not null ? true : false;
}
public static Type GetTypeFromFullName(string fullClassName)
{
return Dictionary.GetOrAdd(fullClassName, SearchType);
}
private static Type SearchType(string fullName)
{
if (string.IsNullOrWhiteSpace(fullName))
{
throw new ArgumentException("fullName is null or empty", nameof(fullName));
}
assemblies ??= AppDomain.CurrentDomain.GetAssemblies();
return assemblies.Select(assembly => assembly.GetType(fullName, false)).FirstOrDefault(type => type is not null);
}
#if UNITY_5_3_OR_NEWER
public static Assembly Compile(params string[] codes)
{
var outputPath = PathHelper.GetTempFilePath();
try
{
if (Installed is false)
{
throw new FileNotFoundException($"未从当前路径找到Roslyn:\n{CSCPath}");
}
var argumentBuilder = new StringBuilder();
var tempList = new List<string> { outputPath };
foreach (var code in codes)
{
var temp = PathHelper.GetTempFilePath();
File.WriteAllText(temp,code);
argumentBuilder.Append(" ");
argumentBuilder.Append(temp);
tempList.Add(temp);
}
argumentBuilder.Append(" -target:library");
argumentBuilder.Append(" /unsafe");
foreach (var x in ReferencedAssemblies)
{
argumentBuilder.Append(" ");
argumentBuilder.Append("-r:");
argumentBuilder.Append(x);
//argumentBuilder.Append(Path.Combine(dllPath, x));
}
argumentBuilder.Append(" ");
argumentBuilder.Append($"-out:{outputPath}");
BIT4Log.Log<BITSharp>("已创建编译参数:");
BIT4Log.Log(argumentBuilder.ToString());
BIT4Log.Log<BITSharp>($"dotnet {CSCPath} {argumentBuilder}");
//Original
// var StartInfo = new ProcessStartInfo
// {
// //FileName = MCSPath,
// FileName = "dotnet",
// Arguments =$"{CSCPath} {argumentBuilder}" ,
// UseShellExecute = true,
// CreateNoWindow = false,
// };
var startInfo = new ProcessStartInfo
{
//FileName = MCSPath,
FileName = "dotnet",
Arguments =$"{CSCPath} {argumentBuilder}" ,
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
StandardErrorEncoding = System.Text.Encoding.GetEncoding("gb2312"),
StandardInputEncoding = System.Text.Encoding.GetEncoding("gb2312"),
StandardOutputEncoding = System.Text.Encoding.GetEncoding("gb2312"),
};
var process = new Process()
{
StartInfo = startInfo,
};
var reportBuilder = new StringBuilder();
process.OutputDataReceived += (sender, args) =>
{
//BIT4Log.Log<BITSharp>(args.Data);
reportBuilder.AppendLine(args.Data);
};
process.ErrorDataReceived += (sender, args) =>
{
//BIT4Log.Warning<BITSharp>(args.Data);
reportBuilder.AppendLine($"<color=yellow>{args.Data}</color>");
};
process.Start();
BIT4Log.Log<BITSharp>("已启动");
process.BeginErrorReadLine();
process.BeginOutputReadLine();
while (process.HasExited is false)
{
Thread.Sleep(100);
if (BITApp.CancellationToken.IsCancellationRequested) throw new OperationCanceledException("程序已退出,取消编译");
}
var bytes = File.ReadAllBytes(outputPath);
if(process.ExitCode is not 0)
{
BIT4Log.LogException(new Exception($"编译失败:{process.ExitCode}"));
}
else
{
foreach (var x in tempList)
{
File.Delete(x);
}
}
BIT4Log.Log<BITSharp>(reportBuilder);
return Assembly.Load(bytes);
}
catch (Exception e)
{
throw new Exception($"编译失败:{e}");
}
// var codeProvider = new CSharpCodeProvider();
// var parameters = new CompilerParameters
// {
// GenerateInMemory = true,
// CompilerOptions = "/unsafe",
// OutputAssembly = outputPath,
// };
// parameters.ReferencedAssemblies.Add("System.dll");
// foreach (var x in ReferencedAssemblies)
// {
// parameters.ReferencedAssemblies.Add(x);
// BIT4Log.Log<BITSharp>($"添加引用:");
// BIT4Log.Log<BITSharp>(x);
// }
//
// BIT4Log.Log<BITSharp>($"程序集输出路径:{outputPath}");
//
// var results = codeProvider.CompileAssemblyFromSource(parameters, codes);
//
// if (results.Errors.Count <= 0)
// {
// BIT4Log.Log<BITSharp>($"编译成功:{results.CompiledAssembly.FullName}");
//
// codeProvider.Dispose();
// return results.CompiledAssembly;
// }
//
// foreach (CompilerError error in results.Errors)
// {
// var sb = new StringBuilder();
// sb.AppendLine(error.FileName);
// sb.AppendLine($"Error ({error.ErrorNumber}): {error.ErrorText}");
// sb.AppendLine($"Line: {error.Line}, Column: {error.Column}");
// sb.AppendLine($"Is Warning: {error.IsWarning}");
// BIT4Log.LogException(new Exception(sb.ToString()));
// }
//
// throw new Exception("编译失败");
}
#endif
}
}