Skip to content

Commit 2c37bea

Browse files
authored
Add support for dependency generator (#12)
1 parent 712ee6f commit 2c37bea

File tree

5 files changed

+322
-0
lines changed

5 files changed

+322
-0
lines changed

source/MetadataProcessor.Console/Program.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,28 @@ public void GenerateSkeleton(
127127
Environment.Exit(1);
128128
}
129129
}
130+
131+
public void GenerateDependency(string fileName)
132+
{
133+
try
134+
{
135+
var dependencyGenerator = new nanoDependencyGenerator(
136+
_assemblyDefinition,
137+
_assemblyBuilder.TablesContext,
138+
fileName);
139+
140+
using (var writer = XmlWriter.Create(fileName))
141+
{
142+
dependencyGenerator.Write(writer);
143+
}
144+
}
145+
catch (Exception)
146+
{
147+
System.Console.Error.WriteLine(
148+
"Unable to generate and write dependency graph for assembly file '{0}'.", fileName);
149+
throw;
150+
}
151+
}
130152
}
131153

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

215238
i += 4;
216239
}
240+
else if (arg == "-generatedependency" && i + 1 < args.Length)
241+
{
242+
md.GenerateDependency(args[++i]);
243+
}
217244
else
218245
{
219246
System.Console.Error.WriteLine("Unknown command line option '{0}' ignored.", arg);

source/MetadataProcessor.Core/MetadataProcessor.Core.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
<Compile Include="Mono.Cecil\CodeWriter.cs" />
7171
<Compile Include="nanoAssemblyBuilder.cs" />
7272
<Compile Include="nanoAssemblyDefinition.cs" />
73+
<Compile Include="nanoDependencyGenerator.cs" />
7374
<Compile Include="nanoSkeletonGenerator.cs" />
7475
<Compile Include="SkeletonGenerator\AssemblyClass.cs" />
7576
<Compile Include="SkeletonGenerator\AssemblyClassStubs.cs" />
@@ -99,6 +100,7 @@
99100
<Compile Include="Utility\nanoBitmapProcessor.cs" />
100101
<Compile Include="Utility\nanoCLR_DataType.cs" />
101102
<Compile Include="Utility\nanoFontProcessor.cs" />
103+
<Compile Include="Utility\nanoDependencyGeneratorWriter.cs" />
102104
<Compile Include="Utility\nanoPdbxFileWriter.cs" />
103105
<Compile Include="Utility\nanoTypeDefinitionFlags.cs" />
104106
<Compile Include="Utility\nanoSerializationType.cs" />

source/MetadataProcessor.Core/Tables/nanoReferenceTableBase.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,13 @@ public abstract class nanoReferenceTableBase<T> : InanoTable
2626
/// Assembly tables context - contains all tables used for building target assembly.
2727
/// </summary>
2828
protected readonly nanoTablesContext _context;
29+
30+
/// <summary>
31+
/// Lookup table for finding item ID by item value.
32+
/// </summary>
33+
protected readonly IEnumerable<T> _items;
34+
35+
public IEnumerable<T> Items => _items;
2936

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

4855
_context = context;
56+
57+
_items = tinyTableItems;
4958
}
5059

