I should have opened the archives before I took them home. I don't have OpenOffice installed at home (and downloading it via my modem is no fun), so I couldn't read the docs that come as Word documents over the weekend.
In the meantime, Steve has had a first look at the docs as well. I agree with most of his points, but disagree on the target dependencies.
In Ant (and I think NAnt as well) targets depend on other targets, period. You declare the dependencies between targets and (N)Ant sorts out which targets to run in which order if you ask it to execute one.
In traditional make, you create files and those files depend on other files and you have rules that tell make how to build files from files. make will sort out which files to build when you tell it your "target" file. If your "target" cannot be expressed as a file, you need ".PHONY" targets, something that is the normal mode of operation in Ant.
This difference is one of the major stumbling blocks for people used to make when they come to Ant. All dependencies in Ant are "phony" and the file timestamp level dependencies are resolved by the tasks themselves. Ant doesn't avoid to run the target containing your compilation tasks by checking timestamps, it leaves this up to the <javac> task which looks at the timestamps.
Ant's model is more powerful1 as it allows tasks to perform smarter dependency checking that just looking at file timestamps. Like <zip> looking into the archive or <cc> parsing header files to calculate dependencies.
At the same time, it requires users to write a new task when all they need is a file-timestamp-checking on top of a target that performs a couple of operations. This is why we invented <apply> and <uptodate>. The former adds file dependency checking to <exec>, the latter sets a property that can be used in <target>'s if/unless attributes.
MSBuild supports both notions of dependencies. <Target> has a DependsOnTargets attribute that can be used in the way Ant's depends attribute works. In addition <Target> can specify its required inputs and the generated outputs. The inputs and outputs can be used by MSBuild to calculate the inter-target dependencies.
I'm not sure what happens when you use both dependency mechanisms together. It may lead to strange situations where the implicit dependencies and the ones stated explicitly in DependsOnTargets contradict each other.
Where Ant puts the burden of dependency checking onto the task writer, MSBuild does that in its core. Ant offers the functionality via utility classes, but the task writer still has to write the code herself.
MSBuild's model does not preclude smarter dependency checking in tasks (this is where I disagree with Steve), but it buries it under the more traditional make like dependency mechanism. I wonder whether for example the compilation tasks perform any file timestamp comparisons at all, the docs are not clear, but from my reading of the walk-through, I'd say they don't. In "Add dependency analysis to 301" they avoid recompilation in CSC by adding Inputs/Outputs to the Target containing the Task.
Supporting both types of dependencies inside MSBuild may be confusing to users. In the end I'd guess only one will survive and the other mechanism will become more or less unused. As it is probably easier to write a task without task-internal dependency checking, this may lead to "dumber" tasks than their (N)Ant counterparts.
If you wanted to write a Zip task that adds all files to an archive that are not already part of it (or are newer than the files inside of the archive) without making the task perform the tests, you'll end up with an incredibly complex dependency engine in the MSBuild core, though. Looking at the file name transformations that they already have to support now (prepend a directory, change the extension, ...), this is asking for trouble IMHO.
path: /en/dotNet/msbuild | #