| File: Linker\DgmlDependencyRecorder.cs | Web Access |
| Project: src\runtime\src\tools\illink\src\linker\Mono.Linker.csproj (illink) |
// Copyright (c) .NET Foundation and contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Xml; namespace Mono.Linker { /// <summary> /// Class which implements IDependencyRecorder and writes the dependencies into an DGML file. /// </summary> public class DgmlDependencyRecorder : IDependencyRecorder, IDisposable { public const string DefaultDependenciesFileName = "linker-dependencies.dgml"; public Dictionary<string, int> nodeList = new(); public HashSet<(string dependent, string dependee, string reason)> linkList = new(); // first element is source, second is target (dependent --> dependee), third is reason private readonly LinkContext context; private XmlWriter? writer; private Stream? stream; public DgmlDependencyRecorder(LinkContext context, string? fileName = null) { this.context = context; XmlWriterSettings settings = new XmlWriterSettings { Indent = true, IndentChars = " " }; fileName ??= DefaultDependenciesFileName; if (string.IsNullOrEmpty(Path.GetDirectoryName(fileName)) && !string.IsNullOrEmpty(context.OutputDirectory)) { fileName = Path.Combine(context.OutputDirectory, fileName); Directory.CreateDirectory(context.OutputDirectory); } var depsFile = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None); stream = depsFile; writer = XmlWriter.Create(stream, settings); writer.WriteStartDocument(); writer.WriteStartElement("DirectedGraph", "http://schemas.microsoft.com/vs/2009/dgml"); } public void FinishRecording() { Debug.Assert(writer != null); writer.WriteStartElement("Nodes"); { foreach (var pair in nodeList) { writer.WriteStartElement("Node"); writer.WriteAttributeString("Id", pair.Value.ToString()); writer.WriteAttributeString("Label", pair.Key); writer.WriteEndElement(); } } writer.WriteEndElement(); writer.WriteStartElement("Links"); { foreach (var tup in linkList) { writer.WriteStartElement("Link"); writer.WriteAttributeString("Source", nodeList[tup.dependent].ToString()); writer.WriteAttributeString("Target", nodeList[tup.dependee].ToString()); writer.WriteAttributeString("Reason", tup.reason); writer.WriteEndElement(); } } writer.WriteEndElement(); writer.WriteStartElement("Properties"); { writer.WriteStartElement("Property"); writer.WriteAttributeString("Id", "Label"); writer.WriteAttributeString("Label", "Label"); writer.WriteAttributeString("DataType", "String"); writer.WriteEndElement(); writer.WriteStartElement("Property"); writer.WriteAttributeString("Id", "Reason"); writer.WriteAttributeString("Label", "Reason"); writer.WriteAttributeString("DataType", "String"); writer.WriteEndElement(); } writer.WriteEndElement(); writer.WriteEndElement(); writer.WriteEndDocument(); writer.Flush(); } public void Dispose() { if (writer == null) return; writer.Dispose(); stream?.Dispose(); writer = null; stream = null; } public void RecordDependency(object target, in DependencyInfo reason, bool marked) { if (writer == null) throw new InvalidOperationException(); if (reason.Kind == DependencyKind.Unspecified) return; // For now, just report a dependency from source to target without noting the DependencyKind. RecordDependency(reason.Source, target, reason.Kind); } public void RecordDependency(object? source, object target, object? reason) { if (writer == null) throw new InvalidOperationException(); if (!DependencyRecorderHelper.ShouldRecord(context, source, target)) return; string dependent = DependencyRecorderHelper.TokenString(context, source); string dependee = DependencyRecorderHelper.TokenString(context, target); // figure out why nodes are sometimes null, are we missing some information in the graph? if (!nodeList.ContainsKey(dependent)) AddNode(dependent); if (!nodeList.ContainsKey(dependee)) AddNode(dependee); if (source != target) { AddLink(dependent, dependee, reason); } } private int _nodeIndex; void AddNode(string node) { nodeList.Add(node, _nodeIndex); _nodeIndex++; } void AddLink(string source, string target, object? kind) { linkList.Add((source, target, DependencyRecorderHelper.TokenString(context, kind))); } public void RecordDependency(object source, object target, bool marked) { throw new NotImplementedException(); } } }