5160
/// <inheritdoc/>
Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
//
2+
// Copyright (c) 2019 The nanoFramework project contributors
3+
// Original work from Oleg Rakhmatulin.
4+
// See LICENSE file in the project root for full license information.
5+
//
6+
7+
using Mono.Cecil;
8+
using System;
9+
using System.Collections.Generic;
10+
using System.Globalization;
11+
using System.Linq;
12+
using System.Xml;
13+
14+
namespace nanoFramework.Tools.MetadataProcessor
15+
{
16+
internal sealed class nanoDependencyGeneratorWriter
17+
{
18+
private readonly nanoTablesContext _context;
19+
private readonly AssemblyDefinition _assemblyDefinition;
20+
21+
public nanoDependencyGeneratorWriter(
22+
AssemblyDefinition assemblyDefinition,
23+
nanoTablesContext context)
24+
{
25+
_context = context;
26+
_assemblyDefinition = assemblyDefinition;
27+
}
28+
29+
public void Write(
30+
XmlWriter writer)
31+
{
32+
writer.WriteStartElement("AssemblyGraph");
33+
34+
writer.WriteStartElement("Assembly");
35+
writer.WriteAttributeString("Name", _context.AssemblyDefinition.Name.Name);
36+
writer.WriteAttributeString("Version", _context.AssemblyDefinition.Name.Version.ToString());
37+
writer.WriteAttributeString("Hash", ComputeAssemblyHash(_assemblyDefinition.MainModule));
38+
writer.WriteAttributeString("Flags", "0x00000000");
39+
40+
// references
41+
foreach(var a in _context.AssemblyDefinition.MainModule.AssemblyReferences)
42+
{
43+
writer.WriteStartElement("AssemblyRef");
44+
writer.WriteAttributeString("Name", a.Name);
45+
writer.WriteAttributeString("Version", a.Version.ToString());
46+
writer.WriteAttributeString("Hash", ComputeAssemblyHash(_assemblyDefinition.MainModule));
47+
writer.WriteAttributeString("Flags", "0x00000000");
48+
// end AssemblyRef element
49+
writer.WriteEndElement();
50+
}
51+
52+
// types
53+
foreach (var t in _context.AssemblyDefinition.MainModule.Types)
54+
{
55+
writer.WriteStartElement("Type");
56+
writer.WriteAttributeString("Name", t.FullName);
57+
writer.WriteAttributeString("Hash", ComputeAssemblyHash(_assemblyDefinition.MainModule));
58+
// end Type element
59+
writer.WriteEndElement();
60+
}
61+
62+
// end Assembly element
63+
writer.WriteEndElement();
64+
65+
// referenced assemblies
66+
foreach (var a in _context.AssemblyReferenceTable.Items)
67+
{
68+
writer.WriteStartElement("Assembly");
69+
writer.WriteAttributeString("Name", a.Name);
70+
writer.WriteAttributeString("Version", a.Version.ToString());
71+
writer.WriteAttributeString("Hash", ComputeAssemblyHash(_assemblyDefinition.MainModule));
72+
writer.WriteAttributeString("Flags", "0x00000000");
73+
74+
//types
75+
// TODO
76+
//foreach (var t in _context.)
77+
//{
78+
// writer.WriteStartElement("Type");
79+
// writer.WriteAttributeString("Name", t.FullName);
80+
// writer.WriteAttributeString("Hash", ComputeAssemblyHash(_assemblyDefinition.MainModule));
81+
// // end Type element
82+
// writer.WriteEndElement();
83+
//}
84+
85+
// end Assembly element
86+
writer.WriteEndElement();
87+
}
88+
89+
90+
91+
//_context.AssemblyDefinition.Modules((token, item) => WriteClassInfo(writer, token, item));
92+
//_context.AssemblyReferenceTable.ForEachItems((token, item) => WriteClassInfo(writer, token, item));
93+
94+
95+
foreach (var module in _assemblyDefinition.Modules)
96+
{
97+
}
98+
99+
//writer.WriteStartElement("Assembly");
100+
101+
//WriteTokensPair(writer, _context.AssemblyDefinition.MetadataToken.ToUInt32(), 0x00000000);
102+
//writer.WriteElementString("FileName", _context.AssemblyDefinition.MainModule.Name);
103+
//WriteVersionInfo(writer, _context.AssemblyDefinition.Name.Version);
104+
105+
//writer.WriteStartElement("Classes");
106+
//_context.TypeDefinitionTable.ForEachItems((token, item) => WriteClassInfo(writer, token, item));
107+
108+
writer.WriteEndDocument();
109+
}
110+
111+
private string ComputeAssemblyHash(ModuleDefinition module)
112+
{
113+
return "0x00000000";
114+
}
115+
116+
private void WriteVersionInfo(
117+
XmlWriter writer,
118+
Version version)
119+
{
120+
writer.WriteStartElement("Version");
121+
122+
writer.WriteElementString("Major", version.Major.ToString("D", CultureInfo.InvariantCulture));
123+
writer.WriteElementString("Minor", version.Minor.ToString("D", CultureInfo.InvariantCulture));
124+
writer.WriteElementString("Build", version.Build.ToString("D", CultureInfo.InvariantCulture));
125+
writer.WriteElementString("Revision", version.Revision.ToString("D", CultureInfo.InvariantCulture));
126+
127+
writer.WriteEndElement();
128+
}
129+
130+
private void WriteClassInfo(
131+
XmlWriter writer,
132+
uint tinyClrItemToken,
133+
TypeDefinition item)
134+
{
135+
writer.WriteStartElement("Class");
136+
137+
WriteTokensPair(writer, item.MetadataToken.ToUInt32(), 0x04000000 | tinyClrItemToken);
138+
139+
writer.WriteStartElement("Methods");
140+
foreach (var tuple in GetMethodsTokens(item.Methods))
141+
{
142+
writer.WriteStartElement("Method");
143+
144+
WriteTokensPair(writer, tuple.Item1, tuple.Item2);
145+
146+
if (!tuple.Item3.HasBody)
147+
{
148+
writer.WriteElementString("HasByteCode", "false");
149+
}
150+
writer.WriteStartElement("ILMap");
151+
foreach (var offset in _context.TypeDefinitionTable.GetByteCodeOffsets(tuple.Item1))
152+
{
153+
writer.WriteStartElement("IL");
154+
155+
writer.WriteElementString("CLR", "0x" + offset.Item1.ToString("X8", CultureInfo.InvariantCulture));
156+
writer.WriteElementString("TinyCLR", "0x" + offset.Item2.ToString("X8", CultureInfo.InvariantCulture));
157+
158+
writer.WriteEndElement();
159+
}
160+
writer.WriteEndElement();
161+
162+
writer.WriteEndElement();
163+
}
164+
writer.WriteEndElement();
165+
166+
writer.WriteStartElement("Fields");
167+
foreach (var pair in GetFieldsTokens(item.Fields))
168+
{
169+
writer.WriteStartElement("Field");
170+
171+
WriteTokensPair(writer, pair.Item1, pair.Item2);
172+
173+
writer.WriteEndElement();
174+
}
175+
writer.WriteEndElement();
176+
177+
writer.WriteEndElement();
178+
}
179+
180+
private IEnumerable<Tuple<uint, uint, MethodDefinition>> GetMethodsTokens(
181+
IEnumerable<MethodDefinition> methods)
182+
{
183+
foreach (var method in methods)
184+
{
185+
ushort fieldToken;
186+
_context.MethodDefinitionTable.TryGetMethodReferenceId(method, out fieldToken);
187+
yield return new Tuple<uint, uint, MethodDefinition>(
188+
method.MetadataToken.ToUInt32(), 0x06000000 | (uint)fieldToken, method);
189+
}
190+
}
191+
192+
private IEnumerable<Tuple<uint, uint>> GetFieldsTokens(
193+
IEnumerable<FieldDefinition> fields)
194+
{
195+
foreach (var field in fields.Where(item => !item.HasConstant))
196+
{
197+
ushort fieldToken;
198+
_context.FieldsTable.TryGetFieldReferenceId(field, false, out fieldToken);
199+
yield return new Tuple<uint, uint>(
200+
field.MetadataToken.ToUInt32(), 0x05000000 | (uint)fieldToken);
201+
}
202+
}
203+
204+
private void WriteTokensPair(
205+
XmlWriter writer,
206+
uint clrToken,
207+
uint tinyClrToken)
208+
{
209+
writer.WriteStartElement("Token");
210+
211+
writer.WriteElementString("CLR", "0x" + clrToken.ToString("X8", CultureInfo.InvariantCulture));
212+
writer.WriteElementString("TinyCLR", "0x" + tinyClrToken.ToString("X8", CultureInfo.InvariantCulture));
213+
214+
writer.WriteEndElement();
215+
}
216+
}
217+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
//
2+
// Copyright (c) 2019 The nanoFramework project contributors
3+
// See LICENSE file in the project root for full license information.
4+
//
5+
6+
using Mono.Cecil;
7+
using nanoFramework.Tools.MetadataProcessor.Core.Extensions;
8+
using Stubble.Core.Builders;
9+
using System;
10+
using System.IO;
11+
using System.Linq;
12+
using System.Text;
13+
using System.Xml;
14+
15+
namespace nanoFramework.Tools.MetadataProcessor.Core
16+
{
17+
/// <summary>
18+
/// Generates dependency graph for a .NET nanoFramework assembly.
19+
/// </summary>
20+
public sealed class nanoDependencyGenerator
21+
{
22+
private readonly nanoTablesContext _tablesContext;
23+
private readonly AssemblyDefinition _assemblyDefinition;
24+
private readonly string _path;
25+
private readonly string _name;
26+
private readonly string _project;
27+
28+
private string _assemblyName;
29+
private nanoTablesContext tablesContext;
30+
private string fileName;
31+
private string _fileName;
32+
33+
public nanoDependencyGenerator(
34+
AssemblyDefinition assemblyDefinition,
35+
nanoTablesContext tablesContext,
36+
string fileName)
37+
{
38+
_assemblyDefinition = assemblyDefinition;
39+
_tablesContext = tablesContext;
40+
_fileName = fileName;
41+
}
42+
43+
public nanoDependencyGenerator(
44+
nanoTablesContext tablesContext,
45+
string path,
46+
string name,
47+
string project,
48+
bool interopCode)
49+
{
50+
_tablesContext = tablesContext;
51+
_path = path;
52+
_name = name;
53+
_project = project;
54+
55+
}
56+
57+
public void Write(
58+
XmlWriter xmlWriter)
59+
{
60+
var dependencyWriter = new nanoDependencyGeneratorWriter(
61+
_assemblyDefinition,
62+
_tablesContext);
63+
dependencyWriter.Write(xmlWriter);
64+
}
65+
66+
}
67+
}

0 commit comments

Comments
 (0)