Original URL: http://www.theregister.co.uk/2007/02/16/uncle_mac_mono_/

Mono on the Mac: Time to look beyond Linux?

Uncle Mac casts a grumpy eye

By Uncle Mac

Posted in Developer, 16th February 2007 07:02 GMT

As you’ll no doubt be aware, the Mono Project is an ambitious, open-source initiative, largely coordinated by Novell. The aim is to build a complete suite of ECMA- compliant .NET tools (C# compiler, runtime, class frameworks, etc) which work across all supported platforms, including Linux, Windows and Mac OS X. For more background on the project, check out “Mono (software)” on Wikipedia.

As a keen Mac user, I’m always looking out for new development tools which not only provide a simple, efficient and intuitive API but also – hopefully – offer cross-platform capabilities too. From this perspective, Mono would seem to be ideal; not least, because I’m a fan of Microsoft’s .NET class frameworks which do such a great job of taming the atrocious Win32 API beneath! So, let’s look further...

Mono on the Mac…

Getting started with Mono is relatively straightforward; go to the Mono Project main page, follow the ‘download now’ link (cunningly hidden in the extreme top-right of the screen) and you’ll be able to obtain the Mono distribution appropriate to your platform. For the Mac, this is currently tagged as “Mono 1.2.3_1 Framework - Universal (Stable)”. Once you’ve downloaded and installed the framework, you’ll initially find … nothing! It’s at this point that Windows users start missing the Start Menu and it’s highlighted list of freshly installed goodies. Nothing in the /Applications folder either…hmm….

Though not blindingly obvious, Mono gets installed as a new framework. The full path is /Library/Frameworks/Mono.framework. The various command-line Mono utilities are accessed via aliases which are automatically placed into /usr/bin. This means that after installing Mono, you can fire up a Terminal window and type (e.g.) ‘mcs’. This will invoke the Mono C# compiler.

Once you’ve got this far, there’s a lot you can do, provided you’re happy to stick with simple text-mode stuff and command line tools. Naturally, the quintessential C# program has got to be a variant on “Hello World” !

using System;

namespace RegDeveloper
{
   class Program
   {
       public static void Main (string[] args)
       {
                             Console.WriteLine ("Hello RegDeveloper");
       }
   }
}

Type this into a file called hello.cs, compile it with the mcs compiler and – voila! – you’ll end up with an executable called hello.exe. First thing to say is that the file is just as tiny as you’d expect from Windows development – around 3Kbytes in this particular case. The reason, of course, is that all the .NET class libraries are located in the aforementioned framework directory. What’s perhaps a little more surprising (at least from the perspective of an OS X purist) is that .exe suffix on the end of the file. If you try disassembling the code with any of the usual OS X tools (e.g. otool) you’ll be told in no uncertain terms that hello.exe isn’t a binary file. So what’s going on?

The key point, if you haven’t twigged, is that the Mono development tools generate executables that are 100% binary compatible with Microsoft’s tools running under Windows. You can take that hello.exe file generated on a Mac, stick it on your PC and run it in the usual way. What you can’t do is run it “in the usual way” on your Mac because OS X doesn’t understand .exe files!

Note: If you’re interested, there’s a new product out called CrossOver for the Mac here, which is based around Wine. This makes it possible to run Win32 applications under OS X fairly seamlessly, although I haven’t investigated whether this extends to the execution of Mono executables.

Assuming you’ve still sitting at the Mac, and you don’t use CrossOver, you can run hello.exe by typing the following in a terminal window:

mono hello.exe

In effect, hello.exe gets passed as an argument to the Mono loader which takes care of the program’s execution. A bit klunky, but it works. The accompanying screenshot (Figure 1) shows a partial dump of the various System-prefix assemblies installed by Mono; obviously, all these goodies are accessible from any command-line tools you build using the C# compiler.

Shows a partial dump of the various System-prefix assemblies installed by Mono.

X Marks The Spot…

But what about GUI, I hear you cry? After all, System.Windows.Forms.dll is rather obviously present in that last screenshot. It turns out that the news isn’t quite so good here. The introductory link Mono web info has this to say: “Mono is primarily developed on Linux, and most of its users are Linux users, so it is the platform best supported” .

You’d better believe it; although support for System.Windows.Forms is going great guns on Linux, things are by no means as positive where OS X is concerned. Yes, you can create graphical applications with forms, dialogs, etc. But it’s all based around X11. On my machine, I wasn’t able to successfully run a Mono GUI application unless I first started the X server running. This is because Mono’s System.Windows.Forms implementation is built on top of System.Drawing which, in turn, makes use of X11. The net result is that instead of seeing the drop-dead-gorgeous Aqua interface that Mac users take for granted (Jobs famously said that it was so attractive, you’d want to lick it) what you actually get is a kind of retro-looking interface that looks more like Windows 98 than anything else. If you don’t start the X11 server before running your Mono app, you’ll see a whole slew of exception errors. And if you want to do the whole thing properly, you also need to install GTK which in turn requires ‘fink’ which… Well, you get the idea. On the positive side, the Mono folks have written a small utility called macpack which packages up a WinForms executable into an application bundle, meaning it can be started from Finder in the usual way. But that’s quite a small positive when set against the overarching problem that the current state of Mono uses X11 rather than Core Graphics. Figure 2 shows a screenshot of MonoDevelop, a C#-based development system which will even run on the Mac, but it knows nowt about Cocoa. Spot the tell-tale ‘X’ icon in the Dock!

Shows a screenshot of MonoDevelop.

There are a number of web sites around which give a somewhat rosier impression of the state of play as far as Mono development on the Mac is concerned. For example, a recent NewsForge article by Nathan Willis here suggests that Novell’s iFolder is based entirely around Mono. Is it? Well, uhhh..no.

I eagerly downloaded iFolder from here, installed it and then sat back to enjoy my first experience of a turnkey Mono application running under OS X. Needless to say, the user interface looked suspiciously native, and a quick peek inside the application using my favourite spelunking tools revealed that – sure enough – the iFolder front-end is a perfectly conventional Objective-C Mac application written using Cocoa frameworks. So conventional, in fact, that it hasn’t even been converted into a universal binary: it’s a PPC executable! All the Mono code resides in the non-GUI back-end.

Note: I should stress there’s nothing dishonest going on here; I subsequently discovered that the complete source code to iFolder is readily available from the aforementioned web site, and it bears out my findings. But, I do take issue with Nathan using iFolder as an example of a “100% .Net application”. If it is, then I’m Lady Godiva. (Private viewings by appointment only, please…)

Similar considerations apply to Unity, a design tool for 3D game development that runs on both OS X and Windows, available for download here. Again, we’re told this is 100% .NET and again, it isn’t; it’s very easy to find the Cocoa classes and .NIB files inside the executable. The developers themselves make it clear that Mono is used by Unity – but as a scripting language. If you think about it, this makes perfect sense since, with little effort, game-engine developers get a powerful scripting language which executes at near native speed, thanks to the JIT compiler that forms part of the Mono bag o’tricks. In fact, the trend seems to be that several games companies are adopting C# through Mono as a scripting language for complex game systems on non-Wintel platforms. There’s got to be a joke somewhere in there about “Mono-gamists” but as with iFolder, the essential point is that the front-end GUI has nothing to do with Mono.

As a little aside, I recently discovered that some folks are successfully using cross-platform tools to create Mac applications with a near-native look and feel. As one example, get thee hence to this site, and you’ll find a cute little application whose main aim in life is to automatically stitch together multiple images so as to create a seamless panorama. It works well, is fast, and currently supports Windows and OS X. (A Linux version is planned). Peek under the hood and you’ll discover a couple of embedded frameworks called QtCore.framework and QtGui.framework. Yes, it’s our old friend Qt, the cross-platform C++ library from Trolltech (see here, for more on this).

So what’s the bottom line here? On the Mac, Mono is ideal if you need a powerful, efficient scripting language or want to create command-line tools that are portable to Linux and Windows. But if you’re looking to build great-looking GUI applications which are indistinguishable from native Cocoa apps, then I think we’ve still got some way to go. I’ve heard rumours that a Core Graphics version of System.Drawing.dll may be in the pipeline, but don’t hold your breath…

Enter Cocoa#

If that was all there was to say, things might be a bit depressing. However, let me introduce you to another interesting little open-source project variously called Cocoa#, CocoaSharp or Cocoa-Sharp depending on which Web site you visit. As the name (possibly!) suggests, Cocoa# is an interface between the world of Mono and C# on the one hand, and Apple’s Objective-C Cocoa framework on the other. The idea is that, with Cocoa#, C# developers get access to the rich functionality contained in the Cocoa libraries. More importantly, it means that Mono applications on the Mac automatically get the native look and feel that Mac users expect.

In effect, Cocoa# is a Mono/C# binding for Cocoa. You can find more (but not much more) here. This suggests that Cocoa# is included with recent distributions of Mono, which it is – sort of – but the source code isn’t included and the binary is hidden away here:

/Library/Frameworks/Mono.framework/Versions/1.2.2.1/lib/mono/cocoa-sharp/

In any event, the included binary is old. A better bet is to go in search of the Cocoa Sharp Wiki – go to here and then click the wiki link in the right-hand corner of the Web page. This will provide rather more useful information and give you a download link for the version 0.9.1 source code which – again – is old. I couldn’t even get it to compile on my machine.

Fortunately, I was rescued by Todd Schavey, who told me that a more recent version of the source is available via SVN at svn://svn.myrealbox.com/source/trunk/cocoa-sharp/ [this is a subversion (SVN) URL that you'll probably only find useful if you have an SVN client installed, which can use it to download the Cocoa Sharp source - Ed]. With his help, I was able to successfully build the Cocoa# assembly and even run some of the sample applications that are included. As far as we can tell, the current version is 0.9.4. Figure 3 shows the CocoaDoc sample, written in C#, running on my Intel iMac.

Shows the CocoaDoc sample

Cocoa# works by exploiting the fact that Cocoa messages are essentially procedural at the level of the runtime library. In other words, regular messages map to a call to a runtime routine called objc_msgSend, “super” messages (to the immediate ancestor class) get mapped to a call to objc_msgSendSuper and so on. In both cases, the first implicit, hidden argument is a reference to ‘self’, just like the C++ or Delphi runtime models. If you want to see some really hairy C# code, download the Cocoa# sources and take a look inside the src/interop directory. Guaranteed to make your brain hurt!

Slightly higher up the food-chain, here’s a little snippet from the SavePanel.cs file, which is part of the glue code providing access to Cocoa’s NSSavePanel class:

public bool CanSelectHiddenExtension 
{
        get
     {
        return (bool) ObjCMessaging.objc_msgSend  (NativeObject,
 "canSelectHiddenExtension", typeof (bool));
        }
        set
     {
        ObjCMessaging.objc_msgSend (NativeObject,
 "setCanSelectHiddenExtension:", 
 typeof (void), typeof (bool), value);
        }
}

On the positive side – joy of joys! – the Cocoa# implementation gives ‘real’ properties rather than having to faff around with two distinct accessor methods. On the negative side, it seems that nobody wants to spend their lives writing reams of glue code like that shown above – activity on this project is currently quite low. That’s a real shame since, in my opinion, of the various Mono initiatives around, Cocoa# offers the best hope for coming up with applications that be aesthetically acceptable to the notoriously finicky Mac community!

While pondering all this stuff, I realised that it ought to be possible to come up with a tool for automating the generation of much of this glue code. There’s a popular developer’s utility called class-dump, which is able to peel apart a Cocoa framework or application, showing the names of all the classes contained therein, as well as the signature of each Cocoa message. I suspect that using something like class-dump, it ought to be possible to take much of the grunt-work out of creating the glue code. However, when suggesting this recently in the appropriate Apple mailing list, I was told it had been tried before without success. If at first you don’t succeed…

Conclusions

Arguably, I’ve been a bit unfair here. The real stomping ground of Mono is undoubtedly Linux and – to a lesser extent – the Win32 platform. That’s apparently where most of the development effort is being expended these days.

As far as OS X is concerned, I fear that Mono is stuck between a rock and a hard place. On the one hand, Cocoa-heads see no compelling reason to embrace a new and alien language while Mac purists (end users, in particular) will have no interest whatsoever in running strange-looking applications which won’t work until they’ve started the X11 server. On the other hand, Linux devotees aren’t particularly fond of OS X, partly because it’s a proprietary closed-source (in part) platform. Furthermore, any efforts expended in terms of building a more feature-complete implementation of Cocoa# would, in a sense, be wasted effort from a portability point of view since Cocoa is obviously only available on the Mac. What’s the point in writing your application using an ECMA certified, platform-neutral language when all you’re doing is making calls to a proprietary, platform-specific toolkit? Sounds a bit daft, doesn’t it?

As regards the other issues I’ve raised, I expect some pundit will be along soon to assure me that if I just added a couple of lines of gobbledegook to this config file, changed a few environment variables here, and altered file permissions there, then it would be possible to get Mono running without X11. Great, and when my Auntie can do that blindfolded, Mono will be ready for the masses. For what it’s worth, I love both C# and Mono, but in terms of how/where they fit into Mac development, I think it’s time to step back and re-evaluate where we’re going.

Further reading on Mono can be found here.