1 // 2 // Copyright (c) 2010-2022 Antmicro 3 // 4 // This file is licensed under the MIT License. 5 // Full license text is available in 'licenses/MIT.txt'. 6 // 7 using System; 8 using System.IO; 9 using System.CodeDom.Compiler; 10 using System.Collections.Generic; 11 using System.Linq; 12 using Antmicro.Renode.Exceptions; 13 using System.Reflection; 14 using Microsoft.CodeAnalysis; 15 using Microsoft.CodeAnalysis.CSharp; 16 using Microsoft.CodeAnalysis.Text; 17 18 namespace Antmicro.Renode.Utilities 19 { 20 public class AdHocCompiler 21 { Compile(string sourcePath)22 public string Compile(string sourcePath) 23 { 24 var tempFilePath = TemporaryFilesManager.Instance.GetTemporaryFile(); 25 // With .NET Core and above, one must explicitly specify a .dll extension for output assembly 26 var outputFilePath = Path.ChangeExtension(tempFilePath, ".dll"); 27 var outputFileName = Path.GetFileName(outputFilePath); 28 29 var sourceCode = File.ReadAllText(sourcePath); 30 var codeString = SourceText.From(sourceCode); 31 var options = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp9); 32 33 var parsedSyntaxTree = SyntaxFactory.ParseSyntaxTree(codeString, options); 34 35 var references = new List<MetadataReference> 36 { 37 MetadataReference.CreateFromFile(typeof(object).Assembly.Location), 38 }; 39 40 AssemblyHelper.GetAssembliesLocations().ToList() 41 .ForEach(location => references.Add(MetadataReference.CreateFromFile(location))); 42 43 var result = CSharpCompilation.Create(outputFileName, 44 new[] { parsedSyntaxTree }, 45 references: references, 46 options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, 47 optimizationLevel: OptimizationLevel.Release, 48 assemblyIdentityComparer: DesktopAssemblyIdentityComparer.Default)).Emit(outputFilePath); 49 50 if (!result.Success) 51 { 52 // Access diagnostic informations 53 var failures = result.Diagnostics.Where(diagnostic => diagnostic.IsWarningAsError || diagnostic.Severity == DiagnosticSeverity.Error); 54 var diagnosticString = string.Join(Environment.NewLine, failures.Select(x => x.ToString())); 55 throw new RecoverableException($"Could not compile assembly from: {sourcePath}\n{diagnosticString}"); 56 } 57 58 return outputFilePath; 59 } 60 } 61 }