[Mono-osx] Embedding into XCode project

Duane Wandless duane at wandless.net
Mon Apr 5 10:29:35 EDT 2010


Here is some info that may help.  There have been prior posts about this on
this forum as well.  It is not trivial but it is also not hard.  Once all of
this is done your C# classes will be available to the xcode world.

Best of luck.
Duane

Here is my init mono code and the main.m (below).  This is invoked when the
xcode application starts, see main.m.  This code fully embeds the mono
runtime assuming Mono 2.6.  There is code here that attempts to setup the
soft debugger as well (not completely working).  In prior mono releases I
ran into issues using a DLL so I use an EXE.  Note my setup is initmono.m
and host.c are compiled into a dynamic library.  That library is then linked
into the main xcode application.

This code uses mobjc but I've used monobjc before.  The code around
mymonoconfig is required so the dylib can be referenced.

Here is a prebuild command that is required to generate a host.c that is
compiled into your xcode application.  The resulting library is linked into
your application.

# shell script goes here
if [ $ACTION = "build" ]; then
export AS="as -arch i386"
export
DYLD_LIBRARY_PATH=/Library/Frameworks/Mono.framework/Versions/Current/lib/
mkbundle -o $SRCROOT/host.c --nomain -c -oo $SRCROOT/Mono/libhost.a
$SRCROOT/Mono/MyMessage.dll $SRCROOT/Mono/MacMonoClient.exe
$SRCROOT/Mono/mobjc.dll $SRCROOT/Mono/mcocoa.dll System.dll System.Core.dll
System.Xml.Linq.dll System.Xml.dll System.Drawing.dll mscorlib.dll
System.Configuration.dll Mono.Security.dll System.Security.dll
--machine-config
/Library/Frameworks/Mono.framework/Versions/Current/etc/mono/2.0/machine.config
fi

I do NOT reference the mono.framework in my xcode project.  Instead I
modified the project settings:
LD_DYLIB_INSTALL_NAME = @loader_path/../Libraries/InitMono.dylib
OTHER_LDFLAGS = -pthread
-L/Library/Frameworks/Mono.framework/Versions/Current/lib -lmono -lpthread
-lm -lgthread-2.0 -lglib-2.0 -lintl -rpath at loader_path/../Libraries
LIBRARY_SEARCH_PATHS = Mono
OTHER_CFLAGS = -D_XOPEN_SOURCE -DPLATFORM_MACOSX -DUSE_MMAP -DUSE_MUNMAP
-DGC_MACOSX_THREADS -DGetCurrentProcess=MonoGetCurrentProcess
-DCreateEvent=MonoCreateEvent -DGetCurrentThread=MonoGetCurrentThread
-I/Library/Frameworks/Mono.framework/Versions/Current/lib/glib-2.0/include
-I/Library/Frameworks/Mono.framework/Versions/Current/include/glib-2.0
-D_THREAD_SAFE -D_REENTRANT
-I/Library/Frameworks/Mono.framework/Headers/mono-1.0

In my application bundle:
../My.app/Contents/Libraries
I have this structure:
InitMono.dylib System.dll
System.Xml.dll                 a.dylib
MacMonoClient.exe lib/
MacMonoClient.exe.mdb libglib-2.0.0.dylib
Mono.Security.dll libgthread-2.0.0.dylib
MyMessage.dll libintl.8.0.2.dylib
System.Configuration.dll libmono.0.dylib
System.Core.dll mcocoa.dll
System.Drawing.dll mobjc.dll
System.Drawing.dll.config mymonoconfig2
System.Xml.Linq.dll

Then under lib I have:
mono/2.0/mscorlib.dll

I then run these libraries (below) through install_name_tool.  You only have
to do these next 2 steps once.  The library names may have changed... I
copied the text below from my post on this forum on 10/1/2008.
libglib-2.0.0.1400.1.dylib    libgthread-2.0.0.1400.1.dylib
libmono.0.0.0.dylib
libgmodule-2.0.0.1400.1.dylib    libintl.8.0.1.dylib

Two things have to be performed on these libraries.  First the id of the
file has to be changed from the /Library/Frameworks/Mono.framework reference
to @loader_path/../Libraries/<name>.  Run otool -L <the dylib file>.
install_name_tool -id @loader_path/../Libraries/libintl.8.0.1.dylib
libintl.8.0.1.dylib

The second operation is to change the references to other dynamic libraries
you are embedding.
install_name_tool -change
/Library/Frameworks/Mono.framework/Versions/1.9.1/lib/libintl.8.0.1.dylib
@loader_path/../Libraries/libintl.8.0.1.dylib libglib-2.0.0.1400.1.dylib

Basically what you are doing is telling the runtime app where to find these
dynmaic libraries.  Rather than in the Frameworks directory look relative to
the application.  Place these modified libraires in
<yourapp>.app/Contents/Libraries.

Compile the xcode application normally.  Then run install_name_tool on it as
well, <yourapp>.app/Contents/MacOS/<yourapp>
install_name_tool -change
/Library/Frameworks/Mono.framework/Versions/1.9.1/lib/libgthread-2.0.0.1400.1.dylib
@loader_path/../Libraries/libgthread-2.0.0.1400.1.dylib <yourapp>

Now remember you have to run this install_name_tool many times.  Once for
each library referenced by your application.  And once for each reference in
the dynamic libraries to another dynamic library that you are trying to
embed.  Use otool -L <file> to find the references you need to modify.

