Pushed initial work-in-progress code for managed-to-native bindings generator.
This commit is contained in:
Родитель
b0d4259c48
Коммит
d965d8797e
|
@ -0,0 +1,34 @@
|
|||
*.pidb
|
||||
configure
|
||||
install-sh
|
||||
aclocal.m4
|
||||
config.status
|
||||
config.log
|
||||
autom4te.cache
|
||||
missing
|
||||
*Makefile
|
||||
*Makefile.in
|
||||
*.dll
|
||||
*.exe
|
||||
bin/
|
||||
*.userprefs
|
||||
tests/output
|
||||
src/generator/generator
|
||||
*.pc
|
||||
.DS_Store
|
||||
*.user
|
||||
*.suo
|
||||
*.DotSettings
|
||||
*.sdf
|
||||
*.opensdf
|
||||
*.pdb
|
||||
*.config
|
||||
*.vcxproj
|
||||
*.filters
|
||||
*.sln
|
||||
*.metagen
|
||||
*.csproj
|
||||
*.ilk
|
||||
*.manifest
|
||||
/build/vs2015
|
||||
/ikvm
|
|
@ -0,0 +1,3 @@
|
|||
[submodule "ikvm"]
|
||||
path = ikvm
|
||||
url = git@github.com:mono/ikvm-fork.git
|
35
LICENSE
35
LICENSE
|
@ -1,21 +1,20 @@
|
|||
The MIT License (MIT)
|
||||
Copyright (c) 2016 Microsoft
|
||||
|
||||
Copyright (c) 2016 João Matos
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
|
23
README.md
23
README.md
|
@ -1,2 +1,21 @@
|
|||
# MonoManagedToNative
|
||||
Generates bindings that allows calling managed code from C and other languages.
|
||||
native-binder
|
||||
==============
|
||||
|
||||
.NET assembly to Mono native C/C++ API bindings generator.
|
||||
|
||||
· Create a native API to access some C# APIs
|
||||
· native-binder Xamarin.Foo.dll –type:Xamarin.Foo.Authenticator –language c –output outdir
|
||||
· Allow for Obj-C binding, Java bindings
|
||||
· Start with desktop
|
||||
· Then work with products
|
||||
|
||||
Can I use it yet?
|
||||
-----------------
|
||||
|
||||
The project is in a development state and should not be used in production scenarios yet.
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
* Cecil
|
||||
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
using System;
|
||||
|
||||
namespace MonoManagedToNative
|
||||
{
|
||||
public class Binder
|
||||
{
|
||||
static string Language;
|
||||
static string MonoIncDir;
|
||||
static string OutputDir;
|
||||
|
||||
static void ParseCommandLineArgs(string[] args)
|
||||
{
|
||||
var showHelp = args.Length == 0;
|
||||
|
||||
var optionSet = new Mono.Options.OptionSet() {
|
||||
{ "language=", "output language", v => Language = v },
|
||||
{ "o|out=", "output directory", v => OutputDir = v },
|
||||
{ "mono=", "Mono include directory", v => MonoIncDir = v },
|
||||
{ "h|help", "show this message and exit", v => showHelp = v != null },
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
optionSet.Parse(args);
|
||||
}
|
||||
catch (Mono.Options.OptionException e)
|
||||
{
|
||||
Console.WriteLine(e.Message);
|
||||
Environment.Exit(0);
|
||||
}
|
||||
|
||||
if (showHelp)
|
||||
{
|
||||
// Print usage and exit.
|
||||
Console.WriteLine("{0} [--gen=c/c++] [--out=dir] "
|
||||
+ "[--mono=dir]",
|
||||
AppDomain.CurrentDomain.FriendlyName);
|
||||
Environment.Exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
ParseCommandLineArgs(args);
|
||||
|
||||
var options = new Options();
|
||||
var driver = new Driver(options);
|
||||
|
||||
driver.Run();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
|
||||
namespace MonoManagedToNative
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the kind of the diagnostic.
|
||||
/// </summary>
|
||||
public enum DiagnosticKind
|
||||
{
|
||||
Debug,
|
||||
Message,
|
||||
Warning,
|
||||
Error
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Keeps information related to a single diagnostic.
|
||||
/// </summary>
|
||||
public struct DiagnosticInfo
|
||||
{
|
||||
public DiagnosticKind Kind;
|
||||
public string Message;
|
||||
public string File;
|
||||
public int Line;
|
||||
public int Column;
|
||||
}
|
||||
|
||||
public interface IDiagnostics
|
||||
{
|
||||
void Emit(DiagnosticInfo info);
|
||||
void PushIndent(int level = 4);
|
||||
void PopIndent();
|
||||
}
|
||||
|
||||
public static class DiagnosticExtensions
|
||||
{
|
||||
public static void Debug(this IDiagnostics consumer,
|
||||
string msg, params object[] args)
|
||||
{
|
||||
var diagInfo = new DiagnosticInfo
|
||||
{
|
||||
Kind = DiagnosticKind.Debug,
|
||||
Message = string.Format(msg, args)
|
||||
};
|
||||
|
||||
consumer.Emit(diagInfo);
|
||||
}
|
||||
|
||||
public static void Message(this IDiagnostics consumer,
|
||||
string msg, params object[] args)
|
||||
{
|
||||
var diagInfo = new DiagnosticInfo
|
||||
{
|
||||
Kind = DiagnosticKind.Message,
|
||||
Message = string.Format(msg, args)
|
||||
};
|
||||
|
||||
consumer.Emit(diagInfo);
|
||||
}
|
||||
|
||||
public static void Warning(this IDiagnostics consumer,
|
||||
string msg, params object[] args)
|
||||
{
|
||||
var diagInfo = new DiagnosticInfo
|
||||
{
|
||||
Kind = DiagnosticKind.Warning,
|
||||
Message = string.Format(msg, args)
|
||||
};
|
||||
|
||||
consumer.Emit(diagInfo);
|
||||
}
|
||||
|
||||
public static void Error(this IDiagnostics consumer,
|
||||
string msg, params object[] args)
|
||||
{
|
||||
var diagInfo = new DiagnosticInfo
|
||||
{
|
||||
Kind = DiagnosticKind.Error,
|
||||
Message = string.Format(msg, args)
|
||||
};
|
||||
|
||||
consumer.Emit(diagInfo);
|
||||
}
|
||||
}
|
||||
|
||||
public class TextDiagnosticPrinter : IDiagnostics
|
||||
{
|
||||
public bool Verbose;
|
||||
public Stack<int> Indents;
|
||||
|
||||
public TextDiagnosticPrinter()
|
||||
{
|
||||
Indents = new Stack<int>();
|
||||
}
|
||||
|
||||
public void Emit(DiagnosticInfo info)
|
||||
{
|
||||
if (info.Kind == DiagnosticKind.Debug && !Verbose)
|
||||
return;
|
||||
|
||||
var currentIndent = Indents.Sum();
|
||||
var message = new string(' ', currentIndent) + info.Message;
|
||||
|
||||
Console.WriteLine(message);
|
||||
Debug.WriteLine(message);
|
||||
}
|
||||
|
||||
public void PushIndent(int level)
|
||||
{
|
||||
Indents.Push(level);
|
||||
}
|
||||
|
||||
public void PopIndent()
|
||||
{
|
||||
Indents.Pop();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,162 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using MonoManagedToNative.Generators;
|
||||
using System;
|
||||
|
||||
namespace MonoManagedToNative
|
||||
{
|
||||
public class Driver
|
||||
{
|
||||
public Options Options { get; private set; }
|
||||
public IDiagnostics Diagnostics { get; private set; }
|
||||
|
||||
public List<IKVM.Reflection.Assembly> Assemblies { get; private set; }
|
||||
|
||||
public ProjectOutput Output { get; private set; }
|
||||
|
||||
public Driver(Options options, IDiagnostics diagnostics = null)
|
||||
{
|
||||
Options = options;
|
||||
Diagnostics = diagnostics;
|
||||
|
||||
if (Diagnostics == null)
|
||||
Diagnostics = new TextDiagnosticPrinter();
|
||||
|
||||
if (Options.OutputDir == null)
|
||||
Options.OutputDir = Directory.GetCurrentDirectory();
|
||||
|
||||
Assemblies = new List<IKVM.Reflection.Assembly>();
|
||||
}
|
||||
|
||||
bool Parse()
|
||||
{
|
||||
var parser = new Parser(Options, Diagnostics);
|
||||
parser.OnAssemblyParsed += HandleAssemblyParsed;
|
||||
|
||||
return parser.Parse(Options.Project);
|
||||
}
|
||||
|
||||
void Process()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Generate()
|
||||
{
|
||||
Output = new ProjectOutput();
|
||||
|
||||
Generator generator = null;
|
||||
switch (Options.Language)
|
||||
{
|
||||
case GeneratorKind.C:
|
||||
generator = new CGenerator(this);
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
foreach (var assembly in Assemblies)
|
||||
{
|
||||
var templates = generator.Generate(assembly);
|
||||
|
||||
foreach (var template in templates)
|
||||
{
|
||||
template.Process();
|
||||
var text = template.Generate();
|
||||
var path = string.Format("{0}.{1}", template.Name, template.FileExtension);
|
||||
|
||||
Output.WriteOutput(path, text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WriteFiles()
|
||||
{
|
||||
if (!Directory.Exists(Options.OutputDir))
|
||||
Directory.CreateDirectory(Options.OutputDir);
|
||||
|
||||
foreach (var output in Output.Files)
|
||||
{
|
||||
var path = output.Key;
|
||||
|
||||
var outputPath = Path.Combine(Options.OutputDir,
|
||||
Path.GetDirectoryName(path));
|
||||
|
||||
// Make sure the target directory exists.
|
||||
Directory.CreateDirectory(outputPath);
|
||||
|
||||
var fullPath = Path.Combine(outputPath, Path.GetFileName(path));
|
||||
|
||||
var outputStream = output.Value;
|
||||
outputStream.Position = 0;
|
||||
|
||||
using (var outputFile = File.Create(fullPath))
|
||||
outputStream.CopyTo(outputFile);
|
||||
|
||||
Diagnostics.Message("Generated: {0}", path);
|
||||
}
|
||||
}
|
||||
|
||||
public void Run()
|
||||
{
|
||||
Options.Project.BuildInputs();
|
||||
|
||||
Diagnostics.Message("Parsing assemblies...");
|
||||
Diagnostics.PushIndent();
|
||||
if (!Parse())
|
||||
return;
|
||||
Diagnostics.PopIndent();
|
||||
|
||||
Diagnostics.Message("Processing assemblies...");
|
||||
Diagnostics.PushIndent();
|
||||
Process();
|
||||
Diagnostics.PopIndent();
|
||||
|
||||
Diagnostics.Message("Generating binding code...");
|
||||
Diagnostics.PushIndent();
|
||||
Generate();
|
||||
WriteFiles();
|
||||
Diagnostics.PopIndent();
|
||||
}
|
||||
|
||||
void HandleParserResult<T>(ParserResult<T> result)
|
||||
{
|
||||
var file = result.Input.FullPath;
|
||||
if (file.StartsWith(result.Input.BasePath))
|
||||
{
|
||||
file = file.Substring(result.Input.BasePath.Length);
|
||||
file = file.TrimStart('\\');
|
||||
}
|
||||
|
||||
switch (result.Kind)
|
||||
{
|
||||
case ParserResultKind.Success:
|
||||
Diagnostics.Message("Parsed '{0}'", file);
|
||||
break;
|
||||
case ParserResultKind.Error:
|
||||
Diagnostics.Message("Error parsing '{0}'", file);
|
||||
break;
|
||||
case ParserResultKind.FileNotFound:
|
||||
Diagnostics.Message("File '{0}' was not found", file);
|
||||
break;
|
||||
}
|
||||
|
||||
foreach (var diag in result.Diagnostics)
|
||||
{
|
||||
Diagnostics.Message(string.Format("{0}({1},{2}): {3}: {4}",
|
||||
diag.FileName, diag.LineNumber, diag.ColumnNumber,
|
||||
diag.Level.ToString().ToLower(), diag.Message));
|
||||
}
|
||||
}
|
||||
|
||||
void HandleAssemblyParsed(ParserResult<IKVM.Reflection.Assembly> result)
|
||||
{
|
||||
HandleParserResult(result);
|
||||
|
||||
if (result.Kind != ParserResultKind.Success)
|
||||
return;
|
||||
|
||||
Assemblies.Add(result.Output);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,259 @@
|
|||
using System;
|
||||
using IKVM.Reflection;
|
||||
using CppSharp.AST;
|
||||
|
||||
namespace MonoManagedToNative.Generators
|
||||
{
|
||||
public class AstGenerator
|
||||
{
|
||||
public TranslationUnit unit;
|
||||
Options options;
|
||||
|
||||
public AstGenerator(Options options)
|
||||
{
|
||||
unit = new TranslationUnit();
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
public TranslationUnit Visit(Assembly assembly)
|
||||
{
|
||||
var name = options.LibraryName ?? assembly.GetName().Name;
|
||||
unit.Name = name;
|
||||
|
||||
foreach (var type in assembly.ExportedTypes)
|
||||
{
|
||||
var decl = Visit(type.GetTypeInfo());
|
||||
unit.Declarations.Add(decl);
|
||||
}
|
||||
|
||||
return unit;
|
||||
}
|
||||
|
||||
public Declaration Visit(TypeInfo typeInfo)
|
||||
{
|
||||
if (typeInfo.IsClass || typeInfo.IsInterface || typeInfo.IsValueType)
|
||||
return VisitRecord(typeInfo);
|
||||
else if (typeInfo.IsEnum)
|
||||
return VisitEnum(typeInfo);
|
||||
|
||||
throw new Exception("Could not visit type: " + typeInfo.ToString());
|
||||
}
|
||||
|
||||
public Class VisitRecord(TypeInfo type)
|
||||
{
|
||||
var @class = new Class { Name = type.Name };
|
||||
VisitMembers(type, @class);
|
||||
|
||||
return @class;
|
||||
}
|
||||
|
||||
public Enumeration VisitEnum(TypeInfo @enum)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public void VisitMembers(TypeInfo type, Class @class)
|
||||
{
|
||||
foreach (var ctor in type.DeclaredConstructors)
|
||||
{
|
||||
var decl = VisitConstructor(ctor, @class);
|
||||
@class.Declarations.Add(decl);
|
||||
}
|
||||
|
||||
foreach (var method in type.DeclaredMethods)
|
||||
{
|
||||
var decl = VisitMethod(method, @class);
|
||||
@class.Declarations.Add(decl);
|
||||
}
|
||||
|
||||
foreach (var field in type.DeclaredFields)
|
||||
{
|
||||
var decl = VisitField(field);
|
||||
@class.Declarations.Add(decl);
|
||||
}
|
||||
|
||||
foreach (var @event in type.DeclaredEvents)
|
||||
{
|
||||
var decl = VisitEvent(@event);
|
||||
@class.Declarations.Add(decl);
|
||||
}
|
||||
|
||||
foreach (var property in type.DeclaredProperties)
|
||||
{
|
||||
var decl = VisitProperty(property);
|
||||
@class.Declarations.Add(decl);
|
||||
}
|
||||
|
||||
foreach (var decl in @class.Declarations)
|
||||
decl.Namespace = @class;
|
||||
}
|
||||
|
||||
public Method VisitConstructor(ConstructorInfo ctor, Class @class)
|
||||
{
|
||||
var method = VisitMethodBase(ctor);
|
||||
var ptrType = new QualifiedType(
|
||||
new PointerType(new QualifiedType(new TagType(@class))));
|
||||
method.ReturnType = ptrType;
|
||||
method.Name = "new";
|
||||
return method;
|
||||
}
|
||||
|
||||
string GetInternalMethodName(MethodBase method)
|
||||
{
|
||||
var @params = string.Empty;
|
||||
var sig = method.ToString();
|
||||
return string.Format("{0}:{1}({2})", method.DeclaringType.FullName,
|
||||
method.Name, @params);
|
||||
}
|
||||
|
||||
Method VisitMethod(MethodInfo methodInfo, Class @class)
|
||||
{
|
||||
var method = VisitMethodBase(methodInfo);
|
||||
method.ReturnType = VisitType(methodInfo.ReturnType);
|
||||
|
||||
var ptrType = new QualifiedType(
|
||||
new PointerType(new QualifiedType(new TagType(@class))));
|
||||
var param = new Parameter { Name = "object", Namespace = @class,
|
||||
QualifiedType = ptrType };
|
||||
method.Parameters.Add(param);
|
||||
|
||||
return method;
|
||||
}
|
||||
|
||||
QualifiedType VisitType(IKVM.Reflection.Type managedType)
|
||||
{
|
||||
CppSharp.AST.Type type = null;
|
||||
switch (IKVM.Reflection.Type.GetTypeCode(managedType))
|
||||
{
|
||||
case TypeCode.Empty:
|
||||
type = new BuiltinType(PrimitiveType.Null);
|
||||
break;
|
||||
case TypeCode.Object:
|
||||
if (managedType.FullName == "System.Void")
|
||||
{
|
||||
type = new BuiltinType(PrimitiveType.Void);
|
||||
break;
|
||||
}
|
||||
throw new NotSupportedException();
|
||||
case TypeCode.DBNull:
|
||||
throw new NotSupportedException();
|
||||
case TypeCode.Boolean:
|
||||
type = new BuiltinType(PrimitiveType.Bool);
|
||||
break;
|
||||
case TypeCode.Char:
|
||||
type = new BuiltinType(PrimitiveType.WideChar);
|
||||
break;
|
||||
case TypeCode.SByte:
|
||||
type = new BuiltinType(PrimitiveType.Char);
|
||||
break;
|
||||
case TypeCode.Byte:
|
||||
type = new BuiltinType(PrimitiveType.UChar);
|
||||
break;
|
||||
case TypeCode.Int16:
|
||||
type = new BuiltinType(PrimitiveType.Short);
|
||||
break;
|
||||
case TypeCode.UInt16:
|
||||
type = new BuiltinType(PrimitiveType.UShort);
|
||||
break;
|
||||
case TypeCode.Int32:
|
||||
type = new BuiltinType(PrimitiveType.Int);
|
||||
break;
|
||||
case TypeCode.UInt32:
|
||||
type = new BuiltinType(PrimitiveType.UInt);
|
||||
break;
|
||||
case TypeCode.Int64:
|
||||
type = new BuiltinType(PrimitiveType.LongLong);
|
||||
break;
|
||||
case TypeCode.UInt64:
|
||||
type = new BuiltinType(PrimitiveType.ULongLong);
|
||||
break;
|
||||
case TypeCode.Single:
|
||||
type = new BuiltinType(PrimitiveType.Float);
|
||||
break;
|
||||
case TypeCode.Double:
|
||||
type = new BuiltinType(PrimitiveType.Double);
|
||||
break;
|
||||
case TypeCode.Decimal:
|
||||
type = new CILType(typeof(decimal));
|
||||
break;
|
||||
case TypeCode.DateTime:
|
||||
type = new CILType(typeof(DateTime));
|
||||
break;
|
||||
case TypeCode.String:
|
||||
type = new CILType(typeof(string));
|
||||
break;
|
||||
}
|
||||
|
||||
return new QualifiedType(type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts from a .NET member acccess mask to a C/C++ access specifier.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
AccessSpecifier ConvertToAccessSpecifier(MethodAttributes mask)
|
||||
{
|
||||
switch (mask)
|
||||
{
|
||||
case MethodAttributes.PrivateScope:
|
||||
case MethodAttributes.Private:
|
||||
return AccessSpecifier.Private;
|
||||
case MethodAttributes.FamANDAssem:
|
||||
case MethodAttributes.Assembly:
|
||||
case MethodAttributes.Family:
|
||||
case MethodAttributes.FamORAssem:
|
||||
return AccessSpecifier.Internal;
|
||||
case MethodAttributes.Public:
|
||||
return AccessSpecifier.Public;
|
||||
}
|
||||
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Method VisitMethodBase(MethodBase methodBase)
|
||||
{
|
||||
var method = new Method
|
||||
{
|
||||
Kind = methodBase.IsConstructor ?
|
||||
CXXMethodKind.Constructor : CXXMethodKind.Normal
|
||||
};
|
||||
method.Name = methodBase.Name;
|
||||
method.OriginalName = GetInternalMethodName(methodBase);
|
||||
|
||||
foreach (var param in methodBase.GetParameters())
|
||||
{
|
||||
var paramDecl = VisitParameter(param);
|
||||
method.Parameters.Add(paramDecl);
|
||||
}
|
||||
|
||||
method.IsStatic = methodBase.IsStatic;
|
||||
method.IsVirtual = methodBase.IsVirtual;
|
||||
method.IsPure = methodBase.IsAbstract;
|
||||
//method.IsFinal = methodBase.IsFinal;
|
||||
var memberAccessMask = (methodBase.Attributes & MethodAttributes.MemberAccessMask);
|
||||
method.Access = ConvertToAccessSpecifier(memberAccessMask);
|
||||
|
||||
return method;
|
||||
}
|
||||
|
||||
public Parameter VisitParameter(ParameterInfo param)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Field VisitField(FieldInfo field)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Event VisitEvent(EventInfo @event)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Property VisitProperty(PropertyInfo @property)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,227 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using IKVM.Reflection;
|
||||
using CppSharp.AST;
|
||||
using CppSharp.Types;
|
||||
|
||||
namespace MonoManagedToNative.Generators
|
||||
{
|
||||
public class CGenerator : Generator
|
||||
{
|
||||
public CGenerator(Driver driver) : base(driver) { }
|
||||
|
||||
public override List<Template> Generate(Assembly assembly)
|
||||
{
|
||||
var moduleGen = new AstGenerator(Driver.Options);
|
||||
var module = moduleGen.Visit(assembly) as TranslationUnit;
|
||||
|
||||
var headers = new CHeaders(Driver, module);
|
||||
var sources = new CSources(Driver, module);
|
||||
|
||||
var templates = new List<Template> { headers, sources };
|
||||
foreach (var template in templates)
|
||||
template.Assembly = assembly;
|
||||
|
||||
return templates;
|
||||
}
|
||||
}
|
||||
|
||||
public class CBlockKind
|
||||
{
|
||||
public const int Includes = BlockKind.LAST + 11;
|
||||
public const int Function = BlockKind.LAST + 12;
|
||||
public const int Class = BlockKind.LAST + 13;
|
||||
public const int Typedef = BlockKind.LAST + 13;
|
||||
}
|
||||
|
||||
public abstract class CTemplate : Template, IDeclVisitor<bool>
|
||||
{
|
||||
public TranslationUnit Unit;
|
||||
|
||||
public CTemplate(Driver driver, TranslationUnit unit) : base(driver)
|
||||
{
|
||||
Unit = unit;
|
||||
}
|
||||
|
||||
public override string Name
|
||||
{
|
||||
get { return Unit.Name; }
|
||||
}
|
||||
|
||||
public string GeneratedIdentifier(string id)
|
||||
{
|
||||
return "__" + id;
|
||||
}
|
||||
|
||||
string PrintCILType(CILType type, TypeQualifiers quals)
|
||||
{
|
||||
if (type.Type == typeof(string))
|
||||
return "const char*";
|
||||
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public CppTypePrinter CTypePrinter
|
||||
{
|
||||
get
|
||||
{
|
||||
var cTypePrinter = new CppTypePrinter { PrintScopeKind = CppTypePrintScopeKind.Qualified };
|
||||
cTypePrinter.CILTypePrinter += PrintCILType;
|
||||
return cTypePrinter;
|
||||
}
|
||||
}
|
||||
|
||||
public void VisitDeclContext(DeclarationContext ctx)
|
||||
{
|
||||
foreach (var decl in ctx.Declarations)
|
||||
decl.Visit(this);
|
||||
}
|
||||
|
||||
public void GenerateFilePreamble()
|
||||
{
|
||||
WriteLine("/*");
|
||||
WriteLine(" * This is autogenerated code.");
|
||||
WriteLine(" * Do not edit this file or all your changes will be lost after re-generation.");
|
||||
WriteLine(" */");
|
||||
}
|
||||
|
||||
public void GenerateMethodSignature(Method method)
|
||||
{
|
||||
var @class = method.Namespace as Class;
|
||||
var retType = method.ReturnType.Visit(CTypePrinter);
|
||||
|
||||
Write("{0} {1}_{2}(", retType, @class.QualifiedName, method.Name);
|
||||
|
||||
Write(GenerateParametersList(method.Parameters));
|
||||
|
||||
Write(")");
|
||||
}
|
||||
|
||||
public string GenerateParametersList(List<Parameter> parameters)
|
||||
{
|
||||
var types = new List<string>();
|
||||
foreach (var param in parameters)
|
||||
types.Add(CTypePrinter.VisitParameter(param));
|
||||
return string.Join(", ", types);
|
||||
}
|
||||
|
||||
#region IDeclVisitor methods
|
||||
|
||||
public virtual bool VisitClassDecl(Class @class)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual bool VisitClassTemplateDecl(ClassTemplate template)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual bool VisitClassTemplateSpecializationDecl(ClassTemplateSpecialization specialization)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual bool VisitDeclaration(Declaration decl)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual bool VisitEnumDecl(Enumeration @enum)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual bool VisitEnumItemDecl(Enumeration.Item item)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual bool VisitEvent(Event @event)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual bool VisitFieldDecl(Field field)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual bool VisitFriend(Friend friend)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual bool VisitFunctionDecl(Function function)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual bool VisitFunctionTemplateDecl(FunctionTemplate template)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual bool VisitMacroDefinition(MacroDefinition macro)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual bool VisitMethodDecl(Method method)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual bool VisitNamespace(Namespace @namespace)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual bool VisitNonTypeTemplateParameterDecl(NonTypeTemplateParameter nonTypeTemplateParameter)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual bool VisitParameterDecl(Parameter parameter)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual bool VisitProperty(Property property)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual bool VisitTemplateParameterDecl(TypeTemplateParameter templateParameter)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual bool VisitTemplateTemplateParameterDecl(TemplateTemplateParameter templateTemplateParameter)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual bool VisitTypeAliasDecl(TypeAlias typeAlias)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual bool VisitTypeAliasTemplateDecl(TypeAliasTemplate typeAliasTemplate)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual bool VisitTypedefDecl(TypedefDecl typedef)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual bool VisitVariableDecl(Variable variable)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
using CppSharp.AST;
|
||||
|
||||
namespace MonoManagedToNative.Generators
|
||||
{
|
||||
public class CHeaders : CTemplate
|
||||
{
|
||||
public CHeaders(Driver driver, TranslationUnit unit) : base(driver, unit)
|
||||
{
|
||||
}
|
||||
|
||||
public override string FileExtension
|
||||
{
|
||||
get { return "h"; }
|
||||
}
|
||||
|
||||
public override void Process()
|
||||
{
|
||||
GenerateFilePreamble();
|
||||
|
||||
PushBlock(CBlockKind.Includes);
|
||||
WriteLine("#pragma once");
|
||||
WriteLine("#include <stdbool.h>");
|
||||
PopBlock(NewLineKind.BeforeNextBlock);
|
||||
|
||||
VisitDeclContext(Unit);
|
||||
}
|
||||
|
||||
public override bool VisitClassDecl(Class @class)
|
||||
{
|
||||
PushBlock(CBlockKind.Class);
|
||||
|
||||
PushBlock();
|
||||
WriteLine("typedef struct {0} {0};", @class.Name);
|
||||
PopBlock(NewLineKind.BeforeNextBlock);
|
||||
|
||||
VisitDeclContext(@class);
|
||||
|
||||
PopBlock(NewLineKind.BeforeNextBlock);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool VisitMethodDecl(Method method)
|
||||
{
|
||||
PushBlock(CBlockKind.Function);
|
||||
|
||||
GenerateMethodSignature(method);
|
||||
WriteLine(";");
|
||||
|
||||
PopBlock();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
using CppSharp.AST;
|
||||
using CppSharp.AST.Extensions;
|
||||
|
||||
namespace MonoManagedToNative.Generators
|
||||
{
|
||||
public class CSources : CTemplate
|
||||
{
|
||||
public CSources(Driver driver, TranslationUnit unit) : base(driver, unit)
|
||||
{
|
||||
}
|
||||
|
||||
public override string FileExtension
|
||||
{
|
||||
get { return "c"; }
|
||||
}
|
||||
|
||||
public string AssemblyId
|
||||
{
|
||||
get
|
||||
{
|
||||
return GeneratedIdentifier(Assembly.GetName().Name).Replace('.', '_');
|
||||
}
|
||||
}
|
||||
|
||||
public override void Process()
|
||||
{
|
||||
GenerateFilePreamble();
|
||||
|
||||
PushBlock();
|
||||
WriteLine("#include \"{0}.h\"", Unit.Name);
|
||||
WriteLine("#include <mono/jit/jit.h>");
|
||||
WriteLine("#include <mono/metadata/assembly.h>");
|
||||
//WriteLine("#include <mono/metadata/domain.h>");
|
||||
WriteLine("#include <mono/metadata/object.h>");
|
||||
WriteLine("#include <mono/metadata/mono-config.h>");
|
||||
WriteLine("#include <mono/metadata/debug-helpers.h>");
|
||||
PopBlock(NewLineKind.BeforeNextBlock);
|
||||
|
||||
PushBlock();
|
||||
WriteLine("extern MonoDomain* {0};", GeneratedIdentifier("mono_domain"));
|
||||
WriteLine("extern bool {0};", GeneratedIdentifier("mono_initialized"));
|
||||
|
||||
WriteLine("extern MonoAssembly* {0}_assembly;", AssemblyId);
|
||||
PopBlock(NewLineKind.BeforeNextBlock);
|
||||
|
||||
GenerateMonoInitialization();
|
||||
GenerateAssemblyLoad();
|
||||
|
||||
VisitDeclContext(Unit);
|
||||
}
|
||||
|
||||
public override bool VisitClassDecl(Class @class)
|
||||
{
|
||||
PushBlock();
|
||||
WriteLine("static MonoClass* {0}_class = 0;", @class.QualifiedName);
|
||||
WriteLine("static MonoObject* {0}_instance = 0;", @class.QualifiedName);
|
||||
PopBlock(NewLineKind.BeforeNextBlock);
|
||||
|
||||
VisitDeclContext(@class);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void GenerateMonoInitialization()
|
||||
{
|
||||
PushBlock();
|
||||
WriteLine("static void {0}()", GeneratedIdentifier("initialize_mono"));
|
||||
WriteStartBraceIndent();
|
||||
|
||||
WriteLine("if ({0})", GeneratedIdentifier("mono_initialized"));
|
||||
WriteLineIndent("return;");
|
||||
|
||||
var domainName = "mono_managed_to_native_binding";
|
||||
var version = "v4.0.30319";
|
||||
WriteLine("{0} = mono_jit_init_version(\"{1}\", \"{2}\");",
|
||||
GeneratedIdentifier("mono_domain"), domainName, version);
|
||||
|
||||
WriteCloseBraceIndent();
|
||||
PopBlock(NewLineKind.BeforeNextBlock);
|
||||
}
|
||||
|
||||
public void GenerateAssemblyLoad()
|
||||
{
|
||||
var assemblyName = Assembly.GetName().Name;
|
||||
var assemblyLookupId = GeneratedIdentifier(string.Format("lookup_{0}_assembly",
|
||||
assemblyName.Replace('.', '_')));
|
||||
|
||||
PushBlock();
|
||||
WriteLine("static void {0}()", assemblyLookupId);
|
||||
WriteStartBraceIndent();
|
||||
|
||||
var monoAssemblyName = string.Format("{0}_assembly", AssemblyId);
|
||||
WriteLine("if ({0})", monoAssemblyName);
|
||||
WriteLineIndent("return;");
|
||||
|
||||
WriteLine("{0} = mono_domain_assembly_open({1}, \"{2}.dll\");",
|
||||
monoAssemblyName, GeneratedIdentifier("mono_domain"), assemblyName);
|
||||
|
||||
WriteCloseBraceIndent();
|
||||
PopBlock(NewLineKind.BeforeNextBlock);
|
||||
}
|
||||
|
||||
public void GenerateMethodLookup(Method method)
|
||||
{
|
||||
var methodId = GeneratedIdentifier("method");
|
||||
WriteLine("const char {0}[] = \"{1}\";", methodId, method.OriginalName);
|
||||
var descId = GeneratedIdentifier("desc");
|
||||
|
||||
WriteLine("MonoMethodDesc* {0} = mono_method_desc_new({1}, /*include_namespace=*/true);",
|
||||
descId, methodId);
|
||||
|
||||
var createInstanceId = GeneratedIdentifier("createInstance");
|
||||
|
||||
var @class = method.Namespace as Class;
|
||||
var classId = string.Format("{0}_class", @class.QualifiedName);
|
||||
|
||||
WriteLine("MonoMethod* {0} = mono_method_desc_search_in_class({1}, {2});",
|
||||
createInstanceId, descId, classId);
|
||||
|
||||
WriteLine("mono_method_desc_free({0});", descId);
|
||||
}
|
||||
|
||||
public void GenerateMethodInvocation(Method method)
|
||||
{
|
||||
//MonoObject* result;
|
||||
//mono_runtime_invoke(lldbDebuggerCreateInstanceMethod, &result, args, nullptr);
|
||||
}
|
||||
|
||||
public override bool VisitMethodDecl(Method method)
|
||||
{
|
||||
PushBlock();
|
||||
|
||||
GenerateMethodSignature(method);
|
||||
NewLine();
|
||||
WriteStartBraceIndent();
|
||||
|
||||
GenerateMethodLookup(method);
|
||||
|
||||
var retType = method.ReturnType;
|
||||
var needsReturn = !retType.Type.IsPrimitiveType(PrimitiveType.Void);
|
||||
|
||||
GenerateMethodInvocation(method);
|
||||
|
||||
if (needsReturn)
|
||||
WriteLine("return 0;");
|
||||
|
||||
WriteCloseBraceIndent();
|
||||
|
||||
PopBlock(NewLineKind.BeforeNextBlock);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,480 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using CppSharp.AST;
|
||||
using CppSharp.AST.Extensions;
|
||||
using Type = CppSharp.AST.Type;
|
||||
|
||||
namespace CppSharp.Types
|
||||
{
|
||||
public enum TypePrinterContextKind
|
||||
{
|
||||
Normal,
|
||||
Template
|
||||
}
|
||||
|
||||
public abstract class TypePrinterContext
|
||||
{
|
||||
protected TypePrinterContext()
|
||||
{
|
||||
Kind = TypePrinterContextKind.Normal;
|
||||
}
|
||||
|
||||
protected TypePrinterContext(TypePrinterContextKind kind)
|
||||
{
|
||||
Kind = kind;
|
||||
}
|
||||
|
||||
public string GetTemplateParameterList()
|
||||
{
|
||||
if (Kind == TypePrinterContextKind.Template)
|
||||
{
|
||||
var template = (Template)Declaration;
|
||||
return string.Join(", ", template.Parameters.Select(p => p.Name));
|
||||
}
|
||||
|
||||
var type = Type.Desugar();
|
||||
IEnumerable<TemplateArgument> templateArgs;
|
||||
var templateSpecializationType = type as TemplateSpecializationType;
|
||||
if (templateSpecializationType != null)
|
||||
templateArgs = templateSpecializationType.Arguments;
|
||||
else
|
||||
templateArgs = ((ClassTemplateSpecialization)((TagType)type).Declaration).Arguments;
|
||||
|
||||
var paramsList = new List<string>();
|
||||
foreach (var arg in templateArgs.Where(a => a.Kind == TemplateArgument.ArgumentKind.Type))
|
||||
{
|
||||
var argType = arg.Type.Type.IsPointerToPrimitiveType()
|
||||
? new CILType(typeof(System.IntPtr))
|
||||
: arg.Type.Type;
|
||||
paramsList.Add(argType.ToString());
|
||||
}
|
||||
|
||||
return string.Join(", ", paramsList);
|
||||
}
|
||||
|
||||
public TypePrinterContextKind Kind;
|
||||
public Declaration Declaration;
|
||||
public Parameter Parameter;
|
||||
public Type Type;
|
||||
}
|
||||
|
||||
public interface ITypePrinter
|
||||
{
|
||||
string ToString(Type type);
|
||||
}
|
||||
|
||||
public interface ITypePrinter<out T> : ITypePrinter, ITypeVisitor<T>
|
||||
{
|
||||
T VisitParameters(IEnumerable<Parameter> @params, bool hasNames);
|
||||
T VisitParameter(Parameter param, bool hasName = true);
|
||||
|
||||
T VisitDelegate(FunctionType function);
|
||||
}
|
||||
|
||||
public enum CppTypePrintScopeKind
|
||||
{
|
||||
Local,
|
||||
Qualified,
|
||||
GlobalQualified
|
||||
}
|
||||
|
||||
public enum CppTypePrintFlavorKind
|
||||
{
|
||||
C,
|
||||
Cpp,
|
||||
}
|
||||
|
||||
public class CppTypePrinter : ITypePrinter<string>, IDeclVisitor<string>
|
||||
{
|
||||
public CppTypePrintFlavorKind PrintFlavorKind;
|
||||
public CppTypePrintScopeKind PrintScopeKind;
|
||||
public bool PrintLogicalNames;
|
||||
public bool PrintTypeQualifiers;
|
||||
|
||||
public CppTypePrinter(bool printTypeQualifiers = true)
|
||||
{
|
||||
PrintFlavorKind = CppTypePrintFlavorKind.Cpp;
|
||||
PrintScopeKind = CppTypePrintScopeKind.GlobalQualified;
|
||||
PrintTypeQualifiers = printTypeQualifiers;
|
||||
}
|
||||
|
||||
public bool ResolveTypedefs { get; set; }
|
||||
|
||||
public string VisitTagType(TagType tag, TypeQualifiers quals)
|
||||
{
|
||||
return tag.Declaration.Visit(this);
|
||||
}
|
||||
|
||||
public string VisitArrayType(ArrayType array, TypeQualifiers quals)
|
||||
{
|
||||
var typeName = array.Type.Visit(this);
|
||||
|
||||
switch (array.SizeType)
|
||||
{
|
||||
case ArrayType.ArraySize.Constant:
|
||||
return string.Format("{0}[{1}]", typeName, array.Size);
|
||||
case ArrayType.ArraySize.Variable:
|
||||
case ArrayType.ArraySize.Dependent:
|
||||
case ArrayType.ArraySize.Incomplete:
|
||||
return string.Format("{0}[]", typeName);
|
||||
}
|
||||
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
static string ConvertModifierToString(PointerType.TypeModifier modifier)
|
||||
{
|
||||
switch (modifier)
|
||||
{
|
||||
case PointerType.TypeModifier.Value: return string.Empty;
|
||||
case PointerType.TypeModifier.Pointer: return "*";
|
||||
case PointerType.TypeModifier.LVReference: return "&";
|
||||
case PointerType.TypeModifier.RVReference: return "&&";
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public string VisitPointerType(PointerType pointer, TypeQualifiers quals)
|
||||
{
|
||||
var pointee = pointer.Pointee;
|
||||
|
||||
var function = pointee as FunctionType;
|
||||
if (function != null)
|
||||
{
|
||||
var arguments = function.Parameters;
|
||||
var returnType = function.ReturnType;
|
||||
var args = string.Empty;
|
||||
|
||||
if (arguments.Count > 0)
|
||||
args = VisitParameters(function.Parameters, hasNames: false);
|
||||
|
||||
return string.Format("{0} (*)({1})", returnType.Visit(this), args);
|
||||
}
|
||||
|
||||
var pointeeType = pointer.Pointee.Visit(this, quals);
|
||||
var mod = ConvertModifierToString(pointer.Modifier);
|
||||
|
||||
var s = PrintTypeQualifiers && quals.IsConst ? "const " : string.Empty;
|
||||
s += string.Format("{0}{1}", pointeeType, mod);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
public string VisitMemberPointerType(MemberPointerType member, TypeQualifiers quals)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public string VisitBuiltinType(BuiltinType builtin, TypeQualifiers quals)
|
||||
{
|
||||
return VisitPrimitiveType(builtin.Type);
|
||||
}
|
||||
|
||||
public string VisitPrimitiveType(PrimitiveType primitive)
|
||||
{
|
||||
switch (primitive)
|
||||
{
|
||||
case PrimitiveType.Bool: return "bool";
|
||||
case PrimitiveType.Void: return "void";
|
||||
case PrimitiveType.Char16:
|
||||
case PrimitiveType.WideChar: return "wchar_t";
|
||||
case PrimitiveType.Char: return "char";
|
||||
case PrimitiveType.UChar: return "unsigned char";
|
||||
case PrimitiveType.Short: return "short";
|
||||
case PrimitiveType.UShort: return "unsigned short";
|
||||
case PrimitiveType.Int: return "int";
|
||||
case PrimitiveType.UInt: return "unsigned int";
|
||||
case PrimitiveType.Long: return "long";
|
||||
case PrimitiveType.ULong: return "unsigned long";
|
||||
case PrimitiveType.LongLong: return "long long";
|
||||
case PrimitiveType.ULongLong: return "unsigned long long";
|
||||
case PrimitiveType.Float: return "float";
|
||||
case PrimitiveType.Double: return "double";
|
||||
case PrimitiveType.LongDouble: return "long double";
|
||||
case PrimitiveType.IntPtr: return "void*";
|
||||
case PrimitiveType.UIntPtr: return "uintptr_t";
|
||||
case PrimitiveType.Null: return "std::nullptr_t";
|
||||
}
|
||||
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public string VisitTypedefType(TypedefType typedef, TypeQualifiers quals)
|
||||
{
|
||||
if (ResolveTypedefs)
|
||||
{
|
||||
var decl = typedef.Declaration;
|
||||
FunctionType func;
|
||||
return decl.Type.IsPointerTo(out func) ? VisitDeclaration(decl) : decl.Type.Visit(this);
|
||||
}
|
||||
return GetDeclName(typedef.Declaration);
|
||||
}
|
||||
|
||||
public string VisitAttributedType(AttributedType attributed, TypeQualifiers quals)
|
||||
{
|
||||
return attributed.Modified.Visit(this);
|
||||
}
|
||||
|
||||
public string VisitDecayedType(DecayedType decayed, TypeQualifiers quals)
|
||||
{
|
||||
return decayed.Decayed.Visit(this);
|
||||
}
|
||||
|
||||
public string VisitTemplateSpecializationType(TemplateSpecializationType template, TypeQualifiers quals)
|
||||
{
|
||||
var specialization = template.GetClassTemplateSpecialization();
|
||||
if (specialization == null)
|
||||
return string.Empty;
|
||||
|
||||
return VisitClassTemplateSpecializationDecl(specialization);
|
||||
}
|
||||
|
||||
public string VisitDependentTemplateSpecializationType(
|
||||
DependentTemplateSpecializationType template, TypeQualifiers quals)
|
||||
{
|
||||
if (template.Desugared != null)
|
||||
return template.Desugared.Visit(this);
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public string VisitTemplateParameterType(TemplateParameterType param, TypeQualifiers quals)
|
||||
{
|
||||
if (param.Parameter.Name == null)
|
||||
return string.Empty;
|
||||
|
||||
return param.Parameter.Name;
|
||||
}
|
||||
|
||||
public string VisitTemplateParameterSubstitutionType(
|
||||
TemplateParameterSubstitutionType param, TypeQualifiers quals)
|
||||
{
|
||||
return param.Replacement.Visit(this);
|
||||
}
|
||||
|
||||
public string VisitInjectedClassNameType(InjectedClassNameType injected, TypeQualifiers quals)
|
||||
{
|
||||
return injected.Class.Visit(this);
|
||||
}
|
||||
|
||||
public string VisitDependentNameType(DependentNameType dependent, TypeQualifiers quals)
|
||||
{
|
||||
return dependent.Desugared != null ? dependent.Desugared.Visit(this) : string.Empty;
|
||||
}
|
||||
|
||||
public string VisitPackExpansionType(PackExpansionType packExpansionType, TypeQualifiers quals)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public Func<CILType , TypeQualifiers, string> CILTypePrinter;
|
||||
|
||||
public string VisitCILType(CILType type, TypeQualifiers quals)
|
||||
{
|
||||
if (CILTypePrinter != null)
|
||||
return CILTypePrinter(type, quals);
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public string VisitPrimitiveType(PrimitiveType type, TypeQualifiers quals)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public string VisitDeclaration(Declaration decl, TypeQualifiers quals)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public string VisitFunctionType(FunctionType function, TypeQualifiers quals)
|
||||
{
|
||||
var arguments = function.Parameters;
|
||||
var returnType = function.ReturnType;
|
||||
var args = string.Empty;
|
||||
|
||||
if (arguments.Count > 0)
|
||||
args = VisitParameters(function.Parameters, hasNames: false);
|
||||
|
||||
return string.Format("{0} ({1})", returnType.Visit(this), args);
|
||||
}
|
||||
|
||||
public string VisitParameters(IEnumerable<Parameter> @params,
|
||||
bool hasNames)
|
||||
{
|
||||
var args = new List<string>();
|
||||
|
||||
foreach (var param in @params)
|
||||
args.Add(VisitParameter(param, hasNames));
|
||||
|
||||
return string.Join(", ", args);
|
||||
}
|
||||
|
||||
public string VisitParameter(Parameter arg, bool hasName = true)
|
||||
{
|
||||
var type = arg.Type.Visit(this, arg.QualifiedType.Qualifiers);
|
||||
var name = arg.Name;
|
||||
|
||||
if (hasName && !string.IsNullOrEmpty(name))
|
||||
return string.Format("{0} {1}", type, name);
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
public string VisitDelegate(FunctionType function)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public string GetDeclName(Declaration declaration)
|
||||
{
|
||||
switch (PrintScopeKind)
|
||||
{
|
||||
case CppTypePrintScopeKind.Local:
|
||||
return PrintLogicalNames ? declaration.LogicalOriginalName
|
||||
: declaration.OriginalName;
|
||||
case CppTypePrintScopeKind.Qualified:
|
||||
return PrintLogicalNames ? declaration.QualifiedLogicalOriginalName
|
||||
: declaration.QualifiedOriginalName;
|
||||
case CppTypePrintScopeKind.GlobalQualified:
|
||||
return "::" + (PrintLogicalNames ? declaration.QualifiedLogicalOriginalName
|
||||
: declaration.QualifiedOriginalName);
|
||||
}
|
||||
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public string VisitDeclaration(Declaration decl)
|
||||
{
|
||||
return GetDeclName(decl);
|
||||
}
|
||||
|
||||
public string VisitClassDecl(Class @class)
|
||||
{
|
||||
return VisitDeclaration(@class);
|
||||
}
|
||||
|
||||
public string VisitClassTemplateSpecializationDecl(ClassTemplateSpecialization specialization)
|
||||
{
|
||||
return string.Format("{0}<{1}>", specialization.TemplatedDecl.Visit(this),
|
||||
string.Join(", ",
|
||||
specialization.Arguments.Where(
|
||||
a => a.Type.Type != null &&
|
||||
!(a.Type.Type is DependentNameType)).Select(a => a.Type.Visit(this))));
|
||||
}
|
||||
|
||||
public string VisitFieldDecl(Field field)
|
||||
{
|
||||
return VisitDeclaration(field);
|
||||
}
|
||||
|
||||
public string VisitFunctionDecl(Function function)
|
||||
{
|
||||
return VisitDeclaration(function);
|
||||
}
|
||||
|
||||
public string VisitMethodDecl(Method method)
|
||||
{
|
||||
return VisitDeclaration(method);
|
||||
}
|
||||
|
||||
public string VisitParameterDecl(Parameter parameter)
|
||||
{
|
||||
return VisitParameter(parameter, hasName: false);
|
||||
}
|
||||
|
||||
public string VisitTypedefDecl(TypedefDecl typedef)
|
||||
{
|
||||
return VisitDeclaration(typedef);
|
||||
}
|
||||
|
||||
public string VisitTypeAliasDecl(TypeAlias typeAlias)
|
||||
{
|
||||
return VisitDeclaration(typeAlias);
|
||||
}
|
||||
|
||||
public string VisitEnumDecl(Enumeration @enum)
|
||||
{
|
||||
return VisitDeclaration(@enum);
|
||||
}
|
||||
|
||||
public string VisitEnumItemDecl(Enumeration.Item item)
|
||||
{
|
||||
return VisitDeclaration(item);
|
||||
}
|
||||
|
||||
public string VisitVariableDecl(Variable variable)
|
||||
{
|
||||
return VisitDeclaration(variable);
|
||||
}
|
||||
|
||||
public string VisitClassTemplateDecl(ClassTemplate template)
|
||||
{
|
||||
return VisitDeclaration(template);
|
||||
}
|
||||
|
||||
public string VisitFunctionTemplateDecl(FunctionTemplate template)
|
||||
{
|
||||
return VisitDeclaration(template);
|
||||
}
|
||||
|
||||
public string VisitMacroDefinition(MacroDefinition macro)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public string VisitNamespace(Namespace @namespace)
|
||||
{
|
||||
return VisitDeclaration(@namespace);
|
||||
}
|
||||
|
||||
public string VisitEvent(Event @event)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public string VisitProperty(Property property)
|
||||
{
|
||||
return VisitDeclaration(property);
|
||||
}
|
||||
|
||||
public string VisitFriend(Friend friend)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public string ToString(Type type)
|
||||
{
|
||||
return type.Visit(this);
|
||||
}
|
||||
|
||||
public string VisitTemplateTemplateParameterDecl(TemplateTemplateParameter templateTemplateParameter)
|
||||
{
|
||||
return templateTemplateParameter.Name;
|
||||
}
|
||||
|
||||
public string VisitTemplateParameterDecl(TypeTemplateParameter templateParameter)
|
||||
{
|
||||
if (templateParameter.DefaultArgument.Type == null)
|
||||
return templateParameter.Name;
|
||||
|
||||
return string.Format("{0} = {1}", templateParameter.Name,
|
||||
templateParameter.DefaultArgument.Visit(this));
|
||||
}
|
||||
|
||||
public string VisitNonTypeTemplateParameterDecl(NonTypeTemplateParameter nonTypeTemplateParameter)
|
||||
{
|
||||
if (nonTypeTemplateParameter.DefaultArgument == null)
|
||||
return nonTypeTemplateParameter.Name;
|
||||
|
||||
return string.Format("{0} = {1}", nonTypeTemplateParameter.Name,
|
||||
nonTypeTemplateParameter.DefaultArgument.String);
|
||||
}
|
||||
|
||||
public string VisitTypeAliasTemplateDecl(TypeAliasTemplate typeAliasTemplate)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
using IKVM.Reflection;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MonoManagedToNative.Generators
|
||||
{
|
||||
public enum GeneratorKind
|
||||
{
|
||||
C
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generators are the base class for each language backend.
|
||||
/// </summary>
|
||||
public abstract class Generator
|
||||
{
|
||||
public Driver Driver { get; private set; }
|
||||
|
||||
protected Generator(Driver driver)
|
||||
{
|
||||
Driver = driver;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates the outputs for a given translation unit.
|
||||
/// </summary>
|
||||
public abstract List<Template> Generate(Assembly assembly);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
using IKVM.Reflection;
|
||||
|
||||
namespace MonoManagedToNative.Generators
|
||||
{
|
||||
public abstract class Template : BlockGenerator
|
||||
{
|
||||
public Driver Driver { get; private set; }
|
||||
public Options Options { get; private set; }
|
||||
|
||||
public IDiagnostics Diagnostics
|
||||
{
|
||||
get { return Driver.Diagnostics; }
|
||||
}
|
||||
|
||||
public Assembly Assembly { get; set; }
|
||||
|
||||
protected Template(Driver driver)
|
||||
{
|
||||
Driver = driver;
|
||||
Options = driver.Options;
|
||||
}
|
||||
|
||||
public abstract string Name { get; }
|
||||
|
||||
public abstract string FileExtension { get; }
|
||||
|
||||
public abstract void Process();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
using MonoManagedToNative.Generators;
|
||||
|
||||
namespace MonoManagedToNative
|
||||
{
|
||||
public class Options
|
||||
{
|
||||
public Options()
|
||||
{
|
||||
Project = new Project();
|
||||
}
|
||||
|
||||
public Project Project;
|
||||
|
||||
// General options
|
||||
public bool ShowHelpText;
|
||||
public bool OutputDebug;
|
||||
|
||||
// Parser options
|
||||
public bool IgnoreParseErrors;
|
||||
|
||||
// Generator options
|
||||
public string LibraryName;
|
||||
public GeneratorKind Language;
|
||||
|
||||
public string OutputNamespace;
|
||||
public string OutputDir;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace MonoManagedToNative
|
||||
{
|
||||
public enum ParserDiagnosticLevel
|
||||
{
|
||||
Ignored,
|
||||
Note,
|
||||
Warning,
|
||||
Error,
|
||||
Fatal
|
||||
}
|
||||
|
||||
public struct ParserDiagnostic
|
||||
{
|
||||
public string FileName;
|
||||
public string Message;
|
||||
public ParserDiagnosticLevel Level;
|
||||
public int LineNumber;
|
||||
public int ColumnNumber;
|
||||
}
|
||||
|
||||
public enum ParserResultKind
|
||||
{
|
||||
Success,
|
||||
Error,
|
||||
FileNotFound
|
||||
}
|
||||
|
||||
public class ParserResult<T>
|
||||
{
|
||||
public ParserResult()
|
||||
{
|
||||
Kind = ParserResultKind.Success;
|
||||
Diagnostics = new List<ParserDiagnostic>();
|
||||
}
|
||||
|
||||
public ProjectInput Input;
|
||||
public ParserResultKind Kind;
|
||||
public List<ParserDiagnostic> Diagnostics;
|
||||
public string Message;
|
||||
|
||||
public T Output;
|
||||
|
||||
public bool HasErrors
|
||||
{
|
||||
get
|
||||
{
|
||||
return Diagnostics.Any(diagnostic =>
|
||||
diagnostic.Level == ParserDiagnosticLevel.Error ||
|
||||
diagnostic.Level == ParserDiagnosticLevel.Fatal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public delegate void ParserHandler<T>(ProjectInput input, ParserResult<T> result);
|
||||
|
||||
public class Parser
|
||||
{
|
||||
private readonly Options Options;
|
||||
private readonly IDiagnostics Diagnostics;
|
||||
|
||||
public delegate void ParsedDelegate<T>(ParserResult<T> result);
|
||||
|
||||
public ParsedDelegate<IKVM.Reflection.Assembly> OnAssemblyParsed = delegate { };
|
||||
|
||||
IKVM.Reflection.Universe Universe;
|
||||
|
||||
public Parser(Options options, IDiagnostics diagostics)
|
||||
{
|
||||
Options = options;
|
||||
Diagnostics = diagostics;
|
||||
Universe = new IKVM.Reflection.Universe(IKVM.Reflection.UniverseOptions.MetadataOnly);
|
||||
}
|
||||
|
||||
public void ParseAssembly(ProjectInput input, ParserResult<IKVM.Reflection.Assembly> result)
|
||||
{
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
var res = Universe.LoadFile(input.FullPath);
|
||||
result.Output = res;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.Message = ex.ToString();
|
||||
result.Kind = ParserResultKind.Error;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
OnAssemblyParsed(result);
|
||||
}
|
||||
}
|
||||
|
||||
ParserResult<T> ParseInput<T>(ProjectInput input, ParserHandler<T> handler)
|
||||
{
|
||||
var result = new ParserResult<T>
|
||||
{
|
||||
Input = input
|
||||
};
|
||||
|
||||
if (!File.Exists(input.FullPath))
|
||||
{
|
||||
result.Kind = ParserResultKind.FileNotFound;
|
||||
return result;
|
||||
}
|
||||
|
||||
handler(input, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool Parse(Project project)
|
||||
{
|
||||
var hasErrors = false;
|
||||
|
||||
foreach (var input in project.AssemblyInputs)
|
||||
{
|
||||
var result = ParseInput<IKVM.Reflection.Assembly>(input, ParseAssembly);
|
||||
hasErrors |= result.HasErrors;
|
||||
}
|
||||
|
||||
return !hasErrors;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace MonoManagedToNative
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an input file in the binding project.
|
||||
/// </summary>
|
||||
public class ProjectInput
|
||||
{
|
||||
/// <summary>
|
||||
/// Full path to the input file.
|
||||
/// </summary>
|
||||
public string FullPath;
|
||||
|
||||
/// <summary>
|
||||
/// Base path to the input file.
|
||||
/// </summary>
|
||||
public string BasePath;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents the output generated for the binding project.
|
||||
/// </summary>
|
||||
public class ProjectOutput
|
||||
{
|
||||
public Dictionary<string, Stream> Files;
|
||||
|
||||
public ProjectOutput()
|
||||
{
|
||||
Files = new Dictionary<string, Stream>();
|
||||
}
|
||||
|
||||
public Stream GetOutput(string path)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
throw new NotSupportedException("Invalid path");
|
||||
|
||||
var stream = new MemoryStream();
|
||||
Files[path] = stream;
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
public Stream WriteOutput(string path, string content)
|
||||
{
|
||||
var stream = GetOutput(path);
|
||||
|
||||
var bytes = Encoding.UTF8.GetBytes(content);
|
||||
stream.Write(bytes, 0, bytes.Length);
|
||||
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a binding project.
|
||||
/// </summary>
|
||||
public class Project
|
||||
{
|
||||
public string Name;
|
||||
public string OutputPath;
|
||||
|
||||
public List<string> AssemblyDirs;
|
||||
public List<string> Assemblies;
|
||||
|
||||
internal List<ProjectInput> AssemblyInputs;
|
||||
|
||||
public Project()
|
||||
{
|
||||
AssemblyDirs = new List<string>();
|
||||
Assemblies = new List<string>();
|
||||
AssemblyInputs = new List<ProjectInput>();
|
||||
}
|
||||
|
||||
public void BuildInputs()
|
||||
{
|
||||
foreach (var path in AssemblyDirs)
|
||||
{
|
||||
if (!Directory.Exists(path)) continue;
|
||||
|
||||
var files = Directory.EnumerateFiles(path, "*.dll");
|
||||
|
||||
foreach (var file in files)
|
||||
{
|
||||
var matches = false;
|
||||
foreach (var assembly in Assemblies)
|
||||
matches |= Regex.IsMatch(Path.GetFileName(file), assembly);
|
||||
|
||||
if (!matches) continue;
|
||||
|
||||
var input = new ProjectInput
|
||||
{
|
||||
BasePath = path,
|
||||
FullPath = file,
|
||||
};
|
||||
|
||||
AssemblyInputs.Add(input);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
using IKVM.Reflection;
|
||||
using System;
|
||||
|
||||
namespace MonoManagedToNative.Generators
|
||||
{
|
||||
public class ReflectionVisitor<T>
|
||||
{
|
||||
public virtual T Visit(Assembly assembly)
|
||||
{
|
||||
foreach (var type in assembly.ExportedTypes)
|
||||
{
|
||||
Visit(type.GetTypeInfo());
|
||||
}
|
||||
|
||||
return default(T);
|
||||
}
|
||||
|
||||
public T Visit(TypeInfo typeInfo)
|
||||
{
|
||||
if (typeInfo.IsClass)
|
||||
return VisitClass(typeInfo);
|
||||
else if (typeInfo.IsEnum)
|
||||
return VisitEnum(typeInfo);
|
||||
else if (typeInfo.IsInterface)
|
||||
return VisitInterface(typeInfo);
|
||||
else if (typeInfo.IsValueType)
|
||||
return VisitStruct(typeInfo);
|
||||
|
||||
throw new Exception("Could not visit type " + typeInfo.ToString());
|
||||
}
|
||||
|
||||
public virtual void VisitMembers(TypeInfo type)
|
||||
{
|
||||
foreach (var ctor in type.DeclaredConstructors)
|
||||
VisitConstructor(ctor);
|
||||
|
||||
foreach (var method in type.DeclaredMethods)
|
||||
VisitMethod(method);
|
||||
|
||||
foreach (var field in type.DeclaredFields)
|
||||
VisitField(field);
|
||||
|
||||
foreach (var @event in type.DeclaredEvents)
|
||||
VisitEvent(@event);
|
||||
|
||||
foreach (var property in type.DeclaredProperties)
|
||||
VisitProperty(property);
|
||||
}
|
||||
|
||||
public virtual T VisitClass(TypeInfo @class)
|
||||
{
|
||||
return default(T);
|
||||
}
|
||||
|
||||
public virtual T VisitEnum(TypeInfo @enum)
|
||||
{
|
||||
return default(T);
|
||||
}
|
||||
|
||||
public virtual T VisitInterface(TypeInfo @interface)
|
||||
{
|
||||
return default(T);
|
||||
}
|
||||
|
||||
public virtual T VisitStruct(TypeInfo @struct)
|
||||
{
|
||||
return default(T);
|
||||
}
|
||||
|
||||
public virtual T VisitConstructor(ConstructorInfo ctor)
|
||||
{
|
||||
return default(T);
|
||||
}
|
||||
|
||||
public virtual T VisitMethod(MethodInfo method)
|
||||
{
|
||||
return default(T);
|
||||
}
|
||||
|
||||
public virtual T VisitField(FieldInfo field)
|
||||
{
|
||||
return default(T);
|
||||
}
|
||||
|
||||
public virtual T VisitEvent(EventInfo @event)
|
||||
{
|
||||
return default(T);
|
||||
}
|
||||
|
||||
public virtual T VisitProperty(PropertyInfo @property)
|
||||
{
|
||||
return default(T);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
using MonoManagedToNative.Generators;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
|
||||
namespace MonoManagedToNative.Tests
|
||||
{
|
||||
/// <summary>
|
||||
/// The main base class for a generator-based tests project.
|
||||
/// </summary>
|
||||
public abstract class TestsGenerator
|
||||
{
|
||||
readonly string name;
|
||||
readonly GeneratorKind languageKind;
|
||||
readonly Driver driver;
|
||||
readonly Options options;
|
||||
|
||||
protected TestsGenerator(string name, GeneratorKind languageKind)
|
||||
{
|
||||
this.name = name;
|
||||
this.languageKind = languageKind;
|
||||
|
||||
options = new Options();
|
||||
driver = new Driver(options);
|
||||
|
||||
Setup();
|
||||
}
|
||||
|
||||
public virtual void Setup()
|
||||
{
|
||||
var outputDir = GetOutputDirectory();
|
||||
options.OutputDir = Path.Combine(outputDir, "gen", name);
|
||||
options.LibraryName = name;
|
||||
|
||||
driver.Diagnostics.Message("");
|
||||
driver.Diagnostics.Message("Generating bindings for {0} ({1})",
|
||||
options.LibraryName, options.Language.ToString());
|
||||
|
||||
var currentDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
||||
options.Project.AssemblyDirs.Add(currentDir);
|
||||
//options.Project.Assemblies.Add(Path.Combine(currentDir, name + ".Managed.dll"));
|
||||
options.Project.Assemblies.Add(name + ".Managed.dll");
|
||||
}
|
||||
|
||||
public virtual void Generate()
|
||||
{
|
||||
driver.Run();
|
||||
}
|
||||
|
||||
#region Helpers
|
||||
public static string GetTestsDirectory(string name)
|
||||
{
|
||||
var directory = Directory.GetParent(Directory.GetCurrentDirectory());
|
||||
|
||||
while (directory != null)
|
||||
{
|
||||
var path = Path.Combine(directory.FullName, "tests", name);
|
||||
|
||||
if (Directory.Exists(path))
|
||||
return path;
|
||||
|
||||
directory = directory.Parent;
|
||||
}
|
||||
|
||||
throw new Exception(string.Format(
|
||||
"Tests directory for project '{0}' was not found", name));
|
||||
}
|
||||
|
||||
static string GetOutputDirectory()
|
||||
{
|
||||
var directory = Directory.GetParent(Directory.GetCurrentDirectory());
|
||||
|
||||
while (directory != null)
|
||||
{
|
||||
var path = Path.Combine(directory.FullName, "obj");
|
||||
|
||||
if (Directory.Exists(path))
|
||||
return directory.FullName;
|
||||
|
||||
directory = directory.Parent;
|
||||
}
|
||||
|
||||
throw new Exception("Could not find tests output directory");
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,399 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace MonoManagedToNative.Generators
|
||||
{
|
||||
public enum NewLineKind
|
||||
{
|
||||
Never,
|
||||
Always,
|
||||
BeforeNextBlock,
|
||||
IfNotEmpty
|
||||
}
|
||||
|
||||
public class BlockKind
|
||||
{
|
||||
public const int Unknown = 0;
|
||||
public const int BlockComment = 1;
|
||||
public const int InlineComment = 2;
|
||||
public const int Header = 3;
|
||||
public const int Footer = 4;
|
||||
public const int LAST = 5;
|
||||
}
|
||||
|
||||
public class Block : ITextGenerator
|
||||
{
|
||||
public TextGenerator Text { get; set; }
|
||||
public int Kind { get; set; }
|
||||
public NewLineKind NewLineKind { get; set; }
|
||||
|
||||
public object Object { get; set; }
|
||||
|
||||
public Block Parent { get; set; }
|
||||
public List<Block> Blocks { get; set; }
|
||||
|
||||
private bool hasIndentChanged;
|
||||
private bool isSubBlock;
|
||||
|
||||
public Func<bool> CheckGenerate;
|
||||
|
||||
public Block() : this(BlockKind.Unknown)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public Block(int kind)
|
||||
{
|
||||
Kind = kind;
|
||||
Blocks = new List<Block>();
|
||||
Text = new TextGenerator();
|
||||
hasIndentChanged = false;
|
||||
isSubBlock = false;
|
||||
}
|
||||
|
||||
public void AddBlock(Block block)
|
||||
{
|
||||
if (Text.StringBuilder.Length != 0 || hasIndentChanged)
|
||||
{
|
||||
hasIndentChanged = false;
|
||||
var newBlock = new Block { Text = Text.Clone(), isSubBlock = true };
|
||||
Text.StringBuilder.Clear();
|
||||
|
||||
AddBlock(newBlock);
|
||||
}
|
||||
|
||||
block.Parent = this;
|
||||
Blocks.Add(block);
|
||||
}
|
||||
|
||||
public IEnumerable<Block> FindBlocks(int kind)
|
||||
{
|
||||
foreach (var block in Blocks)
|
||||
{
|
||||
if (block.Kind == kind)
|
||||
yield return block;
|
||||
|
||||
foreach (var childBlock in block.FindBlocks(kind))
|
||||
yield return childBlock;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual string Generate()
|
||||
{
|
||||
if (CheckGenerate != null && !CheckGenerate())
|
||||
return "";
|
||||
|
||||
if (Blocks.Count == 0)
|
||||
return Text.ToString();
|
||||
|
||||
var builder = new StringBuilder();
|
||||
uint totalIndent = 0;
|
||||
Block previousBlock = null;
|
||||
|
||||
var blockIndex = 0;
|
||||
foreach (var childBlock in Blocks)
|
||||
{
|
||||
var childText = childBlock.Generate();
|
||||
|
||||
var nextBlock = (++blockIndex < Blocks.Count)
|
||||
? Blocks[blockIndex]
|
||||
: null;
|
||||
|
||||
var skipBlock = false;
|
||||
if (nextBlock != null)
|
||||
{
|
||||
var nextText = nextBlock.Generate();
|
||||
if (string.IsNullOrEmpty(nextText) &&
|
||||
childBlock.NewLineKind == NewLineKind.IfNotEmpty)
|
||||
skipBlock = true;
|
||||
}
|
||||
|
||||
if (skipBlock)
|
||||
continue;
|
||||
|
||||
if (string.IsNullOrEmpty(childText))
|
||||
continue;
|
||||
|
||||
var lines = childText.SplitAndKeep(Environment.NewLine).ToList();
|
||||
|
||||
if (previousBlock != null &&
|
||||
previousBlock.NewLineKind == NewLineKind.BeforeNextBlock)
|
||||
builder.AppendLine();
|
||||
|
||||
if (childBlock.isSubBlock)
|
||||
totalIndent = 0;
|
||||
|
||||
foreach (var line in lines)
|
||||
{
|
||||
if (string.IsNullOrEmpty(line))
|
||||
continue;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(line))
|
||||
builder.Append(new string(' ', (int)totalIndent));
|
||||
|
||||
builder.Append(line);
|
||||
|
||||
if (!line.EndsWith(Environment.NewLine, StringComparison.Ordinal))
|
||||
builder.AppendLine();
|
||||
}
|
||||
|
||||
if (childBlock.NewLineKind == NewLineKind.Always)
|
||||
builder.AppendLine();
|
||||
|
||||
totalIndent += childBlock.Text.Indent;
|
||||
|
||||
previousBlock = childBlock;
|
||||
}
|
||||
|
||||
if (Text.StringBuilder.Length != 0)
|
||||
builder.Append(Text.StringBuilder);
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
public StringBuilder GenerateUnformatted(Options options)
|
||||
{
|
||||
if (CheckGenerate != null && !CheckGenerate())
|
||||
return new StringBuilder(0);
|
||||
|
||||
if (Blocks.Count == 0)
|
||||
return Text.StringBuilder;
|
||||
|
||||
var builder = new StringBuilder();
|
||||
Block previousBlock = null;
|
||||
|
||||
var blockIndex = 0;
|
||||
foreach (var childBlock in Blocks)
|
||||
{
|
||||
var childText = childBlock.GenerateUnformatted(options);
|
||||
|
||||
var nextBlock = (++blockIndex < Blocks.Count)
|
||||
? Blocks[blockIndex]
|
||||
: null;
|
||||
|
||||
if (nextBlock != null)
|
||||
{
|
||||
var nextText = nextBlock.GenerateUnformatted(options);
|
||||
if (nextText.Length == 0 &&
|
||||
childBlock.NewLineKind == NewLineKind.IfNotEmpty)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (childText.Length == 0)
|
||||
continue;
|
||||
|
||||
if (previousBlock != null &&
|
||||
previousBlock.NewLineKind == NewLineKind.BeforeNextBlock)
|
||||
builder.AppendLine();
|
||||
|
||||
builder.Append(childText);
|
||||
|
||||
if (childBlock.NewLineKind == NewLineKind.Always)
|
||||
builder.AppendLine();
|
||||
|
||||
previousBlock = childBlock;
|
||||
}
|
||||
|
||||
if (Text.StringBuilder.Length != 0)
|
||||
builder.Append(Text.StringBuilder);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
public bool IsEmpty
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Blocks.Any(block => !block.IsEmpty))
|
||||
return false;
|
||||
|
||||
return string.IsNullOrEmpty(Text.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
#region ITextGenerator implementation
|
||||
|
||||
public uint Indent { get { return Text.Indent; } }
|
||||
|
||||
public void Write(string msg, params object[] args)
|
||||
{
|
||||
Text.Write(msg, args);
|
||||
}
|
||||
|
||||
public void WriteLine(string msg, params object[] args)
|
||||
{
|
||||
Text.WriteLine(msg, args);
|
||||
}
|
||||
|
||||
public void WriteLineIndent(string msg, params object[] args)
|
||||
{
|
||||
Text.WriteLineIndent(msg, args);
|
||||
}
|
||||
|
||||
public void NewLine()
|
||||
{
|
||||
Text.NewLine();
|
||||
}
|
||||
|
||||
public void NewLineIfNeeded()
|
||||
{
|
||||
Text.NewLineIfNeeded();
|
||||
}
|
||||
|
||||
public void NeedNewLine()
|
||||
{
|
||||
Text.NeedNewLine();
|
||||
}
|
||||
|
||||
public void ResetNewLine()
|
||||
{
|
||||
Text.ResetNewLine();
|
||||
}
|
||||
|
||||
public void PushIndent(uint indent = 4u)
|
||||
{
|
||||
hasIndentChanged = true;
|
||||
Text.PushIndent(indent);
|
||||
}
|
||||
|
||||
public void PopIndent()
|
||||
{
|
||||
hasIndentChanged = true;
|
||||
Text.PopIndent();
|
||||
}
|
||||
|
||||
public void WriteStartBraceIndent()
|
||||
{
|
||||
Text.WriteStartBraceIndent();
|
||||
}
|
||||
|
||||
public void WriteCloseBraceIndent()
|
||||
{
|
||||
Text.WriteCloseBraceIndent();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public abstract class BlockGenerator : ITextGenerator
|
||||
{
|
||||
public Block RootBlock { get; private set; }
|
||||
public Block ActiveBlock { get; private set; }
|
||||
|
||||
protected BlockGenerator()
|
||||
{
|
||||
RootBlock = new Block();
|
||||
ActiveBlock = RootBlock;
|
||||
}
|
||||
|
||||
public string Generate()
|
||||
{
|
||||
return RootBlock.Generate();
|
||||
}
|
||||
|
||||
#region Block helpers
|
||||
|
||||
public void AddBlock(Block block)
|
||||
{
|
||||
ActiveBlock.AddBlock(block);
|
||||
}
|
||||
|
||||
public void PushBlock(int kind = 0, object obj = null)
|
||||
{
|
||||
var block = new Block { Kind = kind, Object = obj };
|
||||
PushBlock(block);
|
||||
}
|
||||
|
||||
public void PushBlock(Block block)
|
||||
{
|
||||
block.Parent = ActiveBlock;
|
||||
ActiveBlock.AddBlock(block);
|
||||
ActiveBlock = block;
|
||||
}
|
||||
|
||||
public Block PopBlock(NewLineKind newLineKind = NewLineKind.Never)
|
||||
{
|
||||
var block = ActiveBlock;
|
||||
|
||||
ActiveBlock.NewLineKind = newLineKind;
|
||||
ActiveBlock = ActiveBlock.Parent;
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
public IEnumerable<Block> FindBlocks(int kind)
|
||||
{
|
||||
return RootBlock.FindBlocks(kind);
|
||||
}
|
||||
|
||||
public Block FindBlock(int kind)
|
||||
{
|
||||
return FindBlocks(kind).SingleOrDefault();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ITextGenerator implementation
|
||||
|
||||
public uint Indent { get { return ActiveBlock.Indent; } }
|
||||
|
||||
public void Write(string msg, params object[] args)
|
||||
{
|
||||
ActiveBlock.Write(msg, args);
|
||||
}
|
||||
|
||||
public void WriteLine(string msg, params object[] args)
|
||||
{
|
||||
ActiveBlock.WriteLine(msg, args);
|
||||
}
|
||||
|
||||
public void WriteLineIndent(string msg, params object[] args)
|
||||
{
|
||||
ActiveBlock.WriteLineIndent(msg, args);
|
||||
}
|
||||
|
||||
public void NewLine()
|
||||
{
|
||||
ActiveBlock.NewLine();
|
||||
}
|
||||
|
||||
public void NewLineIfNeeded()
|
||||
{
|
||||
ActiveBlock.NewLineIfNeeded();
|
||||
}
|
||||
|
||||
public void NeedNewLine()
|
||||
{
|
||||
ActiveBlock.NeedNewLine();
|
||||
}
|
||||
|
||||
public void ResetNewLine()
|
||||
{
|
||||
ActiveBlock.ResetNewLine();
|
||||
}
|
||||
|
||||
public void PushIndent(uint indent = 4u)
|
||||
{
|
||||
ActiveBlock.PushIndent(indent);
|
||||
}
|
||||
|
||||
public void PopIndent()
|
||||
{
|
||||
ActiveBlock.PopIndent();
|
||||
}
|
||||
|
||||
public void WriteStartBraceIndent()
|
||||
{
|
||||
ActiveBlock.WriteStartBraceIndent();
|
||||
}
|
||||
|
||||
public void WriteCloseBraceIndent()
|
||||
{
|
||||
ActiveBlock.WriteCloseBraceIndent();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,147 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace MonoManagedToNative
|
||||
{
|
||||
public interface ITextGenerator
|
||||
{
|
||||
uint Indent { get; }
|
||||
void Write(string msg, params object[] args);
|
||||
void WriteLine(string msg, params object[] args);
|
||||
void WriteLineIndent(string msg, params object[] args);
|
||||
void NewLine();
|
||||
void NewLineIfNeeded();
|
||||
void NeedNewLine();
|
||||
void ResetNewLine();
|
||||
void PushIndent(uint indent = TextGenerator.DefaultIndent);
|
||||
void PopIndent();
|
||||
void WriteStartBraceIndent();
|
||||
void WriteCloseBraceIndent();
|
||||
}
|
||||
|
||||
public class TextGenerator : ITextGenerator
|
||||
{
|
||||
public const uint DefaultIndent = 4;
|
||||
|
||||
public StringBuilder StringBuilder;
|
||||
protected bool IsStartOfLine;
|
||||
protected bool NeedsNewLine;
|
||||
protected readonly Stack<uint> CurrentIndent;
|
||||
|
||||
public uint Indent
|
||||
{
|
||||
get { return (uint)CurrentIndent.Sum(u => (int)u); }
|
||||
}
|
||||
|
||||
public TextGenerator()
|
||||
{
|
||||
StringBuilder = new StringBuilder();
|
||||
IsStartOfLine = false;
|
||||
CurrentIndent = new Stack<uint>();
|
||||
}
|
||||
|
||||
public TextGenerator(TextGenerator generator)
|
||||
{
|
||||
StringBuilder = new StringBuilder(generator);
|
||||
IsStartOfLine = generator.IsStartOfLine;
|
||||
NeedsNewLine = generator.NeedsNewLine;
|
||||
CurrentIndent = new Stack<uint>(generator.CurrentIndent);
|
||||
}
|
||||
|
||||
public TextGenerator Clone()
|
||||
{
|
||||
return new TextGenerator(this);
|
||||
}
|
||||
|
||||
public void Write(string msg, params object[] args)
|
||||
{
|
||||
if (string.IsNullOrEmpty(msg))
|
||||
return;
|
||||
|
||||
if (args.Length > 0)
|
||||
msg = string.Format(msg, args);
|
||||
|
||||
foreach (var line in msg.SplitAndKeep(Environment.NewLine))
|
||||
{
|
||||
if (IsStartOfLine && !string.IsNullOrWhiteSpace(line))
|
||||
StringBuilder.Append(new string(' ', (int)CurrentIndent.Sum(u => u)));
|
||||
|
||||
if (line.Length > 0)
|
||||
IsStartOfLine = line.EndsWith(Environment.NewLine);
|
||||
|
||||
StringBuilder.Append(line);
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteLine(string msg, params object[] args)
|
||||
{
|
||||
Write(msg, args);
|
||||
NewLine();
|
||||
}
|
||||
|
||||
public void WriteLineIndent(string msg, params object[] args)
|
||||
{
|
||||
PushIndent();
|
||||
WriteLine(msg, args);
|
||||
PopIndent();
|
||||
}
|
||||
|
||||
public void NewLine()
|
||||
{
|
||||
StringBuilder.AppendLine(string.Empty);
|
||||
IsStartOfLine = true;
|
||||
}
|
||||
|
||||
public void NewLineIfNeeded()
|
||||
{
|
||||
if (!NeedsNewLine) return;
|
||||
|
||||
NewLine();
|
||||
NeedsNewLine = false;
|
||||
}
|
||||
|
||||
public void NeedNewLine()
|
||||
{
|
||||
NeedsNewLine = true;
|
||||
}
|
||||
|
||||
public void ResetNewLine()
|
||||
{
|
||||
NeedsNewLine = false;
|
||||
}
|
||||
|
||||
public void PushIndent(uint indent = DefaultIndent)
|
||||
{
|
||||
CurrentIndent.Push(indent);
|
||||
}
|
||||
|
||||
public void PopIndent()
|
||||
{
|
||||
CurrentIndent.Pop();
|
||||
}
|
||||
|
||||
public void WriteStartBraceIndent()
|
||||
{
|
||||
WriteLine("{");
|
||||
PushIndent();
|
||||
}
|
||||
|
||||
public void WriteCloseBraceIndent()
|
||||
{
|
||||
PopIndent();
|
||||
WriteLine("}");
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return StringBuilder.ToString();
|
||||
}
|
||||
|
||||
public static implicit operator string(TextGenerator tg)
|
||||
{
|
||||
return tg.ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace MonoManagedToNative
|
||||
{
|
||||
public static class StringExtensions
|
||||
{
|
||||
public static string Repeat(this char chatToRepeat, int repeat)
|
||||
{
|
||||
return new string(chatToRepeat, repeat);
|
||||
}
|
||||
|
||||
public static string Repeat(this string stringToRepeat, int repeat)
|
||||
{
|
||||
var builder = new StringBuilder(repeat * stringToRepeat.Length);
|
||||
for (var i = 0; i < repeat; i++)
|
||||
{
|
||||
builder.Append(stringToRepeat);
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
public static IEnumerable<string> SplitAndKeep(this string s, string separator)
|
||||
{
|
||||
string[] obj = s.Split(new string[] { separator }, StringSplitOptions.None);
|
||||
|
||||
for (int i = 0; i < obj.Length; i++)
|
||||
{
|
||||
string result = i == obj.Length - 1 ? obj[i] : obj[i] + separator;
|
||||
yield return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Helpers
|
||||
{
|
||||
public static void CopyDirectory(string sourceDir, string targetDir)
|
||||
{
|
||||
var source = new DirectoryInfo(sourceDir);
|
||||
var target = new DirectoryInfo(targetDir);
|
||||
|
||||
CopyAll(source, target);
|
||||
}
|
||||
|
||||
public static void CopyAll(DirectoryInfo source, DirectoryInfo target)
|
||||
{
|
||||
// Check if the target directory exists, if not, create it.
|
||||
if (!Directory.Exists(target.FullName))
|
||||
Directory.CreateDirectory(target.FullName);
|
||||
|
||||
// Copy each file into it's new directory.
|
||||
foreach (var file in source.GetFiles())
|
||||
file.CopyTo(Path.Combine(target.ToString(), file.Name), true);
|
||||
|
||||
// Copy each subdirectory using recursion.
|
||||
foreach (var sourceSubDir in source.GetDirectories())
|
||||
{
|
||||
var nextTargetSubDir =
|
||||
target.CreateSubdirectory(sourceSubDir.Name);
|
||||
CopyAll(sourceSubDir, nextTargetSubDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
@echo off
|
||||
goto menu
|
||||
|
||||
:menu
|
||||
echo Build Project Generator:
|
||||
echo.
|
||||
echo [0] Clean
|
||||
echo [1] Visual C++ 2015
|
||||
echo [2] GNU Make
|
||||
echo.
|
||||
|
||||
:choice
|
||||
set /P C="Choice: "
|
||||
if "%C%"=="2" goto gmake
|
||||
if "%C%"=="1" goto vs2015
|
||||
if "%C%"=="0" goto clean
|
||||
|
||||
:clean
|
||||
"premake5" --file=premake5.lua clean
|
||||
goto quit
|
||||
|
||||
:vs2015
|
||||
"premake5" --file=premake5.lua vs2015
|
||||
goto quit
|
||||
|
||||
:gmake
|
||||
"premake5" --file=premake5.lua gmake
|
||||
goto quit
|
||||
|
||||
:quit
|
||||
pause
|
||||
:end
|
|
@ -0,0 +1,91 @@
|
|||
-- This module checks for the all the project dependencies.
|
||||
|
||||
action = _ACTION or ""
|
||||
|
||||
depsdir = path.getabsolute("../deps");
|
||||
srcdir = path.getabsolute("../src");
|
||||
incdir = path.getabsolute("../include");
|
||||
bindir = path.getabsolute("../bin");
|
||||
examplesdir = path.getabsolute("../examples");
|
||||
testsdir = path.getabsolute("../tests");
|
||||
|
||||
builddir = path.getabsolute("./" .. action);
|
||||
libdir = path.join(builddir, "lib", "%{cfg.buildcfg}_%{cfg.platform}");
|
||||
gendir = path.join(builddir, "gen");
|
||||
|
||||
function string.starts(str, start)
|
||||
return string.sub(str, 1, string.len(start)) == start
|
||||
end
|
||||
|
||||
function SafePath(path)
|
||||
return "\"" .. path .. "\""
|
||||
end
|
||||
|
||||
msvc_buildflags = { }
|
||||
gcc_buildflags = { "-std=c++11 -fpermissive" }
|
||||
|
||||
msvc_cpp_defines = { }
|
||||
|
||||
function SetupNativeProject()
|
||||
location (path.join(builddir, "projects"))
|
||||
|
||||
local c = configuration "Debug"
|
||||
defines { "DEBUG" }
|
||||
|
||||
configuration "Release"
|
||||
defines { "NDEBUG" }
|
||||
optimize "On"
|
||||
|
||||
-- Compiler-specific options
|
||||
|
||||
configuration "vs*"
|
||||
buildoptions { msvc_buildflags }
|
||||
defines { msvc_cpp_defines }
|
||||
|
||||
configuration { "gmake" }
|
||||
buildoptions { gcc_buildflags }
|
||||
|
||||
configuration { "macosx" }
|
||||
buildoptions { gcc_buildflags, "-stdlib=libc++" }
|
||||
links { "c++" }
|
||||
|
||||
-- OS-specific options
|
||||
|
||||
configuration "Windows"
|
||||
defines { "WIN32", "_WINDOWS" }
|
||||
|
||||
configuration(c)
|
||||
end
|
||||
|
||||
function SetupManagedProject()
|
||||
dotnetframework "4.6"
|
||||
|
||||
location (path.join(builddir, "projects"))
|
||||
|
||||
local c = configuration "vs*"
|
||||
location "."
|
||||
|
||||
configuration(c)
|
||||
end
|
||||
|
||||
function IncludeDir(dir)
|
||||
local deps = os.matchdirs(dir .. "/*")
|
||||
|
||||
for i,dep in ipairs(deps) do
|
||||
local fp = path.join(dep, "premake5.lua")
|
||||
fp = path.join(os.getcwd(), fp)
|
||||
|
||||
if os.isfile(fp) then
|
||||
include(dep)
|
||||
return
|
||||
end
|
||||
|
||||
fp = path.join(dep, "premake4.lua")
|
||||
fp = path.join(os.getcwd(), fp)
|
||||
|
||||
if os.isfile(fp) then
|
||||
--print(string.format(" including %s", dep))
|
||||
include(dep)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,121 @@
|
|||
-- Tests/examples helpers
|
||||
|
||||
function SetupTestProject(name, extraFiles)
|
||||
SetupTestGeneratorProject(name)
|
||||
SetupTestNativeProject(name)
|
||||
SetupTestProjectsCSharp(name, nil, extraFiles)
|
||||
end
|
||||
|
||||
function SetupManagedTestProject()
|
||||
kind "SharedLib"
|
||||
language "C#"
|
||||
flags { "Unsafe" }
|
||||
SetupManagedProject()
|
||||
end
|
||||
|
||||
function SetupTestGeneratorProject(name, depends)
|
||||
project(name .. ".Gen")
|
||||
SetupManagedTestProject()
|
||||
kind "ConsoleApp"
|
||||
|
||||
files { name .. ".Gen.cs" }
|
||||
|
||||
dependson { name .. ".Managed" }
|
||||
|
||||
linktable = {
|
||||
"System.Core",
|
||||
"native-binder",
|
||||
}
|
||||
|
||||
if depends ~= nil then
|
||||
table.insert(linktable, depends .. ".Gen")
|
||||
end
|
||||
|
||||
links(linktable)
|
||||
end
|
||||
|
||||
function SetupTestGeneratorBuildEvent(name)
|
||||
local runtimeExe = os.is("windows") and "" or "mono --debug "
|
||||
if string.starts(action, "vs") then
|
||||
local exePath = SafePath("$(TargetDir)" .. name .. ".Gen.exe")
|
||||
prebuildcommands { runtimeExe .. exePath }
|
||||
else
|
||||
local exePath = SafePath("%{cfg.buildtarget.directory}/" .. name .. ".Gen.exe")
|
||||
prebuildcommands { runtimeExe .. exePath }
|
||||
end
|
||||
end
|
||||
|
||||
local function SetupMono()
|
||||
local monoDir = ''
|
||||
-- Find system-specific Mono include/library paths.
|
||||
-- For Windows, first search the default Mono install location.
|
||||
local monoDefaultDir = "C:\\Program Files (x86)\\Mono"
|
||||
if os.isdir(monoDefaultDir) then
|
||||
monoDir = monoDefaultDir
|
||||
end
|
||||
if not os.isdir(monoDir) then
|
||||
error("Could not find Mono install location, please specify it manually")
|
||||
end
|
||||
|
||||
includedirs { path.join(monoDir, "include", "mono-2.0") }
|
||||
libdirs { path.join(monoDir, "lib") }
|
||||
links { "monosgen-2.0" }
|
||||
end
|
||||
|
||||
function SetupTestNativeProject(name, depends)
|
||||
if string.starts(action, "vs") and not os.is("windows") then
|
||||
return
|
||||
end
|
||||
|
||||
project(name .. ".C")
|
||||
SetupNativeProject()
|
||||
|
||||
kind "SharedLib"
|
||||
language "C"
|
||||
|
||||
flags { common_flags }
|
||||
files
|
||||
{
|
||||
path.join(gendir, name, name .. ".h"),
|
||||
path.join(gendir, name, name .. ".c")
|
||||
}
|
||||
|
||||
dependson { name .. ".Gen" }
|
||||
|
||||
if depends ~= nil then
|
||||
links { depends .. ".C" }
|
||||
end
|
||||
|
||||
SetupTestGeneratorBuildEvent(name)
|
||||
SetupMono()
|
||||
end
|
||||
|
||||
function SetupTestProjectsCSharp(name, depends, extraFiles)
|
||||
project(name .. ".Managed")
|
||||
SetupManagedTestProject()
|
||||
|
||||
files
|
||||
{
|
||||
files { name .. ".cs" }
|
||||
}
|
||||
if extraFiles ~= nil then
|
||||
for _, file in pairs(extraFiles) do
|
||||
files { file .. ".cs" }
|
||||
end
|
||||
end
|
||||
|
||||
linktable = { }
|
||||
|
||||
if depends ~= nil then
|
||||
table.insert(linktable, depends .. ".Managed")
|
||||
end
|
||||
|
||||
links(linktable)
|
||||
|
||||
project(name .. ".Tests.Managed")
|
||||
SetupManagedTestProject()
|
||||
|
||||
files { name .. ".Tests.cs" }
|
||||
links { name .. ".Managed" }
|
||||
dependson { name .. ".C" }
|
||||
end
|
|
@ -0,0 +1,59 @@
|
|||
-- This is the starting point of the build scripts for the project.
|
||||
-- It defines the common build settings that all the projects share
|
||||
-- and calls the build scripts of all the sub-projects.
|
||||
|
||||
dofile "Helpers.lua"
|
||||
dofile "Tests.lua"
|
||||
|
||||
solution "native-binder"
|
||||
|
||||
configurations { "Debug", "Release" }
|
||||
flags { "Unicode", "Symbols" }
|
||||
|
||||
location (builddir)
|
||||
objdir (path.join(builddir, "obj"))
|
||||
targetdir (libdir)
|
||||
libdirs { libdir }
|
||||
debugdir (bindir)
|
||||
|
||||
startproject "native-binder"
|
||||
|
||||
configuration "Release"
|
||||
flags { "Optimize" }
|
||||
|
||||
configuration {}
|
||||
|
||||
project "native-binder"
|
||||
SetupManagedProject()
|
||||
|
||||
kind "ConsoleApp"
|
||||
language "C#"
|
||||
|
||||
location "../binder"
|
||||
files { "../binder/**.cs" }
|
||||
|
||||
libdirs { "../deps" }
|
||||
|
||||
links
|
||||
{
|
||||
"System",
|
||||
"System.Core",
|
||||
"IKVM.Reflection",
|
||||
"CppSharp.AST"
|
||||
}
|
||||
|
||||
external "IKVM.Reflection"
|
||||
location ("../ikvm/reflect")
|
||||
uuid "4CB170EF-DFE6-4A56-9E1B-A85449E827A7"
|
||||
language "C#"
|
||||
kind "SharedLib"
|
||||
|
||||
group "Examples"
|
||||
|
||||
print("Searching for example projects...")
|
||||
IncludeDir(examplesdir)
|
||||
|
||||
group "Tests"
|
||||
|
||||
print("Searching for tests projects...")
|
||||
IncludeDir(testsdir)
|
|
@ -0,0 +1,17 @@
|
|||
using MonoManagedToNative.Generators;
|
||||
|
||||
namespace MonoManagedToNative.Tests
|
||||
{
|
||||
public class BasicTestsGenerator : TestsGenerator
|
||||
{
|
||||
public BasicTestsGenerator(GeneratorKind kind)
|
||||
: base("Basic", kind)
|
||||
{
|
||||
}
|
||||
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
new BasicTestsGenerator(GeneratorKind.C).Generate();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
//using System;
|
||||
//using EmptyTest;
|
||||
//using CppSharp.Utils;
|
||||
//using NUnit.Framework;
|
||||
|
||||
//[TestFixture]
|
||||
//public class EmptyTests : GeneratorTestFixture
|
||||
//{
|
||||
//}
|
||||
//
|
|
@ -0,0 +1,21 @@
|
|||
using System;
|
||||
|
||||
public class BuiltinTypes
|
||||
{
|
||||
public void ReturnsVoid() { }
|
||||
public bool ReturnsBool() { return true; }
|
||||
public sbyte ReturnsSByte() { return -5; }
|
||||
public byte ReturnsByte() { return 5; }
|
||||
public short ReturnsShort() { return -5; }
|
||||
public ushort ReturnsUShort() { return 5; }
|
||||
public int ReturnsInt() { return -5; }
|
||||
public uint ReturnsUInt() { return 5; }
|
||||
public long ReturnsLong() { return -5; }
|
||||
public ulong ReturnsULong() { return 5; }
|
||||
public string ReturnsString() { return "Mono"; }
|
||||
}
|
||||
|
||||
public static class StaticClass
|
||||
{
|
||||
public static void ReturnsVoid() { }
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
group "Tests/Basic"
|
||||
SetupTestProject("Basic")
|
Загрузка…
Ссылка в новой задаче