Skip to content

Add support for dependency generator #12

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions source/MetadataProcessor.Console/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,28 @@ public void GenerateSkeleton(
Environment.Exit(1);
}
}

public void GenerateDependency(string fileName)
{
try
{
var dependencyGenerator = new nanoDependencyGenerator(
_assemblyDefinition,
_assemblyBuilder.TablesContext,
fileName);

using (var writer = XmlWriter.Create(fileName))
{
dependencyGenerator.Write(writer);
}
}
catch (Exception)
{
System.Console.Error.WriteLine(
"Unable to generate and write dependency graph for assembly file '{0}'.", fileName);
throw;
}
}
}

public static void Main(string[] args)
Expand Down Expand Up @@ -162,6 +184,7 @@ public static void Main(string[] args)
System.Console.WriteLine("-loadHints <assembly-name> <path-to-assembly-file> Loads one (or more) assembly file(s) as a dependency(ies).");
System.Console.WriteLine("-excludeClassByName <class-name> Removes the class from an assembly.");
System.Console.WriteLine("-generateskeleton Generate skeleton files with stubs to add native code for an assembly.");
System.Console.WriteLine("-generateDependency Generates an XML file with the relationship between assemblies.");
System.Console.WriteLine("-minimize Minimizes the assembly, removing unwanted elements.");
System.Console.WriteLine("-verbose Outputs each command before executing it.");
System.Console.WriteLine("");
Expand Down Expand Up @@ -214,6 +237,10 @@ public static void Main(string[] args)

i += 4;
}
else if (arg == "-generatedependency" && i + 1 < args.Length)
{
md.GenerateDependency(args[++i]);
}
else
{
System.Console.Error.WriteLine("Unknown command line option '{0}' ignored.", arg);
Expand Down
2 changes: 2 additions & 0 deletions source/MetadataProcessor.Core/MetadataProcessor.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
<Compile Include="Mono.Cecil\CodeWriter.cs" />
<Compile Include="nanoAssemblyBuilder.cs" />
<Compile Include="nanoAssemblyDefinition.cs" />
<Compile Include="nanoDependencyGenerator.cs" />
<Compile Include="nanoSkeletonGenerator.cs" />
<Compile Include="SkeletonGenerator\AssemblyClass.cs" />
<Compile Include="SkeletonGenerator\AssemblyClassStubs.cs" />
Expand Down Expand Up @@ -99,6 +100,7 @@
<Compile Include="Utility\nanoBitmapProcessor.cs" />
<Compile Include="Utility\nanoCLR_DataType.cs" />
<Compile Include="Utility\nanoFontProcessor.cs" />
<Compile Include="Utility\nanoDependencyGeneratorWriter.cs" />
<Compile Include="Utility\nanoPdbxFileWriter.cs" />
<Compile Include="Utility\nanoTypeDefinitionFlags.cs" />
<Compile Include="Utility\nanoSerializationType.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ public abstract class nanoReferenceTableBase<T> : InanoTable
/// Assembly tables context - contains all tables used for building target assembly.
/// </summary>
protected readonly nanoTablesContext _context;

/// <summary>
/// Lookup table for finding item ID by item value.
/// </summary>
protected readonly IEnumerable<T> _items;

public IEnumerable<T> Items => _items;

/// <summary>
/// Creates new instance of <see cref="nanoReferenceTableBase{T}"/> object.
Expand All @@ -46,6 +53,8 @@ protected nanoReferenceTableBase(
comparer);

_context = context;

_items = tinyTableItems;
}

/// <inheritdoc/>
Expand Down
217 changes: 217 additions & 0 deletions source/MetadataProcessor.Core/Utility/nanoDependencyGeneratorWriter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
//
// Copyright (c) 2019 The nanoFramework project contributors
// Original work from Oleg Rakhmatulin.
// See LICENSE file in the project root for full license information.
//

using Mono.Cecil;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Xml;

