LuaCompiler.cs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.IO;
  5. using System.Reflection;
  6. using System.Linq;
  7. using System.Text;
  8. using UnityEditor;
  9. using UnityEngine;
  10. namespace ET
  11. {
  12. public static class LuaCompiler
  13. {
  14. private sealed class CompiledFail: Exception
  15. {
  16. public CompiledFail(string message): base(message)
  17. {
  18. }
  19. }
  20. public static readonly string outDir = Application.dataPath + "/Bundles/Lua/";
  21. private const string dotnet = "dotnet";
  22. private static readonly string toolsDir = "./Tools/CSharpLua";
  23. private static readonly string csharpLua = toolsDir + "/CSharp.lua/CSharp.lua.Launcher.dll";
  24. /// <summary>
  25. /// 编译Dll为Lua
  26. /// </summary>
  27. /// <param name="dllName">Dll名</param>
  28. /// <param name="dllDir">Dll文件夹</param>
  29. /// <param name="outDirName">输出Lua文件夹名</param>
  30. /// <param name="referencedLuaAssemblies">需要被编译成Lua的Dll引用名</param>
  31. /// <param name="isModule">是否其他模块被引用</param>
  32. public static void Compile(string dllName, string dllDir, string outDirName, List<string> referencedLuaAssemblies, bool isModule)
  33. {
  34. if (!CheckDotnetInstall())
  35. {
  36. return;
  37. }
  38. if (!File.Exists(csharpLua))
  39. {
  40. throw new InvalidProgramException($"{csharpLua} not found");
  41. }
  42. var outputDir = outDir + outDirName;
  43. if (Directory.Exists(outputDir))
  44. {
  45. Directory.Delete(outputDir, true);
  46. }
  47. HashSet<string> libs = new HashSet<string>();
  48. FillUnityLibraries(libs);
  49. AssemblyName assemblyName = new AssemblyName(dllName);
  50. Assembly assembly = Assembly.Load(assemblyName);
  51. foreach (var referenced in assembly.GetReferencedAssemblies())
  52. {
  53. if (referenced.Name != "mscorlib" && !referenced.Name.StartsWith("System"))
  54. {
  55. string libPath = Assembly.Load(referenced).Location;
  56. if (referencedLuaAssemblies != null && referencedLuaAssemblies.Contains(referenced.Name))
  57. {
  58. libPath += "!";
  59. }
  60. libs.Add(libPath);
  61. }
  62. }
  63. string lib = string.Join(";", libs.ToArray());
  64. string args = $"{csharpLua} -s \"{dllDir}\" -d \"{outputDir}\" -l \"{lib}\" -m -c -a -e -ei";
  65. UnityEngine.Debug.Log(args);
  66. if (isModule)
  67. {
  68. args += " -module";
  69. }
  70. string definesString = PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup);
  71. if (!string.IsNullOrEmpty(definesString))
  72. {
  73. args += $" -csc -define:{definesString}";
  74. }
  75. var info = new ProcessStartInfo()
  76. {
  77. FileName = dotnet,
  78. Arguments = args,
  79. UseShellExecute = false,
  80. RedirectStandardOutput = true,
  81. RedirectStandardError = true,
  82. StandardOutputEncoding = Encoding.UTF8,
  83. StandardErrorEncoding = Encoding.UTF8,
  84. CreateNoWindow = true
  85. };
  86. using (var p = Process.Start(info))
  87. {
  88. p.WaitForExit();
  89. if (p.ExitCode == 0)
  90. {
  91. UnityEngine.Debug.Log("compile success");
  92. }
  93. else
  94. {
  95. string outString = p.StandardOutput.ReadToEnd();
  96. string errorString = p.StandardError.ReadToEnd();
  97. throw new CompiledFail($"Compile fail, {errorString}\n{outString}\n{dotnet} {args}");
  98. }
  99. }
  100. }
  101. private static void FillUnityLibraries(HashSet<string> libs)
  102. {
  103. string unityObjectPath = typeof (UnityEngine.Object).Assembly.Location;
  104. string baseDir = Path.GetDirectoryName(unityObjectPath);
  105. foreach (string path in Directory.EnumerateFiles(baseDir, "*.dll"))
  106. {
  107. libs.Add(path);
  108. }
  109. }
  110. private static bool CheckDotnetInstall()
  111. {
  112. bool has = InternalCheckDotnetInstall();
  113. if (!has)
  114. {
  115. UnityEngine.Debug.LogWarning("not found dotnet");
  116. if (EditorUtility.DisplayDialog("dotnet未安装", "未安装.NET Core 3.0+运行环境,点击确定前往安装", "确定", "取消"))
  117. {
  118. Application.OpenURL("https://www.microsoft.com/net/download");
  119. }
  120. }
  121. return has;
  122. }
  123. private static bool InternalCheckDotnetInstall()
  124. {
  125. var info = new ProcessStartInfo()
  126. {
  127. FileName = dotnet,
  128. Arguments = "--version",
  129. UseShellExecute = false,
  130. RedirectStandardOutput = true,
  131. RedirectStandardError = true,
  132. CreateNoWindow = true,
  133. StandardOutputEncoding = Encoding.UTF8,
  134. StandardErrorEncoding = Encoding.UTF8,
  135. };
  136. try
  137. {
  138. using (var p = Process.Start(info))
  139. {
  140. p.WaitForExit();
  141. if (p.ExitCode == 0)
  142. {
  143. string version = p.StandardOutput.ReadToEnd();
  144. UnityEngine.Debug.LogFormat("found dotnet {0}", version);
  145. int major = version[0] - '0';
  146. if (major >= 3)
  147. {
  148. return true;
  149. }
  150. else
  151. {
  152. UnityEngine.Debug.LogErrorFormat("dotnet verson {0} must >= 3.0", version);
  153. }
  154. }
  155. return false;
  156. }
  157. }
  158. catch (Exception e)
  159. {
  160. UnityEngine.Debug.LogException(e);
  161. return false;
  162. }
  163. }
  164. }
  165. }