Today was a learning day for me. The subject? MSBuild. I was familiar with the basics and have used nAnt for a while now, but now that Mimeo’s getting ready to transition to VS 2005 + Team Foundation Build we really want to know what we’re going to have to do to migrate our existing scripts.
The number one thing to get your head around is Items and their Metadata. Read this and then read it again immediately. That link also links to this page about well-known Item Metadata which is important to understand. Items are like structs. Items usually represent assets imported into MSBuild from the file system. This could be source files for a compilation task or some binaries that you’re moving around as part of a deployment. One thing to be careful not to fall into the easy trap of thinking that Items only represent assests on the file system though… they don’t. Despite that documentation you just read show absolutely no examples of anything but creating Items from the filesystem, you can create an Item out of thin air with any set of Metadata you want. I think the confusion around this stems from the fact that you have to specify a value for Include. Turns Include really just isn’t a great name. The value for Include doesn’t have to be a file system path at all. For example this is a perfectly valid Item:
Include, when it’s not a path, basically becomes the unique identity of the Item. You can check this yourself via that well-known metadata I mentioned before like so:
<Message Text=“%(Person.Identity)” />
Technically this translates into something in the lower layers of MSBuild called an ItemSpec. Confusing as hell I know, but if you want to really leverage the power of MSBuild you have to use Items and Metadata to communicate between tasks. One last thing about Items that you have to wrap your head around is addressing them and their metadata in different ways.
MSBuild also has properties, but properties are really only there to represent scalar values. You can nest XML in them too which is pretty neat. The XML can even be filled in by more properties which MSBuild will expand. The XML is passed to Task implementations as a string and the task is then responsible for parsing it. The neat part about this though is it’s a nice way to pass structured data to a task for configuration.
For anyone coming from nAnt, the one thing you’ll miss the most is functions… there are none. Everything has to be done with Tasks. You’ll also likely be used to a expanded library of tasks that have been built up around nAnt over the past couple of years. There is a set of community tasks available already that mirrors a lot of the stuff that nAnt and the nAnt-contrib project offer. Unfortunately my first experience with their XmlRead task left a lot to desire. It really doesn’t do a good job working within the rich realm of MSBuild at all. So, also as part of my learning today, I spent some time writing my own XmlSelectNodes task and will be putting together a post with the details on that shortly.
Finally, I did stumble across a bug that I have reported. If you have a single quote anywhere in a path that your Including using the recursive directory feature, the RecursiveDir metadata will not work. This had me ripping my hair out for at least thirty minutes wondering if I totally misunderstood the concept. Then I tried a simple example in a path without a single quote and it just worked. :