In 24 hours I installed Ubuntu, downloaded the latest version of mono, fixed a bug in it and submitted a pull request – the whole process was really simple and I want to let everybody else know how simple it is so they might be inspired to do the same.
In the beginning
I took the decision this week to join the growing number of .NET developers who choose to run Linux, not for any ideological reasons in particular – but just to experience this side of the fence for the first time in a few years, catch up on what has changed and to get my code working over here in Mono.
To that end, I installed Ubuntu 10.04, installed VirtualBox with Windows 7 and Visual Studio, and then proceeded to start building my existing projects in mono to see how they fared. The great thing about Ubuntu is that it comes with Mono, and I haven’t got to do anything to kick-start this process. (Ooh, flame bait here)
My process for building my .NET projects is simply to execute the solution file with xbuild like so
I started with my .NET 2.0 projects, and all but my largest work project built and executed on the version of Mono that ships with Ubuntu 10.04 (the current LTS) – that’s Mono 2.4 – this crashed the C# compiler in a number of places and therefore did not work.
In an effort to get this working I upgraded to Ubuntu 10.10 which gave me Mono 2.6.7, which fared better but still fell over in a number of other slightly different places.
I then decided to upgrade to 2.8, and found somebody who had set up a script to install a parallel version of Mono (without overwriting the system version – rather important for me as I was interested in not breaking my system through ignorance). This had the effect of getting my big failing work .NET 3.5 work project to build (On top of NH, SolrNet, Moq, MySQL, ASP.NET MVC etc – the usual suspects).
Great, now for RavenDB
RavenDB is always going to be an interesting one, it is written in C#4 on top of .NET 4.0 and uses a lot of the latest features in these technologies, the C#4 compiler hasn’t a hope of dealing with this, not even in 2.8 – and falls over with some fairly hairy messages.
There is no technical reason why RavenDB should not work on Linux, and I’m not starting my Mono experience trying to fix C# compiler issues – so I pop into my Windows Virtual Box and do a RavenDB build in Visual Studio via the standard build scripts.
The server is a massive piece of kit, and in the 2.8 environment I set up typing something like this
Resulted in the square root of diddly squat occuring, asking mono to give me a verbose trace of what occurred with
This left me with a large trace and none the wiser about what really went wrong. Back to basics then, eating an elephant and all that.Running the bare minimum for RavenDB, specifying in-memory so we’re definitely using the managed storage engine (not esent), and not even having manage the file aspect of this problem. I build this in MonoDevelop and run it under 2.8.
This falls over with the useful error:
This is clearly a bug in ThreadLocal<T>, and it is at this point I stop and take stock of the situation I find myself in
Let me tell you, option #1 is looking really appealing right now, I am not a Linux user and have survived this far into the process by being a dumb person clicking on buttons in Ubuntu and things somehow “just working” (Parallel Mono 2.8 environment included in that).
After consultation on Twitter, I am assured that the Mono team are friendly and that I’ll get plenty of help on IRC if I need it. I decide to take the plunge and go for Option #2.
Running bleeding edge monoOkay, I didn’t ask that, but what I did ask was
I felt like an idiot for asking such an RTFM-answerable question, but thankfully as promised I got a friendly response pointing me to
Not only two very good links (I’d not have found the first, I’m only now using the term “Parallel Mono Environments”) because I now know that’s what you call them, I also received good solid warnings about doing the right things in the right order to ensure that I built Mono to a secondary location and didn’t overwrite my Ubuntu version.
By following these two sets of instructions, it_just_worked, the process went something like this
There, I now have the latest version of mono and by typing
At any time, whatever I run using mono will use this version of mono! I must admit, I messed it up at first and forgot the PROFILE=net_4_0 bit that I need if I want .NET 4 (which I do), and then I pasted the above script for setting up the mono git environment wrong and missed out the first two characters (oops), but on figuring out that it just worked!
The best thing about this, in order to get whatever everybody has been working on lately, I just doThis is so exciting guys, I am literally dancing in my chair at the prospect of writing and modifying the mono class libraries this effortlessly.
Isolating the bug
This traces every method called during the process of executing my test project and gives me a giant file containing that information, I had to look up a vim cheatsheet for navigating and searching/paging through this mess.
This didn’t really give me a lot of information beyond the error I got when running it the first time, but it did give me a history of calls made and a complete stack trace at the point of crashing.
This led me to the following method in RavenDB
Mmm, tasty - I know that the exception occurs when trying to access the .Value property of the ThreadLocal<ISomeInterface>, so I start with the first instance of it and write a test programThere we go, in Windows on the MS implementation of .NET, Value returns null if not initialized, and on Mono it throws an exception because it can’t find a default constructor for IPointlessActions (Well of course not, it’s an interface!)
Verifying that it is a bug
Back to #mono on irc.gimp.net, I paste the above code example into pastebin, and link to the documentation for the class on MSDN.
We agree that it is probably a bug, and I get helpful feedback on where to start if I want to stand a chance of getting anything pulled into Mono (It’s a really trivial issue, and probably a really trivial fix, not worth the effort of pulling/merging anyway), I’m also advised to add a bugzilla for it on the mono site because that makes it easier to do changelogs.
This is all information that they’ve no doubt had to divulge numerous times to complete novices like myself, and I’m not getting a single snide remark or passive aggressive behaviour – very refreshing!
Fixing the bug
I add a bugzilla, and open two files in vim side by side, they are
The first thing to do is write a test demonstrating the failing behaviour
I can then run the test by typing
make run-test FIXTURE=System.Threading.ThreadLocalTests PROFILE=net_4_0
On verifying the fail, I make the fix (passing in () => default(X) in the default constructor or something to that end), run the test again and push it up to github withand make a pull request which I link to from bugzilla, my work here is done!
I do a build with
And re-run the in memory application, success – it works! I then check basic persistenceThis runs with no problems, now I can continue writing tests that expose more and more of RavenDB until I am happy it is functioning as expected.
A direction for this
I have no timeline for the above, I'm deliberately saving the hardest till last - and I strongly suspect I'll be relying on others taking up the strain where I struggle there, but I've heard good things about turnaround times on compiler bugs so I'm not worried about that
With the support I've seen from the mono community I've contacted so far, I don't have any doubt that this can be made to work as it should, great stuff
2020 © Rob Ashton. ALL Rights Reserved.