MSBuild or NAnt?

For the last 4 years or so I have been involved, either directly or indirectly, with creating standardized build systems that run on the Microsoft platform. Before that I was actually a Unix admin and developer and was very proficient in writing makefiles. When I first got involved in build systems for the Microsoft platform, it seemed like there were very few build script technologies available that were worth using. The best one available was the combination of NAnt and NAntContrib.

There are many arguments about why NAnt (and the Java based Ant build tool) were created instead of using the traditional make-like tools. The biggest difference is that the make-like tools are inherently shell-based while NAnt (and Ant) are XML-based. Shell based tools evaluate a set of dependencies and then execute commands, similar to how you would use a command shell. The benefit is that you can easily extend these tools by using or writing a command line tool for your operating system. The drawback is that you start to restrict yourself to specific platforms. As projects become more complex,  makefiles become increasingly difficult to debug and understand.

On the other hand, NAnt is extended using tasks, which are written in C# (or any other .NET language) and compiled into an extension library. This does remove some of the expressiveness in being able to construct a command, but it gives you the ability to be cross-platform (at least to some extent). Since NAnt is XML-based, you specify a target tree which gets executed. Each task is run by an object that implements a particular Task interface.

Over the last 4 years I have become very proficient in writing NAnt build scripts and have implemented some pretty complex build systems using them. When Microsoft first announced MSBuild, I was skeptical and excited at the same time. My initial thoughts were the typical “Why is Microsoft reinventing the wheel?” type thoughts. There was a perfectly good XML-based build script technology in NAnt that was already available, widely used and widely supported. At TechEd that year, I spoke with some of the MSBuild developers and was told that it’s just like NAnt, that if I was familiar with NAnt MSBuild would be just as easy, and that there would be a large community base adding custom tasks just like NAntContrib. To me, the biggest benefit that MSBuild had over NAnt was that it was going to ship as part of the .NET Framework and not Visual Studio or the .NET SDK. That meant that I no longer needed to install a separate build script technology and worry about developers or build servers getting the wrong version.

As I started looking at MSBuild, however, I became increasingly disappointed. While MSBuild is XML-based and is extended using tasks just like NAnt, it still felt like a makefile. It still seemed like there was a lot of “magic” that happened in order for things to work. You still had long lists of files that were used in various parts of the build process. It was better than a makefile at least, since the Visual Studio projects were MSBuild files themselves. That allowed you to compile a project from the command line the same way Visual Studio compiled the project.

At least, that was the theory. In reality, there were still things that happened when Visual Studio compiled a project (or a solution) that MSBuild couldn’t do. There were still properties that controlled how things were built that were set differently and/or set to different values when running under Visual Studio.

Fast forward a few years to the .NET Framework v3.5 release. This release has a new version of MSBuild as well. This is an interesting release. At first glance, it appears that not much has changed. A few new tasks have been added and some new properties were added to existing tasks. However, if you scratch the surface you will see that a lot has actually changed. There are some new project level elements and additional standard item metadata available. Overall, it feels like a much more complete release. There are still things that Visual Studio can do that MSBuild can’t and there are still some control properties that are set differently, but overall you get a much closer build experience between the command line and a Visual Studio build.

I have been working on implementing a new standard build system using MSBuild for the last 2 months and have been very surprised at how easy it has been. There were a few NAnt features that I thought I would miss, mostly the ability to have functions, but ended up finding better ways to do the same thing. There are still some things about MSBuild that I don’t like (the fact that targets will always and only run once with no way to control or change that behavior and that item and property groups declared inside a target are not visible outside of that project file, just to name a couple) but they are mostly minor annoyances that caused me to change how I wanted the build system to work.

Writing custom build tasks for MSBuild is almost as easy as writing them for NAnt. Again, there are a few differences but most of them are pretty minor. In some ways, writing  custom MSBuild tasks is actually easier since you don’t have to remember to add attributes to everything so it’s visible from within the build script. The logging mechanism could be a bit more flexible, but other than that I don’t really have many complaints.

After spending some time working with MSBuild and really becoming familiar with what it can (and can’t) do, I have been impressed and have actually shifted to being an MSBuild proponent. If you are already familiar with NAnt it does take a little bit of learning to become comfortable with how MSBuild does things as compared to NAnt, but once you get past the initial “strangeness” of declaring property and item groups you will be just as comfortable in MSBuild as you were in NAnt. If MSBuild is your first exposure to XML-based build script technologies, you shouldn’t have any problems. I like the direction MSBuild appears to be heading and I know that the development team is actively working on adding new features and getting feedback from the community.