##### initmono.m

#import <Cocoa/Cocoa.h>
#include <mono/jit/jit.h>
#include <mono/metadata/assembly.h>
#include <mono/metadata/mono-config.h>
#include <mono/metadata/mono-debug.h>
#include <mono/utils/mono-logger.h>

extern void mono_mkbundle_init();

void InitMono(int argc, char *argv[])
{
NSString *mPath = [[[NSBundle mainBundle] bundlePath]
stringByAppendingPathComponent:@"Contents/Libraries/lib"];
//g_setenv("MONO_PATH", [mPath UTF8String], 1);
 //mono_mkbundle_init();  //call this instead of loading the dll below
 MonoDomain *domain;

// these next 2 lines are used to load a file from the bundle directory
// if we call mono_mkbundle_init then we do not need these 2 lines
NSString *libraryPath = [[[NSBundle mainBundle] bundlePath]
stringByAppendingPathComponent:@"Contents/Libraries/"];
NSString *sampleAssemblyPath = [libraryPath stringByAppendingPathComponent:@
"MacMonoClient.exe"];
 //g_setenv("DYLD_LIBRARY_PATH", [libraryPath UTF8String], true);
//const gchar* val;
//val = g_getenv("DYLD_LIBRARY_PATH");
//NSLog(@"Load Library %s", val);
//NSString* monoPath = [libraryPath stringByAppendingPathComponent:@"lib"];
//NSLog(@"Mono %@", monoPath);
//NSLog(@"initmono path %s", getenv("MONO_PATH"));
//setenv("MONO_PATH", [monoPath UTF8String], true);
// NSLog(@"zero");
// else NSLog("one");
//NSString *sampleAssemblyPath = @"MacMonoClient.exe";
NSLog(@"libraryPath: %@", sampleAssemblyPath);

NSString* mymonoconfig = @"<configuration><dllmap dll=\"mobjc-glue.dylib\"
target=\"";
mymonoconfig = [mymonoconfig stringByAppendingString:[libraryPath
stringByAppendingPathComponent:@"a.dylib"]];
mymonoconfig = [mymonoconfig stringByAppendingString:@"\"
/></configuration>"];
[mymonoconfig writeToFile:[libraryPath
stringByAppendingPathComponent:@"mymonoconfig2"]
atomically:YES encoding:NSASCIIStringEncoding error:NULL];

NSString* configFile = [libraryPath stringByAppendingPathComponent:@
"mymonoconfig2"];
mono_config_parse ([configFile UTF8String]);
#if MONO26_MY
 NSLog(@"about to check for MOON_SOFT_DEBUG");
 const gchar *soft_debug;
soft_debug = g_getenv ("MOON_SOFT_DEBUG");
if (soft_debug != NULL) {
NSLog(@"we have MOON_SOFT_DEBUG %s", soft_debug);
gchar *opt = g_strdup_printf ("--debugger-agent=%s", soft_debug);
mono_jit_parse_options (1, &opt);
g_free (opt);
 mono_debug_init (MONO_DEBUG_FORMAT_MONO);
}
#endif

const gchar *my_debug;
my_debug = g_getenv ("MY_MONO_DEBUG");
if (my_debug != NULL) {
NSLog(@"MY DEBUG is %s", my_debug);
mono_debug_init (MONO_DEBUG_FORMAT_MONO);
}
const gchar *mono_trace_level;
mono_trace_level = g_getenv ("PMONO_TRACE_LEVEL");
if (mono_trace_level != NULL)
mono_trace_set_level_string(mono_trace_level);

mono_assembly_setrootdir([mPath UTF8String]);
 domain = mono_jit_init ([sampleAssemblyPath UTF8String]);//, "3.0.04506");
MonoAssembly *monoAssembly = mono_domain_assembly_open(domain,
[sampleAssemblyPath UTF8String]);

NSLog(@"sample assembly: %p", monoAssembly);
mono_jit_exec (domain, monoAssembly, 1, argv);

}

My main.m:
#import <Cocoa/Cocoa.h>

int main(int argc, char *argv[])
{
NSAutoreleasePool *pool;
pool = [[NSAutoreleasePool alloc] init];
InitMono(argc, (char**)argv);
[pool release];

return NSApplicationMain(argc, (const char **) argv);
}

On Mon, Apr 5, 2010 at 9:33 AM, Alexander Chilcott
<alexchilcott at gmail.com>wrote:

> Hey guys,
>
> I am an experienced C# developer and reasonably new to objective c and
> xcode. I am having issues embedding the Mono framework into an objective-C
> project I am working on. I have added the Mono.Framework to my linked
> frameworks in my xcode project, but there are no header files being
> displayed when I expand the Mono.Framework tree node in the xcode project. I
> have installed the latest mono framework and CSDK.
>
> Does anyone have any experience with this? It seems to be a common theme
> among forum posts for embedding mono in objective-c. Apologies if there is a
> simple solution that I have missed, but I assure you I have googled my heart
> out :)
>
> Thanks,
> Alex
>
> _______________________________________________
> Mono-osx mailing list
> Mono-osx at lists.ximian.com
> http://lists.ximian.com/mailman/listinfo/mono-osx
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.ximian.com/pipermail/mono-osx/attachments/20100405/d379c94c/attachment-0001.html 


More information about the Mono-osx mailing list