public static IAssemblySymbol GetCompilation(Stream stream, Stream documentationStream) { PortableExecutableReference reference; using (var memoryStream = new MemoryStream()) { stream.CopyTo(memoryStream); memoryStream.Position = 0; DocumentationProvider documentation = null; if (documentationStream != null) { using var docMemoryStream = new MemoryStream(); documentationStream.CopyTo(docMemoryStream); docMemoryStream.Position = 0; documentation = XmlDocumentationProvider.CreateFromBytes(docMemoryStream.ToArray()); } // MetadataReference.CreateFromStream closes the stream reference = MetadataReference.CreateFromStream(memoryStream, documentation: documentation); } var compilation = CSharpCompilation.Create(null).AddReferences(reference); var corlibLocation = typeof(object).Assembly.Location; var runtimeFolder = Path.GetDirectoryName(corlibLocation); compilation = compilation.AddReferences(MetadataReference.CreateFromFile(corlibLocation)); var trustedAssemblies = ((string)AppContext.GetData("TRUSTED_PLATFORM_ASSEMBLIES")).Split(Path.PathSeparator); foreach (var tpl in trustedAssemblies) { if (tpl.StartsWith(runtimeFolder) || AllowedAssemblies.Contains(Path.GetFileNameWithoutExtension(tpl))) { compilation = compilation.AddReferences(MetadataReference.CreateFromFile(tpl)); } } return((IAssemblySymbol)compilation.GetAssemblyOrModuleSymbol(reference)); }
static async Task Main(string[] args) { var rootFolder = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, @"../../../../..")); var srcFolder = Path.Combine(rootFolder, "src"); // Hack re-add System.Runtime.Intrinsics with doc // @"packs/Microsoft.NETCore.App.Ref/5.0.0/ref/net5.0"; var instances = MSBuildLocator.QueryVisualStudioInstances(new VisualStudioInstanceQueryOptions() { DiscoveryTypes = DiscoveryType.DotNetSdk, WorkingDirectory = AppContext.BaseDirectory }); MetadataReference intrinsicsAssembly = null; foreach (var instance in instances) { var file = Path.GetFullPath(Path.Combine(instance.MSBuildPath, "..", "..", "packs", "Microsoft.NETCore.App.Ref", "5.0.0", "ref", "net5.0", "System.Runtime.Intrinsics.xml")); if (File.Exists(file)) { var docText = File.ReadAllText(file); foreach (var fixDocPair in FixIntrinsicsDocumentation) { docText = docText.Replace(fixDocPair.Key, fixDocPair.Value); } var docProvider = XmlDocumentationProvider.CreateFromBytes(new UTF8Encoding(false).GetBytes(docText)); var assemblyPath = Path.ChangeExtension(file, "dll"); intrinsicsAssembly = MetadataReference.CreateFromFile(assemblyPath, MetadataReferenceProperties.Assembly, docProvider); break; } } if (intrinsicsAssembly == null) { Console.WriteLine("Unable to find System.Runtime.Intrinsics.xml from dotnet SDK installed"); Environment.Exit(1); return; } var workspace = new AdhocWorkspace(); var project = workspace.AddProject("Temp", LanguageNames.CSharp); project = project.AddMetadataReference(intrinsicsAssembly); workspace.TryApplyChanges(project.Solution); // Make sure that doc will be parsed project = project.WithCompilationOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); project = project.WithParseOptions(project.ParseOptions.WithDocumentationMode(DocumentationMode.Parse)); // Compile the project var compilation = await project.GetCompilationAsync(); var errors = compilation.GetDiagnostics().Where(diagnostic => diagnostic.Severity == DiagnosticSeverity.Error).ToList(); if (errors.Count > 0) { Console.WriteLine("Compilation errors:"); foreach (var error in errors) { Console.WriteLine(error); } Console.WriteLine("Error, Exiting."); Environment.Exit(1); return; } var intrinsicModules = FindIntrinsics(compilation); var templateStr = @"//------------------------------------------------------------------------------ // <auto-generated> // This code was generated by a tool. // Date: {{ date.now }} // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // </auto-generated> //------------------------------------------------------------------------------ using System; {{~ for module in intrinsics ~}} namespace {{ module.Namespace }} { public partial class {{ module.ClassName }} { public const string Category = ""{{ module.Category }}""; {{~ for member in module.Members ~}} /// <summary> /// {{ member.Description | string.replace '\n' '\n ///' }} {{~ for param in member.Parameters ~}} /// <param name=""{{param.Name}}"">{{param.Description}}</param> {{~ end ~}} /// </summary> [KalkExport(""{{ member.Name }}"", Category)] {{ member.MethodDeclaration }} {{ member.IndirectMethodDeclaration }} {{~ end ~}} } } {{~ end ~}} "; var template = Template.Parse(templateStr); var result = template.Render(new { intrinsics = intrinsicModules }, x => x.Name); var finalPath = Path.Combine(srcFolder, "Kalk.Core/Modules/HardwareIntrinsics/Intrinsics.generated.cs"); Console.WriteLine($"Writing intrinsics to {finalPath}"); // Replace with platform newlines result = result.Replace("\r\n", "\n").Replace("\n", Environment.NewLine); await File.WriteAllTextAsync(finalPath, result, new UTF8Encoding(false)); }
public IEnumerable <IDocument> Execute(IReadOnlyList <IDocument> inputs, IExecutionContext context) { List <ISymbol> symbols = new List <ISymbol>(); // Create the compilation (have to supply an XmlReferenceResolver to handle include XML doc comments) MetadataReference mscorlib = MetadataReference.CreateFromFile(typeof(object).Assembly.Location); Compilation compilation = CSharpCompilation .Create(CompilationAssemblyName) .WithReferences(mscorlib) .WithOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, xmlReferenceResolver: new XmlFileResolver(context.FileSystem.RootPath.FullPath))); // Handle input documents if (_inputDocuments) { // Get syntax trees (supply path so that XML doc includes can be resolved) ConcurrentBag <SyntaxTree> syntaxTrees = new ConcurrentBag <SyntaxTree>(); context.ParallelForEach(inputs, input => { using (Stream stream = input.GetStream()) { SourceText sourceText = SourceText.From(stream); syntaxTrees.Add(CSharpSyntaxTree.ParseText(sourceText, path: input.String(Keys.SourceFilePath, string.Empty))); } }); compilation = compilation.AddSyntaxTrees(syntaxTrees); } // Handle assemblies IEnumerable <IFile> assemblyFiles = context.FileSystem.GetInputFiles(_assemblyGlobs) .Where(x => (x.Path.Extension == ".dll" || x.Path.Extension == ".exe") && x.Exists); MetadataReference[] assemblyReferences = assemblyFiles.Select(assemblyFile => { // Create the metadata reference for the compilation IFile xmlFile = context.FileSystem.GetFile(assemblyFile.Path.ChangeExtension("xml")); if (xmlFile.Exists) { Trace.Verbose($"Creating metadata reference for assembly {assemblyFile.Path.FullPath} with XML documentation file"); using (Stream xmlStream = xmlFile.OpenRead()) { using (MemoryStream xmlBytes = new MemoryStream()) { xmlStream.CopyTo(xmlBytes); return(MetadataReference.CreateFromStream(assemblyFile.OpenRead(), documentation: XmlDocumentationProvider.CreateFromBytes(xmlBytes.ToArray()))); } } } Trace.Verbose($"Creating metadata reference for assembly {assemblyFile.Path.FullPath} without XML documentation file"); return((MetadataReference)MetadataReference.CreateFromStream(assemblyFile.OpenRead())); }).ToArray(); if (assemblyReferences.Length > 0) { compilation = compilation.AddReferences(assemblyReferences); symbols.AddRange(assemblyReferences .Select(x => (IAssemblySymbol)compilation.GetAssemblyOrModuleSymbol(x)) .Select(x => _assemblySymbols ? x : (ISymbol)x.GlobalNamespace)); } // Get and return the document tree symbols.Add(compilation.Assembly.GlobalNamespace); AnalyzeSymbolVisitor visitor = new AnalyzeSymbolVisitor(compilation, context, _symbolPredicate, _writePath ?? (x => DefaultWritePath(x, _writePathPrefix)), _cssClasses, _docsForImplicitSymbols, _assemblySymbols); foreach (ISymbol symbol in symbols) { visitor.Visit(symbol); } return(visitor.Finish()); }