/// <summary> /// 获取插件程序集对应的pdb文件路径 /// </summary> /// <param name="info">插件信息</param> /// <returns></returns> public static string AssemblyPdbPath(this PluginInfo info) { return Path.Combine(info.BinDirectory(), $"{info.DirectoryName()}.pdb"); }
/// <summary> /// 获取保存编译信息的文件路径 /// 这个文件中有源代码和修改时间的列表 /// 用于检测是否需要重新编译 /// </summary> /// <param name="info">插件信息</param> /// <returns></returns> public static string CompileInfoPath(this PluginInfo info) { return Path.Combine(info.BinDirectory(), "CompileInfo.txt"); }
/// <summary> /// 编译插件 /// </summary> /// <param name="info">插件信息</param> public static void Compile(this PluginInfo info) { // 获取插件的源代码文件列表和各个路径 var sourceDirectory = info.SourceDirectory(); var sourceFiles = info.SourceFiles(); var assemblyPath = info.AssemblyPath(); var assemblyPdbPath = info.AssemblyPdbPath(); var compileInfoPath = info.CompileInfoPath(); // 检查是否需要重新编译 // 会通过对比所有源文件的修改时间是否一致来检查 // 没有源文件时表示只有资源文件或不开源,不需要重新编译 var existCompileInfo = ""; if (File.Exists(compileInfoPath)) { existCompileInfo = File.ReadAllText(compileInfoPath); } var compileInfo = string.Join("\r\n", sourceFiles .Select(s => new { path = s.Substring(sourceDirectory.Length + 1), time = File.GetLastWriteTime(s) }) // 相对路径和修改时间 .OrderBy(s => s.path) // 固定排序 .Select(s => $"{s.path} {s.time}")); // 生成文本 if (sourceFiles.Length > 0 && compileInfo != existCompileInfo) { // 重新编译前把原来的文件重命名为old文件 if (File.Exists(assemblyPath)) { File.Move(assemblyPath, $"{assemblyPath}.{DateTime.UtcNow.Ticks}.old"); } if (File.Exists(assemblyPdbPath)) { File.Move(assemblyPdbPath, $"{assemblyPdbPath}.{DateTime.UtcNow.Ticks}.old"); } // 编译,debug = true可以生成pdb文件以支持断点 var references = info.References.Concat(DefaultReferences); var referenceLocations = references.Select( r => Assembly.Load(r).Location).ToArray(); Directory.CreateDirectory(info.BinDirectory()); CSScript.CompileFiles(sourceFiles, assemblyPath, true, referenceLocations); // 保存编译信息 File.WriteAllText(compileInfoPath, compileInfo); // 删除old文件 // 有可能因为文件占用而删除不成功,忽略删除失败时的例外 Directory.EnumerateFiles(info.BinDirectory(), "*.old").ForEach( path => { try { File.Delete(path); } catch { } }); } }