diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 8b6406b6..b1283c56 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -145,7 +145,7 @@ jobs:
nuGetFeedType: external
packagesToPush: '$(Build.ArtifactStagingDirectory)/*.nupkg'
publishFeedCredentials: 'AzureArtifacts'
- continueOnError: true
+ continueOnError: true
condition: succeeded()
displayName: Push NuGet packages to Azure Artifacts
diff --git a/source/MetadataProcessor.Console/MetadataProcessor.Console.csproj b/source/MetadataProcessor.Console/MetadataProcessor.Console.csproj
index 20b0bdb0..cbcf5a70 100644
--- a/source/MetadataProcessor.Console/MetadataProcessor.Console.csproj
+++ b/source/MetadataProcessor.Console/MetadataProcessor.Console.csproj
@@ -35,6 +35,7 @@
..\packages\Costura.Fody.3.3.3\lib\net40\Costura.dll
+
..\packages\Mono.Cecil.0.11.1\lib\net40\Mono.Cecil.dll
diff --git a/source/MetadataProcessor.Console/Program.cs b/source/MetadataProcessor.Console/Program.cs
index 927624bc..3eb785cb 100644
--- a/source/MetadataProcessor.Console/Program.cs
+++ b/source/MetadataProcessor.Console/Program.cs
@@ -5,6 +5,7 @@
//
using Mono.Cecil;
+using nanoFramework.Tools.MetadataProcessor.Core;
using System;
using System.Collections.Generic;
using System.Globalization;
@@ -22,6 +23,7 @@ private sealed class MetadataProcessor
new Dictionary(StringComparer.Ordinal);
private AssemblyDefinition _assemblyDefinition;
+ private nanoAssemblyBuilder _assemblyBuilder;
private List _classNamesToExclude = new List();
@@ -52,17 +54,17 @@ public void Compile(string fileName)
{
if (Verbose) System.Console.WriteLine("Compiling assembly...");
- var builder = new nanoAssemblyBuilder(_assemblyDefinition, _classNamesToExclude, Minimize, Verbose);
+ _assemblyBuilder = new nanoAssemblyBuilder(_assemblyDefinition, _classNamesToExclude, Minimize, Verbose);
using (var stream = File.Open(fileName, FileMode.Create, FileAccess.ReadWrite))
using (var writer = new BinaryWriter(stream))
{
- builder.Write(GetBinaryWriter(writer));
+ _assemblyBuilder.Write(GetBinaryWriter(writer));
}
using (var writer = XmlWriter.Create(Path.ChangeExtension(fileName, "pdbx")))
{
- builder.Write(writer);
+ _assemblyBuilder.Write(writer);
}
}
catch (Exception)
@@ -90,6 +92,41 @@ public void AddClassToExclude(
{
_classNamesToExclude.Add(className);
}
+
+ public void GenerateSkeleton(
+ string file,
+ string name,
+ string project,
+ bool interopCode)
+ {
+ try
+ {
+ if (interopCode)
+ {
+ System.Console.Error.WriteLine("Generator for Interop stubs is not supported yet.");
+
+ Environment.Exit(1);
+ }
+
+ if (Verbose) System.Console.WriteLine("Generating skeleton files...");
+
+ var skeletonGenerator = new nanoSkeletonGenerator(
+ _assemblyBuilder.TablesContext,
+ file,
+ name,
+ project,
+ interopCode);
+
+ skeletonGenerator.GenerateSkeleton();
+ }
+ catch (Exception ex)
+ {
+ System.Console.Error.WriteLine(
+ "Unable to generate skeleton files");
+
+ Environment.Exit(1);
+ }
+ }
}
public static void Main(string[] args)
@@ -124,6 +161,7 @@ public static void Main(string[] args)
System.Console.WriteLine("-compile Compiles an assembly into nanoCLR format.");
System.Console.WriteLine("-loadHints Loads one (or more) assembly file(s) as a dependency(ies).");
System.Console.WriteLine("-excludeClassByName 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("-minimize Minimizes the assembly, removing unwanted elements.");
System.Console.WriteLine("-verbose Outputs each command before executing it.");
System.Console.WriteLine("");
@@ -136,7 +174,7 @@ public static void Main(string[] args)
{
md.Compile(args[++i]);
}
- else if (arg == "-excludeclassbyName" && i + 1 < args.Length)
+ else if (arg == "-excludeclassbyname" && i + 1 < args.Length)
{
md.AddClassToExclude(args[++i]);
}
@@ -153,6 +191,29 @@ public static void Main(string[] args)
md.AddLoadHint(args[i + 1], args[i + 2]);
i += 2;
}
+ else if (arg == "-generateskeleton" && i + 2 < args.Length)
+ {
+ // fill in arguments
+ string file = args[i + 1];
+ string name = args[i + 2];
+ string project = args[i + 3];
+ bool interopCode = false;
+
+ if (!bool.TryParse(args[i + 4], out interopCode))
+ {
+ System.Console.Error.WriteLine("Bad parameter for generateSkeleton. Generate code without Interop support has to be 'true' or 'false'.");
+
+ Environment.Exit(1);
+ }
+
+ md.GenerateSkeleton(
+ file,
+ name,
+ project,
+ interopCode);
+
+ i += 4;
+ }
else
{
System.Console.Error.WriteLine("Unknown command line option '{0}' ignored.", arg);
diff --git a/source/MetadataProcessor.Core/Extensions/TypeDefinitionExtensions.cs b/source/MetadataProcessor.Core/Extensions/TypeDefinitionExtensions.cs
new file mode 100644
index 00000000..1f987770
--- /dev/null
+++ b/source/MetadataProcessor.Core/Extensions/TypeDefinitionExtensions.cs
@@ -0,0 +1,33 @@
+//
+// Copyright (c) 2019 The nanoFramework project contributors
+// See LICENSE file in the project root for full license information.
+//
+
+using Mono.Cecil;
+
+namespace nanoFramework.Tools.MetadataProcessor.Core.Extensions
+{
+ internal static class TypeDefinitionExtensions
+ {
+ public static bool IncludeInStub(this TypeDefinition value)
+ {
+ var typeDefFlags = nanoTypeDefinitionTable.GetFlags(value);
+
+ if (typeDefFlags.HasFlag(
+ nanoTypeDefinitionFlags.TD_Delegate |
+ nanoTypeDefinitionFlags.TD_MulticastDelegate))
+ {
+ return false;
+ }
+
+ // Only generate a stub for classes and value types.
+ if (value.IsClass ||
+ value.IsValueType)
+ {
+ return true;
+ }
+
+ return false;
+ }
+ }
+}
diff --git a/source/MetadataProcessor.Core/MetadataProcessor.Core.csproj b/source/MetadataProcessor.Core/MetadataProcessor.Core.csproj
index 0d6cd659..38615351 100644
--- a/source/MetadataProcessor.Core/MetadataProcessor.Core.csproj
+++ b/source/MetadataProcessor.Core/MetadataProcessor.Core.csproj
@@ -33,6 +33,7 @@
true
+
..\packages\Mono.Cecil.0.11.1\lib\net40\Mono.Cecil.dll
@@ -45,17 +46,34 @@
..\packages\Mono.Cecil.0.11.1\lib\net40\Mono.Cecil.Rocks.dll
+
+ ..\packages\Stubble.Core.1.6.3\lib\net45\Stubble.Core.dll
+
+
+ ..\packages\System.Collections.Immutable.1.5.0\lib\netstandard2.0\System.Collections.Immutable.dll
+
+
+ ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll
+
+
+ ..\packages\System.Threading.Tasks.Extensions.4.5.1\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll
+
+
+
+
+
+
@@ -82,13 +100,16 @@
+
+
+
diff --git a/source/MetadataProcessor.Core/SkeletonGenerator/AssemblyClass.cs b/source/MetadataProcessor.Core/SkeletonGenerator/AssemblyClass.cs
new file mode 100644
index 00000000..82c86fbb
--- /dev/null
+++ b/source/MetadataProcessor.Core/SkeletonGenerator/AssemblyClass.cs
@@ -0,0 +1,47 @@
+//
+// Copyright (c) 2019 The nanoFramework project contributors
+// See LICENSE file in the project root for full license information.
+//
+
+using System.Collections.Generic;
+
+namespace nanoFramework.Tools.MetadataProcessor.Core
+{
+ public class AssemblyDeclaration
+ {
+ public string Name;
+ public string ShortName;
+ public string ShortNameUpper;
+
+ public List Classes = new List();
+ }
+
+ public class Class
+ {
+ public string Name;
+ public string AssemblyName;
+
+ public List StaticFields = new List();
+ public List InstanceFields = new List();
+ public List Methods = new List();
+ }
+
+ public class StaticField
+ {
+ public string Name;
+ public int ReferenceIndex;
+ }
+
+ public class InstanceField
+ {
+ public string Name;
+ public int ReferenceIndex;
+
+ public string FieldWarning;
+ }
+
+ public class Method
+ {
+ public string Declaration;
+ }
+}
diff --git a/source/MetadataProcessor.Core/SkeletonGenerator/AssemblyClassStubs.cs b/source/MetadataProcessor.Core/SkeletonGenerator/AssemblyClassStubs.cs
new file mode 100644
index 00000000..d1c8d42d
--- /dev/null
+++ b/source/MetadataProcessor.Core/SkeletonGenerator/AssemblyClassStubs.cs
@@ -0,0 +1,16 @@
+//
+// Copyright (c) 2019 The nanoFramework project contributors
+// See LICENSE file in the project root for full license information.
+//
+
+using System.Collections.Generic;
+
+namespace nanoFramework.Tools.MetadataProcessor.Core
+{
+ public class AssemblyClassStubs
+ {
+ public string HeaderFileName;
+
+ public List Functions = new List();
+ }
+}
diff --git a/source/MetadataProcessor.Core/SkeletonGenerator/AssemblyLookupTable.cs b/source/MetadataProcessor.Core/SkeletonGenerator/AssemblyLookupTable.cs
new file mode 100644
index 00000000..79dbcb9c
--- /dev/null
+++ b/source/MetadataProcessor.Core/SkeletonGenerator/AssemblyLookupTable.cs
@@ -0,0 +1,22 @@
+//
+// Copyright (c) 2019 The nanoFramework project contributors
+// See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.Collections.Generic;
+
+namespace nanoFramework.Tools.MetadataProcessor.Core
+{
+ public class AssemblyLookupTable
+ {
+ public string Name;
+ public string AssemblyName;
+ public string HeaderFileName;
+ public string NativeCRC32;
+
+ public Version NativeVersion;
+
+ public List LookupTable = new List();
+ }
+}
diff --git a/source/MetadataProcessor.Core/SkeletonGenerator/SkeletonTemplates.cs b/source/MetadataProcessor.Core/SkeletonGenerator/SkeletonTemplates.cs
new file mode 100644
index 00000000..6945b7b2
--- /dev/null
+++ b/source/MetadataProcessor.Core/SkeletonGenerator/SkeletonTemplates.cs
@@ -0,0 +1,108 @@
+//
+// Copyright (c) 2019 The nanoFramework project contributors
+// See LICENSE file in the project root for full license information.
+//
+
+namespace nanoFramework.Tools.MetadataProcessor
+{
+ internal partial class SkeletonTemplates
+ {
+ internal static string AssemblyHeaderTemplate =
+@"//-----------------------------------------------------------------------------
+//
+// ** WARNING! **
+// This file was generated automatically by a tool.
+// Re-running the tool will overwrite this file.
+// You should copy this file to a custom location
+// before adding any customization in the copy to
+// prevent loss of your changes when the tool is
+// re-run.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef _{{ShortNameUpper}}_H_
+#define _{{ShortNameUpper}}_H_
+
+#include
+#include
+#include
+
+{{#Classes}}
+struct Library_{{AssemblyName}}_{{Name}}
+{
+ {{#StaticFields}}
+ static const int FIELD_STATIC__{{Name}} = {{ReferenceIndex}};
+ {{/StaticFields}}
+ {{#InstanceFields}}
+ {{#FieldWarning}}
+ {{FieldWarning}}
+ {{/FieldWarning}}
+ static const int FIELD__{{Name}} = {{ReferenceIndex}};
+ {{/InstanceFields}}
+
+ {{#Methods}}
+ NANOCLR_NATIVE_DECLARE({{Declaration}});
+ {{/Methods}}
+
+ //--//
+
+};
+
+{{/Classes}}
+
+extern const CLR_RT_NativeAssemblyData g_CLR_AssemblyNative_{{Name}};
+
+#endif //_{{ShortNameUpper}}_H_
+";
+
+ internal static string AssemblyLookupTemplate =
+@"#include ""{{HeaderFileName}}.h\""
+
+static const CLR_RT_MethodHandler method_lookup[] =
+{
+{{#LookupTable}}
+ {{Declaration}},
+{{/LookupTable}}
+};
+
+const CLR_RT_NativeAssemblyData g_CLR_AssemblyNative_{{AssemblyName}} =
+{
+ ""{{Name}}"",
+ {{NativeCRC32}},
+ method_lookup,
+ ////////////////////////////////////////////////////////////////////////////////////
+ // check if the version bellow matches the one in AssemblyNativeVersion attribute //
+ ////////////////////////////////////////////////////////////////////////////////////
+ { {{NativeVersion.Major}}, {{NativeVersion.Minor}}, {{NativeVersion.Revision}}, {{NativeVersion.Build}} }
+};
+";
+
+ internal static string ClassStubTemplate =
+@"//-----------------------------------------------------------------------------
+//
+// ** WARNING! **
+// This file was generated automatically by a tool.
+// Re-running the tool will overwrite this file.
+// You should copy this file to a custom location
+// before adding any customization in the copy to
+// prevent loss of your changes when the tool is
+// re-run.
+//
+//-----------------------------------------------------------------------------
+
+#include ""{{HeaderFileName}}.h\""
+
+{{#Functions}}
+HRESULT {{Declaration}}( CLR_RT_StackFrame& stack )
+{
+ NANOCLR_HEADER();
+
+ NANOCLR_SET_AND_LEAVE(stack.NotImplementedStub());
+
+ NANOCLR_NOCLEANUP();
+}
+
+{{/Functions}}
+";
+ }
+}
diff --git a/source/MetadataProcessor.Core/Tables/nanoByteCodeTable.cs b/source/MetadataProcessor.Core/Tables/nanoByteCodeTable.cs
index b659ff59..119af1f8 100644
--- a/source/MetadataProcessor.Core/Tables/nanoByteCodeTable.cs
+++ b/source/MetadataProcessor.Core/Tables/nanoByteCodeTable.cs
@@ -78,7 +78,6 @@ public ushort GetMethodId(
var rva = method.HasBody ? _lastAvailableRva : (ushort)0xFFFF;
var id = (ushort)_methods.Count;
- _context.NativeMethodsCrc.UpdateCrc(method);
var byteCode = CreateByteCode(method);
_methods.Add(method);
diff --git a/source/MetadataProcessor.Core/Tables/nanoFieldDefinitionTable.cs b/source/MetadataProcessor.Core/Tables/nanoFieldDefinitionTable.cs
index a5a4e191..3d6baea0 100644
--- a/source/MetadataProcessor.Core/Tables/nanoFieldDefinitionTable.cs
+++ b/source/MetadataProcessor.Core/Tables/nanoFieldDefinitionTable.cs
@@ -84,13 +84,6 @@ public bool TryGetFieldReferenceId(
bool trackMaxReferenceId,
out ushort referenceId)
{
- // compare against classes to exclude
- if (_context.ClassNamesToExclude.Contains(field.FullName))
- {
- referenceId = 0;
- return false;
- }
-
var found = TryGetIdByValue(field, out referenceId);
if (trackMaxReferenceId && found)
{
diff --git a/source/MetadataProcessor.Core/Tables/nanoMethodDefinitionTable.cs b/source/MetadataProcessor.Core/Tables/nanoMethodDefinitionTable.cs
index 40c4aa28..0d4d1267 100644
--- a/source/MetadataProcessor.Core/Tables/nanoMethodDefinitionTable.cs
+++ b/source/MetadataProcessor.Core/Tables/nanoMethodDefinitionTable.cs
@@ -54,13 +54,6 @@ public bool TryGetMethodReferenceId(
MethodDefinition methodDefinition,
out ushort referenceId)
{
- // compare against classes to exclude
- if (_context.ClassNamesToExclude.Contains(methodDefinition.FullName))
- {
- referenceId = 0;
- return false;
- }
-
return TryGetIdByValue(methodDefinition, out referenceId);
}
diff --git a/source/MetadataProcessor.Core/Tables/nanoSignaturesTable.cs b/source/MetadataProcessor.Core/Tables/nanoSignaturesTable.cs
index eced3911..59056e5b 100644
--- a/source/MetadataProcessor.Core/Tables/nanoSignaturesTable.cs
+++ b/source/MetadataProcessor.Core/Tables/nanoSignaturesTable.cs
@@ -40,33 +40,33 @@ public int GetHashCode(byte[] that)
}
}
- private static readonly IDictionary _primitiveTypes =
+ internal static readonly IDictionary PrimitiveTypes =
new Dictionary(StringComparer.Ordinal);
static nanoSignaturesTable()
{
- _primitiveTypes.Add(typeof(void).FullName, nanoCLR_DataType.DATATYPE_VOID);
+ PrimitiveTypes.Add(typeof(void).FullName, nanoCLR_DataType.DATATYPE_VOID);
- _primitiveTypes.Add(typeof(sbyte).FullName, nanoCLR_DataType.DATATYPE_I1);
- _primitiveTypes.Add(typeof(short).FullName, nanoCLR_DataType.DATATYPE_I2);
- _primitiveTypes.Add(typeof(int).FullName, nanoCLR_DataType.DATATYPE_I4);
- _primitiveTypes.Add(typeof(long).FullName, nanoCLR_DataType.DATATYPE_I8);
+ PrimitiveTypes.Add(typeof(sbyte).FullName, nanoCLR_DataType.DATATYPE_I1);
+ PrimitiveTypes.Add(typeof(short).FullName, nanoCLR_DataType.DATATYPE_I2);
+ PrimitiveTypes.Add(typeof(int).FullName, nanoCLR_DataType.DATATYPE_I4);
+ PrimitiveTypes.Add(typeof(long).FullName, nanoCLR_DataType.DATATYPE_I8);
- _primitiveTypes.Add(typeof(byte).FullName, nanoCLR_DataType.DATATYPE_U1);
- _primitiveTypes.Add(typeof(ushort).FullName, nanoCLR_DataType.DATATYPE_U2);
- _primitiveTypes.Add(typeof(uint).FullName, nanoCLR_DataType.DATATYPE_U4);
- _primitiveTypes.Add(typeof(ulong).FullName, nanoCLR_DataType.DATATYPE_U8);
+ PrimitiveTypes.Add(typeof(byte).FullName, nanoCLR_DataType.DATATYPE_U1);
+ PrimitiveTypes.Add(typeof(ushort).FullName, nanoCLR_DataType.DATATYPE_U2);
+ PrimitiveTypes.Add(typeof(uint).FullName, nanoCLR_DataType.DATATYPE_U4);
+ PrimitiveTypes.Add(typeof(ulong).FullName, nanoCLR_DataType.DATATYPE_U8);
- _primitiveTypes.Add(typeof(float).FullName, nanoCLR_DataType.DATATYPE_R4);
- _primitiveTypes.Add(typeof(double).FullName, nanoCLR_DataType.DATATYPE_R8);
+ PrimitiveTypes.Add(typeof(float).FullName, nanoCLR_DataType.DATATYPE_R4);
+ PrimitiveTypes.Add(typeof(double).FullName, nanoCLR_DataType.DATATYPE_R8);
- _primitiveTypes.Add(typeof(char).FullName, nanoCLR_DataType.DATATYPE_CHAR);
- _primitiveTypes.Add(typeof(string).FullName, nanoCLR_DataType.DATATYPE_STRING);
- _primitiveTypes.Add(typeof(bool).FullName, nanoCLR_DataType.DATATYPE_BOOLEAN);
+ PrimitiveTypes.Add(typeof(char).FullName, nanoCLR_DataType.DATATYPE_CHAR);
+ PrimitiveTypes.Add(typeof(string).FullName, nanoCLR_DataType.DATATYPE_STRING);
+ PrimitiveTypes.Add(typeof(bool).FullName, nanoCLR_DataType.DATATYPE_BOOLEAN);
- _primitiveTypes.Add(typeof(object).FullName, nanoCLR_DataType.DATATYPE_OBJECT);
- _primitiveTypes.Add(typeof(IntPtr).FullName, nanoCLR_DataType.DATATYPE_I4);
- _primitiveTypes.Add(typeof(UIntPtr).FullName, nanoCLR_DataType.DATATYPE_U4);
+ PrimitiveTypes.Add(typeof(object).FullName, nanoCLR_DataType.DATATYPE_OBJECT);
+ PrimitiveTypes.Add(typeof(IntPtr).FullName, nanoCLR_DataType.DATATYPE_I4);
+ PrimitiveTypes.Add(typeof(UIntPtr).FullName, nanoCLR_DataType.DATATYPE_U4);
}
///
@@ -225,7 +225,7 @@ public void WriteDataType(
bool expandEnumType)
{
nanoCLR_DataType dataType;
- if (_primitiveTypes.TryGetValue(typeDefinition.FullName, out dataType))
+ if (PrimitiveTypes.TryGetValue(typeDefinition.FullName, out dataType))
{
writer.WriteByte((byte)dataType);
return;
@@ -309,7 +309,7 @@ private byte[] GetSignature(
}
}
- private byte[] GetSignature(
+ internal byte[] GetSignature(
IMethodSignature methodReference)
{
using (var buffer = new MemoryStream())
@@ -441,7 +441,7 @@ private void WriteAttributeArgumentValue(
CustomAttributeArgument argument)
{
nanoCLR_DataType dataType;
- if (_primitiveTypes.TryGetValue(argument.Type.FullName, out dataType))
+ if (PrimitiveTypes.TryGetValue(argument.Type.FullName, out dataType))
{
switch (dataType)
{
diff --git a/source/MetadataProcessor.Core/Tables/nanoTablesContext.cs b/source/MetadataProcessor.Core/Tables/nanoTablesContext.cs
index 92994196..08390ba3 100644
--- a/source/MetadataProcessor.Core/Tables/nanoTablesContext.cs
+++ b/source/MetadataProcessor.Core/Tables/nanoTablesContext.cs
@@ -103,8 +103,6 @@ public nanoTablesContext(
}
}
- NativeMethodsCrc = new NativeMethodsCrc(assemblyDefinition);
-
var mainModule = AssemblyDefinition.MainModule;
// External references
@@ -116,28 +114,17 @@ public nanoTablesContext(
.Where(item => !IsAttribute(item))
.ToList();
- // copy collection to remove classes to exclude
- TypeReference[] typeReferencesCopy = new TypeReference[typeReferences.Count];
- typeReferences.CopyTo(typeReferencesCopy);
-
- // compare against classes to remove
- foreach (TypeReference t in typeReferencesCopy)
- {
- if (ClassNamesToExclude.Contains(t.FullName))
- {
- typeReferences.Remove(t);
- }
- }
-
TypeReferencesTable = new nanoTypeReferenceTable(
typeReferences, this);
var typeReferencesNames = new HashSet(
typeReferences.Select(item => item.FullName),
StringComparer.Ordinal);
+
var memberReferences = mainModule.GetMemberReferences()
.Where(item => typeReferencesNames.Contains(item.DeclaringType.FullName))
.ToList();
+
FieldReferencesTable = new nanoFieldReferenceTable(
memberReferences.OfType(), this);
MethodReferencesTable = new nanoMethodReferenceTable(
@@ -158,6 +145,12 @@ public nanoTablesContext(
MethodDefinitionTable = new nanoMethodDefinitionTable(methods, this);
+ NativeMethodsCrc = new NativeMethodsCrc(
+ assemblyDefinition,
+ ClassNamesToExclude);
+
+ NativeMethodsCrc.UpdateCrc(TypeDefinitionTable);
+
AttributesTable = new nanoAttributesTable(
GetAttributes(types, applyAttributesCompression),
GetAttributes(fields, applyAttributesCompression),
@@ -388,7 +381,7 @@ private static IEnumerable GetTypesList(
}
}
- private static IEnumerable GetOrderedMethods(
+ internal static IEnumerable GetOrderedMethods(
IEnumerable methods)
{
var ordered = methods
diff --git a/source/MetadataProcessor.Core/Tables/nanoTypeDefinitionTable.cs b/source/MetadataProcessor.Core/Tables/nanoTypeDefinitionTable.cs
index 4ab64a5a..47372019 100644
--- a/source/MetadataProcessor.Core/Tables/nanoTypeDefinitionTable.cs
+++ b/source/MetadataProcessor.Core/Tables/nanoTypeDefinitionTable.cs
@@ -42,6 +42,8 @@ public int GetHashCode(TypeDefinition item)
private IDictionary>> _byteCodeOffsets =
new Dictionary>>();
+ public List TypeDefinitions { get; }
+
///
/// Creates new instance of object.
///
@@ -54,6 +56,8 @@ public nanoTypeDefinitionTable(
nanoTablesContext context)
: base(items, new TypeDefinitionEqualityComparer(), context)
{
+ TypeDefinitions = items
+ .Select(t => t).ToList();
}
///
@@ -139,7 +143,7 @@ protected override void WriteSingleItem(
writer.WriteBytes(stream.ToArray());
}
- writer.WriteUInt16(GetFlags(item)); // flags
+ writer.WriteUInt16((ushort)GetFlags(item)); // flags
}
private void WriteClassFields(
@@ -259,120 +263,93 @@ private ushort GetTypeReferenceOrDefinitionId(
return 0xFFFF;
}
- private ushort GetFlags(
+ internal static nanoTypeDefinitionFlags GetFlags(
TypeDefinition definition)
{
- const ushort TD_Scope_Public = 0x0001; // Class is public scope.
- const ushort TD_Scope_NestedPublic = 0x0002; // Class is nested with public visibility.
- const ushort TD_Scope_NestedPrivate = 0x0003; // Class is nested with private visibility.
- const ushort TD_Scope_NestedFamily = 0x0004; // Class is nested with family visibility.
- const ushort TD_Scope_NestedAssembly = 0x0005; // Class is nested with assembly visibility.
- const ushort TD_Scope_NestedFamANDAssem = 0x0006; // Class is nested with family and assembly visibility.
- const ushort TD_Scope_NestedFamORAssem = 0x0007; // Class is nested with family or assembly visibility.
-
- const ushort TD_Serializable = 0x0008;
-
- const ushort TD_Semantics_ValueType = 0x0010;
- const ushort TD_Semantics_Interface = 0x0020;
- const ushort TD_Semantics_Enum = 0x0030;
-
- const ushort TD_Abstract = 0x0040;
- const ushort TD_Sealed = 0x0080;
-
- const ushort TD_SpecialName = 0x0100;
- const ushort TD_Delegate = 0x0200;
- const ushort TD_MulticastDelegate = 0x0400;
- const ushort TD_Patched = 0x0800;
-
- const ushort TD_BeforeFieldInit = 0x1000;
- const ushort TD_HasSecurity = 0x2000;
- const ushort TD_HasFinalizer = 0x4000;
- const ushort TD_HasAttributes = 0x8000;
-
- var flags = 0x0000;
+ var flags = nanoTypeDefinitionFlags.TD_Scope_None;
if (definition.IsPublic)
{
- flags = TD_Scope_Public;
+ flags = nanoTypeDefinitionFlags.TD_Scope_Public;
}
else if (definition.IsNestedPublic)
{
- flags = TD_Scope_NestedPublic;
+ flags = nanoTypeDefinitionFlags.TD_Scope_NestedPublic;
}
else if (definition.IsNestedPrivate)
{
- flags = TD_Scope_NestedPrivate;
+ flags = nanoTypeDefinitionFlags.TD_Scope_NestedPrivate;
}
else if (definition.IsNestedFamily)
{
- flags = TD_Scope_NestedFamily;
+ flags = nanoTypeDefinitionFlags.TD_Scope_NestedFamily;
}
else if (definition.IsNestedAssembly)
{
- flags = TD_Scope_NestedAssembly;
+ flags = nanoTypeDefinitionFlags.TD_Scope_NestedAssembly;
}
else if (definition.IsNestedFamilyAndAssembly)
{
- flags = TD_Scope_NestedFamANDAssem;
+ flags = nanoTypeDefinitionFlags.TD_Scope_NestedFamANDAssem;
}
else if (definition.IsNestedFamilyOrAssembly)
{
- flags = TD_Scope_NestedFamORAssem;
+ flags = nanoTypeDefinitionFlags.TD_Scope_NestedFamORAssem;
}
if (definition.IsSerializable)
{
- flags |= TD_Serializable;
+ flags |= nanoTypeDefinitionFlags.TD_Serializable;
}
if (definition.IsEnum)
{
- flags |= TD_Semantics_Enum;
- flags |= TD_Serializable;
+ flags |= nanoTypeDefinitionFlags.TD_Semantics_Enum;
+ flags |= nanoTypeDefinitionFlags.TD_Serializable;
}
else if (definition.IsValueType)
{
- flags |= TD_Semantics_ValueType;
+ flags |= nanoTypeDefinitionFlags.TD_Semantics_ValueType;
}
else if (definition.IsInterface)
{
- flags |= TD_Semantics_Interface;
+ flags |= nanoTypeDefinitionFlags.TD_Semantics_Interface;
}
if (definition.IsAbstract)
{
- flags |= TD_Abstract;
+ flags |= nanoTypeDefinitionFlags.TD_Abstract;
}
if (definition.IsSealed)
{
- flags |= TD_Sealed;
+ flags |= nanoTypeDefinitionFlags.TD_Sealed;
}
if (definition.IsSpecialName)
{
- flags |= TD_SpecialName;
+ flags |= nanoTypeDefinitionFlags.TD_SpecialName;
}
if (definition.IsBeforeFieldInit)
{
- flags |= TD_BeforeFieldInit;
+ flags |= nanoTypeDefinitionFlags.TD_BeforeFieldInit;
}
if (definition.HasSecurity)
{
- flags |= TD_HasSecurity;
+ flags |= nanoTypeDefinitionFlags.TD_HasSecurity;
}
if (definition.HasCustomAttributes)
{
- flags |= TD_HasAttributes;
+ flags |= nanoTypeDefinitionFlags.TD_HasAttributes;
}
var baseType = definition.BaseType;
if (baseType != null && baseType.FullName == "System.MulticastDelegate")
{
- flags |= TD_MulticastDelegate;
+ flags |= nanoTypeDefinitionFlags.TD_MulticastDelegate;
}
- return (ushort)flags;
+ return flags;
}
}
}
diff --git a/source/MetadataProcessor.Core/Utility/NativeMethodsCrc.cs b/source/MetadataProcessor.Core/Utility/NativeMethodsCrc.cs
index 5fa45c43..47b6dd9e 100644
--- a/source/MetadataProcessor.Core/Utility/NativeMethodsCrc.cs
+++ b/source/MetadataProcessor.Core/Utility/NativeMethodsCrc.cs
@@ -5,30 +5,32 @@
//
using Mono.Cecil;
+using nanoFramework.Tools.MetadataProcessor.Core.Extensions;
using System;
using System.Collections.Generic;
-using System.Globalization;
using System.Text;
namespace nanoFramework.Tools.MetadataProcessor
{
///
- /// Helper class for calculating native methods CRC value. Really caclulates CRC32 value
+ /// Helper class for calculating native methods CRC value. Really calculates CRC32 value
/// for native method signatures (not methods itself) and signatures treated as string
- /// values, formatted by weird rules incompartible with all rest codebase.
+ /// values, formatted by weird rules backported from .NETMF original implementation.
///
public sealed class NativeMethodsCrc
{
- private readonly HashSet _generatedNames = new HashSet(StringComparer.Ordinal);
-
private readonly byte[] _null = Encoding.ASCII.GetBytes("NULL");
private readonly byte[] _name;
+ private readonly List _classNamesToExclude;
+
public NativeMethodsCrc(
- AssemblyDefinition assembly)
+ AssemblyDefinition assembly,
+ List classNamesToExclude)
{
_name = Encoding.ASCII.GetBytes(assembly.Name.Name);
+ _classNamesToExclude = classNamesToExclude;
}
public uint Current { get; private set; }
@@ -36,8 +38,9 @@ public NativeMethodsCrc(
public void UpdateCrc(MethodDefinition method)
{
var type = method.DeclaringType;
- if ((type.IsClass || type.IsValueType) &&
- (method.RVA == 0xFFFFFFF && !method.IsAbstract))
+
+ if (type.IncludeInStub() &&
+ (method.RVA == 0 && !method.IsAbstract) )
{
Current = Crc32.Compute(_name, Current);
Current = Crc32.Compute(Encoding.ASCII.GetBytes(GetClassName(type)), Current);
@@ -49,16 +52,16 @@ public void UpdateCrc(MethodDefinition method)
}
}
- private string GetClassName(
+ internal static string GetClassName(
TypeDefinition type)
{
return (type != null
- ? string.Concat(GetClassName(type.DeclaringType), type.Namespace, type.Name)
- .Replace(".", string.Empty)
+ ? string.Join("_", GetClassName(type.DeclaringType), type.Namespace, type.Name)
+ .Replace(".", "_").TrimStart('_')
: string.Empty);
}
- private string GetMethodName(
+ internal static string GetMethodName(
MethodDefinition method)
{
var name = string.Concat(method.Name, (method.IsStatic ? "___STATIC__" : "___"),
@@ -66,18 +69,10 @@ private string GetMethodName(
var originalName = name.Replace(".", string.Empty);
- var index = 1;
- name = originalName;
- while (_generatedNames.Add(name))
- {
- name = string.Concat(originalName, index.ToString(CultureInfo.InvariantCulture));
- ++index;
- }
-
- return name;
+ return originalName;
}
- private IEnumerable GetAllParameters(
+ private static IEnumerable GetAllParameters(
MethodDefinition method)
{
yield return GetParameterType(method.ReturnType);
@@ -91,10 +86,73 @@ private IEnumerable GetAllParameters(
}
}
- private string GetParameterType(
+ private static string GetParameterType(
TypeReference parameterType)
{
- return parameterType.Name.ToUpper();
+ var typeName = "";
+ bool continueProcessing = true;
+
+ // special processing for arrays
+ if(parameterType.IsArray)
+ {
+ typeName += nanoCLR_DataType.DATATYPE_SZARRAY + "_" + GetnanoClrTypeName(parameterType.GetElementType());
+ continueProcessing = false;
+ }
+ else if (parameterType.IsByReference)
+ {
+ typeName += nanoCLR_DataType.DATATYPE_BYREF + "_" + GetnanoClrTypeName(parameterType.GetElementType());
+ continueProcessing = false;
+ }
+ else if(!parameterType.IsPrimitive &&
+ parameterType.IsValueType)
+ {
+ // TBD
+ continueProcessing = false;
+ }
+
+ if (continueProcessing)
+ {
+ typeName = GetnanoClrTypeName(parameterType);
+ }
+
+ // clear 'DATATYPE_' prefixes
+ // and make it upper case
+ return typeName.Replace("DATATYPE_", "").ToUpper();
+ }
+
+ internal static string GetnanoClrTypeName(TypeReference parameterType)
+ {
+ // try getting primitive type
+
+ nanoCLR_DataType myType;
+ if(nanoSignaturesTable.PrimitiveTypes.TryGetValue(parameterType.FullName, out myType))
+ {
+ return myType.ToString();
+ }
+ else
+ {
+ // type is not primitive, get full qualified type name
+ return parameterType.FullName;
+ }
+ }
+
+ internal void UpdateCrc(nanoTypeDefinitionTable typeDefinitionTable)
+ {
+ foreach (var c in typeDefinitionTable.TypeDefinitions)
+ {
+ if (c.IncludeInStub() && !IsClassToExclude(c))
+ {
+ foreach (var m in nanoTablesContext.GetOrderedMethods(c.Methods))
+ {
+ UpdateCrc(m);
+ }
+ }
+ }
+ }
+
+ private bool IsClassToExclude(TypeDefinition td)
+ {
+ return _classNamesToExclude.Contains(td.FullName);
}
}
}
diff --git a/source/MetadataProcessor.Core/Utility/nanoTypeDefinitionFlags.cs b/source/MetadataProcessor.Core/Utility/nanoTypeDefinitionFlags.cs
new file mode 100644
index 00000000..95838405
--- /dev/null
+++ b/source/MetadataProcessor.Core/Utility/nanoTypeDefinitionFlags.cs
@@ -0,0 +1,71 @@
+//
+// Copyright (c) 2019 The nanoFramework project contributors
+// See LICENSE file in the project root for full license information.
+//
+
+using System;
+
+namespace nanoFramework.Tools.MetadataProcessor
+{
+ ///
+ /// This list contains the type definition flags
+ ///
+ [Flags]
+ internal enum nanoTypeDefinitionFlags : ushort
+ {
+ // these where defined @ struct CLR_RECORD_TYPEDEF
+ TD_Scope_None = 0x0000,
+
+ // Class is public scope.
+ TD_Scope_Public = 0x0001,
+ // Class is nested with public visibility.
+ TD_Scope_NestedPublic = 0x0002,
+ // Class is nested with private visibility.
+ TD_Scope_NestedPrivate = 0x0003,
+ // Class is nested with family visibility.
+ TD_Scope_NestedFamily = 0x0004,
+ // Class is nested with assembly visibility.
+ TD_Scope_NestedAssembly = 0x0005,
+ // Class is nested with family and assembly visibility.
+ TD_Scope_NestedFamANDAssem = 0x0006,
+ // Class is nested with family or assembly visibility.
+ TD_Scope_NestedFamORAssem = 0x0007,
+
+ ///
+ /// Mask for scope flags
+ ///
+ TD_Scope =
+ (TD_Scope_Public |
+ TD_Scope_NestedPublic |
+ TD_Scope_NestedPrivate |
+ TD_Scope_NestedFamily |
+ TD_Scope_NestedAssembly |
+ TD_Scope_NestedFamANDAssem |
+ TD_Scope_NestedFamORAssem ),
+
+ TD_Serializable = 0x0008,
+
+ TD_Semantics_ValueType = 0x0010,
+ TD_Semantics_Interface = 0x0020,
+ TD_Semantics_Enum = 0x0030,
+
+ ///
+ /// Mask for semantics flags
+ ///
+ TD_Semantics = (TD_Semantics_ValueType | TD_Semantics_Interface | TD_Semantics_Enum),
+
+ TD_Abstract = 0x0040,
+ TD_Sealed = 0x0080,
+
+ TD_SpecialName = 0x0100,
+ TD_Delegate = 0x0200,
+ TD_MulticastDelegate = 0x0400,
+
+ TD_Patched = 0x0800,
+
+ TD_BeforeFieldInit = 0x1000,
+ TD_HasSecurity = 0x2000,
+ TD_HasFinalizer = 0x4000,
+ TD_HasAttributes = 0x8000,
+ }
+}
diff --git a/source/MetadataProcessor.Core/nanoAssemblyBuilder.cs b/source/MetadataProcessor.Core/nanoAssemblyBuilder.cs
index 61639bd5..4aa1d8f2 100644
--- a/source/MetadataProcessor.Core/nanoAssemblyBuilder.cs
+++ b/source/MetadataProcessor.Core/nanoAssemblyBuilder.cs
@@ -22,6 +22,8 @@ public sealed class nanoAssemblyBuilder
private readonly bool _minimize;
private readonly bool _verbose;
+ public nanoTablesContext TablesContext => _tablesContext;
+
///
/// Creates new instance of object.
///
diff --git a/source/MetadataProcessor.Core/nanoSkeletonGenerator.cs b/source/MetadataProcessor.Core/nanoSkeletonGenerator.cs
new file mode 100644
index 00000000..0bb7cfff
--- /dev/null
+++ b/source/MetadataProcessor.Core/nanoSkeletonGenerator.cs
@@ -0,0 +1,263 @@
+//
+// 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;
+
+namespace nanoFramework.Tools.MetadataProcessor.Core
+{
+ ///
+ /// Generator of skeleton files from a .NET nanoFramework assembly.
+ ///
+ public sealed class nanoSkeletonGenerator
+ {
+ private readonly nanoTablesContext _tablesContext;
+ private readonly string _path;
+ private readonly string _name;
+ private readonly string _project;
+ private readonly bool _interopCode;
+
+ private string _assemblyName;
+
+ public nanoSkeletonGenerator(
+ nanoTablesContext tablesContext,
+ string path,
+ string name,
+ string project,
+ bool interopCode)
+ {
+ _tablesContext = tablesContext;
+ _path = path;
+ _name = name;
+ _project = project;
+ _interopCode = interopCode;
+ }
+
+ public void GenerateSkeleton()
+ {
+ // replaces "." with "_" so the assembly name can be part of C++ identifier name
+ _assemblyName = _name.Replace('.', '_');
+
+ // create .h with the structs declarations
+ GenerateAssemblyHeader();
+
+ // generate .cpp with the lookup definition
+ GenerateAssemblyLookup();
+
+ // generate _.cpp files with the type definition and stubs.
+ GenerateStubs();
+ }
+
+ private void GenerateStubs()
+ {
+ foreach (var c in _tablesContext.TypeDefinitionTable.TypeDefinitions)
+ {
+ if (c.IncludeInStub() && !IsClassToExclude(c))
+ {
+ var className = NativeMethodsCrc.GetClassName(c);
+
+ var classStubs = new AssemblyClassStubs()
+ {
+ HeaderFileName = _project
+ };
+
+ foreach (var m in nanoTablesContext.GetOrderedMethods(c.Methods))
+ {
+ var rva = _tablesContext.ByteCodeTable.GetMethodRva(m);
+
+ // check method inclusion
+ if (rva == 0xFFFF &&
+ !m.IsAbstract)
+ {
+ classStubs.Functions.Add(new Method()
+ {
+ Declaration = $"Library_{_project}_{className}::{NativeMethodsCrc.GetMethodName(m)}"
+ });
+ }
+ }
+
+ // anything to add to the header?
+ if (classStubs.Functions.Count > 0)
+ {
+ var stubble = new StubbleBuilder().Build();
+
+ using (var headerFile = File.CreateText(Path.Combine(_path, $"{_project}_{className}.cpp")))
+ {
+ var output = stubble.Render(SkeletonTemplates.ClassStubTemplate, classStubs);
+ headerFile.Write(output);
+ }
+ }
+ }
+ }
+ }
+
+ private void GenerateAssemblyLookup()
+ {
+ // grab native version from assembly attribute
+ var nativeVersionAttribute = _tablesContext.AssemblyDefinition.CustomAttributes.FirstOrDefault(a => a.AttributeType.Name == "AssemblyNativeVersionAttribute");
+ Version nativeVersion = new Version((string)nativeVersionAttribute.ConstructorArguments[0].Value);
+
+ var assemblyLookup = new AssemblyLookupTable()
+ {
+ Name = _name,
+ AssemblyName = _assemblyName,
+ HeaderFileName = _project,
+ NativeVersion = nativeVersion,
+ NativeCRC32 = "0x" + _tablesContext.NativeMethodsCrc.Current.ToString("X")
+ };
+
+
+ foreach (var c in _tablesContext.TypeDefinitionTable.TypeDefinitions)
+ {
+ if (c.IncludeInStub() && !IsClassToExclude(c))
+ {
+ var className = NativeMethodsCrc.GetClassName(c);
+
+ foreach (var m in nanoTablesContext.GetOrderedMethods(c.Methods))
+ {
+ var rva = _tablesContext.ByteCodeTable.GetMethodRva(m);
+
+ // check method inclusion
+ if ((rva == 0xFFFF &&
+ !m.IsAbstract))
+ {
+ assemblyLookup.LookupTable.Add(new Method()
+ {
+ Declaration = $"Library_{_project}_{className}::{NativeMethodsCrc.GetMethodName(m)}"
+ });
+ }
+ else
+ {
+ assemblyLookup.LookupTable.Add(new Method()
+ {
+ Declaration = "NULL"
+ });
+ }
+ }
+ }
+ }
+
+ var stubble = new StubbleBuilder().Build();
+
+ using (var headerFile = File.CreateText(Path.Combine(_path, $"{_project}.cpp")))
+ {
+ var output = stubble.Render(SkeletonTemplates.AssemblyLookupTemplate, assemblyLookup);
+ headerFile.Write(output);
+ }
+ }
+
+ private void GenerateAssemblyHeader()
+ {
+ int staticFieldCount = 0;
+
+ var assemblyData = new AssemblyDeclaration()
+ {
+ Name = _name,
+ ShortName = _project,
+ ShortNameUpper = _project.ToUpperInvariant()
+ };
+
+ foreach (var c in _tablesContext.TypeDefinitionTable.TypeDefinitions)
+ {
+ if (c.IncludeInStub() && !IsClassToExclude(c))
+ {
+ var classData = new Class()
+ {
+ AssemblyName = _project,
+ Name = NativeMethodsCrc.GetClassName(c)
+ };
+
+ // static fields
+ int fieldCount = 0;
+ foreach (var f in c.Fields.Where(f => f.IsStatic))
+ {
+ classData.StaticFields.Add(new StaticField()
+ {
+ Name = f.Name,
+ ReferenceIndex = staticFieldCount + fieldCount++
+ });
+ }
+
+ // instance fields
+ fieldCount = 0;
+ foreach (var f in c.Fields.Where(f => !f.IsStatic))
+ {
+ // sanity check for field name
+ // like auto-vars and such
+ if (f.Name.IndexOfAny(new char[] { '<', '>' }) > 0)
+ {
+ classData.InstanceFields.Add(new InstanceField()
+ {
+ FieldWarning = $"*** Something wrong with field '{f.Name}'. Possibly its backing field is missing (mandatory for nanoFramework).\n"
+ });
+ }
+ else
+ {
+ ushort fieldRefId;
+ if (_tablesContext.FieldsTable.TryGetFieldReferenceId(f, false, out fieldRefId))
+ {
+ classData.InstanceFields.Add(new InstanceField()
+ {
+ Name = f.Name,
+ ReferenceIndex = fieldRefId + 1
+ });
+ }
+ fieldCount++;
+ }
+ }
+
+ // methods
+ if(c.HasMethods)
+ {
+ foreach (var m in nanoTablesContext.GetOrderedMethods(c.Methods))
+ {
+ var rva = _tablesContext.ByteCodeTable.GetMethodRva(m);
+
+ if( rva == 0xFFFF &&
+ !m.IsAbstract)
+ {
+ classData.Methods.Add(new Method()
+ {
+ Declaration = NativeMethodsCrc.GetMethodName(m)
+ });
+ }
+ }
+
+ }
+
+ // anything to add to the header?
+ if( classData.StaticFields.Count > 0 ||
+ classData.InstanceFields.Count > 0 ||
+ classData.Methods.Count > 0)
+ {
+ assemblyData.Classes.Add(classData);
+ }
+ }
+
+ staticFieldCount += c.Fields.Count(f => f.IsStatic);
+ }
+
+ var stubble = new StubbleBuilder().Build();
+
+ Directory.CreateDirectory(_path);
+
+ using (var headerFile = File.CreateText(Path.Combine(_path, $"{_project}.h")))
+ {
+ var output = stubble.Render(SkeletonTemplates.AssemblyHeaderTemplate, assemblyData);
+ headerFile.Write(output);
+ }
+ }
+
+ private bool IsClassToExclude(TypeDefinition td)
+ {
+ return _tablesContext.ClassNamesToExclude.Contains(td.FullName);
+ }
+ }
+}
diff --git a/source/MetadataProcessor.Core/packages.config b/source/MetadataProcessor.Core/packages.config
index 778a66e9..15570e2b 100644
--- a/source/MetadataProcessor.Core/packages.config
+++ b/source/MetadataProcessor.Core/packages.config
@@ -2,4 +2,8 @@
+
+
+
+
\ No newline at end of file