namespace nanoFramework.Tools.MetadataProcessor
{
internal sealed class nanoDependencyGeneratorWriter
{
private readonly nanoTablesContext _context;
private readonly AssemblyDefinition _assemblyDefinition;

public nanoDependencyGeneratorWriter(
AssemblyDefinition assemblyDefinition,
nanoTablesContext context)
{
_context = context;
_assemblyDefinition = assemblyDefinition;
}

public void Write(
XmlWriter writer)
{
writer.WriteStartElement("AssemblyGraph");

writer.WriteStartElement("Assembly");
writer.WriteAttributeString("Name", _context.AssemblyDefinition.Name.Name);
writer.WriteAttributeString("Version", _context.AssemblyDefinition.Name.Version.ToString());
writer.WriteAttributeString("Hash", ComputeAssemblyHash(_assemblyDefinition.MainModule));
writer.WriteAttributeString("Flags", "0x00000000");

// references
foreach(var a in _context.AssemblyDefinition.MainModule.AssemblyReferences)
{
writer.WriteStartElement("AssemblyRef");
writer.WriteAttributeString("Name", a.Name);
writer.WriteAttributeString("Version", a.Version.ToString());
writer.WriteAttributeString("Hash", ComputeAssemblyHash(_assemblyDefinition.MainModule));
writer.WriteAttributeString("Flags", "0x00000000");
// end AssemblyRef element
writer.WriteEndElement();
}

// types
foreach (var t in _context.AssemblyDefinition.MainModule.Types)
{
writer.WriteStartElement("Type");
writer.WriteAttributeString("Name", t.FullName);
writer.WriteAttributeString("Hash", ComputeAssemblyHash(_assemblyDefinition.MainModule));
// end Type element
writer.WriteEndElement();
}

// end Assembly element
writer.WriteEndElement();

// referenced assemblies
foreach (var a in _context.AssemblyReferenceTable.Items)
{
writer.WriteStartElement("Assembly");
writer.WriteAttributeString("Name", a.Name);
writer.WriteAttributeString("Version", a.Version.ToString());
writer.WriteAttributeString("Hash", ComputeAssemblyHash(_assemblyDefinition.MainModule));
writer.WriteAttributeString("Flags", "0x00000000");

//types
// TODO
//foreach (var t in _context.)
//{
// writer.WriteStartElement("Type");
// writer.WriteAttributeString("Name", t.FullName);
// writer.WriteAttributeString("Hash", ComputeAssemblyHash(_assemblyDefinition.MainModule));
// // end Type element
// writer.WriteEndElement();
//}

// end Assembly element
writer.WriteEndElement();
}



//_context.AssemblyDefinition.Modules((token, item) => WriteClassInfo(writer, token, item));
//_context.AssemblyReferenceTable.ForEachItems((token, item) => WriteClassInfo(writer, token, item));


foreach (var module in _assemblyDefinition.Modules)
{
}

//writer.WriteStartElement("Assembly");

//WriteTokensPair(writer, _context.AssemblyDefinition.MetadataToken.ToUInt32(), 0x00000000);
//writer.WriteElementString("FileName", _context.AssemblyDefinition.MainModule.Name);
//WriteVersionInfo(writer, _context.AssemblyDefinition.Name.Version);

//writer.WriteStartElement("Classes");
//_context.TypeDefinitionTable.ForEachItems((token, item) => WriteClassInfo(writer, token, item));

writer.WriteEndDocument();
}

private string ComputeAssemblyHash(ModuleDefinition module)
{
return "0x00000000";
}

private void WriteVersionInfo(
XmlWriter writer,
Version version)
{
writer.WriteStartElement("Version");

writer.WriteElementString("Major", version.Major.ToString("D", CultureInfo.InvariantCulture));
writer.WriteElementString("Minor", version.Minor.ToString("D", CultureInfo.InvariantCulture));
writer.WriteElementString("Build", version.Build.ToString("D", CultureInfo.InvariantCulture));
writer.WriteElementString("Revision", version.Revision.ToString("D", CultureInfo.InvariantCulture));

writer.WriteEndElement();
}

private void WriteClassInfo(
XmlWriter writer,
uint tinyClrItemToken,
TypeDefinition item)
{
writer.WriteStartElement("Class");

WriteTokensPair(writer, item.MetadataToken.ToUInt32(), 0x04000000 | tinyClrItemToken);

writer.WriteStartElement("Methods");
foreach (var tuple in GetMethodsTokens(item.Methods))
{
writer.WriteStartElement("Method");

WriteTokensPair(writer, tuple.Item1, tuple.Item2);

if (!tuple.Item3.HasBody)
{
writer.WriteElementString("HasByteCode", "false");
}
writer.WriteStartElement("ILMap");
foreach (var offset in _context.TypeDefinitionTable.GetByteCodeOffsets(tuple.Item1))
{
writer.WriteStartElement("IL");

writer.WriteElementString("CLR", "0x" + offset.Item1.ToString("X8", CultureInfo.InvariantCulture));
writer.WriteElementString("TinyCLR", "0x" + offset.Item2.ToString("X8", CultureInfo.InvariantCulture));

writer.WriteEndElement();
}
writer.WriteEndElement();

writer.WriteEndElement();
}
writer.WriteEndElement();

writer.WriteStartElement("Fields");
foreach (var pair in GetFieldsTokens(item.Fields))
{
writer.WriteStartElement("Field");

WriteTokensPair(writer, pair.Item1, pair.Item2);

writer.WriteEndElement();
}
writer.WriteEndElement();

writer.WriteEndElement();
}

private IEnumerable<Tuple<uint, uint, MethodDefinition>> GetMethodsTokens(
IEnumerable<MethodDefinition> methods)
{
foreach (var method in methods)
{
ushort fieldToken;
_context.MethodDefinitionTable.TryGetMethodReferenceId(method, out fieldToken);
yield return new Tuple<uint, uint, MethodDefinition>(
method.MetadataToken.ToUInt32(), 0x06000000 | (uint)fieldToken, method);
}
}

private IEnumerable<Tuple<uint, uint>> GetFieldsTokens(
IEnumerable<FieldDefinition> fields)
{
foreach (var field in fields.Where(item => !item.HasConstant))
{
ushort fieldToken;
_context.FieldsTable.TryGetFieldReferenceId(field, false, out fieldToken);
yield return new Tuple<uint, uint>(
field.MetadataToken.ToUInt32(), 0x05000000 | (uint)fieldToken);
}
}

private void WriteTokensPair(
XmlWriter writer,
uint clrToken,
uint tinyClrToken)
{
writer.WriteStartElement("Token");

writer.WriteElementString("CLR", "0x" + clrToken.ToString("X8", CultureInfo.InvariantCulture));
writer.WriteElementString("TinyCLR", "0x" + tinyClrToken.ToString("X8", CultureInfo.InvariantCulture));

writer.WriteEndElement();
}
}
}
67 changes: 67 additions & 0 deletions source/MetadataProcessor.Core/nanoDependencyGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//
// Copyright (c) 2019 The nanoFramework project contributors
// See LICENSE file in the project root for full license information.
//

