Evaluating build tools for altdotmono.org - part two

Three days ago I thought about which build tool to use for the altdotmono.org projects. I came up with the conclusion, that CMake, SCons and Autotools should be on my short list.

First a small correction: I wrote, that Rant doesn't have any native CSharp support. That's not true! It has a CSharp generator, that can be used as simple as this:

import 'csharp'
gen CSharp, "example.dll", :sources => sys["**/*.cs"]

Unfortunately it doesn't work very well. Simply adding a reference makes it fail:

gen CSharp, "example.dll", :sources => sys["**/*.cs"],
                           :libs    => ["System.Web"]

rant: [ERROR] in file `/usr/lib/ruby/1.8/rant/rantlib.rb', line 577: 
              in prerequisites: no such file or task: `System.Web'

This should be easy to fix in Rant, I just added a bug report. Sadly Rant doesn't seem to be very popular. There has been no commit within a year, only ten bug reports within 3 years and although Rant is packaged in Debian, not a single package in Lenny uses Rant as a build tool. (But I should also add, that not more than six packages build-depend on Rake compared to more than 100 packages depending on CMake and more then 50 packages depending on SCons.)

Rake is much more popular but misses some features, that Rant provides (e.g. MD5 checksums instead of timestamps for dependency checking). I haven't really considered Rake yet, because I couldn't find any project using it for building C#/Mono projects. But after playing around with SCons and CMake I didn't had the feeling of having found the right tool, so I tried Rake anyway.

I wrote a custom TaskLib supporting gmcs within half an hour, so that my Rakefile for building two libs now looks like this:

require 'rake'
require 'rake/gmcs'

task :default => ['StructureMap.dll', 'StructureMap.AutoMocking.dll']

signingKey = 'structuremap.snk'

# The Core StructureMap Assembly
sources    = FileList['StructureMap/**/*.cs']
references = ['System.Web', 'System.Configuration']

Rake::GmcsTask.new 'StructureMap.dll' => {:sources => sources,
  :references => references, :keyfile => signingKey}

# StructureMap Rhino.Mocks automocking support
sources    = FileList['StructureMap.AutoMocking/**/*.cs']
references = ['#../../Rhino.Mocks.dll', '#StructureMap.dll']

Rake::GmcsTask.new 'StructureMap.AutoMocking.dll' => {:sources => sources,
  :references => references, :keyfile => signingKey}

This comes pretty close to what I would like to have. The Gmcs task basically reads:

"Build StructureMap from the list of sources, linking to the list of references and sign it with the signingKey."

GmcsTask will create a Rake file task and will automatically make it pre-depend on the sources, the local references and the key file. This means, that StructureMape.Automocking.dll will only be built. if the timestamp of the sources, of StructureMap.dll, RhinoMocks.dll or the key file change. Because I can't make a dependency to a reference called "System.Web", I needed a way to specify which references are local file dependencies and which are not. This is simply done by prefixing the reference with '#', something I saw in the SCons build files of Diva.

I think this is pretty easy and it can probably be made even easier by writing a Visual Studio *.csproj-Parser, which extracts the sources, references and resources from the project files. And by even adding a solution parser, the whole build of multiple projects might be stripped down to something like:

task :default => SolutionParser.new('StructureMap.sln').ProjectTasks

"Easy Peasy" as Jamie Oliver would say. I'm not sure if it is a good idea to completely rely on the Visual Studio solution and project files, but I think I will try to drive the Rake approach for building the Alltdotmono projects a little bit further.

Published on 27/09/2008 at 12:35 by , tags , , , ,

Searching for the holy grail of build systems

For my new OpenSource project "altdotnet.org", which is about making OSS from the Microsoft .NET world available to Linux/Mono, I have to decide now, which build system to use. There's a bunch of build tools to be considered: NAnt, Autotools, CMake, SCons, Waf, Rant, Rake, Waf.

While NAnt is more or less the only tool, which may already be used by the original author in the Microsoft .NET world, it's not simply portable to Linux/Mono. Often NAnt is just used to simply run msbuild on the project files or solutions. But the msbuild counterpart on Mono isn't very actively maintained and doesn't support VisualStudio 2008 yet. Besides this NAnt is too much XML for my taste.

Autotools seems to be the preferred approach on Linux. A quick scan for *.dll's in the Debian project showed, that most of these packages use Autotools for building Mono libs and applications. When I asked someone from the Debian Mono packaging project, how to package something using Nant, he also advised me, to go with a plain Makefile and Autotools instead. Monodevelop can create the required Autotools files and takes cares of all the dirty details, so this is not so hard to get going. But I'm not a big Autotools fan. I love it as a user, when ./configure and make just work out of the box, but as a Maintainer I hate Autotools, because I never fully understood, how everything really works inside.

CMake and the Python based SCons offer an alternative to the Autotools. Both don't really come with any native support for C#/Mono, but can easily be used for this. CMake is used within the KDE bindings to build Mono libs and a quick search for Scons brought up at least two projects (Diva and DCSharp) using it for building Mono applications. So there is plenty of sample code available to getting started with. While CMake uses it's own macro language and SCons is plain Python, the learning curve for CMake is probably a little bit steeper. But while looking at the above mentioned samples, I could understand most of the CMake and SCons code out of the box, so this probably isn't much of an issue.

Waf is an SCons spin-off, but it isn't available on Debian yet and I couldn't find any projects targeting Mono, that use Waf.

