| | | 1 | | using Microsoft.CodeAnalysis; |
| | | 2 | | using Microsoft.CodeAnalysis.CSharp; |
| | | 3 | | using pva.Helpers.Extensions; |
| | | 4 | | using pva.SuperV.Engine.Exceptions; |
| | | 5 | | using System.Text; |
| | | 6 | | |
| | | 7 | | namespace pva.SuperV.Engine |
| | | 8 | | { |
| | | 9 | | /// <summary> |
| | | 10 | | /// Class for building a <see cref="WipProject"/> and convert it to a <see cref="RunnableProject"/> by generating an |
| | | 11 | | /// </summary> |
| | | 12 | | public static class ProjectBuilder |
| | | 13 | | { |
| | | 14 | | /// <summary> |
| | | 15 | | /// Builds the specified <see cref="WipProject"/>. |
| | | 16 | | /// </summary> |
| | | 17 | | /// <param name="wipProject">The WIP project.</param> |
| | | 18 | | /// <returns>a <see cref="RunnableProject"/></returns> |
| | | 19 | | /// <exception cref="pva.SuperV.Engine.Exceptions.ProjectBuildException"></exception> |
| | | 20 | | public static async Task<RunnableProject> BuildAsync(WipProject wipProject) |
| | 126 | 21 | | { |
| | 126 | 22 | | RunnableProject runnableProject = wipProject.CloneAsRunnable(); |
| | 124 | 23 | | wipProject.Dispose(); |
| | 124 | 24 | | await BuildAsync(runnableProject); |
| | 124 | 25 | | return runnableProject; |
| | 124 | 26 | | } |
| | | 27 | | |
| | | 28 | | public static async ValueTask BuildAsync(RunnableProject runnableProject) |
| | 327 | 29 | | { |
| | 327 | 30 | | if (!File.Exists(runnableProject.GetAssemblyFileName())) |
| | 124 | 31 | | { |
| | 124 | 32 | | string projectAssemblyFileName = runnableProject.GetAssemblyFileName(); |
| | 124 | 33 | | string projectCode = runnableProject.GetCode(); |
| | 124 | 34 | | var compilation = CreateCompilation(CSharpSyntaxTree.ParseText(projectCode), $"{runnableProject.Name}-V{ |
| | 124 | 35 | | using MemoryStream dllStream = new(); |
| | 124 | 36 | | using MemoryStream pdbStream = new(); |
| | 124 | 37 | | using Stream win32ResStream = compilation.CreateDefaultWin32Resources( |
| | 124 | 38 | | versionResource: true, // Important! |
| | 124 | 39 | | noManifest: false, |
| | 124 | 40 | | manifestContents: null, |
| | 124 | 41 | | iconInIcoFormat: null); |
| | 124 | 42 | | var compilationResult = compilation.Emit( |
| | 124 | 43 | | peStream: dllStream, |
| | 124 | 44 | | pdbStream: pdbStream, |
| | 124 | 45 | | win32Resources: win32ResStream); |
| | | 46 | | |
| | 124 | 47 | | if (!compilationResult.Success) |
| | 0 | 48 | | { |
| | 0 | 49 | | StringBuilder diagnostics = new(); |
| | 0 | 50 | | compilationResult.Diagnostics |
| | 0 | 51 | | .ForEach(diagnostic => diagnostics.AppendLine(diagnostic.ToString())); |
| | 0 | 52 | | throw new ProjectBuildException(runnableProject, diagnostics.ToString()); |
| | | 53 | | } |
| | 124 | 54 | | await File.WriteAllBytesAsync(projectAssemblyFileName, dllStream.ToArray()); |
| | 124 | 55 | | } |
| | 327 | 56 | | } |
| | | 57 | | |
| | | 58 | | /// <summary> |
| | | 59 | | /// Creates a <see cref="CSharpCompilation"/> to generate an assembly for the project. |
| | | 60 | | /// </summary> |
| | | 61 | | /// <param name="tree">The tree.</param> |
| | | 62 | | /// <param name="name">The name.</param> |
| | | 63 | | /// <returns>A <see cref="CSharpCompilation"/></returns> |
| | | 64 | | private static CSharpCompilation CreateCompilation(SyntaxTree tree, string name) |
| | 124 | 65 | | { |
| | 124 | 66 | | var assemblyPath = Path.GetDirectoryName(typeof(object).Assembly.Location); |
| | 124 | 67 | | List<MetadataReference> refs = |
| | 124 | 68 | | [ |
| | 124 | 69 | | /* |
| | 124 | 70 | | * Adding some necessary .NET assemblies |
| | 124 | 71 | | * These assemblies couldn't be loaded correctly via the same construction as above, |
| | 124 | 72 | | * in specific the System.Runtime. |
| | 124 | 73 | | */ |
| | 124 | 74 | | MetadataReference.CreateFromFile(Path.Combine(assemblyPath!, "mscorlib.dll")), |
| | 124 | 75 | | MetadataReference.CreateFromFile(Path.Combine(assemblyPath!, "System.dll")), |
| | 124 | 76 | | MetadataReference.CreateFromFile(Path.Combine(assemblyPath!, "System.Core.dll")), |
| | 124 | 77 | | MetadataReference.CreateFromFile(Path.Combine(assemblyPath!, "System.Runtime.dll")), |
| | 124 | 78 | | MetadataReference.CreateFromFile(Path.Combine(assemblyPath!, "System.Collections.dll")), |
| | 124 | 79 | | // Basic types assembly |
| | 124 | 80 | | MetadataReference.CreateFromFile(typeof(string).Assembly.Location), |
| | 124 | 81 | | // SuperV Project assembly |
| | 124 | 82 | | MetadataReference.CreateFromFile(typeof(Project).Assembly.Location) |
| | 124 | 83 | | ]; |
| | | 84 | | |
| | 124 | 85 | | return CSharpCompilation |
| | 124 | 86 | | .Create(name, options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)) |
| | 124 | 87 | | .AddReferences(refs) |
| | 124 | 88 | | .AddSyntaxTrees(tree); |
| | 124 | 89 | | } |
| | | 90 | | } |
| | | 91 | | } |