[objc] Simpler generator that, so far, only handle static properties (#29)

The ObjC syntax for properties match the proposal from PR #25 [1].

Unit tests added for the matching features.

[1] https://github.com/mono/Embeddinator-4000/pull/25
This commit is contained in:
Sebastien Pouliot 2017-03-31 10:21:23 -05:00 коммит произвёл GitHub
Родитель ca77db338c
Коммит 5cc5ea587d
21 изменённых файлов: 1949 добавлений и 0 удалений

1
.gitignore поставляемый
Просмотреть файл

@ -11,6 +11,7 @@ missing
*.dll
*.exe
bin/
obj/
*.userprefs
*.pc
.DS_Store

35
generator.sln Normal file
Просмотреть файл

@ -0,0 +1,35 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "objcgen", "objcgen\objcgen.csproj", "{C166803B-011F-4EAF-B8C2-D7DBBA3CF1EC}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{21776062-DBDA-4408-BF22-9DCB2682DCBC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "objcgentest", "tests\objcgentest\objcgentest.csproj", "{076A871B-0C13-47D8-8923-B9242995BFF8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "managed", "tests\managed\managed.csproj", "{D56A7E3F-FF5C-4EC2-879F-1260ABBD1903}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C166803B-011F-4EAF-B8C2-D7DBBA3CF1EC}.Debug|x86.ActiveCfg = Debug|x86
{C166803B-011F-4EAF-B8C2-D7DBBA3CF1EC}.Debug|x86.Build.0 = Debug|x86
{C166803B-011F-4EAF-B8C2-D7DBBA3CF1EC}.Release|x86.ActiveCfg = Release|x86
{C166803B-011F-4EAF-B8C2-D7DBBA3CF1EC}.Release|x86.Build.0 = Release|x86
{076A871B-0C13-47D8-8923-B9242995BFF8}.Debug|x86.ActiveCfg = Debug|Any CPU
{076A871B-0C13-47D8-8923-B9242995BFF8}.Debug|x86.Build.0 = Debug|Any CPU
{076A871B-0C13-47D8-8923-B9242995BFF8}.Release|x86.ActiveCfg = Release|Any CPU
{076A871B-0C13-47D8-8923-B9242995BFF8}.Release|x86.Build.0 = Release|Any CPU
{D56A7E3F-FF5C-4EC2-879F-1260ABBD1903}.Debug|x86.ActiveCfg = Debug|Any CPU
{D56A7E3F-FF5C-4EC2-879F-1260ABBD1903}.Debug|x86.Build.0 = Debug|Any CPU
{D56A7E3F-FF5C-4EC2-879F-1260ABBD1903}.Release|x86.ActiveCfg = Release|Any CPU
{D56A7E3F-FF5C-4EC2-879F-1260ABBD1903}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{076A871B-0C13-47D8-8923-B9242995BFF8} = {21776062-DBDA-4408-BF22-9DCB2682DCBC}
{D56A7E3F-FF5C-4EC2-879F-1260ABBD1903} = {21776062-DBDA-4408-BF22-9DCB2682DCBC}
EndGlobalSection
EndGlobal

72
objcgen/driver.cs Normal file
Просмотреть файл

@ -0,0 +1,72 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Text;
using ObjC;
namespace Embeddinator {
static class Driver {
// TODO: use Mono.Options
// TODO: add errors.cs
public static int Main (string [] args)
{
bool shared = true; // dylib
Console.WriteLine ("Parsing assemblies...");
var assemblies = new List<Assembly> ();
foreach (var arg in args) {
assemblies.Add (Assembly.LoadFile (arg));
Console.WriteLine ($"\tParsed '{arg}'");
}
// by default the first specified assembly
var name = Path.GetFileNameWithoutExtension (args [0]);
Console.WriteLine ("Processing assemblies...");
var g = new ObjCGenerator ();
g.Process (assemblies);
Console.WriteLine ("Generating binding code...");
g.Generate (assemblies);
g.Write ();
var exe = typeof (Driver).Assembly;
foreach (var res in exe.GetManifestResourceNames ()) {
if (res == "main.c") {
// no main is needed for dylib and don't re-write an existing main.c file - it's a template
if (shared || File.Exists ("main.c"))
continue;
}
Console.WriteLine ($"\tGenerated: {res}");
using (var sw = new StreamWriter (res))
exe.GetManifestResourceStream (res).CopyTo (sw.BaseStream);
}
Console.WriteLine ("Compiling binding code...");
StringBuilder options = new StringBuilder ("clang ");
options.Append ("-DMONO_EMBEDDINATOR_DLL_EXPORT ");
options.Append ("-framework CoreFoundation ");
options.Append ("-I\"/Library/Frameworks/Mono.framework/Versions/Current/include/mono-2.0\" -L\"/Library/Frameworks/Mono.framework/Versions/Current/lib/\" -lmonosgen-2.0 ");
options.Append ("glib.c mono_embeddinator.c bindings.m ");
if (shared)
options.Append ($"-dynamiclib -install_name lib{name}.dylib ");
else
options.Append ("main.c ");
options.Append ($"-o lib{name}.dylib -ObjC -lobjc");
Console.WriteLine ("Compiling binding code...");
Console.WriteLine ($"\tInvoking: xcrun {options}");
var p = Process.Start ("xcrun", options.ToString ());
p.WaitForExit ();
Console.WriteLine ("Done");
return 0;
}
}
}

41
objcgen/generator.cs Normal file
Просмотреть файл

@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.Reflection;
namespace Embeddinator {
public class Generator {
public virtual void Process (IEnumerable<Assembly> assemblies)
{
}
public virtual void Generate (IEnumerable<Assembly> assemblies)
{
foreach (var a in assemblies) {
Generate (a);
}
}
protected virtual void Generate (Assembly a)
{
foreach (var t in a.GetTypes ()) {
if (!t.IsPublic)
continue;
Generate (t);
}
}
protected virtual void Generate (Type t)
{
}
protected virtual void Generate (PropertyInfo pi)
{
}
public virtual void Write ()
{
}
}
}

73
objcgen/objcgen.csproj Normal file
Просмотреть файл

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProjectGuid>{C166803B-011F-4EAF-B8C2-D7DBBA3CF1EC}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>objcgen</RootNamespace>
<AssemblyName>objcgen</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ExternalConsole>true</ExternalConsole>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ExternalConsole>true</ExternalConsole>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="Mono.Options">
<HintPath>..\packages\Mono.Options.4.4.0.0\lib\net4-client\Mono.Options.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="generator.cs" />
<Compile Include="objcgenerator.cs" />
<Compile Include="driver.cs">
<LogicalName>main.c</LogicalName>
</Compile>
</ItemGroup>
<ItemGroup>
<Folder Include="support\" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="..\support\glib.c">
<Link>support\glib.c</Link>
<LogicalName>glib.c</LogicalName>
</EmbeddedResource>
<EmbeddedResource Include="..\support\glib.h">
<Link>support\glib.h</Link>
<LogicalName>glib.h</LogicalName>
</EmbeddedResource>
<EmbeddedResource Include="..\support\mono_embeddinator.c">
<Link>support\mono_embeddinator.c</Link>
<LogicalName>mono_embeddinator.c</LogicalName>
</EmbeddedResource>
<EmbeddedResource Include="..\support\mono_embeddinator.h">
<Link>support\mono_embeddinator.h</Link>
<LogicalName>mono_embeddinator.h</LogicalName>
</EmbeddedResource>
<EmbeddedResource Include="..\support\main.c">
<Link>support\main.c</Link>
<LogicalName>main.c</LogicalName>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>

247
objcgen/objcgenerator.cs Normal file
Просмотреть файл

@ -0,0 +1,247 @@
using System;
using System.Collections.Generic;
using System.IO;
// TODO: bad, need to choose either IKVM.Reflection or Cecil
using System.Reflection;
using Embeddinator;
namespace ObjC {
public class ObjCGenerator : Generator {
static TextWriter headers = new StringWriter ();
static TextWriter implementation = new StringWriter ();
List<Type> types = new List<Type> ();
public override void Process (IEnumerable<Assembly> assemblies)
{
foreach (var a in assemblies) {
foreach (var t in a.GetTypes ()) {
if (!t.IsPublic)
continue;
// gather types for forward declarations
types.Add (t);
}
}
Console.WriteLine ($"\t{types.Count} types found");
}
public override void Generate (IEnumerable<Assembly> assemblies)
{
headers.WriteLine ("#include \"mono_embeddinator.h\"");
headers.WriteLine ("#import <Foundation/Foundation.h>");
headers.WriteLine ();
headers.WriteLine ("MONO_EMBEDDINATOR_BEGIN_DECLS");
headers.WriteLine ();
headers.WriteLine ("// forward declarations");
foreach (var t in types)
headers.WriteLine ($"@class {GetTypeName (t)};");
headers.WriteLine ();
implementation.WriteLine ("#include \"bindings.h\"");
implementation.WriteLine ("#include \"glib.h\"");
implementation.WriteLine ("#include <mono/jit/jit.h>");
implementation.WriteLine ("#include <mono/metadata/assembly.h>");
implementation.WriteLine ("#include <mono/metadata/object.h>");
implementation.WriteLine ("#include <mono/metadata/mono-config.h>");
implementation.WriteLine ("#include <mono/metadata/debug-helpers.h>");
implementation.WriteLine ();
implementation.WriteLine ("mono_embeddinator_context_t __mono_context;");
implementation.WriteLine ();
foreach (var a in assemblies)
implementation.WriteLine ($"MonoImage* __{a.GetName ().Name}_image;");
implementation.WriteLine ();
foreach (var t in types)
implementation.WriteLine ($"static MonoClass* {t.Name}_class = nil;");
implementation.WriteLine ();
implementation.WriteLine ("static void __initialize_mono ()");
implementation.WriteLine ("{");
implementation.WriteLine ("\tif (__mono_context.domain)");
implementation.WriteLine ("\t\treturn;");
implementation.WriteLine ("\tmono_embeddinator_init (&__mono_context, \"mono_embeddinator_binding\");");
implementation.WriteLine ("}");
implementation.WriteLine ();
base.Generate (assemblies);
headers.WriteLine ();
headers.WriteLine ("MONO_EMBEDDINATOR_END_DECLS");
}
protected override void Generate (Assembly a)
{
var name = a.GetName ().Name;
implementation.WriteLine ($"static void __lookup_assembly_{name} ()");
implementation.WriteLine ("{");
implementation.WriteLine ($"\tif (__{name}_image)");
implementation.WriteLine ("\t\treturn;");
implementation.WriteLine ($"\t__{name}_image = mono_embeddinator_load_assembly (&__mono_context, \"{name}.dll\");");
implementation.WriteLine ("}");
implementation.WriteLine ();
foreach (var t in a.GetTypes ()) {
if (!t.IsPublic)
continue;
Generate (t);
}
}
protected override void Generate (Type t)
{
var managed_name = t.Name;
implementation.WriteLine ($"static void __lookup_class_{managed_name} ()");
implementation.WriteLine ("{");
implementation.WriteLine ($"\tif (!{managed_name}_class) {{");
implementation.WriteLine ("\t\t__initialize_mono ();");
implementation.WriteLine ("\t\t__lookup_assembly_managed ();");
implementation.WriteLine ($"\t\t{managed_name}_class = mono_class_from_name (__{t.Assembly.GetName ().Name}_image, \"\", \"{managed_name}\");");
implementation.WriteLine ("\t}");
implementation.WriteLine ("}");
var native_name = GetTypeName (t);
headers.WriteLine ($"// {t.AssemblyQualifiedName}");
headers.WriteLine ($"@interface {native_name} : {GetTypeName (t.BaseType)} {{");
headers.WriteLine ("\tMonoEmbedObject* _object;");
headers.WriteLine ("}");
headers.WriteLine ();
if (t.IsSealed && t.IsAbstract) {
// don't allow instantiation of static types from ObjC code
headers.WriteLine ("// a .net static type cannot be initialized");
headers.WriteLine ("- (instancetype)init NS_UNAVAILABLE;");
headers.WriteLine ();
}
implementation.WriteLine ($"// {t.AssemblyQualifiedName}");
implementation.WriteLine ($"@implementation {managed_name}");
implementation.WriteLine ();
foreach (var pi in t.GetProperties ())
Generate (pi);
headers.WriteLine ();
headers.WriteLine ("@end");
implementation.WriteLine ();
implementation.WriteLine ("@end");
}
protected override void Generate (PropertyInfo pi)
{
var getter = pi.GetGetMethod ();
var setter = pi.GetSetMethod ();
// FIXME: setter only is valid, even if discouraged, in .NET - we should create a SetX method
if (getter == null && setter != null)
throw new NotSupportedException ();
// TODO override with attribute ? e.g. [ObjC.Selector ("foo")]
var name = CamelCase (pi.Name);
headers.Write ("@property (nonatomic");
if (getter.IsStatic)
headers.Write (", class");
if (setter == null)
headers.Write (", readonly");
else
headers.Write (", readwrite");
var property_type = GetTypeName (pi.PropertyType);
headers.WriteLine ($") {property_type} {name};");
var managed_type_name = pi.DeclaringType.Name;
implementation.Write (getter.IsStatic ? '+' : '-');
implementation.WriteLine ($" ({property_type}) {name}");
implementation.WriteLine ("{");
implementation.WriteLine ($"\tconst char __method_name [] = \"{managed_type_name}:{getter.Name}()\";");
implementation.WriteLine ("\tstatic MonoMethod* __method = nil;");
implementation.WriteLine ("\tif (!__method) {");
implementation.WriteLine ($"\t\t__lookup_class_{managed_type_name} ();");
implementation.WriteLine ($"\t\t__method = mono_embeddinator_lookup_method (__method_name, {managed_type_name}_class);");
implementation.WriteLine ("\t}");
implementation.WriteLine ("\tMonoObject* __exception = nil;");
implementation.WriteLine ("\tMonoObject* __result = mono_runtime_invoke (__method, nil, nil, &__exception);");
implementation.WriteLine ("\tif (__exception)");
implementation.WriteLine ("\t\tmono_embeddinator_throw_exception (__exception);");
ReturnValue (pi.PropertyType);
implementation.WriteLine ("}");
if (setter == null)
return;
// TODO override with attribute ? e.g. [ObjC.Selector ("foo")]
implementation.Write (getter.IsStatic ? '+' : '-');
implementation.WriteLine ($" (void) set{pi.Name}:({property_type})value");
implementation.WriteLine ("{");
implementation.WriteLine ($"\tconst char __method_name [] = \"{managed_type_name}:{setter.Name}({property_type})\";");
implementation.WriteLine ("\tstatic MonoMethod* __method = nil;");
implementation.WriteLine ("\tif (!__method) {");
implementation.WriteLine ($"\t\t__lookup_class_{managed_type_name} ();");
implementation.WriteLine ($"\t\t__method = mono_embeddinator_lookup_method (__method_name, {managed_type_name}_class);");
implementation.WriteLine ("\t}");
implementation.WriteLine ("\tvoid* __args [1];");
implementation.WriteLine ("\t__args [0] = &value;");
implementation.WriteLine ("\tMonoObject* __exception = nil;");
implementation.WriteLine ("\tMonoObject* __result = mono_runtime_invoke (__method, nil, __args, &__exception);");
implementation.WriteLine ("\tif (__exception)");
implementation.WriteLine ("\t\tmono_embeddinator_throw_exception (__exception);");
implementation.WriteLine ("}");
}
void ReturnValue (Type t)
{
switch (Type.GetTypeCode (t)) {
// unboxing
case TypeCode.Boolean:
case TypeCode.Int32:
var name = GetTypeName (t);
implementation.WriteLine ("\tvoid* __unbox = mono_object_unbox (__result);");
implementation.WriteLine ($"\treturn *(({name}*)__unbox);");
break;
default:
throw new NotSupportedException ();
}
}
void WriteFile (string name, string content)
{
Console.WriteLine ($"\tGenerated: {name}");
File.WriteAllText (name, content);
}
public override void Write ()
{
WriteFile ("bindings.h", headers.ToString ());
WriteFile ("bindings.m", implementation.ToString ());
}
// TODO complete mapping (only with corresponding tests)
// TODO override with attribute ? e.g. [Obj.Name ("XAMType")]
public static string GetTypeName (Type t)
{
switch (Type.GetTypeCode (t)) {
case TypeCode.Object:
return t == typeof (object) ? "NSObject" : t.Name;
case TypeCode.Boolean:
return "bool";
case TypeCode.Int32:
return "int";
default:
throw new NotSupportedException ();
}
}
public static string CamelCase (string s)
{
if (s == null)
return null;
if (s.Length == 0)
return String.Empty;
return Char.ToLowerInvariant (s [0]) + s.Substring (1, s.Length - 1);
}
}
}

Просмотреть файл

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{D56A7E3F-FF5C-4EC2-879F-1260ABBD1903}</ProjectGuid>
<OutputType>Library</OutputType>
<RootNamespace>managed</RootNamespace>
<AssemblyName>managed</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<Compile Include="properties.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>

Просмотреть файл

@ -0,0 +1,21 @@
using System;
// static type
public static class Platform {
// static get-only property
public static bool IsWindows {
get {
switch (Environment.OSVersion.Platform) {
case PlatformID.Win32NT:
case PlatformID.Win32S:
case PlatformID.Win32Windows:
case PlatformID.WinCE:
return true;
}
return false;
}
}
public static int ExitCode { get; set; }
}

22
tests/objc-cli/bindings.h Normal file
Просмотреть файл

@ -0,0 +1,22 @@
#include "mono_embeddinator.h"
#import <Foundation/Foundation.h>
MONO_EMBEDDINATOR_BEGIN_DECLS
// forward declarations
@class Platform;
// Platform, managed, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
@interface Platform : NSObject {
MonoEmbedObject* _object;
}
// a .net static type cannot be initialized
- (instancetype)init NS_UNAVAILABLE;
@property (nonatomic, class, readonly) bool isWindows;
@property (nonatomic, class, readwrite) int exitCode;
@end
MONO_EMBEDDINATOR_END_DECLS

86
tests/objc-cli/bindings.m Normal file
Просмотреть файл

@ -0,0 +1,86 @@
#include "bindings.h"
#include "glib.h"
#include <mono/jit/jit.h>
#include <mono/metadata/assembly.h>
#include <mono/metadata/object.h>
#include <mono/metadata/mono-config.h>
#include <mono/metadata/debug-helpers.h>
mono_embeddinator_context_t __mono_context;
MonoImage* __managed_image;
static MonoClass* Platform_class = nil;
static void __initialize_mono ()
{
if (__mono_context.domain)
return;
mono_embeddinator_init (&__mono_context, "mono_embeddinator_binding");
}
static void __lookup_assembly_managed ()
{
if (__managed_image)
return;
__managed_image = mono_embeddinator_load_assembly (&__mono_context, "managed.dll");
}
static void __lookup_class_Platform ()
{
if (!Platform_class) {
__initialize_mono ();
__lookup_assembly_managed ();
Platform_class = mono_class_from_name (__managed_image, "", "Platform");
}
}
// Platform, managed, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
@implementation Platform
+ (bool) isWindows
{
const char __method_name [] = "Platform:get_IsWindows()";
static MonoMethod* __method = nil;
if (!__method) {
__lookup_class_Platform ();
__method = mono_embeddinator_lookup_method (__method_name, Platform_class);
}
MonoObject* __exception = nil;
MonoObject* __result = mono_runtime_invoke (__method, nil, nil, &__exception);
if (__exception)
mono_embeddinator_throw_exception (__exception);
void* __unbox = mono_object_unbox (__result);
return *((bool*)__unbox);
}
+ (int) exitCode
{
const char __method_name [] = "Platform:get_ExitCode()";
static MonoMethod* __method = nil;
if (!__method) {
__lookup_class_Platform ();
__method = mono_embeddinator_lookup_method (__method_name, Platform_class);
}
MonoObject* __exception = nil;
MonoObject* __result = mono_runtime_invoke (__method, nil, nil, &__exception);
if (__exception)
mono_embeddinator_throw_exception (__exception);
void* __unbox = mono_object_unbox (__result);
return *((int*)__unbox);
}
+ (void) setExitCode:(int)value
{
const char __method_name [] = "Platform:set_ExitCode(int)";
static MonoMethod* __method = nil;
if (!__method) {
__lookup_class_Platform ();
__method = mono_embeddinator_lookup_method (__method_name, Platform_class);
}
void* __args [1];
__args [0] = &value;
MonoObject* __exception = nil;
MonoObject* __result = mono_runtime_invoke (__method, nil, __args, &__exception);
if (__exception)
mono_embeddinator_throw_exception (__exception);
}
@end

464
tests/objc-cli/glib.c Normal file
Просмотреть файл

@ -0,0 +1,464 @@
/*
* String functions
*
* Author:
* Miguel de Icaza (miguel@novell.com)
* Aaron Bockover (abockover@novell.com)
*
* (C) 2006 Novell, Inc.
*
* 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 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.
*/
#include <stdio.h>
#include "glib.h"
void g_free (void *ptr)
{
free(ptr);
}
gpointer g_realloc (gpointer obj, gsize size)
{
return realloc(obj, size);
}
gpointer g_malloc (gsize x)
{
return malloc(x);
}
gpointer g_malloc0 (gsize x)
{
return calloc(1, x);
}
gpointer
g_memdup (gconstpointer mem, guint byte_size)
{
gpointer ptr;
if (mem == NULL)
return NULL;
ptr = g_malloc (byte_size);
if (ptr != NULL)
memcpy (ptr, mem, byte_size);
return ptr;
}
gchar *
g_strdup (const gchar *str)
{
if (str) { return (gchar*) g_memdup (str, (guint)strlen (str) + 1); }
return NULL;
}
#define INITIAL_CAPACITY 16
#define element_offset(p,i) ((p)->array.data + (i) * (p)->element_size)
#define element_length(p,i) ((i) * (p)->element_size)
typedef struct {
GArray array;
gboolean clear_;
guint element_size;
gboolean zero_terminated;
guint capacity;
} GArrayPriv;
static void
ensure_capacity (GArrayPriv *priv, guint capacity)
{
guint new_capacity;
if (capacity <= priv->capacity)
return;
new_capacity = (capacity + 63) & ~63;
priv->array.data = g_realloc (priv->array.data, element_length (priv, new_capacity));
if (priv->clear_) {
memset (element_offset (priv, priv->capacity),
0,
element_length (priv, new_capacity - priv->capacity));
}
priv->capacity = new_capacity;
}
GArray *
g_array_new (gboolean zero_terminated,
gboolean clear_,
guint element_size)
{
GArrayPriv *rv = g_new0 (GArrayPriv, 1);
rv->zero_terminated = zero_terminated;
rv->clear_ = clear_;
rv->element_size = element_size;
ensure_capacity (rv, INITIAL_CAPACITY);
return (GArray*)rv;
}
GArray *
g_array_sized_new (gboolean zero_terminated,
gboolean clear_,
guint element_size,
guint reserved_size)
{
GArrayPriv *rv = g_new0 (GArrayPriv, 1);
rv->zero_terminated = zero_terminated;
rv->clear_ = clear_;
rv->element_size = element_size;
ensure_capacity (rv, reserved_size);
return (GArray*)rv;
}
gchar*
g_array_free (GArray *array,
gboolean free_segment)
{
gchar* rv = NULL;
g_return_val_if_fail (array != NULL, NULL);
if (free_segment)
g_free (array->data);
else
rv = array->data;
g_free (array);
return rv;
}
GArray *
g_array_append_vals (GArray *array,
gconstpointer data,
guint len)
{
GArrayPriv *priv = (GArrayPriv*)array;
g_return_val_if_fail (array != NULL, NULL);
ensure_capacity (priv, priv->array.len + len + (priv->zero_terminated ? 1 : 0));
memmove (element_offset (priv, priv->array.len),
data,
element_length (priv, len));
priv->array.len += len;
if (priv->zero_terminated) {
memset (element_offset (priv, priv->array.len),
0,
priv->element_size);
}
return array;
}
GArray*
g_array_insert_vals (GArray *array,
guint index_,
gconstpointer data,
guint len)
{
GArrayPriv *priv = (GArrayPriv*)array;
guint extra = (priv->zero_terminated ? 1 : 0);
g_return_val_if_fail (array != NULL, NULL);
ensure_capacity (priv, array->len + len + extra);
/* first move the existing elements out of the way */
memmove (element_offset (priv, index_ + len),
element_offset (priv, index_),
element_length (priv, array->len - index_));
/* then copy the new elements into the array */
memmove (element_offset (priv, index_),
data,
element_length (priv, len));
array->len += len;
if (priv->zero_terminated) {
memset (element_offset (priv, priv->array.len),
0,
priv->element_size);
}
return array;
}
GArray*
g_array_remove_index (GArray *array,
guint index_)
{
GArrayPriv *priv = (GArrayPriv*)array;
g_return_val_if_fail (array != NULL, NULL);
memmove (element_offset (priv, index_),
element_offset (priv, index_ + 1),
element_length (priv, array->len - index_));
array->len --;
if (priv->zero_terminated) {
memset (element_offset (priv, priv->array.len),
0,
priv->element_size);
}
return array;
}
GArray*
g_array_remove_index_fast (GArray *array,
guint index_)
{
GArrayPriv *priv = (GArrayPriv*)array;
g_return_val_if_fail (array != NULL, NULL);
memmove (element_offset (priv, index_),
element_offset (priv, array->len - 1),
element_length (priv, 1));
array->len --;
if (priv->zero_terminated) {
memset (element_offset (priv, priv->array.len),
0,
priv->element_size);
}
return array;
}
void
g_array_set_size (GArray *array, gint length)
{
GArrayPriv *priv = (GArrayPriv*)array;
g_return_if_fail (array != NULL);
g_return_if_fail (length >= 0);
if (length == priv->capacity)
return; // nothing to be done
if (length > priv->capacity) {
// grow the array
ensure_capacity (priv, length);
}
array->len = length;
}
#define GROW_IF_NECESSARY(s,l) { \
if(s->len + l >= s->allocated_len) { \
s->allocated_len = (s->allocated_len + l + 16) * 2; \
s->str = g_realloc(s->str, s->allocated_len); \
} \
}
GString *
g_string_new_len (const gchar *init, gssize len)
{
GString *ret = g_new (GString, 1);
if (init == NULL)
ret->len = 0;
else
ret->len = len < 0 ? strlen(init) : len;
ret->allocated_len = MAX(ret->len + 1, 16);
ret->str = g_malloc(ret->allocated_len);
if (init)
memcpy(ret->str, init, ret->len);
ret->str[ret->len] = 0;
return ret;
}
GString *
g_string_new (const gchar *init)
{
return g_string_new_len(init, -1);
}
GString *
g_string_sized_new (gsize default_size)
{
GString *ret = g_new (GString, 1);
ret->str = g_malloc (default_size);
ret->str [0] = 0;
ret->len = 0;
ret->allocated_len = default_size;
return ret;
}
gchar *
g_string_free (GString *string, gboolean free_segment)
{
gchar *data;
g_return_val_if_fail (string != NULL, NULL);
data = string->str;
g_free(string);
if(!free_segment) {
return data;
}
g_free(data);
return NULL;
}
GString *
g_string_append_len (GString *string, const gchar *val, gssize len)
{
g_return_val_if_fail(string != NULL, NULL);
g_return_val_if_fail(val != NULL, string);
if(len < 0) {
len = strlen(val);
}
GROW_IF_NECESSARY(string, len);
memcpy(string->str + string->len, val, len);
string->len += len;
string->str[string->len] = 0;
return string;
}
GString *
g_string_append (GString *string, const gchar *val)
{
g_return_val_if_fail(string != NULL, NULL);
g_return_val_if_fail(val != NULL, string);
return g_string_append_len(string, val, -1);
}
GString *
g_string_append_c (GString *string, gchar c)
{
g_return_val_if_fail(string != NULL, NULL);
GROW_IF_NECESSARY(string, 1);
string->str[string->len] = c;
string->str[string->len + 1] = 0;
string->len++;
return string;
}
GString *
g_string_prepend (GString *string, const gchar *val)
{
gssize len;
g_return_val_if_fail (string != NULL, string);
g_return_val_if_fail (val != NULL, string);
len = strlen (val);
GROW_IF_NECESSARY(string, len);
memmove(string->str + len, string->str, string->len + 1);
memcpy(string->str, val, len);
return string;
}
GString *
g_string_insert (GString *string, gssize pos, const gchar *val)
{
gssize len;
g_return_val_if_fail (string != NULL, string);
g_return_val_if_fail (val != NULL, string);
g_return_val_if_fail (pos <= string->len, string);
len = strlen (val);
GROW_IF_NECESSARY(string, len);
memmove(string->str + pos + len, string->str + pos, string->len - pos - len + 1);
memcpy(string->str + pos, val, len);
return string;
}
GString *
g_string_truncate (GString *string, gsize len)
{
g_return_val_if_fail (string != NULL, string);
/* Silent return */
if (len >= string->len)
return string;
string->len = len;
string->str[len] = 0;
return string;
}
GString *
g_string_set_size (GString *string, gsize len)
{
g_return_val_if_fail (string != NULL, string);
GROW_IF_NECESSARY(string, len);
string->len = len;
string->str[len] = 0;
return string;
}
GString *
g_string_erase (GString *string, gssize pos, gssize len)
{
g_return_val_if_fail (string != NULL, string);
/* Silent return */
if (pos >= string->len)
return string;
if (len == -1 || (pos + len) >= string->len) {
string->str[pos] = 0;
}
else {
memmove (string->str + pos, string->str + pos + len, string->len - (pos + len) + 1);
string->len -= len;
}
return string;
}

247
tests/objc-cli/glib.h Normal file
Просмотреть файл

@ -0,0 +1,247 @@
#ifndef __GLIB_H
#define __GLIB_H
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stddef.h>
#include <ctype.h>
#include <limits.h>
#include <stdint.h>
#ifdef G_HAVE_ALLOCA_H
#include <alloca.h>
#endif
#ifdef WIN32
/* For alloca */
#include <malloc.h>
#endif
#ifndef offsetof
# define offsetof(s_name,n_name) (size_t)(char *)&(((s_name*)0)->m_name)
#endif
#define __EGLIB_X11 1
#ifdef __cplusplus
#define G_BEGIN_DECLS extern "C" {
#define G_END_DECLS }
#else
#define G_BEGIN_DECLS
#define G_END_DECLS
#endif
G_BEGIN_DECLS
/*
* Basic data types
*/
typedef int gint;
typedef unsigned int guint;
typedef short gshort;
typedef unsigned short gushort;
typedef long glong;
typedef unsigned long gulong;
typedef void * gpointer;
typedef const void * gconstpointer;
typedef char gchar;
typedef unsigned char guchar;
/* Types defined in terms of the stdint.h */
typedef int8_t gint8;
typedef uint8_t guint8;
typedef int16_t gint16;
typedef uint16_t guint16;
typedef int32_t gint32;
typedef uint32_t guint32;
typedef int64_t gint64;
typedef uint64_t guint64;
typedef float gfloat;
typedef double gdouble;
typedef int32_t gboolean;
typedef guint16 gunichar2;
typedef guint32 gunichar;
typedef unsigned long gsize;
typedef signed long gssize;
/*
* Macros
*/
#define G_N_ELEMENTS(s) (sizeof(s) / sizeof ((s) [0]))
#define FALSE 0
#define TRUE 1
#define G_MINSHORT SHRT_MIN
#define G_MAXSHORT SHRT_MAX
#define G_MAXUSHORT USHRT_MAX
#define G_MAXINT INT_MAX
#define G_MININT INT_MIN
#define G_MAXINT32 INT32_MAX
#define G_MAXUINT32 UINT32_MAX
#define G_MININT32 INT32_MIN
#define G_MININT64 INT64_MIN
#define G_MAXINT64 INT64_MAX
#define G_MAXUINT64 UINT64_MAX
#define G_LITTLE_ENDIAN 1234
#define G_BIG_ENDIAN 4321
#define G_STMT_START do
#define G_STMT_END while (0)
#define G_USEC_PER_SEC 1000000
#ifndef ABS
#define ABS(a) ((a) > 0 ? (a) : -(a))
#endif
#define G_STRUCT_OFFSET(p_type,field) offsetof(p_type,field)
#define EGLIB_STRINGIFY(x) #x
#define EGLIB_TOSTRING(x) EGLIB_STRINGIFY(x)
#define G_STRLOC __FILE__ ":" EGLIB_TOSTRING(__LINE__) ":"
#define G_CONST_RETURN const
#define G_GUINT64_FORMAT PRIu64
#define G_GINT64_FORMAT PRIi64
#define G_GUINT32_FORMAT PRIu32
#define G_GINT32_FORMAT PRIi32
/*
* Allocation
*/
void g_free (void *ptr);
gpointer g_realloc (gpointer obj, gsize size);
gpointer g_malloc (gsize x);
gpointer g_malloc0 (gsize x);
gpointer g_calloc (gsize n, gsize x);
gpointer g_try_malloc (gsize x);
gpointer g_try_realloc (gpointer obj, gsize size);
#define g_new(type,size) ((type *) g_malloc (sizeof (type) * (size)))
#define g_new0(type,size) ((type *) g_malloc0 (sizeof (type)* (size)))
#define g_newa(type,size) ((type *) alloca (sizeof (type) * (size)))
#define g_memmove(dest,src,len) memmove (dest, src, len)
#define g_renew(struct_type, mem, n_structs) g_realloc (mem, sizeof (struct_type) * n_structs)
#define g_alloca(size) alloca (size)
gpointer g_memdup (gconstpointer mem, guint byte_size);
gchar *g_strdup (const gchar *str);
gchar **g_strdupv (gchar **str_array);
/*
* Precondition macros
*/
#define g_warn_if_fail(x) G_STMT_START { if (!(x)) { g_warning ("%s:%d: assertion '%s' failed", __FILE__, __LINE__, #x); } } G_STMT_END
#define g_return_if_fail(x) G_STMT_START { if (!(x)) { g_critical ("%s:%d: assertion '%s' failed", __FILE__, __LINE__, #x); return; } } G_STMT_END
#define g_return_val_if_fail(x,e) G_STMT_START { if (!(x)) { g_critical ("%s:%d: assertion '%s' failed", __FILE__, __LINE__, #x); return (e); } } G_STMT_END
/*
* Array
*/
typedef struct _GArray GArray;
struct _GArray {
gchar *data;
gint len;
};
GArray *g_array_new (gboolean zero_terminated, gboolean clear_, guint element_size);
GArray *g_array_sized_new (gboolean zero_terminated, gboolean clear_, guint element_size, guint reserved_size);
gchar* g_array_free (GArray *array, gboolean free_segment);
GArray *g_array_append_vals (GArray *array, gconstpointer data, guint len);
GArray* g_array_insert_vals (GArray *array, guint index_, gconstpointer data, guint len);
GArray* g_array_remove_index (GArray *array, guint index_);
GArray* g_array_remove_index_fast (GArray *array, guint index_);
void g_array_set_size (GArray *array, gint length);
#define g_array_append_val(a,v) (g_array_append_vals((a),&(v),1))
#define g_array_insert_val(a,i,v) (g_array_insert_vals((a),(i),&(v),1))
#define g_array_index(a,t,i) *(t*)(((a)->data) + sizeof(t) * (i))
/*
* String type
*/
typedef struct _GString {
char *str;
gsize len;
gsize allocated_len;
} GString;
GString *g_string_new (const gchar *init);
GString *g_string_new_len (const gchar *init, gssize len);
GString *g_string_sized_new (gsize default_size);
gchar *g_string_free (GString *string, gboolean free_segment);
GString *g_string_append (GString *string, const gchar *val);
GString *g_string_append_c (GString *string, gchar c);
GString *g_string_append (GString *string, const gchar *val);
GString *g_string_append_len (GString *string, const gchar *val, gssize len);
GString *g_string_truncate (GString *string, gsize len);
GString *g_string_prepend (GString *string, const gchar *val);
GString *g_string_insert (GString *string, gssize pos, const gchar *val);
GString *g_string_set_size (GString *string, gsize len);
GString *g_string_erase (GString *string, gssize pos, gssize len);
#define g_string_sprintfa g_string_append_printf
#ifndef MAX
#define MAX(a,b) (((a)>(b)) ? (a) : (b))
#endif
#ifndef MIN
#define MIN(a,b) (((a)<(b)) ? (a) : (b))
#endif
#ifndef CLAMP
#define CLAMP(a,low,high) (((a) < (low)) ? (low) : (((a) > (high)) ? (high) : (a)))
#endif
#if defined(_MSC_VER)
#define eg_unreachable() __assume(0)
#elif defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && (__GNUC_MINOR__ >= 5)))
#define eg_unreachable() __builtin_unreachable()
#else
#define eg_unreachable()
#endif
#define g_assert(x) G_STMT_START { if (G_UNLIKELY (!(x))) g_assertion_message ("* Assertion at %s:%d, condition `%s' not met\n", __FILE__, __LINE__, #x); } G_STMT_END
#define g_assert_not_reached() G_STMT_START { g_assertion_message ("* Assertion: should not be reached at %s:%d\n", __FILE__, __LINE__); eg_unreachable(); } G_STMT_END
#define g_critical(format, ...)
/*
* Path
*/
#ifdef _MSC_VER
#define G_DIR_SEPARATOR '\\'
#define G_DIR_SEPARATOR_S "\\"
#else
#define G_DIR_SEPARATOR '/'
#define G_DIR_SEPARATOR_S "/"
#endif
gchar *g_build_path (const gchar *separator, const gchar *first_element, ...);
#define g_build_filename(x, ...) g_build_path(G_DIR_SEPARATOR_S, x, __VA_ARGS__)
gchar *g_path_get_dirname (const gchar *filename);
gchar *g_path_get_basename (const char *filename);
gchar *g_find_program_in_path (const gchar *program);
gchar *g_get_current_dir (void);
gboolean g_path_is_absolute (const char *filename);
#define _EGLIB_MAJOR 2
#define _EGLIB_MIDDLE 4
#define _EGLIB_MINOR 0
#define GLIB_CHECK_VERSION(a,b,c) ((a < _EGLIB_MAJOR) || (a == _EGLIB_MAJOR && (b < _EGLIB_MIDDLE || (b == _EGLIB_MIDDLE && c <= _EGLIB_MINOR))))
G_END_DECLS
#endif

Двоичные данные
tests/objc-cli/libmanaged.dylib Executable file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,279 @@
/*
* Mono managed-to-native support code.
*
* Author:
* Joao Matos (joao.matos@xamarin.com)
*
* (C) 2016 Microsoft, Inc.
*
* 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 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.
*/
#include "mono_embeddinator.h"
#include "glib.h"
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined(__APPLE__)
#include <errno.h>
#include <libproc.h>
#include <unistd.h>
#endif
#if defined(__OBJC__)
#include <objc/runtime.h>
#include <objc/objc-runtime.h>
#endif
#ifdef _WIN32
#include <Windows.h>
#endif
#include <mono/jit/jit.h>
#include <mono/metadata/mono-config.h>
#include <mono/metadata/assembly.h>
#include <mono/metadata/debug-helpers.h>
mono_embeddinator_context_t* _current_context;
mono_embeddinator_context_t* mono_embeddinator_get_context()
{
return _current_context;
}
void mono_embeddinator_set_context(mono_embeddinator_context_t* ctx)
{
_current_context = ctx;
}
#if defined(__OBJC__)
id allocAndInitAutoreleasePool()
{
Class NSAutoreleasePoolClass = objc_getClass("NSAutoreleasePool");
id pool = class_createInstance(NSAutoreleasePoolClass, 0);
return objc_msgSend(pool, sel_registerName("init"));
}
void drainAutoreleasePool(id pool)
{
(void)objc_msgSend(pool, sel_registerName("drain"));
}
#define AUTORELEASE_POOL_DEFAULT_VALUE ((id)-1)
static id _autoreleasePool = AUTORELEASE_POOL_DEFAULT_VALUE;
#endif
int mono_embeddinator_init(mono_embeddinator_context_t* ctx, const char* domain)
{
if (ctx == 0 || ctx->domain != 0)
return false;
mono_config_parse(NULL);
ctx->domain = mono_jit_init_version(domain, "v4.0.30319");
mono_embeddinator_set_context(ctx);
#if defined(__OBJC__)
if (_autoreleasePool == AUTORELEASE_POOL_DEFAULT_VALUE)
_autoreleasePool = allocAndInitAutoreleasePool();
#endif
return true;
}
int mono_embeddinator_destroy(mono_embeddinator_context_t* ctx)
{
if (ctx == 0 || ctx->domain != 0)
return false;
mono_jit_cleanup (ctx->domain);
#if defined(__OBJC__)
if (_autoreleasePool != AUTORELEASE_POOL_DEFAULT_VALUE)
{
drainAutoreleasePool(_autoreleasePool);
_autoreleasePool = AUTORELEASE_POOL_DEFAULT_VALUE;
}
#endif
return true;
}
static GString* get_current_executable_path()
{
#if defined(__APPLE__)
int ret;
pid_t pid;
char pathbuf[PROC_PIDPATHINFO_MAXSIZE];
pid = getpid();
ret = proc_pidpath (pid, pathbuf, sizeof(pathbuf));
return (ret > 0) ? g_string_new(pathbuf) : 0;
#elif defined(_WIN32)
HMODULE hModule = GetModuleHandleW(0);
CHAR pathbuf[MAX_PATH];
DWORD ret = GetModuleFileNameA(hModule, pathbuf, MAX_PATH);
return (ret > 0) ? g_string_new(pathbuf) : 0;
#else
g_assert_not_reached();
#endif
}
static gchar*
strrchr_seperator (const gchar* filename)
{
#ifdef G_OS_WIN32
char *p2;
#endif
char *p;
p = strrchr (filename, G_DIR_SEPARATOR);
#ifdef G_OS_WIN32
p2 = strrchr (filename, '/');
if (p2 > p)
p = p2;
#endif
return p;
}
char* mono_embeddinator_search_assembly(const char* assembly)
{
GString* path = get_current_executable_path();
gchar* sep = strrchr_seperator(path->str);
g_string_truncate(path, sep - path->str);
g_string_append(path, G_DIR_SEPARATOR_S);
g_string_append(path, assembly);
char* data = path->str;
g_string_free(path, /*free_segment=*/ FALSE);
return data;
}
MonoImage* mono_embeddinator_load_assembly(mono_embeddinator_context_t* ctx, const char* assembly)
{
const char* path = mono_embeddinator_search_assembly(assembly);
MonoAssembly* mono_assembly = mono_domain_assembly_open(ctx->domain, path);
if (mono_assembly == 0)
{
mono_embeddinator_error_t __error;
__error.type = MONO_EMBEDDINATOR_ASSEMBLY_OPEN_FAILED;
__error.string = path;
mono_embeddinator_error(__error);
return 0;
}
return mono_assembly_get_image(mono_assembly);
}
static mono_embeddinator_assembly_search_hook_t g_assembly_search_hook = 0;
void* mono_embeddinator_install_assembly_search_hook(mono_embeddinator_assembly_search_hook_t hook)
{
mono_embeddinator_assembly_search_hook_t prev = g_assembly_search_hook;
g_assembly_search_hook = hook;
return (void*)prev;
}
MonoClass* mono_embeddinator_search_class(const char* assembly, const char* _namespace,
const char* name)
{
mono_embeddinator_context_t* ctx = mono_embeddinator_get_context();
const char* path = mono_embeddinator_search_assembly(assembly);
MonoAssembly* mono_assembly = mono_domain_assembly_open(ctx->domain, path);
if (mono_assembly == 0)
{
mono_embeddinator_error_t error;
error.type = MONO_EMBEDDINATOR_ASSEMBLY_OPEN_FAILED;
error.string = path;
mono_embeddinator_error(error);
}
MonoImage* image = mono_assembly_get_image(mono_assembly);
MonoClass* klass = mono_class_from_name(image, _namespace, name);
return klass;
}
MonoMethod* mono_embeddinator_lookup_method(const char* method_name, MonoClass *klass)
{
MonoMethodDesc* desc = mono_method_desc_new(method_name, /*include_namespace=*/true);
MonoMethod* method = mono_method_desc_search_in_class(desc, klass);
mono_method_desc_free(desc);
if (!method)
{
mono_embeddinator_error_t error;
error.type = MONO_EMBEDDINATOR_METHOD_LOOKUP_FAILED;
error.string = method_name;
mono_embeddinator_error(error);
}
return method;
}
void mono_embeddinator_throw_exception(MonoObject *exception)
{
mono_embeddinator_error_t error;
error.type = MONO_EMBEDDINATOR_EXCEPTION_THROWN;
error.exception = (MonoException*) exception;
mono_embeddinator_error(error);
}
static mono_embeddinator_error_report_hook_t g_error_report_hook = 0;
void* mono_embeddinator_install_error_report_hook(mono_embeddinator_error_report_hook_t hook)
{
mono_embeddinator_error_report_hook_t prev = g_error_report_hook;
g_error_report_hook = hook;
return prev;
}
void mono_embeddinator_error(mono_embeddinator_error_t error)
{
if (g_error_report_hook == 0)
return;
g_error_report_hook(error);
}
void* mono_embeddinator_create_object(MonoObject* instance)
{
MonoEmbedObject* object = g_new(MonoEmbedObject, 1);
mono_embeddinator_init_object(object, instance);
return object;
}
void mono_embeddinator_init_object(MonoEmbedObject* object, MonoObject* instance)
{
object->_class = mono_object_get_class(instance);
object->_handle = mono_gchandle_new(instance, /*pinned=*/false);
}

Просмотреть файл

@ -0,0 +1,222 @@
/*
* Mono managed-to-native support code.
*
* Author:
* Joao Matos (joao.matos@xamarin.com)
*
* (C) 2016 Microsoft, Inc.
*
* 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 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.
*/
#pragma once
#ifdef __cplusplus
#include <cstdbool>
#include <cstdint>
#else
#include <stdbool.h>
#include <stdint.h>
#endif
#ifdef __cplusplus
#define MONO_EMBEDDINATOR_BEGIN_DECLS extern "C" {
#define MONO_EMBEDDINATOR_END_DECLS }
#else
#define MONO_EMBEDDINATOR_BEGIN_DECLS
#define MONO_EMBEDDINATOR_END_DECLS
#endif
#if defined(_MSC_VER)
#define MONO_EMBEDDINATOR_API_EXPORT __declspec(dllexport)
#define MONO_EMBEDDINATOR_API_IMPORT __declspec(dllimport)
#else
#define MONO_EMBEDDINATOR_API_EXPORT __attribute__ ((visibility ("default")))
#define MONO_EMBEDDINATOR_API_IMPORT
#endif
#if defined(MONO_EMBEDDINATOR_DLL_EXPORT)
#define MONO_EMBEDDINATOR_API MONO_EMBEDDINATOR_API_EXPORT
#else
#define MONO_EMBEDDINATOR_API MONO_EMBEDDINATOR_API_IMPORT
#endif
typedef uint16_t gunichar2;
typedef struct _GArray GArray;
typedef struct _GString GString;
typedef struct _MonoDomain MonoDomain;
typedef struct _MonoException MonoException;
typedef struct _MonoClass MonoClass;
typedef struct _MonoObject MonoObject;
typedef struct _MonoImage MonoImage;
typedef struct _MonoMethod MonoMethod;
MONO_EMBEDDINATOR_BEGIN_DECLS
/**
* Represents a managed-to-native binding context.
*/
typedef struct
{
MonoDomain* domain;
} mono_embeddinator_context_t;
/**
* Initializes a managed-to-native binding context.
* Returns a boolean indicating success or failure.
*/
MONO_EMBEDDINATOR_API
int mono_embeddinator_init(mono_embeddinator_context_t* ctx, const char* domain);
/**
* Destroys the managed-to-native binding context.
* Returns a boolean indicating success or failure.
*/
MONO_EMBEDDINATOR_API
int mono_embeddinator_destroy(mono_embeddinator_context_t* ctx);
/**
* Returns the current context.
*/
MONO_EMBEDDINATOR_API
mono_embeddinator_context_t* mono_embeddinator_get_context();
/**
* Sets the current context.
*/
MONO_EMBEDDINATOR_API
void mono_embeddinator_set_context(mono_embeddinator_context_t* ctx);
/**
* Loads an assembly into the context.
*/
MONO_EMBEDDINATOR_API
MonoImage* mono_embeddinator_load_assembly(mono_embeddinator_context_t* ctx,
const char* assembly);
/**
* Searches and returns the path to the given managed assembly.
*/
MONO_EMBEDDINATOR_API
char* mono_embeddinator_search_assembly(const char* assembly);
/** Represents the assembly search hook function type. */
typedef const char* (*mono_embeddinator_assembly_search_hook_t)(const char*);
/**
* Installs an hook that returns the path to the given managed assembly.
* Returns the previous installed hook.
*/
MONO_EMBEDDINATOR_API
void* mono_embeddinator_install_assembly_search_hook(mono_embeddinator_assembly_search_hook_t hook);
/**
* Searches and returns for the Mono class in the given assembly.
*/
MONO_EMBEDDINATOR_API
MonoClass* mono_embeddinator_search_class(const char* assembly, const char* _namespace,
const char* name);
/**
* Looks up and returns a MonoMethod* for a given Mono class and method name.
*/
MONO_EMBEDDINATOR_API
MonoMethod* mono_embeddinator_lookup_method(const char* method_name, MonoClass* klass);
/**
* Throws an exception based on a given Mono exception object.
*/
MONO_EMBEDDINATOR_API
void mono_embeddinator_throw_exception(MonoObject* exception);
/**
* Represents the different types of errors to be reported.
*/
typedef enum
{
MONO_EMBEDDINATOR_OK = 0,
// Mono managed exception
MONO_EMBEDDINATOR_EXCEPTION_THROWN,
// Mono failed to load assembly
MONO_EMBEDDINATOR_ASSEMBLY_OPEN_FAILED,
// Mono failed to lookup method
MONO_EMBEDDINATOR_METHOD_LOOKUP_FAILED
} mono_embeddinator_error_type_t;
/**
* Represents the error type and associated data.
*/
typedef struct
{
mono_embeddinator_error_type_t type;
// Contains exception object if type is MONO_EMBEDDINATOR_EXCEPTION_THROWN
MonoException* exception;
const char* string;
} mono_embeddinator_error_t;
/**
* Fires an error and calls the installed error hook for handling.
*/
MONO_EMBEDDINATOR_API
void mono_embeddinator_error(mono_embeddinator_error_t error);
/** Represents the error report hook function type. */
typedef void (*mono_embeddinator_error_report_hook_t)(mono_embeddinator_error_t);
/**
* Installs an hook that is called for each error reported.
*/
MONO_EMBEDDINATOR_API
void* mono_embeddinator_install_error_report_hook(mono_embeddinator_error_report_hook_t hook);
/**
* Arrays
*/
typedef struct
{
GArray* array;
} MonoEmbedArray;
/**
* Objects
*/
typedef struct
{
MonoClass* _class;
uint32_t _handle;
} MonoEmbedObject;
/**
* Creates a MonoEmbedObject support object from a Mono object instance.
*/
MONO_EMBEDDINATOR_API
void* mono_embeddinator_create_object(MonoObject* instance);
/**
* Initializes a MonoEmbedObject object from a Mono object instance.
*/
MONO_EMBEDDINATOR_API
void mono_embeddinator_init_object(MonoEmbedObject* object, MonoObject* instance);
MONO_EMBEDDINATOR_END_DECLS

Двоичные данные
tests/objc-cli/perf-cli Executable file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,15 @@
#import <Foundation/Foundation.h>
#include "mono_embeddinator.h"
#include "bindings.h"
int main (int argc, const char * argv[])
{
@autoreleasepool {
int counter = argc == 1 ? 1000000 : atoi (argv [0]);
for (int i = 0; i < counter; i++) {
assert (![Platform isWindows]);
}
}
return 0;
}

Двоичные данные
tests/objc-cli/test-cli Executable file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,15 @@
#import <Foundation/Foundation.h>
#include "mono_embeddinator.h"
#include "bindings.h"
int main ()
{
@autoreleasepool {
NSLog (@"%s static property getter only", [Platform isWindows] ? "[FAIL]" : "[PASS]");
NSLog (@"%s static property getter", [Platform exitCode] == 0 ? "[PASS]" : "[FAIL]");
Platform.exitCode = 255;
NSLog (@"%s static property setter check", [Platform exitCode] == 255 ? "[PASS]" : "[FAIL]");
}
return 0;
}

Просмотреть файл

@ -0,0 +1,27 @@
using NUnit.Framework;
using System;
using ObjC;
namespace ObjCGeneratorTest {
[TestFixture]
public class Helpers {
[Test]
public void CamelCase ()
{
Assert.Null (ObjCGenerator.CamelCase (null), "null");
Assert.That (ObjCGenerator.CamelCase (String.Empty), Is.EqualTo (""), "length == 0");
Assert.That (ObjCGenerator.CamelCase ("S"), Is.EqualTo ("s"), "length == 1");
Assert.That (ObjCGenerator.CamelCase ("TU"), Is.EqualTo ("tU"), "length == 2");
}
[Test]
public void TypeMatch ()
{
Assert.That (ObjCGenerator.GetTypeName (typeof (bool)), Is.EqualTo ("bool"), "bool");
Assert.That (ObjCGenerator.GetTypeName (typeof (int)), Is.EqualTo ("int"), "int");
Assert.That (ObjCGenerator.GetTypeName (typeof (object)), Is.EqualTo ("NSObject"), "object");
}
}
}

Просмотреть файл

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{076A871B-0C13-47D8-8923-B9242995BFF8}</ProjectGuid>
<OutputType>Library</OutputType>
<RootNamespace>objcgentest</RootNamespace>
<AssemblyName>objcgentest</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="nunit.framework">
<HintPath>..\..\packages\NUnit.2.6.4\lib\nunit.framework.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="ObjCGeneratorTest.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\objcgen\objcgen.csproj">
<Project>{C166803B-011F-4EAF-B8C2-D7DBBA3CF1EC}</Project>
<Name>objcgen</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>