The ruby based build tools Rant and Rake don't have any native support for building Mono applications as well. While Rant surely is a nice tool, it seems to suffer from a lack of support. Upstream development seems to be stalled. There hasn't been a single commit in over a year. The Rake development seems to be much more active, so I would probably prefer this. Besides this I've already used Rake for small C++ toy projects and of course for Ruby projects, so I'm kinda familiar with it. But there doesn't seem to be any projects (besides IronRuby) that decided to use Rake, so I would more or less have to build everything from ground up.

There are also other interesting build tools out there (like e.g. the Boo Build System, formerly known as "Boobs"), which I simply haven't considered, just because of their low popularity. As a Debian maintainer I prefer a "grown up" and well supported build system, which is already included in the Distribution and surely other distribution maintainers do so as well. So to make distribution packaging as easy as possible, I'll stick with one of the major build tools.

Currently CMake, SCons and Autotools are on the shortlist. If I haven't missed any cool "Off Broadway" tools, it will be one of these. I'll probably give CMake and SCons a try and then decide, if one of them works well enough for my needs to avoid Autotools.

Published on 24/09/2008 at 09:56 by , tags , , , , , , , ,

The Microsoft .NET C# compiler has it's issues as well

While working on porting StructureMap to Mono I stumbled across some bugs in the Mono C# compiler. I did expected this, fixed or worked around the bugs and reported them. What I didn't expected, was to find some trivial bugs in Microsoft's C# compiler as well. It's nothing critical, but annoying. Consider this code:

using System;

namespace Test
    public class BuggyClass
        private string foo = String.Empty;
        private int _bar = 5;
        private int _wrongBar = 5;

        public int Bar
            get { return _bar; }
            set { _wrongBar = value; }

        public void DoSomething()
            string msg = "foo" + 1.ToString();

It contains three variables and fields which are never used, so I would expect the compiler to emit three warnings. But csc does nothing - in none of three different versions:

c:\tmp\--->C:\WINDOWS\Microsoft.NET\Framework\v3.5\csc.exe /warn:4 /target:library test.cs 
Microsoft (R) Visual C# 2008 Compiler Version 3.5.30729.1
, fr Microsoft (R) .NET Framework Version 3.5
Copyright (C) Microsoft Corporation. Alle Rechte vorbehalten.

c:\tmp\--->C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\csc.exe /warn:4 /target:library test.cs 
Microsoft (R) Visual C# 2005, Compilerversion 8.00.50727.3053
fr Microsoft (R) Windows (R) 2005 Framework, Version 2.0.50727
Copyright (C) Microsoft Corporation 2001-2005. Alle Rechte vorbehalten.

c:\tmp\--->C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\csc.exe /warn:4 /target:library test.cs 
Microsoft (R) Visual C# .NET-Compilerversion 7.10.6001.4
fr Microsoft (R) .NET Framework, Version 1.1.4322
Copyright (C) Microsoft Corporation 2001-2002. Alle Rechte vorbehalten.

This point goes to the Mono C# compiler, for correctly identifying these warnings:

c:\tmp\--->C:\Programme\Mono-1.9.1\lib\mono\1.0\mcs.exe /warn:4 /target:library test.cs 
test.cs(19,20): warning CS0219: The variable `msg' is assigned but its value is never used
test.cs(7,24): warning CS0169: The private field `Test.BuggyClass.foo' is assigned but its value is never used
test.cs(9,21): warning CS0169: The private field `Test.BuggyClass._wrongBar' is assigned but its value is never used
Compilation succeeded - 3 warning(s)

You might say, that this is just a trivial warning and usually it doesn't hurt to have some unused variables around. But look at the Bar property above. It sets a different value than the one it returns. Looks like a serious bug to me - maybe caused by wrongly renaming the field. If this isn't covered by a unit test and the compiler doesn't even give a warning, chances are good, that this bug will find it's way into production code.

I've also reported this to Microsoft's Bug Nirvana BugTracker (FeedbackID 362970).

Published on 22/08/2008 at 13:28 by , tags , , ,

Doing .NET the "hard" way

One of my favorite tools for .NET development is the dependency injection framework StructureMap from Jeremy D. Miller. It's free and it's Open Source, but it's only available in the Windows world. Compared to Castle Windsor, StructureMap is much more lightweight and compact, but with the recent enhancements in the upcoming release just as powerful.

So I thought, it couldn't be so hard, to make StructureMap work with Mono and package it for Debian, but actually, it's not THAT easy.

The heavy usage of .NET 3.5 features, like lambdas, requires a recent development version of Mono. Took me 2-3 hours to have Mono and Monodevelop compiled from SVN and installed in parallel to my old Mono packages to /opt/mono. But that's working fine now.

The StructureMap VS2008 solution loads fine in Monodevelop, which makes life a lot easier. The only 3'rd party-dependency that StructureMap has, is Rhino.Mocks (another of my favorite development tools). The Rhino.Mocks assembly seems to work with Mono, but compiling it from source is probably much harder, because of it's dependency to DynamicProxy, so I decided to leave that by side for now, skip StructureMap.Automocking and concentrate on the core parts of StructureMap.

After working about a week on this, I already found three bugs in the Mono C# compiler, but the good news is, that StructureMap now compiles fine with some small patches (that Jeremy hopefully will include in the upcoming release).

Luckily, StructureMap is very well covered with unit tests, which makes testing it on Mono much easier. The state of affairs is, that most of the tests go green. I have about 70 failures within more then 600 tests and I'm pretty confident, that I can solve the remaining issues as well.

Published on 21/08/2008 at 01:19 by , tags , , , , ,

Powered by Publify | Photo Startup stock photos