using Mono.Cecil;
using nanoFramework.Tools.MetadataProcessor.Core.Extensions;
using Stubble.Core.Builders;
using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;

namespace nanoFramework.Tools.MetadataProcessor.Core
{
/// <summary>
/// Generates dependency graph for a .NET nanoFramework assembly.
/// </summary>
public sealed class nanoDependencyGenerator
{
private readonly nanoTablesContext _tablesContext;
private readonly AssemblyDefinition _assemblyDefinition;
private readonly string _path;
private readonly string _name;
private readonly string _project;

private string _assemblyName;
private nanoTablesContext tablesContext;
private string fileName;
private string _fileName;

public nanoDependencyGenerator(
AssemblyDefinition assemblyDefinition,
nanoTablesContext tablesContext,
string fileName)
{
_assemblyDefinition = assemblyDefinition;
_tablesContext = tablesContext;
_fileName = fileName;
}

public nanoDependencyGenerator(
nanoTablesContext tablesContext,
string path,
string name,
string project,
bool interopCode)
{
_tablesContext = tablesContext;
_path = path;
_name = name;
_project = project;

}

public void Write(
XmlWriter xmlWriter)
{
var dependencyWriter = new nanoDependencyGeneratorWriter(
_assemblyDefinition,
_tablesContext);
dependencyWriter.Write(xmlWriter);
}

}
}