Chris and I spent time in
MSBuild-land this week to better automate some of our work.
In the past, I've been a big fan of NMAKE, which makes me a bit of an odd duck at Microsoft where most projects use build.exe to do their builds.
I tried to get the zen of build.exe in my head when I started at the firm, but like many, I fell into the standard "copy a build configuration from an existing project" habit which really rubs me the wrong way. I'm one of those "I need to understand what I'm doing" people, and I was never able to attain the same level of understanding I had with NMAKE.
My day job now involves automating builds using MSBuild. I, like many people, made the mistake of diving into the extensibility model (ITask) first, rather than groking the build workflow first. After hitting my head against a few walls, I finally got my MSBuild understanding over the bar that I believe I have written my last MAKEFILE.
In fact, I just wrote what I hope to be my last makefile here as the tutorial I always wanted. Here it is:
INTERMEDIATEFILE=f2.txt
all : t1 t2
clean :
del /f f3.txt f4.txt
t1 : f3.txt
t2 : f4.txt
f3.txt : f1.txt
copy /y f1.txt $(INTERMEDIATEFILE)
copy /y $(INTERMEDIATEFILE) f3.txt
del /f $(INTERMEDIATEFILE)
f4.txt : f1.txt
copy /y f1.txt f4.txt
And here's the corresponding MSBuild project file that accomplishes the same task:
<Target Name="all" DependsOnTargets="t1;t2" />
<Target Name="clean" >
<Delete Files="f3.txt;f4.txt" />
</Target>
<Target Name="t1" Inputs="f1.txt" Outputs="f3.txt" >
<Copy SourceFiles="f1.txt" DestinationFiles="@(IntermediateFile)" />
<Copy SourceFiles="@(IntermediateFile)" DestinationFiles="f3.txt" />
<Delete Files="@(IntermediateFile)" />
</Target>
<Target Name="t2" Inputs="f1.txt" Outputs="f4.txt" >
<Copy SourceFiles="f1.txt" DestinationFiles="f4.txt" />
</Target>
</Project>
Yes, it's more verbose, but this one has the following advantages:
I get intellisense in my favorite XML editor.
I can load it up as a project in VS and have it do something reasonable. Not great, but reasonable.
I can process and generate the project metadata as XML using my favorite XML programming system.
I can host the workflow engine that interprets that metadata from any .NET program.
MSBUILD.exe is part of the redist for the .NET Framework, NMAKE isn't.
As for point #2, if I were expecting VS users to load my project file (and I do), I'd have authored it like this:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="all">
<ItemGroup>
<IntermediateFile Include="f2.txt" >
<InProject>false</InProject>
</IntermediateFile>
<InputFile Include="f1.txt" />
</ItemGroup>
<Target Name="all" DependsOnTargets="t1;t2" />
<Target Name="clean">
<Delete Files="f3.txt;f4.txt" />
</Target> <Target Name="rebuild" DependsOnTargets="clean;all" />
<Target Name="t1" Inputs="@(InputFile)" Outputs="f3.txt">
<Copy SourceFiles="@(InputFile)" DestinationFiles="@(IntermediateFile)" />
<Copy SourceFiles="@(IntermediateFile)" DestinationFiles="f3.txt" />
<Delete Files="@(IntermediateFile)" />
</Target>
<Target Name="t2" Inputs="@(InputFile)" Outputs="f4.txt">
<Copy SourceFiles="@(InputFile)" DestinationFiles="f4.txt" />
</Target>
</Project>
Note that I used the <InProject> element to suppress the intermediate file f2.txt from showing up in solution explorer. I just wanted it as a variable, not as part of catalog of the input to my project.
Also, I added an item for my input file, which I do want to show up in solution explorer. For hygiene reasons, I used the Item variable in the actual targets.
Finally, I added a named target called "rebuild." VS has three common commands that invoke msbuild against different targets. Here's how it works:
Selecting Clean Solution or Clean ProjectName in VS will build the target named Clean.
Selecting Rebuild Solution or Rebuild ProjectName in VS will build the target named Rebuild.
Selecting
Build Solution or
Build ProjectName in VS will build "default targets" which is either the first target in the project file or (when present) the semi-colon delimited list of targets in the
Project/@DefaultTargets attribute.
Posted
Jul 18 2005, 03:57 AM
by
don-box