Daniel Cazzulino: Bite-sized reusable MSBuild targets, properties and tasks
I’m a long-time MSBuild fan. Now that it’s open source,
I’ve even played with bootstrapping it with xbuild
to use it even on Mac. It works like a charm, for the most part 🙂
I’ve always wished I could just reuse fragments of MSBuild targets that are
generic enough to fit in lots of projects. Things like determining whether
we’re being built with XBuild or MSBuild,
determining the location of Git,
or the particular assembly location for a CodeTaskAssembly
(which isn’t exactly trivial).
Those kinds of things are probably a few lines of XML that could even be
distributed via NuGet.
And so I started doing just that for my own stuff, and thus MSBuilder
was born. It is sort of like NetFx
but for MSBuild rather than .NET code. It may still suffer from that project’s Achilles heel
though, namely, discoverability. But with any luck, the extremely low barrier of entry for
contributors, plus the almost real-time pull-request building and subsequent nuget publishing,
thanks to a paid super-responsive AppVeyor-based
CI system, will make it useful enough to gain traction. Time will tell.
In the meantime, I’ve already added a few very useful MSBuilder blocks already:
MSBuilder.DumpItems
One of my most frequently used ones is surely MSBuilder.DumpItems.
Whenever I’m tweaking MSBuild targets, especially if they are the built-in ones in either
MSBuild/CSharp itself, or WiX, I more often than not want to inspect what various item groups
contain at certain points, as well as potentially useful item metadata I might want to use
for my task at hand.
For example, say you want to do something interesting with project references
that requires you to know precisely what’s going on in the built-in targets after project
and assembly references are resolved. You can just create a console app, install the package
install-package MSBuilder.DumpItems
and edit the .csproj to dump items on AfterBuild for inspection of the items built by one
of the many targets involving ResolveReferences,
such as the _ResolvedProjectReferencePaths which
looks kinda interesting:
<Target Name="AfterBuild">
<DumpItems Items="@(_ResolvedProjectReferencePaths)" />
</Target>
And you get a full dump of all those items and their metadata, right in the Visual Studio
output window, such as:
2>AfterBuild:
2> Item: C:DeleteConsoleApplication13srcConsoleApplication1ClassLibrary1binDebugClassLibrary1.dll
2> AccessedTime=2015-07-19 01:18:52.2170776
2> BuildReference=true
2> Configuration=Debug
2> CreatedTime=2015-07-19 01:16:15.3999053
2> DefiningProjectDirectory=C:Program Files (x86)MSBuild12.0bin
2> DefiningProjectExtension=.targets
2> DefiningProjectFullPath=C:Program Files (x86)MSBuild12.0binMicrosoft.Common.CurrentVersion.targets
2> DefiningProjectName=Microsoft.Common.CurrentVersion
2> Directory=DeleteConsoleApplication13srcConsoleApplication1ClassLibrary1binDebug
2> Extension=.dll
2> Filename=ClassLibrary1
2> FullConfiguration=Debug|AnyCPU
2> FullPath=C:DeleteConsoleApplication13srcConsoleApplication1ClassLibrary1binDebugClassLibrary1.dll
2> Identity=C:DeleteConsoleApplication13srcConsoleApplication1ClassLibrary1binDebugClassLibrary1.dll
2> ModifiedTime=2015-07-19 01:18:52.2070760
2> MSBuildSourceProjectFile=C:DeleteConsoleApplication13srcConsoleApplication1ClassLibrary1ClassLibrary1.csproj
2> MSBuildSourceTargetName=GetTargetPath
2> Name=ClassLibrary1
2> OriginalItemSpec=..ClassLibrary1ClassLibrary1.csproj
2> OriginalProjectReferenceItemSpec=..ClassLibrary1ClassLibrary1.csproj
2> OutputItemType=
2> Platform=AnyCPU
2> Project={e9288a56-aa1b-4127-97c5-7b3a6d487d63}
2> RecursiveDir=
2> ReferenceOutputAssembly=true
2> ReferenceSourceTarget=ProjectReference
2> RelativeDir=C:DeleteConsoleApplication13srcConsoleApplication1ClassLibrary1binDebug
2> RootDir=C:
2> SetConfiguration=Configuration=Debug
2> SetPlatform=Platform=AnyCPU
2> Targets=
2>
2>Build succeeded.
As I come across more useful bits of MSBuild that
are generic enough that deserve becoming MSBuilder blocks, I’ll surely publish them, so stay tunned.
Enjoy!